Skip to content

feat: unify popup customization in React and Vue - #785

Open
jedrazb wants to merge 5 commits into
mainfrom
feat/771-dialog-customization
Open

feat: unify popup customization in React and Vue#785
jedrazb wants to merge 5 commits into
mainfrom
feat/771-dialog-customization

Conversation

@jedrazb

@jedrazb jedrazb commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Customize editor popups

Pass popups to the editor or Root. Use definePopup(MyPopup) to supply
an ordinary React component or Vue single-file component. The editor opens it
and supplies its typed props. Forward those props to the default component to
retain its state, validation, and commands.

Replace a button

These examples replace Apply in Page Setup. You do not need to manage its
opening state or create a session.

React

import { DocxEditor, definePopup } from "@docx-editor.dev/react";
import type {
  DocxEditorPageSetupDialogProps,
  DocxEditorPopups,
} from "@docx-editor.dev/react";
import "@docx-editor.dev/core/styles/editor.css";

function PageSetup(props: DocxEditorPageSetupDialogProps) {
  return (
    <DocxEditor.PageSetupDialog {...props}>
      <DocxEditor.PageSetupDialog.Apply asChild>
        <button className="app-apply">Apply changes</button>
      </DocxEditor.PageSetupDialog.Apply>
    </DocxEditor.PageSetupDialog>
  );
}

const popups: DocxEditorPopups = { pageSetup: definePopup(PageSetup) };

export function Editor({ document }: { document: ArrayBuffer }) {
  return <DocxEditor document={document} popups={popups} />;
}

Vue

Create PageSetup.vue:

<script setup lang="ts">
import { DocxEditorPageSetupDialog as Dialog } from "@docx-editor.dev/vue";
import type { DocxEditorPageSetupDialogProps } from "@docx-editor.dev/vue";

const props = withDefaults(defineProps<DocxEditorPageSetupDialogProps>(), {
  preset: true,
});
const Apply = Dialog.Apply;
</script>

<template>
  <Dialog v-bind="props">
    <Apply as-child>
      <button class="app-apply">Apply changes</button>
    </Apply>
  </Dialog>
</template>

Keep preset: true when forwarding Vue props; omitted Boolean props otherwise
become false. Register the component in your editor:

<script setup lang="ts">
import { DocxEditor, definePopup } from "@docx-editor.dev/vue";
import type { DocxEditorPopups } from "@docx-editor.dev/vue";
import PageSetup from "./PageSetup.vue";
import "@docx-editor.dev/core/styles/editor.css";

defineProps<{ document: ArrayBuffer }>();
const popups: DocxEditorPopups = { pageSetup: definePopup(PageSetup) };
</script>

<template>
  <DocxEditor :document="document" :popups="popups" />
</template>

Custom button components must forward refs, attributes, and listeners to their
native button. Preserve the supplied handler and disabled state.

Render callbacks also work: pageSetup: (props) => <PageSetup {...props} /> in
React, or pageSetup: (props) => h(PageSetup, props) in Vue. Call hooks inside
components, not render callbacks.

Choose a popup

Each entry accepts a definePopup() result, render callback, or false.
Props match the surface; dialogs, menus, and value widgets retain distinct contracts.

Entry Supplied props
pageSetup, paragraph Controlled dialog props: open, onClose
textFormField { session: TextFormFieldDialogSession }
hyperlink HyperLinkProps
contentControl ContentControlProps
equation No state props
contextMenu DocxEditorContextMenuProps
imageProperties DocxEditorImagePropertiesDialogProps
imageAltText DocxEditorImageAltTextPopupProps
noteProperties DocxEditorNotePropertiesDialogProps
notesContextMenu DocxEditorNotesContextMenuProps
notePreview DocxEditorNotePreviewProps
contentControlWidget { session: ContentControlWidgetSession }
invalidTextFormField { session: InvalidTextFormFieldSession }

Omitted entries retain existing behavior, including native widget and invalid-field
dialogs. The packaged editor supplies defaults. Root mounts configured surfaces;
image and note overrides use their existing triggers. Explicit entries override
menu.onPageSetup, hyperlinkPopup, and contextMenu shortcuts.

For manual ownership, use false and mount the surface yourself. You then own its
trigger and visibility. Ordinary component customization does not need this option.
Toolbar menus and pickers use their existing compound .Content parts, outside this map.

Arrange parts and custom fields

Page Setup, Paragraph Options, and Field Options expose Header, Title, Body,
Footer, Apply, Cancel, Error, and typed Field parts. Parts accept
className, style, hidden, and asChild. Other popups retain their existing parts.

Named children replace default parts. Use hidden to remove a part or
preset={false} to supply the complete arrangement. Include a title, error region,
and accessible Apply and Cancel controls. Omitted fields retain their draft values.

Page Setup's pageSize part is its size selector. Paragraph's tabStops part
contains the collection control; specialBy appears when relevant.

For custom value controls, call usePageSetupDialog(), useParagraphDialog(), or
useTextFormFieldDialog() inside a child of the matching dialog. Each supplies
values, setValue(name, value), errors, isEnabled, apply(), and cancel().
Vue exposes state as refs. Use these draft APIs instead of creating another form session.

A Field represents the labeled row; asChild does not adapt input value events.
Page Setup dimensions use twips: 1,440 per inch. Paragraph also exposes mixed-selection state.
See React hooks or
Vue composables for types.

See the customization guide for styling, accessibility, and full examples.

Fixes #771.

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docx-editor Ready Ready Preview Sep 8, 2026 3:54pm UTC

Request Review

@eigenpal-release-pal

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅

Posted by the CLA bot.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Performance benchmark

Typing latency (browser)

