{"id":50720060,"url":"https://github.com/jaichangpark/flutter_rhwp","last_synced_at":"2026-06-09T23:01:32.619Z","repository":{"id":360029507,"uuid":"1248042071","full_name":"JAICHANGPARK/flutter_rhwp","owner":"JAICHANGPARK","description":"flutter_rhwp ","archived":false,"fork":false,"pushed_at":"2026-06-01T11:28:23.000Z","size":7733,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-01T11:28:42.835Z","etag":null,"topics":["rhwp"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/flutter_rhwp","language":"Dart","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/JAICHANGPARK.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-24T05:33:28.000Z","updated_at":"2026-06-01T11:28:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/JAICHANGPARK/flutter_rhwp","commit_stats":null,"previous_names":["jaichangpark/flutter_rhwp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JAICHANGPARK/flutter_rhwp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JAICHANGPARK%2Fflutter_rhwp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JAICHANGPARK%2Fflutter_rhwp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JAICHANGPARK%2Fflutter_rhwp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JAICHANGPARK%2Fflutter_rhwp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JAICHANGPARK","download_url":"https://codeload.github.com/JAICHANGPARK/flutter_rhwp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JAICHANGPARK%2Fflutter_rhwp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34129072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"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":["rhwp"],"created_at":"2026-06-09T23:01:30.579Z","updated_at":"2026-06-09T23:01:32.607Z","avatar_url":"https://github.com/JAICHANGPARK.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flutter_rhwp\n\nFlutter plugin for reading, viewing, editing, saving, and exporting HWP/HWPX\ndocuments.\n\n- Repository: [JAICHANGPARK/flutter_rhwp](https://github.com/JAICHANGPARK/flutter_rhwp)\n- Rust core: [edwardkim/rhwp](https://github.com/edwardkim/rhwp), vendored at\n  `rust/vendor/rhwp`\n- Bridge: `flutter_rust_bridge` v2\n- Version: `2026.6.6`\n\n## Features\n\n- Open HWP/HWPX bytes.\n- Render pages as SVG.\n- Extract text and Markdown.\n- Export HWP, HWPX, PDF, DOCX, text, Markdown, and page SVG.\n- Use `RhwpViewer` for Flutter-native viewing.\n- Use `RhwpFullEditor` for the upstream Web editor UI.\n- Use `RhwpNativeEditor` for the Flutter widget editor track.\n- Evaluate table formulas from the Flutter-native table ribbon or the Dart API.\n- Format selected table-cell numbers with thousands separators and decimal\n  place increase/decrease actions.\n- Create, configure, and remove table captions from the Flutter-native table\n  properties dialog or Dart table-properties API.\n- Create, configure, and remove picture captions from the Flutter-native object\n  properties dialog or Dart object-properties API.\n- Rotate and flip selected shape/picture objects from the Flutter-native object\n  properties dialog or Dart object-properties API.\n- Manage bookmarks from the Flutter-native input ribbon or the Dart API.\n- Insert hyperlinks and hidden comments in body text or active table-cell text\n  from the Flutter-native input ribbon or the Dart API.\n- Read, edit, and delete hidden comments in body text or active table-cell text\n  from the Flutter-native input ribbon or the Dart API.\n- Edit hyperlink URLs and display text from the Flutter-native tools ribbon or\n  the Dart API.\n- Manage HWP fields/누름틀 values from the Flutter-native tools ribbon or the\n  Dart API.\n- Inspect and remove field markers, including ClickHere and hyperlink fields,\n  while preserving their visible text.\n- Inspect, edit ClickHere field properties, and remove field markers at the\n  Flutter-native caret through the tools ribbon or Dart API.\n- Convert distribution/read-only documents to editable mode when\n  `RhwpNativeEditor` loads, matching the upstream Web editor path.\n- Apply HWP page hide flags from the Flutter-native page ribbon or Dart API.\n- List and delete HWP header/footer controls from the Flutter-native page\n  ribbon or Dart API.\n- Split and merge paragraphs inside active table cells from the Flutter-native\n  editor with Enter, Backspace, and Delete.\n- Keep native-editor typing, IME composing, caret, and selection overlays\n  separate from the rendered SVG page surface to reduce refresh churn on large\n  documents.\n- `holdTextRefreshWhileFocused` is enabled by default so Space/text input stays\n  in the Flutter overlay through transient desktop focus/IME churn until focus\n  moves outside the editor.\n- Use `RhwpCommandEditor` for the earlier command-editor compatibility name.\n\n## Installation\n\nUntil this package is published, add it from GitHub:\n\n```yaml\ndependencies:\n  flutter_rhwp:\n    git:\n      url: https://github.com/JAICHANGPARK/flutter_rhwp.git\n      ref: main\n```\n\nThen run:\n\n```sh\nflutter pub get\n```\n\nRequirements:\n\n- Flutter `\u003e=3.35.0`\n- Windows full editor: Microsoft WebView2 runtime\n- Linux full editor: WebKitGTK 4.1\n- Sandboxed macOS full editor with remote `@rhwp/editor`: outgoing network\n  client entitlement\n\n## Documentation\n\n- [API spec](docs/API_SPEC.md): editor callbacks, toolbar command mapping, and\n  save/export contracts.\n- [Native editor parity](docs/NATIVE_EDITOR_PARITY.md): upstream Web editor\n  menu coverage versus the Flutter-native editor.\n- [Roadmap](docs/ROADMAP.md) and [TODO](docs/TODO.md): remaining native editor,\n  export, platform, and release work.\n\n## Quick Start\n\n```dart\nimport 'dart:io';\n\nimport 'package:flutter_rhwp/flutter_rhwp.dart';\n\nfinal bytes = await File('sample.hwp').readAsBytes();\nfinal document = await Rhwp.open(bytes, fileName: 'sample.hwp');\n\nfinal pageCount = await document.pageCount;\nfinal firstPageSvg = await document.renderPageSvg(0);\nfinal text = await document.extractText();\nfinal exportedPdf = await document.exportDocument(RhwpExportFormat.pdf);\n\nawait document.close();\n```\n\n## Usage\n\nViewer:\n\n```dart\nRhwpViewer(document: document)\n```\n\nFull editor:\n\n```dart\nfinal controller = RhwpFullEditorController();\n\nRhwpFullEditor(\n  controller: controller,\n  initialBytes: bytes,\n  fileName: 'sample.hwp',\n);\n\nfinal editedHwp = await controller.exportHwp();\n```\n\nFlutter-native editor:\n\n```dart\nRhwpNativeEditor(\n  document: document,\n  convertToEditableOnLoad: true,\n  editRefreshDelay: const Duration(milliseconds: 1200),\n  onDirtyChanged: updateUnsavedIndicator,\n  onUnsavedChanges: confirmUnsavedChanges,\n  onNewRequested: createBlankDocument,\n  onOpenRequested: pickAndOpenDocument,\n  onCloseRequested: closeDocument,\n  onImageRequested: pickImageForEditor,\n  onExported: saveExportedDocument,\n  onPrintRequested: printPdfDocument,\n)\n```\n\nEdit with Rust bridge commands:\n\n```dart\nawait document.insertText(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  text: 'Hello',\n);\n\nawait document.applyParaFormatRange(\n  section: 0,\n  startParagraph: 0,\n  endParagraph: 2,\n  alignment: 'center',\n);\n\nawait document.insertTable(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  rows: 2,\n  columns: 3,\n);\n\nawait document.createTableEx(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  rows: 2,\n  columns: 2,\n  treatAsChar: true,\n  columnWidths: const [2000, 2100],\n);\n\nawait document.insertTableRow(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  row: 0,\n);\n\nawait document.insertPicture(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  imageData: imageBytes,\n  width: 15000,\n  height: 10000,\n  naturalWidthPx: 200,\n  naturalHeightPx: 133,\n  extension: 'png',\n);\n\nawait document.insertShape(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  shapeType: 'rectangle',\n);\n\nawait document.addBookmark(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  name: 'intro',\n);\n\nawait document.insertHyperlink(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  url: 'https://example.com',\n  text: 'Example',\n);\n\nawait document.updateHyperlink(\n  fieldId: 1,\n  url: 'https://updated.example',\n  text: 'Updated link',\n);\n\nfinal cellLink = await document.fieldInfoAtInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 1,\n  cellParagraph: 0,\n  offset: 0,\n);\nif (cellLink.inField \u0026\u0026 cellLink.fieldType == 'hyperlink') {\n  await document.updateHyperlink(\n    fieldId: cellLink.fieldId!,\n    url: 'https://cell-updated.example',\n    text: 'Updated cell link',\n  );\n}\n\nawait document.insertHiddenComment(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n  text: '검토 의견',\n);\n\nawait document.insertHyperlinkInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 1,\n  cellParagraph: 0,\n  offset: 0,\n  url: 'https://example.com',\n  text: 'Cell link',\n);\n\nawait document.insertHiddenCommentInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 1,\n  cellParagraph: 0,\n  offset: 0,\n  text: '셀 검토 의견',\n);\n\nfinal cellComment = await document.hiddenCommentAtInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 1,\n  cellParagraph: 0,\n  offset: 0,\n);\nif (cellComment.hit) {\n  await document.updateHiddenCommentAtInTableCell(\n    section: 0,\n    paragraph: 0,\n    controlIndex: 0,\n    cellIndex: 1,\n    cellParagraph: 0,\n    offset: 0,\n    text: '셀 수정 의견',\n  );\n}\n\nawait document.deleteHiddenCommentAtInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 1,\n  cellParagraph: 0,\n  offset: 0,\n);\n\nfinal comment = await document.hiddenCommentAt(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n);\nif (comment.hit) {\n  await document.updateHiddenCommentAt(\n    section: 0,\n    paragraph: 0,\n    offset: 0,\n    text: '수정 의견',\n  );\n}\n\nawait document.deleteHiddenCommentAt(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n);\n\nfinal bookmarks = await document.bookmarks();\nfinal bookmarkPage = await document.pageOfPosition(\n  section: bookmarks.first.section,\n  paragraph: bookmarks.first.paragraph,\n);\n\nfinal fields = await document.fields();\nawait document.setFieldValue(fieldId: fields.first.fieldId, value: 'Updated');\n\nfinal fieldInfo = await document.fieldInfoAt(\n  section: 0,\n  paragraph: 0,\n  offset: 0,\n);\nif (fieldInfo.inField \u0026\u0026 fieldInfo.fieldId != null) {\n  final props = await document.clickHereProperties(fieldInfo.fieldId!);\n  await document.updateClickHereProperties(\n    fieldId: fieldInfo.fieldId!,\n    guide: props.guide,\n    memo: props.memo,\n    name: props.name,\n    editable: props.editable,\n  );\n}\n\nawait document.createHeader(section: 0);\nawait document.createFooter(section: 0);\n\nfinal snapshotId = await document.saveSnapshot();\nawait document.restoreSnapshot(snapshotId);\n\nawait document.mergeTableCells(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  startRow: 0,\n  startColumn: 0,\n  endRow: 1,\n  endColumn: 1,\n);\n\nawait document.splitTableCellInto(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  row: 0,\n  column: 0,\n  rows: 2,\n  columns: 2,\n);\n\nawait document.splitTableCellsInRange(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  startRow: 0,\n  startColumn: 0,\n  endRow: 1,\n  endColumn: 1,\n  rows: 2,\n  columns: 2,\n  equalRowHeight: true,\n);\n\nawait document.resizeTableCells(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  updates: const [\n    RhwpTableCellResize(cellIndex: 0, widthDelta: 120),\n    RhwpTableCellResize(cellIndex: 1, heightDelta: -80),\n  ],\n);\n\nawait document.evaluateTableFormula(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  row: 1,\n  column: 0,\n  formula: '=SUM(A1:B1)',\n);\n\nawait document.splitParagraphInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 0,\n  cellParagraph: 0,\n  offset: 2,\n);\n\nawait document.mergeParagraphInTableCell(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 0,\n  cellParagraph: 1,\n);\n\nawait document.moveTableOffset(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  deltaH: 120,\n  deltaV: -60,\n);\n\nawait document.deleteTableControl(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n);\n\nawait document.setTableProperties(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellSpacing: 10,\n  paddingLeft: 100,\n  paddingRight: 100,\n  paddingTop: 80,\n  paddingBottom: 80,\n  pageBreak: 1,\n  repeatHeader: true,\n);\n\nawait document.setCellProperties(\n  section: 0,\n  paragraph: 0,\n  controlIndex: 0,\n  cellIndex: 0,\n  width: 6000,\n  height: 3200,\n  paddingLeft: 120,\n  paddingRight: 120,\n  paddingTop: 80,\n  paddingBottom: 80,\n  verticalAlign: 1,\n  isHeader: true,\n);\n\nfinal html = await document.exportSelectionHtml(\n  section: 0,\n  startParagraph: 0,\n  startOffset: 0,\n  endParagraph: 0,\n  endOffset: 5,\n);\n\nawait document.pasteHtml(\n  section: 0,\n  paragraph: 0,\n  offset: 5,\n  html: html,\n);\n```\n\nExport with save metadata:\n\n```dart\nfinal exported = await document.exportDocument(\n  RhwpExportFormat.pdf,\n  sourceFileName: 'sample.hwp',\n);\n\n// exported.bytes\n// exported.fileName\n// exported.mimeType\n```\n\n## Example\n\n```sh\ncd example\nflutter run -d macos\n```\n\nThe example can open the bundled HWP asset or a picked HWP/HWPX file, then\nexport HWP/HWPX/PDF/DOCX/TXT/MD/SVG.\n\n## Notes\n\n- `RhwpFullEditor` uses upstream `@rhwp/editor`.\n- On Web it embeds the editor directly.\n- On Android, iOS, macOS, Windows, and Linux it uses `webview_all`.\n- Initial full-editor file loading uses `editor.loadFile(data, fileName)`.\n- `RhwpNativeEditor` is the 100% Flutter widget editor path and currently\n  includes an HWP-style Flutter ribbon toolbar, page viewport, page-layer caret\n  hit testing, blinking caret/drag-selection overlay, keyboard caret movement\n  including\n  double-click word selection, triple-click paragraph selection, Shift+click\n  selection extension, page-layer geometry based ArrowUp/ArrowDown,\n  PageUp/PageDown, and Home/End,\n  plus Ctrl/Cmd+Home/End, Ctrl/Option word navigation, and Ctrl/Option word\n  delete, IME\n  composing preview, context menus, HWP/HWPX/PDF quick export callbacks and a\n  DOCX/Text/Markdown/current-page SVG export menu from the file ribbon,\n  app-level Print callback with PDF artifacts, Ctrl/Cmd+S HWP save,\n  Ctrl/Cmd+Shift+S HWPX save, Ctrl/Cmd+P Print when `onPrintRequested` is\n  supplied or PDF export fallback otherwise, app-level file new/open/close\n  callbacks with Ctrl/Cmd+N/O/W shortcuts and document information from the file\n  ribbon, page navigation controls,\n  direct go-to-page from the view ribbon and\n  Ctrl/Cmd+G, scroll-tracked current page reporting and previous/next page\n  controls in the status bar, page setup from the page ribbon and F7,\n  transparent table border overlays,\n  synchronized view/status zoom controls with explicit fit-width and fit-page\n  commands and preset menus using the upstream web editor's 25%, 50%, 75%,\n  100%, 125%, 150%, 200%, and 300% steps, Ctrl/Cmd zoom shortcuts,\n  Ctrl/Cmd+mouse-wheel zoom, Escape state clearing, text commit, select-all,\n  copy/cut/paste with same-editor HTML clipboard import/export for body text\n  and single selected table cells, Enter paragraph splitting,\n  Shift+Enter soft line breaks,\n  Backspace/Delete paragraph-boundary merging,\n  Tab text insertion, multiline clipboard paste as paragraph insertion,\n  multi-paragraph selection\n  replacement, multi-paragraph selected-text bold/italic/underline/strike\n  formatting, inline font family, font size field and stepper with\n  Ctrl/Cmd+Shift+Period/Comma shortcuts, text color,\n  text background,\n  toggleable Bold/Italic/Underline/Strike, superscript, subscript, emboss, and\n  engrave controls with Ctrl/Cmd+Shift+X and Ctrl/Cmd+Period/Comma shortcuts,\n  inline paragraph alignment, indent with Ctrl/Cmd+BracketLeft/BracketRight\n  shortcuts, and line spacing with Ctrl/Cmd+1/2/5 shortcuts\n  controls, a character shape\n  dialog with `Alt+L` shortcut support for font family, font size, text color,\n  text background,\n  superscript, subscript, emboss, and engrave, preloaded from the current\n  caret character shape,\n  collapsed-selection pending character\n  formatting for the next inserted body text, caret character-shape sync for\n  the format ribbon, caret paragraph alignment/line-spacing sync for the\n  format ribbon, paragraph alignment commands and line-spacing presets,\n  Ctrl/Cmd+L/E/R/J alignment shortcuts, a paragraph\n  shape dialog that preloads the current caret paragraph's line spacing,\n  indent, and paragraph margins with `Alt+T` shortcut support, style picker\n  command with F6 shortcut support, header/footer\n  creation from the page ribbon,\n  header/footer list and deletion from the page ribbon,\n  page hide flags for header, footer, master page, border, fill, and page\n  number,\n  snapshot-backed undo/redo from the edit ribbon with continuous text-input\n  undo batching, layer-tree text search with\n  Ctrl/Cmd+F focus and search-text selection, Ctrl/Cmd+H replace-field focus,\n  F3/Shift+F3 and search-field\n  Enter/Shift+Enter result navigation, debounced live search field input,\n  search-field Escape clearing, result highlighting, active-match replace,\n  replace-all, table-cell find/replace, and a tools-ribbon compare dialog\n  backed by text extraction, field list/value/property/remove actions from the\n  tools ribbon and body/table-cell context menus, and basic\n  text/table/picture/shape\n  insert/delete from the ribbon and body context menu, with shape presets for\n  rectangle, ellipse, line, and text box,\n  footnote, equation, and bookmark insertion from the input ribbon and body\n  context menu, footnote/equation/bookmark insertion with\n  Ctrl/Cmd+Alt+F/E/B shortcuts,\n  table insertion with Ctrl/Cmd+Alt+T shortcut,\n  picture insertion with Ctrl/Cmd+Alt+I shortcut,\n  shape preset insertion with Ctrl/Cmd+Alt+R/O/L/X shortcuts,\n  bookmark list/add/delete/rename/go-to navigation through the input ribbon,\n  page/column break and new-number insertion, plus table\n  row above/below insertion and row deletion, column left/right insertion and\n  column deletion, and cell\n  merge/split/split-into-grid/range split command flow, selected-cell range\n  resize through rhwp table resize commands, inline extended table insertion\n  with optional column widths, table formula evaluation, table properties\n  editing, and\n  selected-cell properties, fill, border, and vertical alignment editing from\n  the ribbon and context menu with table-cell hit testing, selected-cell\n  highlighting, object/control hit testing, highlighting, pointer drag move and\n  resize handles for selected non-table objects, dedicated table-object\n  movement through rhwp table offset commands, Delete/Backspace table-control\n  deletion, Delete/Backspace object deletion, object size/position properties,\n  rotation/flip properties, picture caption settings, and object z-order\n  actions from the edit ribbon and context menu,\n  scroll-preserving page refresh after edits, and drag range\n  selection and Shift+click range extension for rendered table cells, plus\n  selected-cell\n  text insert/delete/clear/copy/cut/paste, tab/newline multi-cell paste,\n  active-cell paragraph split/merge with Enter, Backspace, and Delete,\n  cell text offset hit testing, Arrow/Tab/Enter keyboard handling for selected\n  table cells, F5 selected-cell edit entry, Esc return from active cell text\n  editing to cell selection and from cell selection to table-object selection,\n  Enter/F5 table-object re-entry to cell selection, Arrow/Shift+Arrow object\n  nudging, and Shift+drag\n  aspect-ratio preserving object resize. Insert/Overwrite input mode toggles\n  with the Insert key, and overwrite typing replaces body and active table cell\n  text through Rust delete/insert commands. Text input, paste, tab input, and\n  keyboard delete\n  defer page SVG refresh so normal typing does not reload the rendered page\n  after every keystroke. Text-input commits stay in a Flutter overlay while the\n  editor still has focus, even if `TextInputAction.done` or connection-close\n  events arrive; `editRefreshDelay` starts only after the active input session\n  is released. For large desktop documents, `holdTextRefreshWhileFocused` keeps\n  Space/text commits in the Flutter overlay through transient focus/IME churn\n  and delays external-focus release while desktop text input settles, then\n  releases the deferred page refresh when focus moves outside the editor. Rapid\n  input commits are queued while previous edit commands finish.\n  Committed text is shown through a\n  temporary Flutter overlay with a pending caret until the refreshed page render\n  completes, including table cell text input. Set\n  `holdTextRefreshWhileFocused: false` only when an app needs eager SVG sync\n  while the editor still has focus. Deleted body text is temporarily\n  masked until the refreshed page render completes. The example app uses a 5 s\n  refresh delay for a steadier typing feel on large HWP files and defers HWP\n  snapshot export until the user saves/exports or switches from the native\n  editor to the full editor.\n  `onDirtyChanged` reports when Rust-backed edit commands make the document\n  unsaved and when HWP/HWPX save callbacks complete. The same state is exposed\n  as `RhwpEditorController.dirty`, and apps can call\n  `RhwpEditorController.markClean()` after host-driven saves or discards.\n  The native editor status bar shows a modified indicator while this dirty\n  state is active. `onUnsavedChanges` lets the host app show a save/discard\n  guard before native-editor New/Open/Close file actions proceed.\n  Dirty means the in-memory document has changed since the last accepted\n  HWP/HWPX save or explicit discard.\n  File-ribbon New/Open/Close and Ctrl/Cmd+N/O/W call app-provided callbacks,\n  so platform-specific document creation, picking, and close/discard prompts\n  stay in the host app.\n  Pending text previews are updated through a scoped overlay notifier, so\n  normal typing updates the caret/text preview without rebuilding the whole\n  native editor surface. Viewer controller notifications are scoped so cursor\n  updates during typing do not rebuild the page viewport unless zoom changes.\n  The status bar reports dirty state, body cursor, active table cell,\n  and selected object context. The view ribbon also includes a paragraph mark toggle\n  that paints paragraph-end markers from page layer tree text runs. Documents\n  are converted to editable mode on load by default, matching upstream\n  `convertToEditable`; set `convertToEditableOnLoad: false` only when preserving\n  an original distribution/read-only state is required.\n- `rust/vendor/rhwp` should be committed. `rust/target` should stay ignored.\n\n## Documentation\n\n- [Roadmap](docs/ROADMAP.md)\n- [TODO](docs/TODO.md)\n- [API spec](docs/API_SPEC.md)\n- [Changelog](CHANGELOG.md)\n\n## License\n\nMIT. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for bundled source and\ndependency notices.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaichangpark%2Fflutter_rhwp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaichangpark%2Fflutter_rhwp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaichangpark%2Fflutter_rhwp/lists"}