Scenario Base frame Head frame Δ Frame p95 Input p95
521pp-editing-character 59.85 ms 76.05 ms ⚪ +27.1% 89.30 ms 0.10 ms
521pp-editing-wrap 65.45 ms 64.75 ms ⚪ -1.1% 76.95 ms 0.10 ms
521pp-suggesting-character 104.40 ms 110.05 ms ⚪ +5.4% 136.25 ms 0.10 ms
editing-character 57.70 ms 53.80 ms ⚪ -6.8% 58.60 ms 0.15 ms
editing-wrap 46.35 ms 51.45 ms ⚪ +11.0% 60.00 ms 0.10 ms
suggesting-character 99.80 ms 104.80 ms ⚪ +5.0% 121.30 ms 0.10 ms
suggesting-wrap 84.40 ms 104.05 ms 🔴 +23.3% ⚠️ 112.55 ms 0.15 ms
tracked-editing-character 31.65 ms 31.70 ms ⚪ +0.2% 34.00 ms 0.10 ms
tracked-suggesting-character 51.10 ms 52.50 ms ⚪ +2.7% 64.25 ms 0.10 ms
tracked-suggesting-wrap 54.55 ms 58.15 ms ⚪ +6.6% 67.55 ms 0.10 ms
huge-open-to-ready 5845.50 ms 6018.50 ms ⚪ +3.0% 6018.50 ms 6018.50 ms
huge-suggesting-character 116.00 ms 107.10 ms ⚪ -7.7% 133.25 ms 0.10 ms
huge-suggesting-wrap 124.55 ms 139.50 ms ⚪ +12.0% 154.05 ms 0.15 ms
huge-paste-50k 398.55 ms 377.15 ms ⚪ -5.4% 540.85 ms 0.10 ms

Engine layout (headless)

Scenario Base median Head median Δ Head p95
steady-middle-text 22.76 ms 29.20 ms ⚪ +28.3% 35.32 ms
wrap-middle-text 23.95 ms 27.96 ms ⚪ +16.8% 33.32 ms
forced-middle-reflow 22.79 ms 34.63 ms ⚪ +52.0% 41.42 ms
forced-early-reflow 28.16 ms 33.55 ms ⚪ +19.1% 37.30 ms
enter-split-middle 26.97 ms 31.64 ms ⚪ +17.3% 36.98 ms
backspace-join-middle 25.80 ms 22.58 ms ⚪ -12.5% 24.22 ms
enter-split-early 25.83 ms 22.62 ms ⚪ -12.4% 32.41 ms
page-break-middle 21.96 ms 23.53 ms ⚪ +7.2% 26.53 ms
How to read these tables
  • Base: the main commit this PR builds on. Head: this PR.
  • Median: the typical sample. p95: 95 of 100 samples were faster than this.
  • Browser table: frame is the time from the keystroke until the edit is
    visible on screen — the number a typing user feels. Input p95 is how long
    the keystroke handler blocked the page (typing buffers its work off the input
    task, so this stays near zero by design).
  • 521pp-* rows run the pinned 521-page reproduction; the other rows run the
    small synthetic fixtures that exist for deterministic work-counter gates.
  • Δ: 🟢 faster, 🔴 slower, ⚪ inside the noise. Each side runs interleaved
    rounds; a delta smaller than the run-to-run spread renders neutral.
  • Work counters: exact counts of layout work (paragraphs placed, pages
    reused, full passes). They are deterministic: a change means different
    behavior, not just different speed.

Work counters: unchanged.

Head report (full JSON)
{
  "schema": 1,
  "fixture": "/home/runner/_work/docx-editor/docx-editor/e2e/fixtures/synthetic-long-edit.docx",
  "fixtureBytes": 27897,
  "fixtureSha256": "ca8ee28a8d40ae7914a820303b96ddbbe8f06d37325b0fc2ae6f1140aea96321",
  "environment": {
    "runtime": "Bun 1.4.2",
    "arch": "x64"
  },
  "config": {
    "runs": 3,
    "warmup": 2,
    "measurer": "fixed(6px,14px)"
  },
  "scenarios": [
    {
      "name": "steady-middle-text",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 28.42068100000006,
        "p95Ms": 41.84817900000007,
        "minMs": 25.103927000000112,
        "maxMs": 41.84817900000007
      },
      "layout": {
        "medianMs": 5.828435999999783,
        "p95Ms": 6.881011999999828,
        "minMs": 5.509298000000399,
        "maxMs": 6.881011999999828
      },
      "total": {
        "medianMs": 35.30169299999989,
        "p95Ms": 47.676614999999856,
        "minMs": 30.61322500000051,
        "maxMs": 47.676614999999856
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "wrap-middle-text",
      "target": {
        "paragraphIndex": 1599,
        "paragraphId": "/word/document.xml#0.0.1599"
      },
      "transaction": {
        "medianMs": 34.23644399999921,
        "p95Ms": 34.36717000000044,
        "minMs": 24.37949899999967,
        "maxMs": 34.36717000000044
      },
      "layout": {
        "medianMs": 5.117403000000195,
        "p95Ms": 6.058038000000124,
        "minMs": 4.83846899999935,
        "maxMs": 6.058038000000124
      },
      "total": {
        "medianMs": 39.20563899999979,
        "p95Ms": 40.294481999999334,
        "minMs": 29.496901999999864,
        "maxMs": 40.294481999999334
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "forced-middle-reflow",
      "target": {
        "paragraphIndex": 1599,
        "paragraphId": "/word/document.xml#0.0.1599"
      },
      "transaction": {
        "medianMs": 24.807410999999775,
        "p95Ms": 33.90278899999976,
        "minMs": 19.86764199999925,
        "maxMs": 33.90278899999976
      },
      "layout": {
        "medianMs": 4.225298999999723,
        "p95Ms": 6.301244000000224,
        "minMs": 3.974326999999903,
        "maxMs": 6.301244000000224
      },
      "total": {
        "medianMs": 29.032709999999497,
        "p95Ms": 40.20403299999998,
        "minMs": 23.841968999999153,
        "maxMs": 40.20403299999998
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "forced-early-reflow",
      "target": {
        "paragraphIndex": 159,
        "paragraphId": "/word/document.xml#0.0.159"
      },
      "transaction": {
        "medianMs": 19.174581000001126,
        "p95Ms": 20.204664000000776,
        "minMs": 18.46646200000032,
        "maxMs": 20.204664000000776
      },
      "layout": {
        "medianMs": 3.5005479999999807,
        "p95Ms": 3.5773129999997764,
        "minMs": 3.113822999999684,
        "maxMs": 3.5773129999997764
      },
      "total": {
        "medianMs": 22.675129000001107,
        "p95Ms": 23.781977000000552,
        "minMs": 21.580285000000003,
        "maxMs": 23.781977000000552
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 155,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "enter-split-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 16.53765299999941,
        "p95Ms": 17.90092100000038,
        "minMs": 16.310395999998946,
        "maxMs": 17.90092100000038
      },
      "layout": {
        "medianMs": 3.4771049999999377,
        "p95Ms": 3.7280659999996715,
        "minMs": 3.1562430000012682,
        "maxMs": 3.7280659999996715
      },
      "total": {
        "medianMs": 20.014757999999347,
        "p95Ms": 21.628987000000052,
        "minMs": 19.466639000000214,
        "maxMs": 21.628987000000052
      },
      "work": {
        "placed": 14,
        "total": 3201,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3202,
          "evictions": 0,
          "size": 3202
        }
      }
    },
    {
      "name": "backspace-join-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 17.7218699999994,
        "p95Ms": 17.801664999999048,
        "minMs": 17.24024499999905,
        "maxMs": 17.801664999999048
      },
      "layout": {
        "medianMs": 3.6224889999994048,
        "p95Ms": 3.7812560000002122,
        "minMs": 3.3759460000001127,
        "maxMs": 3.7812560000002122
      },
      "total": {
        "medianMs": 21.344358999998803,
        "p95Ms": 21.58292099999926,
        "minMs": 20.616190999999162,
        "maxMs": 21.58292099999926
      },
      "work": {
        "placed": 12,
        "total": 3199,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 11,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "enter-split-early",
      "target": {
        "paragraphIndex": 159,
        "paragraphId": "/word/document.xml#0.0.159"
      },
      "transaction": {
        "medianMs": 22.05128700000023,
        "p95Ms": 30.43555699999888,
        "minMs": 21.623273000001063,
        "maxMs": 30.43555699999888
      },
      "layout": {
        "medianMs": 3.829678000000058,
        "p95Ms": 4.166762000000745,
        "minMs": 3.691478000000643,
        "maxMs": 4.166762000000745
      },
      "total": {
        "medianMs": 26.218049000000974,
        "p95Ms": 34.12703499999952,
        "minMs": 25.45295100000112,
        "maxMs": 34.12703499999952
      },
      "work": {
        "placed": 14,
        "total": 3201,
        "reusedPages": 155,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3202,
          "evictions": 0,
          "size": 3202
        }
      }
    },
    {
      "name": "page-break-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 19.540468000001056,
        "p95Ms": 23.06979300000239,
        "minMs": 18.581185000000914,
        "maxMs": 23.06979300000239
      },
      "layout": {
        "medianMs": 3.8910539999997127,
        "p95Ms": 4.578796999998303,
        "minMs": 3.7776899999989837,
        "maxMs": 4.578796999998303
      },
      "total": {
        "medianMs": 23.31815800000004,
        "p95Ms": 27.648590000000695,
        "minMs": 22.472239000000627,
        "maxMs": 27.648590000000695
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 99,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 205,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    }
  ]
}
Base report (full JSON)
{
  "schema": 1,
  "fixture": "/home/runner/_work/_temp/base/e2e/fixtures/synthetic-long-edit.docx",
  "fixtureBytes": 27897,
  "fixtureSha256": "ca8ee28a8d40ae7914a820303b96ddbbe8f06d37325b0fc2ae6f1140aea96321",
  "environment": {
    "runtime": "Bun 1.4.2",
    "arch": "x64"
  },
  "config": {
    "runs": 3,
    "warmup": 2,
    "measurer": "fixed(6px,14px)"
  },
  "scenarios": [
    {
      "name": "steady-middle-text",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 16.97729000000004,
        "p95Ms": 17.960677000000032,
        "minMs": 16.092227000000094,
        "maxMs": 17.960677000000032
      },
      "layout": {
        "medianMs": 3.8959380000001147,
        "p95Ms": 3.9503409999999803,
        "minMs": 3.7627880000000005,
        "maxMs": 3.9503409999999803
      },
      "total": {
        "medianMs": 20.92763100000002,
        "p95Ms": 21.723465000000033,
        "minMs": 19.98816500000021,
        "maxMs": 21.723465000000033
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "wrap-middle-text",
      "target": {
        "paragraphIndex": 1599,
        "paragraphId": "/word/document.xml#0.0.1599"
      },
      "transaction": {
        "medianMs": 18.056396999999833,
        "p95Ms": 21.162930999999844,
        "minMs": 16.763698000000204,
        "maxMs": 21.162930999999844
      },
      "layout": {
        "medianMs": 3.0271660000003067,
        "p95Ms": 3.94495999999981,
        "minMs": 2.8256179999998494,
        "maxMs": 3.94495999999981
      },
      "total": {
        "medianMs": 22.001356999999643,
        "p95Ms": 24.19009700000015,
        "minMs": 19.589316000000053,
        "maxMs": 24.19009700000015
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "forced-middle-reflow",
      "target": {
        "paragraphIndex": 1599,
        "paragraphId": "/word/document.xml#0.0.1599"
      },
      "transaction": {
        "medianMs": 16.134377000000313,
        "p95Ms": 18.19881499999974,
        "minMs": 16.07936300000074,
        "maxMs": 18.19881499999974
      },
      "layout": {
        "medianMs": 2.9453119999998307,
        "p95Ms": 4.292121999999836,
        "minMs": 2.7158909999998286,
        "maxMs": 4.292121999999836
      },
      "total": {
        "medianMs": 19.02467500000057,
        "p95Ms": 22.490936999999576,
        "minMs": 18.850268000000142,
        "maxMs": 22.490936999999576
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "forced-early-reflow",
      "target": {
        "paragraphIndex": 159,
        "paragraphId": "/word/document.xml#0.0.159"
      },
      "transaction": {
        "medianMs": 23.61433599999964,
        "p95Ms": 31.134211000000505,
        "minMs": 23.456359999999222,
        "maxMs": 31.134211000000505
      },
      "layout": {
        "medianMs": 4.812218999999459,
        "p95Ms": 5.094429999999193,
        "minMs": 4.344309999999496,
        "maxMs": 5.094429999999193
      },
      "total": {
        "medianMs": 28.426554999999098,
        "p95Ms": 36.2286409999997,
        "minMs": 27.800669999998718,
        "maxMs": 36.2286409999997
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 155,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "enter-split-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 18.68022800000108,
        "p95Ms": 24.397768000000724,
        "minMs": 18.043601999999737,
        "maxMs": 24.397768000000724
      },
      "layout": {
        "medianMs": 4.900884999999107,
        "p95Ms": 4.945238000000245,
        "minMs": 3.839600999999675,
        "maxMs": 4.945238000000245
      },
      "total": {
        "medianMs": 23.581113000000187,
        "p95Ms": 29.34300600000097,
        "minMs": 21.883202999999412,
        "maxMs": 29.34300600000097
      },
      "work": {
        "placed": 14,
        "total": 3201,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3202,
          "evictions": 0,
          "size": 3202
        }
      }
    },
    {
      "name": "backspace-join-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 26.984926999999516,
        "p95Ms": 32.05038299999978,
        "minMs": 16.262737000000925,
        "maxMs": 32.05038299999978
      },
      "layout": {
        "medianMs": 3.250195000000531,
        "p95Ms": 3.3381090000002587,
        "minMs": 3.224076000000423,
        "maxMs": 3.3381090000002587
      },
      "total": {
        "medianMs": 30.235122000000047,
        "p95Ms": 35.38849200000004,
        "minMs": 19.486813000001348,
        "maxMs": 35.38849200000004
      },
      "work": {
        "placed": 12,
        "total": 3199,
        "reusedPages": 154,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 11,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    },
    {
      "name": "enter-split-early",
      "target": {
        "paragraphIndex": 159,
        "paragraphId": "/word/document.xml#0.0.159"
      },
      "transaction": {
        "medianMs": 18.450856999999814,
        "p95Ms": 21.631851999998617,
        "minMs": 17.358776000000944,
        "maxMs": 21.631851999998617
      },
      "layout": {
        "medianMs": 3.132092999998349,
        "p95Ms": 3.7182749999992666,
        "minMs": 2.4061899999996967,
        "maxMs": 3.7182749999992666
      },
      "total": {
        "medianMs": 22.16913199999908,
        "p95Ms": 24.763944999996966,
        "minMs": 19.76496600000064,
        "maxMs": 24.763944999996966
      },
      "work": {
        "placed": 14,
        "total": 3201,
        "reusedPages": 155,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 204,
        "cache": {
          "hits": 12,
          "misses": 3202,
          "evictions": 0,
          "size": 3202
        }
      }
    },
    {
      "name": "page-break-middle",
      "target": {
        "paragraphIndex": 1919,
        "paragraphId": "/word/document.xml#0.0.1919"
      },
      "transaction": {
        "medianMs": 17.156134999999267,
        "p95Ms": 17.46863200000007,
        "minMs": 15.802833999998256,
        "maxMs": 17.46863200000007
      },
      "layout": {
        "medianMs": 3.340383999999176,
        "p95Ms": 3.347617999999784,
        "minMs": 2.535160999999789,
        "maxMs": 3.347617999999784
      },
      "total": {
        "medianMs": 20.50375299999905,
        "p95Ms": 20.809015999999247,
        "minMs": 18.337994999998045,
        "maxMs": 20.809015999999247
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 99,
        "fullPasses": 1,
        "pagesBefore": 204,
        "pagesAfter": 205,
        "cache": {
          "hits": 12,
          "misses": 3201,
          "evictions": 0,
          "size": 3201
        }
      }
    }
  ]
}
Browser report (full JSON)
{
  "schema": 1,
  "fixture": "synthetic-long-edit.docx",
  "fixtureSha256": "ca8ee28a8d40ae7914a820303b96ddbbe8f06d37325b0fc2ae6f1140aea96321",
  "environment": {
    "browser": "chromium",
    "browserVersion": "149.0.7827.55",
    "platform": "linux",
    "arch": "x64"
  },
  "config": {
    "runs": 5,
    "warmup": 2,
    "sustainedEdits": 120,
    "reviewRail": true,
    "viewport": "1440x1000@1x",
    "injectedDelayMs": 0
  },
  "scenarios": [
    {
      "name": "521pp-editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.20000000001164153,
        "minMs": 0,
        "maxMs": 0.20000000001164153
      },
      "frame": {
        "medianMs": 96.89999999999418,
        "p95Ms": 115.5,
        "minMs": 75.90000000000873,
        "maxMs": 115.5
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 19.79999999998836,
        "p95Ms": 31.80000000000291,
        "minMs": 14.10000000000582,
        "maxMs": 31.80000000000291
      },
      "paint": {
        "medianMs": 1.7999999999883585,
        "p95Ms": 2,
        "minMs": 1.3999999999941792,
        "maxMs": 2
      },
      "selection": {
        "medianMs": 0.8000000000029104,
        "p95Ms": 0.8999999999941792,
        "minMs": 0.5,
        "maxMs": 0.8999999999941792
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2152,
        "materializedPages": 4,
        "selectionSpans": 743
      }
    },
    {
      "name": "521pp-editing-wrap",
      "mode": "edit",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 79.5,
        "p95Ms": 93.10000000000582,
        "minMs": 66.19999999999709,
        "maxMs": 93.10000000000582
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 15.400000000008731,
        "p95Ms": 23.70000000001164,
        "minMs": 12.599999999991269,
        "maxMs": 23.70000000001164
      },
      "paint": {
        "medianMs": 1.5,
        "p95Ms": 4.80000000000291,
        "minMs": 1.1999999999970896,
        "maxMs": 4.80000000000291
      },
      "selection": {
        "medianMs": 0.6999999999970896,
        "p95Ms": 0.8000000000029104,
        "minMs": 0.6000000000058208,
        "maxMs": 0.8000000000029104
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2172,
        "materializedPages": 4,
        "selectionSpans": 762
      }
    },
    {
      "name": "521pp-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.09999999999126885,
        "minMs": 0,
        "maxMs": 0.09999999999126885
      },
      "frame": {
        "medianMs": 113,
        "p95Ms": 161.6999999999971,
        "minMs": 100.29999999998836,
        "maxMs": 161.6999999999971
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 15.80000000000291,
        "p95Ms": 22.80000000000291,
        "minMs": 11.60000000000582,
        "maxMs": 22.80000000000291
      },
      "paint": {
        "medianMs": 1.3000000000029104,
        "p95Ms": 2.1000000000058208,
        "minMs": 1.0999999999912689,
        "maxMs": 2.1000000000058208
      },
      "selection": {
        "medianMs": 0.7999999999883585,
        "p95Ms": 1.1999999999970896,
        "minMs": 0.6999999999970896,
        "maxMs": 1.1999999999970896
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2154,
        "materializedPages": 4,
        "selectionSpans": 743
      }
    },
    {
      "name": "editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.09999999999126885,
        "p95Ms": 0.19999999999708962,
        "minMs": 0,
        "maxMs": 0.19999999999708962
      },
      "frame": {
        "medianMs": 54.29999999998836,
        "p95Ms": 57.69999999999709,
        "minMs": 53.39999999999418,
        "maxMs": 57.69999999999709
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 3.1000000000058208,
        "p95Ms": 3.8999999999941792,
        "minMs": 2.8000000000029104,
        "maxMs": 3.8999999999941792
      },
      "paint": {
        "medianMs": 3.599999999991269,
        "p95Ms": 3.8999999999941792,
        "minMs": 3.3000000000029104,
        "maxMs": 3.8999999999941792
      },
      "selection": {
        "medianMs": 0.8999999999941792,
        "p95Ms": 1,
        "minMs": 0.8000000000029104,
        "maxMs": 1
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2234,
        "materializedPages": 4,
        "selectionSpans": 1739
      }
    },
    {
      "name": "editing-wrap",
      "mode": "edit",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.09999999999126885,
        "p95Ms": 0.09999999999126885,
        "minMs": 0,
        "maxMs": 0.09999999999126885
      },
      "frame": {
        "medianMs": 54.30000000000291,
        "p95Ms": 65.39999999999418,
        "minMs": 53.39999999999418,
        "maxMs": 65.39999999999418
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.3000000000029104,
        "p95Ms": 3.1999999999970896,
        "minMs": 2.099999999991269,
        "maxMs": 3.1999999999970896
      },
      "paint": {
        "medianMs": 4.2000000000116415,
        "p95Ms": 4.69999999999709,
        "minMs": 3.900000000008731,
        "maxMs": 4.69999999999709
      },
      "selection": {
        "medianMs": 1.1000000000058208,
        "p95Ms": 1.5,
        "minMs": 1,
        "maxMs": 1.5
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2255,
        "materializedPages": 4,
        "selectionSpans": 1759
      }
    },
    {
      "name": "suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.09999999999126885,
        "minMs": 0,
        "maxMs": 0.09999999999126885
      },
      "frame": {
        "medianMs": 114.60000000000582,
        "p95Ms": 133.79999999998836,
        "minMs": 110.90000000000873,
        "maxMs": 133.79999999998836
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 3.5,
        "p95Ms": 4.599999999991269,
        "minMs": 2.099999999991269,
        "maxMs": 4.599999999991269
      },
      "paint": {
        "medianMs": 0.5,
        "p95Ms": 0.6999999999970896,
        "minMs": 0.5,
        "maxMs": 0.6999999999970896
      },
      "selection": {
        "medianMs": 1.1999999999970896,
        "p95Ms": 1.3000000000029104,
        "minMs": 0.8999999999941792,
        "maxMs": 1.3000000000029104
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2234,
        "materializedPages": 4,
        "selectionSpans": 1739
      }
    },
    {
      "name": "suggesting-wrap",
      "mode": "suggest",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.19999999999708962,
        "minMs": 0,
        "maxMs": 0.19999999999708962
      },
      "frame": {
        "medianMs": 114.69999999999709,
        "p95Ms": 123.69999999999709,
        "minMs": 109.19999999999709,
        "maxMs": 123.69999999999709
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.6999999999970896,
        "p95Ms": 3,
        "minMs": 2.3000000000029104,
        "maxMs": 3
      },
      "paint": {
        "medianMs": 0.39999999999417923,
        "p95Ms": 0.6000000000058208,
        "minMs": 0.3000000000029104,
        "maxMs": 0.6000000000058208
      },
      "selection": {
        "medianMs": 1,
        "p95Ms": 1.1000000000058208,
        "minMs": 0.8999999999941792,
        "maxMs": 1.1000000000058208
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2255,
        "materializedPages": 4,
        "selectionSpans": 1759
      }
    },
    {
      "name": "tracked-editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.09999999999126885,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 32,
        "p95Ms": 35.29999999998836,
        "minMs": 31.30000000000291,
        "maxMs": 35.29999999998836
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.400000000008731,
        "p95Ms": 3.1999999999970896,
        "minMs": 2.1000000000058208,
        "maxMs": 3.1999999999970896
      },
      "paint": {
        "medianMs": 2.8999999999941792,
        "p95Ms": 3.2000000000116415,
        "minMs": 2.7000000000116415,
        "maxMs": 3.2000000000116415
      },
      "selection": {
        "medianMs": 0.5,
        "p95Ms": 0.7000000000116415,
        "minMs": 0.39999999999417923,
        "maxMs": 0.7000000000116415
      },
      "work": {
        "placed": 3,
        "total": 620,
        "reusedPages": 151,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2100,
        "materializedPages": 3,
        "selectionSpans": 1741
      }
    },
    {
      "name": "tracked-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 51.10000000000582,
        "p95Ms": 60.39999999999418,
        "minMs": 48,
        "maxMs": 60.39999999999418
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.3999999999941792,
        "p95Ms": 2.5,
        "minMs": 2.1000000000058208,
        "maxMs": 2.5
      },
      "paint": {
        "medianMs": 0.3000000000029104,
        "p95Ms": 0.5,
        "minMs": 0.19999999999708962,
        "maxMs": 0.5
      },
      "selection": {
        "medianMs": 0.6000000000058208,
        "p95Ms": 0.7000000000116415,
        "minMs": 0.39999999999417923,
        "maxMs": 0.7000000000116415
      },
      "work": {
        "placed": 3,
        "total": 620,
        "reusedPages": 151,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2102,
        "materializedPages": 3,
        "selectionSpans": 1741
      }
    },
    {
      "name": "tracked-suggesting-wrap",
      "mode": "suggest",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.09999999999126885,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 51.19999999999709,
        "p95Ms": 53.40000000000873,
        "minMs": 49.30000000000291,
        "maxMs": 53.40000000000873
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.5,
        "p95Ms": 2.8999999999941792,
        "minMs": 2.3999999999941792,
        "maxMs": 2.8999999999941792
      },
      "paint": {
        "medianMs": 0.3000000000029104,
        "p95Ms": 0.3000000000029104,
        "minMs": 0.09999999999126885,
        "maxMs": 0.3000000000029104
      },
      "selection": {
        "medianMs": 0.5999999999912689,
        "p95Ms": 0.6000000000058208,
        "minMs": 0.5,
        "maxMs": 0.6000000000058208
      },
      "work": {
        "placed": 8,
        "total": 620,
        "reusedPages": 150,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2122,
        "materializedPages": 3,
        "selectionSpans": 1760
      }
    },
    {
      "name": "huge-open-to-ready",
      "mode": "edit",
      "textLength": 0,
      "inputTask": {
        "medianMs": 5815,
        "p95Ms": 5815,
        "minMs": 5490,
        "maxMs": 5815
      },
      "frame": {
        "medianMs": 5815,
        "p95Ms": 5815,
        "minMs": 5490,
        "maxMs": 5815
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "paint": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "selection": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "work": {
        "placed": 0,
        "total": 4250,
        "reusedPages": 0,
        "fullPasses": 0,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2504,
        "materializedPages": 2,
        "selectionSpans": 0
      }
    },
    {
      "name": "huge-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 112,
        "p95Ms": 145.80000000001746,
        "minMs": 106.79999999998836,
        "maxMs": 145.80000000001746
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 7.399999999994179,
        "p95Ms": 10.300000000017462,
        "minMs": 6,
        "maxMs": 10.300000000017462
      },
      "paint": {
        "medianMs": 1.1000000000058208,
        "p95Ms": 4.2000000000116415,
        "minMs": 1,
        "maxMs": 4.2000000000116415
      },
      "selection": {
        "medianMs": 1.1000000000058208,
        "p95Ms": 1.2999999999883585,
        "minMs": 0.8999999999941792,
        "m
… truncated …
Browser baseline (full JSON)
{
  "schema": 1,
  "fixture": "synthetic-long-edit.docx",
  "fixtureSha256": "ca8ee28a8d40ae7914a820303b96ddbbe8f06d37325b0fc2ae6f1140aea96321",
  "environment": {
    "browser": "chromium",
    "browserVersion": "149.0.7827.55",
    "platform": "linux",
    "arch": "x64"
  },
  "config": {
    "runs": 5,
    "warmup": 2,
    "sustainedEdits": 120,
    "reviewRail": true,
    "viewport": "1440x1000@1x",
    "injectedDelayMs": 0
  },
  "scenarios": [
    {
      "name": "521pp-editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 63.79999999998836,
        "p95Ms": 67.10000000000582,
        "minMs": 57.60000000000582,
        "maxMs": 67.10000000000582
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 12.699999999982538,
        "p95Ms": 18.199999999982538,
        "minMs": 12.199999999982538,
        "maxMs": 18.199999999982538
      },
      "paint": {
        "medianMs": 1.2000000000116415,
        "p95Ms": 4.099999999976717,
        "minMs": 1.1000000000058208,
        "maxMs": 4.099999999976717
      },
      "selection": {
        "medianMs": 0.5,
        "p95Ms": 0.5999999999767169,
        "minMs": 0.29999999998835847,
        "maxMs": 0.5999999999767169
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2152,
        "materializedPages": 4,
        "selectionSpans": 743
      }
    },
    {
      "name": "521pp-editing-wrap",
      "mode": "edit",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.09999999997671694,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 74,
        "p95Ms": 90.30000000001746,
        "minMs": 68.19999999998254,
        "maxMs": 90.30000000001746
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 14.39999999999418,
        "p95Ms": 17.5,
        "minMs": 13.699999999982538,
        "maxMs": 17.5
      },
      "paint": {
        "medianMs": 1.3000000000174623,
        "p95Ms": 1.7000000000116415,
        "minMs": 1.2999999999883585,
        "maxMs": 1.7000000000116415
      },
      "selection": {
        "medianMs": 0.6999999999825377,
        "p95Ms": 0.9000000000232831,
        "minMs": 0.5999999999767169,
        "maxMs": 0.9000000000232831
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2172,
        "materializedPages": 4,
        "selectionSpans": 762
      }
    },
    {
      "name": "521pp-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 108.79999999998836,
        "p95Ms": 504.3999999999942,
        "minMs": 104,
        "maxMs": 504.3999999999942
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 13.699999999982538,
        "p95Ms": 36.5,
        "minMs": 12.800000000017462,
        "maxMs": 36.5
      },
      "paint": {
        "medianMs": 1.3000000000174623,
        "p95Ms": 1.5,
        "minMs": 1,
        "maxMs": 1.5
      },
      "selection": {
        "medianMs": 0.7000000000116415,
        "p95Ms": 0.8000000000174623,
        "minMs": 0.7000000000116415,
        "maxMs": 0.8000000000174623
      },
      "work": {
        "placed": 11,
        "total": 6540,
        "reusedPages": 517,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2154,
        "materializedPages": 4,
        "selectionSpans": 743
      }
    },
    {
      "name": "editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.09999999997671694,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 52.5,
        "p95Ms": 60.39999999999418,
        "minMs": 48.29999999998836,
        "maxMs": 60.39999999999418
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.6000000000058208,
        "p95Ms": 4.2999999999883585,
        "minMs": 2.3999999999941792,
        "maxMs": 4.2999999999883585
      },
      "paint": {
        "medianMs": 4,
        "p95Ms": 6.899999999994179,
        "minMs": 3.1999999999825377,
        "maxMs": 6.899999999994179
      },
      "selection": {
        "medianMs": 0.7999999999883585,
        "p95Ms": 1.1999999999825377,
        "minMs": 0.7999999999883585,
        "maxMs": 1.1999999999825377
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2234,
        "materializedPages": 4,
        "selectionSpans": 1739
      }
    },
    {
      "name": "editing-wrap",
      "mode": "edit",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0.09999999997671694,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 41.29999999998836,
        "p95Ms": 46.10000000000582,
        "minMs": 38.70000000001164,
        "maxMs": 46.10000000000582
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 1.900000000023283,
        "p95Ms": 3,
        "minMs": 1.7999999999883585,
        "maxMs": 3
      },
      "paint": {
        "medianMs": 3,
        "p95Ms": 3.5,
        "minMs": 3,
        "maxMs": 3.5
      },
      "selection": {
        "medianMs": 0.7000000000116415,
        "p95Ms": 0.8000000000174623,
        "minMs": 0.6999999999825377,
        "maxMs": 0.8000000000174623
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2255,
        "materializedPages": 4,
        "selectionSpans": 1759
      }
    },
    {
      "name": "suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 101,
        "p95Ms": 112.69999999998254,
        "minMs": 76.70000000001164,
        "maxMs": 112.69999999998254
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.7000000000116415,
        "p95Ms": 3.8000000000174623,
        "minMs": 2.3000000000174623,
        "maxMs": 3.8000000000174623
      },
      "paint": {
        "medianMs": 0.39999999999417923,
        "p95Ms": 0.6000000000058208,
        "minMs": 0.29999999998835847,
        "maxMs": 0.6000000000058208
      },
      "selection": {
        "medianMs": 0.7000000000116415,
        "p95Ms": 1,
        "minMs": 0.7000000000116415,
        "maxMs": 1
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2234,
        "materializedPages": 4,
        "selectionSpans": 1739
      }
    },
    {
      "name": "suggesting-wrap",
      "mode": "suggest",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 91.10000000000582,
        "p95Ms": 97,
        "minMs": 81.19999999998254,
        "maxMs": 97
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.3000000000174623,
        "p95Ms": 3,
        "minMs": 2,
        "maxMs": 3
      },
      "paint": {
        "medianMs": 0.29999999998835847,
        "p95Ms": 0.39999999999417923,
        "minMs": 0.29999999998835847,
        "maxMs": 0.39999999999417923
      },
      "selection": {
        "medianMs": 1,
        "p95Ms": 1.1000000000058208,
        "minMs": 0.7999999999883585,
        "maxMs": 1.1000000000058208
      },
      "work": {
        "placed": 13,
        "total": 3200,
        "reusedPages": 154,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2255,
        "materializedPages": 4,
        "selectionSpans": 1759
      }
    },
    {
      "name": "tracked-editing-character",
      "mode": "edit",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0.09999999997671694,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 32.10000000000582,
        "p95Ms": 35.39999999999418,
        "minMs": 31.20000000001164,
        "maxMs": 35.39999999999418
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.3999999999941792,
        "p95Ms": 2.7000000000116415,
        "minMs": 2.2000000000116415,
        "maxMs": 2.7000000000116415
      },
      "paint": {
        "medianMs": 3.1000000000058208,
        "p95Ms": 3.2000000000116415,
        "minMs": 2.7000000000116415,
        "maxMs": 3.2000000000116415
      },
      "selection": {
        "medianMs": 0.6000000000058208,
        "p95Ms": 0.6000000000058208,
        "minMs": 0.5,
        "maxMs": 0.6000000000058208
      },
      "work": {
        "placed": 3,
        "total": 620,
        "reusedPages": 151,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2100,
        "materializedPages": 3,
        "selectionSpans": 1741
      }
    },
    {
      "name": "tracked-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 54.20000000001164,
        "p95Ms": 59.69999999998254,
        "minMs": 51.09999999997672,
        "maxMs": 59.69999999998254
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.599999999976717,
        "p95Ms": 2.8999999999941792,
        "minMs": 2.1000000000058208,
        "maxMs": 2.8999999999941792
      },
      "paint": {
        "medianMs": 0.29999999998835847,
        "p95Ms": 0.7000000000116415,
        "minMs": 0.20000000001164153,
        "maxMs": 0.7000000000116415
      },
      "selection": {
        "medianMs": 0.6000000000058208,
        "p95Ms": 0.7000000000116415,
        "minMs": 0.5,
        "maxMs": 0.7000000000116415
      },
      "work": {
        "placed": 3,
        "total": 620,
        "reusedPages": 151,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2102,
        "materializedPages": 3,
        "selectionSpans": 1741
      }
    },
    {
      "name": "tracked-suggesting-wrap",
      "mode": "suggest",
      "textLength": 100,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 57.10000000000582,
        "p95Ms": 60.30000000001746,
        "minMs": 54.89999999999418,
        "maxMs": 60.30000000001746
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 2.7999999999883585,
        "p95Ms": 2.8999999999941792,
        "minMs": 2.5,
        "maxMs": 2.8999999999941792
      },
      "paint": {
        "medianMs": 0.39999999999417923,
        "p95Ms": 0.40000000002328306,
        "minMs": 0.20000000001164153,
        "maxMs": 0.40000000002328306
      },
      "selection": {
        "medianMs": 0.7000000000116415,
        "p95Ms": 0.8000000000174623,
        "minMs": 0.7000000000116415,
        "maxMs": 0.8000000000174623
      },
      "work": {
        "placed": 8,
        "total": 620,
        "reusedPages": 150,
        "fullPasses": 1,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2122,
        "materializedPages": 3,
        "selectionSpans": 1760
      }
    },
    {
      "name": "huge-open-to-ready",
      "mode": "edit",
      "textLength": 0,
      "inputTask": {
        "medianMs": 6100,
        "p95Ms": 6100,
        "minMs": 5930,
        "maxMs": 6100
      },
      "frame": {
        "medianMs": 6100,
        "p95Ms": 6100,
        "minMs": 5930,
        "maxMs": 6100
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "paint": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "selection": {
        "medianMs": 0,
        "p95Ms": 0,
        "minMs": 0,
        "maxMs": 0
      },
      "work": {
        "placed": 0,
        "total": 4250,
        "reusedPages": 0,
        "fullPasses": 0,
        "staleDiscards": 0,
        "cancelledRuns": 0
      },
      "dom": {
        "nodes": 2503,
        "materializedPages": 2,
        "selectionSpans": 0
      }
    },
    {
      "name": "huge-suggesting-character",
      "mode": "suggest",
      "textLength": 1,
      "inputTask": {
        "medianMs": 0.10000000000582077,
        "p95Ms": 0.10000000000582077,
        "minMs": 0,
        "maxMs": 0.10000000000582077
      },
      "frame": {
        "medianMs": 113.89999999999418,
        "p95Ms": 125.10000000000582,
        "minMs": 104,
        "maxMs": 125.10000000000582
      },
      "eventDuration": null,
      "eventDelay": null,
      "layout": {
        "medianMs": 7.600000000005821,
        "p95Ms": 12.299999999988358,
        "minMs": 5.399999999994179,
        "maxMs": 12.299999999988358
      },
      "paint": {
        "medianMs": 1.1000000000058208,
        "p95Ms": 1.1000000000058208,
        "minMs": 1,
        "maxMs": 1.1000000000058208
      },
      "selection": {
        "medianMs": 1.2000000000116415,
        "p95Ms": 1.2999999999883585,
        "minMs
… truncated …

Refresh the source-scanner baseline after dialog composition changes.
The scanner does not resolve inherited DialogCustomizationProps and can
consume implementation object literals after interface declarations:
Vue runtime props and React page setup draft values therefore appear as
signature drift despite matching public API snapshots. Root dialogs is
declared in DocxEditorRoot in React and useDocxEditorRoot in Vue. Remove
obsolete inline-style entries as part of the same baseline update.

Include the feature gate in check:parity so pre-commit runs the same gate
as CI, and remove the redundant standalone CI invocation.
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📦 Package size report

Package Tarball vs main Unpacked vs main
@docx-editor.dev/core 1.78 MB +11.0 KB (+0.6%) 5.90 MB +37.9 KB (+0.6%)
@docx-editor.dev/editor-api 115.6 KB ±0.0 KB (±0.0%) 486.5 KB ±0.0 KB (±0.0%)
@docx-editor.dev/fonts 4.01 MB ±0.0 KB (±0.0%) 8.11 MB ±0.0 KB (±0.0%)
@docx-editor.dev/i18n 261.9 KB ±0.0 KB (±0.0%) 1.15 MB ±0.0 KB (±0.0%)
@docx-editor.dev/pro 310.4 KB ±0.0 KB (±0.0%) 1.10 MB ±0.0 KB (±0.0%)
@docx-editor.dev/react 318.6 KB +9.4 KB (+3.0%) 1.17 MB +61.4 KB (+5.4%)
@docx-editor.dev/vue 221.3 KB +10.5 KB (+5.0%) 1.10 MB +70.4 KB (+6.7%)

Tarball = npm pack gzipped size. ⚠️ over ±5%, 🚨 fails CI over +20% and +25.0 KB (label size-increase-expected to allow).

Replace the unreleased dialogs configuration with one typed popups map
covering 14 editor-owned surfaces in React and Vue. Explicit entries win
over legacy shortcuts; omitted entries preserve existing defaults and
false relinquishes automatic rendering to manual owners.

Add guarded core widget/invalid-field sessions and fallback registrations,
extract reusable image/note popup defaults, and preserve per-editor focus,
state, and translations. Fix Vue asChild handlers on fragment-wrapped
buttons, exposed by the real custom hyperlink workflow.

Update concise docs, examples, public snapshots, and parity contracts.
The source-scanner baseline reflects adapter syntax and extracted popup
components; public interface and composable parity checks remain strict.

Validation: 12,450 repository tests and seven browser checks pass, plus
package builds, fresh consumer installs, API/parity, and documentation checks.
@jedrazb jedrazb changed the title feat: add composable dialog customization for React and Vue feat: unify popup customization in React and Vue Sep 8, 2026
…mization

# Conflicts:
#	docs/api/docx-editor-core/editor.api.md
#	docs/api/docx-editor-core/index.api.md
#	packages/core/src/editor/__tests__/text-form-field-interaction.test.ts
#	packages/core/src/editor/paginated-surface.ts
#	packages/core/src/editor/surface-text-form-fields.ts
#	packages/core/src/editor/text-form-field-dialog.ts
#	packages/core/src/editor/text-form-field-invalid-dialog.ts
#	packages/react/test/context-menu.test.tsx
#	packages/vue/src/components/DocxEditor.tsx
#	packages/vue/test/context-menu.test.ts
#	scripts/parity/parity.contract.json
Add definePopup for ordinary React components and Vue SFCs in the existing
popups map. Preserve component state across registration rerenders and reset
custom drafts when the editor starts a new form session.

Check inferred component props, including required and narrowed Vue props.
Use template SFC examples and component-first documentation.

Refresh the feature-parity baseline for three explicit Vue children runtime
declarations. React already inherits these props; Vue must consume them to
prevent forwarded SFC props from leaking onto native dialog elements.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add consistent dialog and popover customization APIs

1 participant