@beyondwork/docx-react-component 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -104
- package/package.json +66 -15
- package/src/api/public-types.ts +1 -1
- package/src/compare/diff-engine.ts +530 -0
- package/src/compare/export-redlines.ts +162 -0
- package/src/compare/snapshot.ts +37 -0
- package/src/core/commands/index.ts +1 -1
- package/src/core/state/editor-state.ts +2 -2
- package/src/index.ts +45 -0
- package/src/legal/bookmarks.ts +196 -0
- package/src/legal/cross-references.ts +356 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/runtime/document-runtime.ts +3 -5
- package/src/runtime/table-commands.ts +4 -1
- package/src/runtime/table-schema.ts +17 -2
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/ui/WordReviewEditor.tsx +256 -35
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +2 -2
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +16 -2
- package/.codex/config.toml +0 -5
- package/.corepack/v1/pnpm/10.30.3/.corepack +0 -1
- package/.corepack/v1/pnpm/10.30.3/LICENSE +0 -22
- package/.corepack/v1/pnpm/10.30.3/README.md +0 -240
- package/.corepack/v1/pnpm/10.30.3/dist/node-gyp-bin/node-gyp +0 -6
- package/.corepack/v1/pnpm/10.30.3/dist/node-gyp-bin/node-gyp.cmd +0 -5
- package/.corepack/v1/pnpm/10.30.3/dist/pnpm.cjs +0 -195400
- package/.corepack/v1/pnpm/10.30.3/dist/pnpmrc +0 -2
- package/.corepack/v1/pnpm/10.30.3/dist/reflink.darwin-arm64-2HJ4WGO6.node +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/reflink.darwin-x64-3G3H6IW4.node +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/reflink.win32-arm64-msvc-Q6BARPPB.node +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/reflink.win32-x64-msvc-J2TZHRQI.node +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/templates/completion.bash +0 -31
- package/.corepack/v1/pnpm/10.30.3/dist/templates/completion.fish +0 -22
- package/.corepack/v1/pnpm/10.30.3/dist/templates/completion.ps1 +0 -193
- package/.corepack/v1/pnpm/10.30.3/dist/templates/completion.zsh +0 -27
- package/.corepack/v1/pnpm/10.30.3/dist/vendor/fastlist-0.3.0-x64.exe +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/vendor/fastlist-0.3.0-x86.exe +0 -0
- package/.corepack/v1/pnpm/10.30.3/dist/worker.js +0 -10119
- package/.corepack/v1/pnpm/10.30.3/package.json +0 -192
- package/.cursor/mcp.json +0 -7
- package/.github/workflows/ci.yml +0 -35
- package/.mcp.json +0 -7
- package/.openclaw/workspace-state.json +0 -4
- package/.pnpmrc.json +0 -1
- package/.wave-launch.sh +0 -7
- package/.workspace-marker +0 -1
- package/AGENTS.md +0 -78
- package/CHANGELOG.md +0 -177
- package/DESIGN.md +0 -929
- package/HEARTBEAT.md +0 -7
- package/IDENTITY.md +0 -23
- package/SOUL.md +0 -36
- package/TOOLS.md +0 -40
- package/USER.md +0 -17
- package/docs/README.md +0 -107
- package/docs/agents/wave-cont-eval-role.md +0 -36
- package/docs/agents/wave-cont-qa-role.md +0 -52
- package/docs/agents/wave-deploy-verifier-role.md +0 -34
- package/docs/agents/wave-design-role.md +0 -47
- package/docs/agents/wave-documentation-role.md +0 -34
- package/docs/agents/wave-infra-role.md +0 -34
- package/docs/agents/wave-integration-role.md +0 -37
- package/docs/agents/wave-launcher-role.md +0 -41
- package/docs/agents/wave-orchestrator-role.md +0 -52
- package/docs/agents/wave-planner-role.md +0 -39
- package/docs/agents/wave-security-role.md +0 -40
- package/docs/architecture/docx/README.md +0 -10
- package/docs/architecture/future/README.md +0 -8
- package/docs/architecture/ooxml-upgrade-analysis.md +0 -134
- package/docs/architecture/platform/shared-openxml-editor-platform.md +0 -153
- package/docs/architecture/xlsx/canonical-workbook-model-and-commands.md +0 -187
- package/docs/architecture/xlsx/spreadsheet-editor-frontend-architecture.md +0 -150
- package/docs/comment-redline-overview.md +0 -350
- package/docs/concepts/context7-vs-skills.md +0 -118
- package/docs/concepts/operating-modes.md +0 -91
- package/docs/concepts/runtime-agnostic-orchestration.md +0 -111
- package/docs/concepts/what-is-a-wave.md +0 -217
- package/docs/context7/bundles.json +0 -222
- package/docs/context7/planner-agent/README.md +0 -28
- package/docs/context7/planner-agent/manifest.json +0 -83
- package/docs/context7/planner-agent/papers/cooperbench-why-coding-agents-cannot-be-your-teammates-yet.md +0 -3283
- package/docs/context7/planner-agent/papers/dova-deliberation-first-multi-agent-orchestration-for-autonomous-research-automation.md +0 -1699
- package/docs/context7/planner-agent/papers/dpbench-large-language-models-struggle-with-simultaneous-coordination.md +0 -2251
- package/docs/context7/planner-agent/papers/incremental-planning-to-control-a-blackboard-based-problem-solver.md +0 -1729
- package/docs/context7/planner-agent/papers/silo-bench-a-scalable-environment-for-evaluating-distributed-coordination-in-multi-agent-llm-systems.md +0 -3747
- package/docs/context7/planner-agent/papers/todoevolve-learning-to-architect-agent-planning-systems.md +0 -1675
- package/docs/context7/planner-agent/papers/verified-multi-agent-orchestration-a-plan-execute-verify-replan-framework-for-complex-query-resolution.md +0 -1173
- package/docs/context7/planner-agent/papers/why-do-multi-agent-llm-systems-fail.md +0 -5211
- package/docs/context7/planner-agent/topics/planning-and-orchestration.md +0 -24
- package/docs/evals/arm-templates/README.md +0 -13
- package/docs/evals/arm-templates/full-wave.json +0 -15
- package/docs/evals/arm-templates/single-agent.json +0 -15
- package/docs/evals/benchmark-catalog.json +0 -670
- package/docs/evals/cases/README.md +0 -47
- package/docs/evals/cases/wave-blackboard-inbox-targeting.json +0 -73
- package/docs/evals/cases/wave-contradiction-conflict.json +0 -104
- package/docs/evals/cases/wave-expert-routing-preservation.json +0 -69
- package/docs/evals/cases/wave-hidden-profile-private-evidence.json +0 -81
- package/docs/evals/cases/wave-premature-closure-guard.json +0 -71
- package/docs/evals/cases/wave-silo-cross-agent-state.json +0 -77
- package/docs/evals/cases/wave-simultaneous-lockstep.json +0 -92
- package/docs/evals/external-benchmarks.json +0 -85
- package/docs/evals/external-command-config.sample.json +0 -9
- package/docs/evals/external-command-config.swe-bench-pro.json +0 -8
- package/docs/evals/pilots/README.md +0 -47
- package/docs/evals/pilots/swe-bench-pro-public-full-wave-review-10.json +0 -64
- package/docs/evals/pilots/swe-bench-pro-public-pilot.json +0 -111
- package/docs/evals/wave-benchmark-program.md +0 -302
- package/docs/guides/planner.md +0 -220
- package/docs/guides/recommendations-0.8.9.md +0 -133
- package/docs/guides/signal-wrappers.md +0 -165
- package/docs/guides/terminal-surfaces.md +0 -96
- package/docs/image copy.png +0 -0
- package/docs/image.png +0 -0
- package/docs/images/image.png +0 -0
- package/docs/legal-feedback-architecture.md +0 -498
- package/docs/plans/component-cutover-matrix.json +0 -1072
- package/docs/plans/component-cutover-matrix.md +0 -307
- package/docs/plans/context7-wave-orchestrator.md +0 -155
- package/docs/plans/current-state.md +0 -198
- package/docs/plans/docx/README.md +0 -9
- package/docs/plans/examples/wave-benchmark-improvement.md +0 -108
- package/docs/plans/examples/wave-example-live-proof.md +0 -435
- package/docs/plans/master-plan.md +0 -224
- package/docs/plans/migration.md +0 -538
- package/docs/plans/operations/README.md +0 -7
- package/docs/plans/operations/wave-10-word-certification.md +0 -87
- package/docs/plans/operations/wave-8-railway-staging.md +0 -153
- package/docs/plans/operations/wave-9-manual-certification.md +0 -73
- package/docs/plans/platform/README.md +0 -9
- package/docs/plans/reference/legal-checklist-coverage.md +0 -258
- package/docs/plans/wave-orchestrator.md +0 -423
- package/docs/plans/waves/README.md +0 -75
- package/docs/plans/waves/completed/wave-0.md +0 -195
- package/docs/plans/waves/completed/wave-1.md +0 -379
- package/docs/plans/waves/completed/wave-10.md +0 -670
- package/docs/plans/waves/completed/wave-11.md +0 -335
- package/docs/plans/waves/completed/wave-12.md +0 -417
- package/docs/plans/waves/completed/wave-13.md +0 -316
- package/docs/plans/waves/completed/wave-14.md +0 -319
- package/docs/plans/waves/completed/wave-15.md +0 -321
- package/docs/plans/waves/completed/wave-16.md +0 -316
- package/docs/plans/waves/completed/wave-17.md +0 -331
- package/docs/plans/waves/completed/wave-18.md +0 -328
- package/docs/plans/waves/completed/wave-2.md +0 -438
- package/docs/plans/waves/completed/wave-3.md +0 -435
- package/docs/plans/waves/completed/wave-4.md +0 -430
- package/docs/plans/waves/completed/wave-5.md +0 -430
- package/docs/plans/waves/completed/wave-6.md +0 -430
- package/docs/plans/waves/completed/wave-7.md +0 -526
- package/docs/plans/waves/completed/wave-8.md +0 -596
- package/docs/plans/waves/completed/wave-9.md +0 -552
- package/docs/plans/waves/deferred/README.md +0 -14
- package/docs/plans/waves/deferred/encrypted-intake-contracts.md +0 -282
- package/docs/plans/waves/deferred/legal-feedback-wave-expansion.md +0 -308
- package/docs/plans/waves/deferred/wave-encrypted-intake.md +0 -451
- package/docs/plans/waves/design/README.md +0 -5
- package/docs/plans/waves/design/wave-1-a1.md +0 -309
- package/docs/plans/waves/reviews/README.md +0 -5
- package/docs/plans/waves/reviews/wave-0-cont-qa.md +0 -151
- package/docs/plans/waves/reviews/wave-1-cont-qa.md +0 -46
- package/docs/plans/waves/reviews/wave-10-accessibility-and-design.md +0 -51
- package/docs/plans/waves/reviews/wave-10-cont-qa.md +0 -24
- package/docs/plans/waves/reviews/wave-10-dashboard-proof.md +0 -46
- package/docs/plans/waves/reviews/wave-10-performance-signoff.md +0 -55
- package/docs/plans/waves/reviews/wave-10-regression-proof.md +0 -23
- package/docs/plans/waves/reviews/wave-10-release-audit.md +0 -31
- package/docs/plans/waves/reviews/wave-10-service-proof.md +0 -83
- package/docs/plans/waves/reviews/wave-10-word-certification.md +0 -31
- package/docs/plans/waves/reviews/wave-18-ai-contract-closure.md +0 -277
- package/docs/plans/waves/reviews/wave-18-cont-qa.md +0 -255
- package/docs/plans/waves/reviews/wave-18-parity-proof.md +0 -271
- package/docs/plans/waves/reviews/wave-19-cont-qa.md +0 -59
- package/docs/plans/waves/reviews/wave-2-cont-qa.md +0 -72
- package/docs/plans/waves/reviews/wave-20-cont-qa.md +0 -60
- package/docs/plans/waves/reviews/wave-25-cont-qa.md +0 -48
- package/docs/plans/waves/reviews/wave-28-cont-qa.md +0 -46
- package/docs/plans/waves/reviews/wave-29-cont-qa.md +0 -53
- package/docs/plans/waves/reviews/wave-3-cont-qa.md +0 -53
- package/docs/plans/waves/reviews/wave-3-core-proof.md +0 -77
- package/docs/plans/waves/reviews/wave-3-validator-proof.md +0 -73
- package/docs/plans/waves/reviews/wave-32-cont-qa.md +0 -43
- package/docs/plans/waves/reviews/wave-33-cont-qa.md +0 -526
- package/docs/plans/waves/reviews/wave-34-cont-qa.md +0 -100
- package/docs/plans/waves/reviews/wave-35-cont-qa.md +0 -145
- package/docs/plans/waves/reviews/wave-4-cont-qa.md +0 -47
- package/docs/plans/waves/reviews/wave-4-structure-proof.md +0 -69
- package/docs/plans/waves/reviews/wave-5-comment-proof.md +0 -158
- package/docs/plans/waves/reviews/wave-5-cont-qa.md +0 -68
- package/docs/plans/waves/reviews/wave-6-cont-qa.md +0 -416
- package/docs/plans/waves/reviews/wave-6-redline-proof.md +0 -130
- package/docs/plans/waves/reviews/wave-7-cont-qa.md +0 -82
- package/docs/plans/waves/reviews/wave-7-ooxml-compliance.md +0 -85
- package/docs/plans/waves/reviews/wave-7-preservation-proof.md +0 -119
- package/docs/plans/waves/reviews/wave-7-trust-ux.md +0 -87
- package/docs/plans/waves/reviews/wave-8-accessibility-and-design.md +0 -128
- package/docs/plans/waves/reviews/wave-8-cont-qa.md +0 -92
- package/docs/plans/waves/reviews/wave-8-live-proof.md +0 -140
- package/docs/plans/waves/reviews/wave-8-security.md +0 -47
- package/docs/plans/waves/reviews/wave-9-editor-embedding.md +0 -39
- package/docs/plans/waves/reviews/wave-9-fixture-runner.md +0 -56
- package/docs/plans/waves/reviews/wave-9-live-proof.md +0 -105
- package/docs/plans/waves/reviews/wave-9-usability-and-performance.md +0 -152
- package/docs/plans/waves/specs/README.md +0 -5
- package/docs/plans/waves/specs/wave-1-component-boundaries.md +0 -322
- package/docs/plans/waves/specs/wave-1-ooxml-contracts.md +0 -323
- package/docs/plans/waves/specs/wave-1-review-and-ui-contracts.md +0 -339
- package/docs/plans/waves/specs/wave-1-runtime-contracts.md +0 -509
- package/docs/plans/waves/wave-19.md +0 -341
- package/docs/plans/waves/wave-20.md +0 -308
- package/docs/plans/waves/wave-21.md +0 -289
- package/docs/plans/waves/wave-22.md +0 -221
- package/docs/plans/waves/wave-23.md +0 -295
- package/docs/plans/waves/wave-24.md +0 -286
- package/docs/plans/waves/wave-25.md +0 -313
- package/docs/plans/waves/wave-26.md +0 -300
- package/docs/plans/waves/wave-27.md +0 -299
- package/docs/plans/waves/wave-28.md +0 -368
- package/docs/plans/waves/wave-29.md +0 -303
- package/docs/plans/waves/wave-30.md +0 -307
- package/docs/plans/waves/wave-31.md +0 -231
- package/docs/plans/waves/wave-32.md +0 -152
- package/docs/plans/waves/wave-33.md +0 -147
- package/docs/plans/waves/wave-34.md +0 -148
- package/docs/plans/waves/wave-35.md +0 -141
- package/docs/plans/waves/wave-36.md +0 -146
- package/docs/plans/xlsx/README.md +0 -14
- package/docs/plans/xlsx/xlsx-fixture-corpus-and-certification-plan.md +0 -126
- package/docs/reference/cli-reference.md +0 -600
- package/docs/reference/coordination-and-closure.md +0 -487
- package/docs/reference/deep-research-report (15).md +0 -25
- package/docs/reference/docx/README.md +0 -10
- package/docs/reference/legal-checklist.md +0 -445
- package/docs/reference/live-proof-waves.md +0 -199
- package/docs/reference/ooxml-compliance.md +0 -129
- package/docs/reference/ooxml-feature-parity-matrix.md +0 -172
- package/docs/reference/platform/shared-ooxml-platform-guidance.md +0 -77
- package/docs/reference/prototype-agent-prompt-legal-fidelity.md +0 -155
- package/docs/reference/public-api.md +0 -456
- package/docs/reference/repository-guidance.md +0 -58
- package/docs/reference/runtime-config/README.md +0 -182
- package/docs/reference/runtime-config/claude.md +0 -110
- package/docs/reference/runtime-config/codex.md +0 -82
- package/docs/reference/runtime-config/opencode.md +0 -93
- package/docs/reference/sample-waves.md +0 -105
- package/docs/reference/skills.md +0 -237
- package/docs/reference/templates/AGENTS.md +0 -78
- package/docs/reference/templates/HEARTBEAT.md +0 -7
- package/docs/reference/templates/IDENTITY.md +0 -23
- package/docs/reference/templates/SOUL.md +0 -36
- package/docs/reference/templates/TOOLS.md +0 -40
- package/docs/reference/templates/USER.md +0 -17
- package/docs/reference/wave-control.md +0 -184
- package/docs/reference/wave-planning-lessons.md +0 -167
- package/docs/reference/word-review-editor-frontend-architecture.md +0 -479
- package/docs/reference/word-review-editor-ux-guide.md +0 -253
- package/docs/reference/xlsx/xlsx-ooxml-compliance.md +0 -137
- package/docs/research/agent-context-sources.md +0 -178
- package/docs/research/coordination-failure-review.md +0 -290
- package/docs/research/docx-react-component/Canonical Document Schema Specification for a React-based Word-compatible Editor.md +0 -2317
- package/docs/research/docx-react-component/Feature Compatibility Matrix for a React Word Compatible Legal Editor v1.md +0 -219
- package/docs/research/docx-react-component/React Component Architecture and Front-End Structure Specification for a Word-Compatible Legal Review Editor.md +0 -1112
- package/docs/research/docx-react-component/document_compatibility_and_testing_spec.md +0 -751
- package/docs/research/xlsx/raw/README.md +0 -13
- package/docs/roadmap.md +0 -174
- package/docs/superpowers/plans/2026-03-28-harness-control-bar.md +0 -677
- package/docs/superpowers/specs/2026-03-28-harness-control-bar-design.md +0 -274
- package/docs/xlsx-react/README.md +0 -38
- package/docs/xlsx-react/agent-llm-interaction-layer-docx-xlsx.md +0 -621
- package/docs/xlsx-react/canonical-workbook-model-and-commands.md +0 -948
- package/docs/xlsx-react/shared-openxml-editor-platform-docx-xlsx.md +0 -228
- package/docs/xlsx-react/spreadsheet-editor-component-architecture.md +0 -809
- package/docs/xlsx-react/spreadsheet-editor-frontend-architecture.md +0 -537
- package/docs/xlsx-react/spreadsheet-editor-ux-guide.md +0 -520
- package/docs/xlsx-react/xlsx-editor-research-pack.md +0 -871
- package/docs/xlsx-react/xlsx-fixture-corpus-and-certification-plan.md +0 -436
- package/docs/xlsx-react/xlsx-ooxml-compliance.md +0 -320
- package/examples/README.md +0 -16
- package/memory/MEMORY.md +0 -24
- package/pnpm-workspace.yaml +0 -4
- package/scripts/check-no-authored-js.sh +0 -13
- package/scripts/context7-api-check.sh +0 -65
- package/scripts/context7-export-env.sh +0 -42
- package/scripts/run-context7-mcp.sh +0 -8
- package/scripts/run-workspace-tests.sh +0 -15
- package/scripts/start-wave-10-local.sh +0 -189
- package/scripts/wave-agent-attach.sh +0 -47
- package/scripts/wave-auto-answer.sh +0 -118
- package/scripts/wave-dashboard-attach.sh +0 -13
- package/scripts/wave-launch.sh +0 -273
- package/scripts/wave-overnight-supervisor.sh +0 -145
- package/scripts/wave-status.sh +0 -379
- package/scripts/wave-watch.sh +0 -231
- package/services/README.md +0 -17
- package/services/openxml-validator/Dockerfile +0 -29
- package/services/openxml-validator/OpenXmlValidator.Api.csproj +0 -12
- package/services/openxml-validator/Program.cs +0 -436
- package/services/openxml-validator/README.md +0 -152
- package/services/openxml-validator/railway.json +0 -16
- package/services/react-word-editor/.tmp-a4/src/api/public-types.ts +0 -318
- package/services/react-word-editor/.tmp-a4/src/ui/WordReviewEditor.tsx +0 -1302
- package/services/react-word-editor/.tmp-a4/src/ui/editor-surface/editor-surface.tsx +0 -546
- package/services/react-word-editor/.tmp-a4/test/ui/word-review-editor.test.tsx +0 -146
- package/services/react-word-editor/.tmp-a4-build/src/api/public-types.js +0 -2
- package/services/react-word-editor/.tmp-a4-build/src/ui/WordReviewEditor.js +0 -818
- package/services/react-word-editor/.tmp-a4-build/src/ui/editor-surface/editor-surface.js +0 -229
- package/services/react-word-editor/.tmp-a4-build/test/ui/word-review-editor.test.js +0 -121
- package/services/react-word-editor/.tmp-wave-4-a3-tsconfig.json +0 -21
- package/services/react-word-editor/.tmp-wave-4-a3-tsconfig.tsbuildinfo +0 -1
- package/services/react-word-editor/Dockerfile +0 -26
- package/services/react-word-editor/README.md +0 -254
- package/services/react-word-editor/app/api/certification/route.ts +0 -79
- package/services/react-word-editor/app/api/demo-sessions/route.ts +0 -109
- package/services/react-word-editor/app/api/deploy-health/route.ts +0 -23
- package/services/react-word-editor/app/api/exports/[exportId]/route.ts +0 -34
- package/services/react-word-editor/app/api/exports/route.ts +0 -81
- package/services/react-word-editor/app/api/fixtures/[fixtureId]/run/route.ts +0 -100
- package/services/react-word-editor/app/api/health/route.ts +0 -70
- package/services/react-word-editor/app/api/runs/[runId]/route.ts +0 -36
- package/services/react-word-editor/app/api/scenarios/[scenarioId]/run/route.ts +0 -85
- package/services/react-word-editor/app/api/sessions/[sessionId]/route.ts +0 -199
- package/services/react-word-editor/app/api/sessions/[sessionId]/source/route.ts +0 -45
- package/services/react-word-editor/app/api/uploads/route.ts +0 -70
- package/services/react-word-editor/app/api/validate/route.ts +0 -310
- package/services/react-word-editor/app/certification/[runId]/page.tsx +0 -14
- package/services/react-word-editor/app/certification/page.tsx +0 -32
- package/services/react-word-editor/app/dashboard/page.tsx +0 -7
- package/services/react-word-editor/app/demo/page.tsx +0 -30
- package/services/react-word-editor/app/demo/prototype-client.tsx +0 -1080
- package/services/react-word-editor/app/editor/[sessionId]/page.tsx +0 -33
- package/services/react-word-editor/app/fixtures/page.tsx +0 -7
- package/services/react-word-editor/app/globals.css +0 -121
- package/services/react-word-editor/app/layout.tsx +0 -32
- package/services/react-word-editor/app/page.tsx +0 -30
- package/services/react-word-editor/app/runs/[runId]/page.tsx +0 -34
- package/services/react-word-editor/app/wave-10-word-review/page.tsx +0 -7
- package/services/react-word-editor/components/harness-control-bar.tsx +0 -289
- package/services/react-word-editor/components/harness-editor-session-client.tsx +0 -1214
- package/services/react-word-editor/components/harness-workspace-page.tsx +0 -715
- package/services/react-word-editor/components/reduced-motion-toggle.tsx +0 -79
- package/services/react-word-editor/components/workspace-certification-panel.tsx +0 -307
- package/services/react-word-editor/lib/certification-bundle.ts +0 -796
- package/services/react-word-editor/lib/certification-store.ts +0 -661
- package/services/react-word-editor/lib/demo-fixtures.test.mjs +0 -195
- package/services/react-word-editor/lib/demo-fixtures.ts +0 -1519
- package/services/react-word-editor/lib/editor-session-summary.test.mjs +0 -68
- package/services/react-word-editor/lib/editor-session-summary.ts +0 -14
- package/services/react-word-editor/lib/editor-session.ts +0 -228
- package/services/react-word-editor/lib/exports-route.test.mjs +0 -32
- package/services/react-word-editor/lib/harness-client.ts +0 -347
- package/services/react-word-editor/lib/harness-config.json +0 -30
- package/services/react-word-editor/lib/harness-config.test.mjs +0 -31
- package/services/react-word-editor/lib/harness-config.ts +0 -21
- package/services/react-word-editor/lib/harness-editor-datastore.test.mjs +0 -220
- package/services/react-word-editor/lib/harness-editor-datastore.ts +0 -161
- package/services/react-word-editor/lib/private-mode.test.mjs +0 -42
- package/services/react-word-editor/lib/private-mode.ts +0 -61
- package/services/react-word-editor/lib/regression-report.test.mjs +0 -352
- package/services/react-word-editor/lib/regression-report.ts +0 -896
- package/services/react-word-editor/lib/run-artifacts.ts +0 -934
- package/services/react-word-editor/lib/run-history.ts +0 -755
- package/services/react-word-editor/lib/scenario-artifacts.test.mjs +0 -41
- package/services/react-word-editor/lib/scenario-artifacts.ts +0 -44
- package/services/react-word-editor/lib/storage.ts +0 -953
- package/services/react-word-editor/lib/validator-client.test.mjs +0 -54
- package/services/react-word-editor/lib/validator-client.ts +0 -95
- package/services/react-word-editor/lib/workspace-navigation.ts +0 -79
- package/services/react-word-editor/middleware.ts +0 -35
- package/services/react-word-editor/next-env.d.ts +0 -6
- package/services/react-word-editor/next.config.mjs +0 -15
- package/services/react-word-editor/package.json +0 -38
- package/services/react-word-editor/postcss.config.mjs +0 -8
- package/services/react-word-editor/railway.json +0 -21
- package/services/react-word-editor/scripts/wave-10-certification.mjs +0 -101
- package/services/react-word-editor/scripts/wave-9-live-usability-pilot.mjs +0 -911
- package/services/react-word-editor/tsconfig.json +0 -39
- package/services/react-word-editor/tsconfig.tsbuildinfo +0 -1
- package/skills/README.md +0 -48
- package/skills/domain-docx-compatibility/SKILL.md +0 -44
- package/skills/domain-docx-compatibility/skill.json +0 -19
- package/skills/domain-editor-architecture/SKILL.md +0 -49
- package/skills/domain-editor-architecture/skill.json +0 -19
- package/skills/domain-legal-review/SKILL.md +0 -39
- package/skills/domain-legal-review/skill.json +0 -19
- package/skills/provider-aws/SKILL.md +0 -117
- package/skills/provider-aws/adapters/claude.md +0 -1
- package/skills/provider-aws/adapters/codex.md +0 -1
- package/skills/provider-aws/references/service-verification.md +0 -39
- package/skills/provider-aws/skill.json +0 -54
- package/skills/provider-custom-deploy/SKILL.md +0 -64
- package/skills/provider-custom-deploy/skill.json +0 -50
- package/skills/provider-docker-compose/SKILL.md +0 -96
- package/skills/provider-docker-compose/adapters/local.md +0 -1
- package/skills/provider-docker-compose/skill.json +0 -53
- package/skills/provider-github-release/SKILL.md +0 -121
- package/skills/provider-github-release/adapters/claude.md +0 -1
- package/skills/provider-github-release/adapters/codex.md +0 -1
- package/skills/provider-github-release/skill.json +0 -55
- package/skills/provider-kubernetes/SKILL.md +0 -143
- package/skills/provider-kubernetes/adapters/claude.md +0 -1
- package/skills/provider-kubernetes/adapters/codex.md +0 -1
- package/skills/provider-kubernetes/references/kubectl-patterns.md +0 -58
- package/skills/provider-kubernetes/skill.json +0 -52
- package/skills/provider-railway/SKILL.md +0 -123
- package/skills/provider-railway/adapters/claude.md +0 -1
- package/skills/provider-railway/adapters/codex.md +0 -1
- package/skills/provider-railway/adapters/local.md +0 -1
- package/skills/provider-railway/adapters/opencode.md +0 -1
- package/skills/provider-railway/references/verification-commands.md +0 -39
- package/skills/provider-railway/skill.json +0 -71
- package/skills/provider-ssh-manual/SKILL.md +0 -97
- package/skills/provider-ssh-manual/skill.json +0 -54
- package/skills/repo-coding-rules/SKILL.md +0 -55
- package/skills/repo-coding-rules/skill.json +0 -34
- package/skills/role-cont-eval/SKILL.md +0 -91
- package/skills/role-cont-eval/adapters/codex.md +0 -1
- package/skills/role-cont-eval/skill.json +0 -36
- package/skills/role-cont-qa/SKILL.md +0 -100
- package/skills/role-cont-qa/adapters/claude.md +0 -1
- package/skills/role-cont-qa/skill.json +0 -36
- package/skills/role-deploy/SKILL.md +0 -97
- package/skills/role-deploy/skill.json +0 -36
- package/skills/role-design/SKILL.md +0 -50
- package/skills/role-design/skill.json +0 -36
- package/skills/role-documentation/SKILL.md +0 -76
- package/skills/role-documentation/skill.json +0 -36
- package/skills/role-implementation/SKILL.md +0 -45
- package/skills/role-implementation/skill.json +0 -36
- package/skills/role-infra/SKILL.md +0 -81
- package/skills/role-infra/skill.json +0 -36
- package/skills/role-integration/SKILL.md +0 -91
- package/skills/role-integration/skill.json +0 -36
- package/skills/role-planner/SKILL.md +0 -39
- package/skills/role-planner/skill.json +0 -21
- package/skills/role-research/SKILL.md +0 -65
- package/skills/role-research/skill.json +0 -36
- package/skills/role-security/SKILL.md +0 -60
- package/skills/role-security/skill.json +0 -36
- package/skills/runtime-claude/SKILL.md +0 -66
- package/skills/runtime-claude/skill.json +0 -36
- package/skills/runtime-codex/SKILL.md +0 -58
- package/skills/runtime-codex/skill.json +0 -36
- package/skills/runtime-local/SKILL.md +0 -46
- package/skills/runtime-local/skill.json +0 -36
- package/skills/runtime-opencode/SKILL.md +0 -58
- package/skills/runtime-opencode/skill.json +0 -36
- package/skills/signal-hygiene/SKILL.md +0 -51
- package/skills/signal-hygiene/skill.json +0 -20
- package/skills/tui-design/SKILL.md +0 -77
- package/skills/tui-design/references/tui-design.md +0 -259
- package/skills/tui-design/skill.json +0 -36
- package/skills/wave-core/SKILL.md +0 -141
- package/skills/wave-core/references/marker-syntax.md +0 -70
- package/skills/wave-core/skill.json +0 -35
- package/test/README.md +0 -16
- package/test/core/formatting-commands.test.ts +0 -285
- package/test/core/image-commands.test.ts +0 -298
- package/test/core/mapping.test.ts +0 -186
- package/test/core/text-commands.test.ts +0 -176
- package/test/fixtures/docx/F01-basic-contract.docx +0 -0
- package/test/fixtures/docx/F01-basic-contract.md +0 -33
- package/test/fixtures/docx/F02-headings-styles.docx +0 -0
- package/test/fixtures/docx/F02-headings-styles.md +0 -33
- package/test/fixtures/docx/F03-legal-outline-numbering.docx +0 -0
- package/test/fixtures/docx/F03-legal-outline-numbering.md +0 -34
- package/test/fixtures/docx/F04-restart-numbering-schedules.docx +0 -0
- package/test/fixtures/docx/F04-restart-numbering-schedules.md +0 -33
- package/test/fixtures/docx/F05-table-heavy-agreement.docx +0 -0
- package/test/fixtures/docx/F05-table-heavy-agreement.md +0 -34
- package/test/fixtures/docx/F06-merged-cells-signature-table.docx +0 -0
- package/test/fixtures/docx/F06-merged-cells-signature-table.md +0 -34
- package/test/fixtures/docx/F07-inline-images-exhibit.docx +0 -0
- package/test/fixtures/docx/F07-inline-images-exhibit.md +0 -34
- package/test/fixtures/docx/F08-hyperlinks.docx +0 -0
- package/test/fixtures/docx/F08-hyperlinks.md +0 -33
- package/test/fixtures/docx/F09-comments-single-paragraph.docx +0 -0
- package/test/fixtures/docx/F09-comments-single-paragraph.md +0 -33
- package/test/fixtures/docx/F10-threaded-comments-resolve.docx +0 -0
- package/test/fixtures/docx/F10-threaded-comments-resolve.md +0 -33
- package/test/fixtures/docx/F11-redlines-basic.docx +0 -0
- package/test/fixtures/docx/F11-redlines-basic.md +0 -33
- package/test/fixtures/docx/F12-redlines-paragraph-joins-splits.docx +0 -0
- package/test/fixtures/docx/F12-redlines-paragraph-joins-splits.md +0 -33
- package/test/fixtures/docx/F13-comments-on-deleted-text.docx +0 -0
- package/test/fixtures/docx/F13-comments-on-deleted-text.md +0 -33
- package/test/fixtures/docx/F14-revisions-in-tables-and-lists.docx +0 -0
- package/test/fixtures/docx/F14-revisions-in-tables-and-lists.md +0 -33
- package/test/fixtures/docx/F15-sections-headers-footers.docx +0 -0
- package/test/fixtures/docx/F15-sections-headers-footers.md +0 -33
- package/test/fixtures/docx/F16-footnotes-endnotes.docx +0 -0
- package/test/fixtures/docx/F16-footnotes-endnotes.md +0 -33
- package/test/fixtures/docx/F17-fields-and-toc.docx +0 -0
- package/test/fixtures/docx/F17-fields-and-toc.md +0 -33
- package/test/fixtures/docx/F18-content-controls-template.docx +0 -0
- package/test/fixtures/docx/F18-content-controls-template.md +0 -33
- package/test/fixtures/docx/F19-custom-xml-doc-assembly.docx +0 -0
- package/test/fixtures/docx/F19-custom-xml-doc-assembly.md +0 -35
- package/test/fixtures/docx/F20-unknown-ooxml-and-alternatecontent.docx +0 -0
- package/test/fixtures/docx/F20-unknown-ooxml-and-alternatecontent.md +0 -33
- package/test/fixtures/docx/F21-malformed-broken-docx.docx +0 -0
- package/test/fixtures/docx/F21-malformed-broken-docx.md +0 -33
- package/test/fixtures/docx/README.md +0 -74
- package/test/fixtures/docx/certification-manifest.json +0 -104
- package/test/fixtures/docx/fixtures.manifest.json +0 -196
- package/test/fixtures/encrypted-docx/README.md +0 -27
- package/test/fixtures/encrypted-docx/certification-manifest.json +0 -9
- package/test/fixtures/encrypted-docx/fixtures.manifest.json +0 -47
- package/test/fixtures/scenarios/docx/README.md +0 -25
- package/test/fixtures/scenarios/docx/S01-sow-template.docx +0 -0
- package/test/fixtures/scenarios/docx/S01-sow-template.md +0 -30
- package/test/fixtures/scenarios/docx/S02-bw-partner-user-licence-agreement-redlines.docx +0 -0
- package/test/fixtures/scenarios/docx/S02-bw-partner-user-licence-agreement-redlines.md +0 -32
- package/test/fixtures/scenarios/docx/scenario-manifest.json +0 -53
- package/test/formats/xlsx/io/xlsx-import.test.ts +0 -766
- package/test/formats/xlsx/model/workbook.test.ts +0 -669
- package/test/helpers/dom-setup.ts +0 -124
- package/test/io/comment-roundtrip.test.ts +0 -272
- package/test/io/complex-content-roundtrip.test.ts +0 -632
- package/test/io/docx-compatibility-regression.test.ts +0 -199
- package/test/io/docx-session.test.ts +0 -1495
- package/test/io/footnotes-roundtrip.test.ts +0 -318
- package/test/io/headers-footers-roundtrip.test.ts +0 -547
- package/test/io/numbering-roundtrip.test.ts +0 -234
- package/test/io/package-reader.test.ts +0 -199
- package/test/io/paragraph-properties-roundtrip.test.ts +0 -129
- package/test/io/preserved-package-roundtrip.test.ts +0 -365
- package/test/io/property-completeness.test.ts +0 -292
- package/test/io/revision-roundtrip.test.ts +0 -347
- package/test/io/structural-blocks.test.ts +0 -202
- package/test/io/table-media-roundtrip.test.ts +0 -448
- package/test/io/table-properties-roundtrip.test.ts +0 -569
- package/test/io/table-roundtrip.test.ts +0 -302
- package/test/io/text-roundtrip.test.ts +0 -344
- package/test/model/canonical-document.test.ts +0 -285
- package/test/preservation/opaque-fragment-store.test.ts +0 -121
- package/test/preservation/package-preservation.test.ts +0 -395
- package/test/preservation/store.test.ts +0 -84
- package/test/review/comment-remapping.test.ts +0 -220
- package/test/review/comment-store.test.ts +0 -180
- package/test/review/move-revisions.test.ts +0 -143
- package/test/review/property-change-revisions.test.ts +0 -225
- package/test/review/revision-actions.test.ts +0 -330
- package/test/review/revision-store.test.ts +0 -193
- package/test/runtime/session-capabilities.test.ts +0 -260
- package/test/runtime/table-commands.test.ts +0 -356
- package/test/runtime/table-schema.test.ts +0 -221
- package/test/runtime/tracked-changes-toggle.test.ts +0 -107
- package/test/ui/comment-review-surface.test.tsx +0 -114
- package/test/ui/reduced-motion-toggle.test.tsx +0 -137
- package/test/ui/word-review-editor.imported-scenarios.test.tsx +0 -169
- package/test/ui/word-review-editor.interaction.test.tsx +0 -1198
- package/test/ui/word-review-editor.test.js +0 -188
- package/test/ui/word-review-editor.test.tsx +0 -280
- package/test/ui-tailwind/search-plugin.test.ts +0 -286
- package/test/validation/compatibility-engine.test.ts +0 -336
- package/test/validation/compatibility-report.test.ts +0 -189
- package/test/validation/low-priority-word-surfaces.test.ts +0 -282
- package/test/validation/malformed-doc.test.ts +0 -113
- package/test-results/.last-run.json +0 -4
- package/wave.config.json +0 -406
|
@@ -1,809 +0,0 @@
|
|
|
1
|
-
# React Component Architecture and Front-End Structure Specification for an Excel-Compatible Spreadsheet Editor
|
|
2
|
-
|
|
3
|
-
## Interpretation of the problem
|
|
4
|
-
|
|
5
|
-
You want an XLSX sibling to an existing React OpenXML DOCX editor, with the same “architectural rigor and product honesty,” but with spreadsheet-native thinking rather than “rich text + cells.” The end product must be a single embeddable React component whose UI is a projection of a runtime-owned canonical workbook state. All edits must flow through commands → transactions → commit, never via direct UI mutation.
|
|
6
|
-
|
|
7
|
-
The file format must be treated as an OOXML/Open Packaging Conventions package: not “a handful of XML files,” but a ZIP-based part + relationship graph with content types, implicit/explicit relationships, extension parts, and Excel’s documented deviations/constraints.
|
|
8
|
-
|
|
9
|
-
Round-trip safety is the bar: import → runtime edit → export → reopen in modern Excel must work without repair prompts and without silently losing supported content. Anything that cannot meet that standard must be explicitly classified as preserve-only or unsupported-fatal (blocked). This is especially important because Excel relies heavily on extension lists, markup compatibility, and product-specific restrictions that go beyond XSD permissiveness.
|
|
10
|
-
|
|
11
|
-
## Research plan
|
|
12
|
-
|
|
13
|
-
The research goal was to produce implementation-ready architecture + product boundary specs grounded in primary standards and Excel behavior notes, with explicit separation between normative format rules and Excel-specific processing constraints.
|
|
14
|
-
|
|
15
|
-
**Information needs prioritized**
|
|
16
|
-
- What is structurally *required* for a valid XLSX package (OPC part graph, relationship rules, minimum workbook parts), and what is optional but common in real Excel files.
|
|
17
|
-
- How core SpreadsheetML constructs map to runtime state: workbook → sheets → rows/cols → sparse cells; cell value typing; shared strings; formulas and cached values; merge semantics; views/panes; comments (legacy + threaded) and their part graph.
|
|
18
|
-
- Where Excel’s real behavior diverges from ISO/ECMA descriptions: cell value restrictions, pane semantics, calc-chain behavior, formula/data-table restrictions, and “schema allows but Office forbids.”
|
|
19
|
-
- What must be preserved to avoid silent loss: extension lists (`extLst`), ignorable namespaces, and Excel extension parts (threaded comments, rich data, feature property bags, etc.).
|
|
20
|
-
- Safety + robustness considerations for ZIP/OPC parsing and export (duplicate entries, path traversal).
|
|
21
|
-
|
|
22
|
-
**Source strategy**
|
|
23
|
-
- OOXML packaging + structure: ECMA/c-rex OPC material and Microsoft Learn SpreadsheetML structure docs.
|
|
24
|
-
- “Office Implementation” notes against ISO: Microsoft Open Specifications for Office (notably MS-OI29500 and MS-OE376).
|
|
25
|
-
- Excel-specific extensions: Microsoft’s [MS-XLSX] spec PDF and pages on threaded comments/legacy placeholders.
|
|
26
|
-
- Open XML SDK references for part names and schema attribute mapping (useful for validation tooling and CI gates, not for runtime).
|
|
27
|
-
|
|
28
|
-
Primary standards provenance (for clarity): publishes ECMA-376; and publish ISO/IEC 29500; and publishes Office Open Specifications and Open XML SDK documentation.
|
|
29
|
-
|
|
30
|
-
## Findings
|
|
31
|
-
|
|
32
|
-
**XLSX is an OPC package with a relationship graph, not “files in a ZIP.”** In OPC, the package has a content type manifest (`/[Content_Types].xml`) and relationship parts that form a directed graph. Package-level relationships live in `/_rels/.rels`, and each part `/a/b/c.xml` has relationships in `/a/b/_rels/c.xml.rels`. Relationship IDs and relationship types are first-class; they are how parts refer to each other without hardcoding paths.
|
|
33
|
-
|
|
34
|
-
**A minimum SpreadsheetML workbook is workbook-centric and sheet parts are referenced by relationship IDs.** The `<workbook/>` contains `<sheets/>` with `<sheet/>` entries that refer to worksheet parts via `r:id` relationship IDs. Each worksheet is its own part, and the workbook’s relationships part binds those IDs to targets. This is the base that must survive round-trip unchanged unless intentionally modified.
|
|
35
|
-
|
|
36
|
-
**Cell storage is typed and has Excel-specific restrictions beyond the base standard.** SpreadsheetML represents a cell as `<c>` with a reference `r`, optional style index `s`, value element `<v>`, optional formula `<f>`, and (for inline strings) `<is>` instead of `<v>`. If `t="inlineStr"`, `<is>` is used rather than `<v>`.
|
|
37
|
-
Office imposes tight constraints on `<v>`: strings stored via shared strings must have `<v>` be a 0-based shared-string index; booleans must be `0/1`; errors must be one of the canonical error strings; formula cells store the last calculated result in `<v>`. Excel also enforces a maximum of 32,767 characters for the `<v>` text.
|
|
38
|
-
|
|
39
|
-
**Shared strings are a cross-workbook table with strict cardinality.** The shared string table (`<sst/>`) exists to deduplicate strings; SpreadsheetML expects exactly one shared string table part per workbook when shared-string storage is used.
|
|
40
|
-
Practically: a runtime must be able to map between shared-string indices and actual string content, and must not casually rewrite the SST unless it can do so without breaking indices, preserving ordering, and preserving unused-but-referenced entries.
|
|
41
|
-
|
|
42
|
-
**Formulas are not just strings: shared formulas, arrays, and data tables exist, and Excel adds extra restrictions.** The `<f>` element encodes the formula expression and has attributes such as `t` (normal/shared/array/dataTable) and `si` for shared formula groups; shared formulas use a “master formula” plus relative offsets for dependent cells.
|
|
43
|
-
Excel places additional constraints around data-table formulas (input cell restrictions, `bx` usage, etc.), and those constraints matter for export fidelity if your editor touches these structures.
|
|
44
|
-
|
|
45
|
-
**Calculation metadata is both spec-level and Excel-version-level.** Spreadsheet calculation metadata includes workbook and sheet calculation properties (e.g., `fullCalcOnLoad`). The `fullCalcOnLoad` attribute exists at least at the worksheet calculation property layer, and its semantics are explicitly “force full calculate on load.”
|
|
46
|
-
Excel has additional calculation-engine versioning mechanisms (e.g., `calcId` + calc feature lists) that affect when Excel decides to recalculate on open. The [MS-XLSX] spec describes calc feature lists that add granularity and can trigger recalculation if features are missing.
|
|
47
|
-
|
|
48
|
-
**Merged cells have a real semantic constraint: only the top-left cell owns content/formatting.** The merged cell ranges are expressed under `<mergeCells>` with `<mergeCell ref="C2:F2"/>` etc, and the merged range’s content/format is stored in the top-left cell; other cells in the merge are effectively ignored for content. This is not optional behavior; Excel relies on it.
|
|
49
|
-
|
|
50
|
-
**Comments/notes are structurally multi-part, and Excel’s modern threaded comments layer adds more complexity.**
|
|
51
|
-
Legacy cell comments (“notes”) are stored in a dedicated comments part (`application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml`) with authors + comment list, and each worksheet that has comments has exactly one comments part.
|
|
52
|
-
The *visual comment box* is persisted via VML and linked from the worksheet via `legacyDrawing` relationships to a `.vml` drawing part; this makes “editing comments safely” inherently a multi-part edit (comments XML + VML + relationships).
|
|
53
|
-
Threaded comments are separate parts with their own content types and relationship expectations, and Excel often creates legacy comment placeholders to support backward compatibility; those placeholders have formatting/author conventions (e.g., `author` containing `tc={uid}`) that are part of real Excel behavior.
|
|
54
|
-
|
|
55
|
-
**View metadata and frozen panes are a place where Office behavior diverges from the written standard.** Microsoft’s standards-support notes document that pane attributes in the standard are underspecified or reversed relative to Office behavior (e.g., xSplit/ySplit reversed, TopLeftCell treated as required in some cases, and xSplit/ySplit not supported as zero in SheetView). If you write panes naïvely “by the book,” you can create files that Excel “repairs” or “interprets differently.”
|
|
56
|
-
|
|
57
|
-
**Extension lists and markup compatibility are not edge cases in Excel; they’re normal.** The [MS-XLSX] PDF contains many cases of extensions to existing elements via `extLst`, including requirements that extension namespaces be marked ignorable to maintain compatibility. If you reserialize without preserving `extLst` or `mc:Ignorable` semantics, you’ll silently drop content that Excel cares about (slicers/timelines/rich features, etc.).
|
|
58
|
-
|
|
59
|
-
**Security/robustness note: ZIP parsing must defend against duplicate-entry attacks.** OOXML files are ZIPs. If a ZIP contains duplicate file names/paths, different consumers might pick different entries, which creates both security and interoperability hazards. A GitHub-reviewed advisory for Apache POI highlights this exact class of issue for OOXML formats. Your editor must treat this as unsafe input and fail fast.
|
|
60
|
-
|
|
61
|
-
## Recommended design / decisions
|
|
62
|
-
|
|
63
|
-
**Design stance**
|
|
64
|
-
- Treat the runtime’s workbook model as a spreadsheet-native data structure: sheets, rows/cols, ranges, formula graphs, styles, and view metadata. The UI is a projection of this state, not the owner of it.
|
|
65
|
-
- Treat the XLSX package as a preserved graph: you must track parts, relationships, and content types, and decide—explicitly—what you own vs. what you only preserve. That’s the difference between “edits spreadsheets” and “exports spreadsheets that Excel trusts.”
|
|
66
|
-
|
|
67
|
-
**Shared vs spreadsheet-specific architecture**
|
|
68
|
-
- **Shareable platform layer (should be common with your DOCX editor):** command bus and transaction boundaries; undo/redo journal; runtime subscription (`useSyncExternalStore` integration); compatibility report and response taxonomy (preserve/lock/warn/block/fail); persistence/autosave adapters; and a generic OPC package store that can preserve unknown parts/relationships without loss. OPC is common across DOCX/XLSX/PPTX.
|
|
69
|
-
- **Spreadsheet-specific (must not be forced into a rich-text-shaped abstraction):** cell grid model; selection semantics; formula parsing, dependency graphs, and reference rewrite rules; sheet views/panes; sheet tab metadata; row/column structural edits; merged cell topology; and spreadsheet styling/number formats.
|
|
70
|
-
|
|
71
|
-
**Scope honesty decisions (v1 defaults)**
|
|
72
|
-
- **Supported-roundtrip (must pass import→edit→export→reopen without repair prompts):** cell values (string/number/bool/error), shared strings and inline strings, basic styles (fonts/fills/borders + cellXfs references), number formats (custom + a sane built-in subset), merges, row/column insert/delete with reference rewrites, sheet creation/rename/reorder, and frozen panes basic support.
|
|
73
|
-
- **Preserve-only (must preserve bytes/markup, can render read-only, but runtime cannot safely mutate):** chartsheet, pivot tables/caches, slicers/timelines, rich value types, external data models, any `extLst` content not explicitly modeled, threaded comments (edit), and most advanced conditional formatting and table features unless specifically implemented. This is aligned with the reality that Excel’s extension ecosystem is huge and frequently uses extension parts.
|
|
74
|
-
- **Unsupported-fatal (block import or block export):** encrypted/protected workbooks if you can’t decrypt; invalid OPC packages (duplicate part names, illegal paths, broken relationship graph); and any workbook where editing would require reserializing unknown extensions in ways you can’t preserve.
|
|
75
|
-
|
|
76
|
-
**Formula stance (practical and Excel-compatible)**
|
|
77
|
-
- Do not promise a full Excel-compatible calc engine in-browser. That’s a multi-year project because function semantics and calc-engine versioning are deep.
|
|
78
|
-
- Still treat formulas as first-class runtime entities: parse, index dependencies, and rewrite references on structural edits; allow editing formula text with solid validation and clear error states. Shared-formula groups (`t="shared"`, `si`, `ref`) must be preserved and updated correctly when edits intersect their ranges, or you should degrade them to explicit formulas as a deliberate, visible transaction decision (with a warning).
|
|
79
|
-
- Export strategy for calc correctness: set `fullCalcOnLoad` (workbook and/or sheet-level as appropriate) when any formula-affecting change occurs, and treat cached `<v>` values as best-effort display data rather than authoritative. This keeps Excel as the computation authority and reduces the risk of stale cached results being interpreted as “truth.”
|
|
80
|
-
|
|
81
|
-
**Comments stance (honest and safe)**
|
|
82
|
-
- v1: **support legacy comments/notes editing** only if you implement the multi-part update correctly (comments XML + VML drawing + relationships), and you have fixtures across Excel versions. Otherwise, make comments preserve-only. The format literally stores the visible comment box in VML, so “edit comments” is not a single XML edit.
|
|
83
|
-
- Threaded comments: preserve-only in v1; editing them safely requires also maintaining placeholders and associated structures described in [MS-XLSX].
|
|
84
|
-
|
|
85
|
-
## Risks and open questions
|
|
86
|
-
|
|
87
|
-
**Excel compatibility debt is mostly in the “unknown unknowns” of extensions and application behavior.** The [MS-XLSX] document explicitly warns that schema/XSD may be less restrictive than application processing rules, and then layers product-specific restrictions on top. This means “XSD-valid” is not the same as “Excel-opens-without-repair.” Your validation gates must target Excel behavior, not just XML well-formedness.
|
|
88
|
-
|
|
89
|
-
**Pane/view metadata is a known trap.** If you write frozen panes based on a naïve reading of standard text, Office can interpret xSplit/ySplit differently, treat TopLeftCell differently, and reject “zero” splits in some contexts. This is exactly the kind of thing that causes repair prompts.
|
|
90
|
-
|
|
91
|
-
**Formula engine scope creep is real.** Even if you don’t compute values, you still must correctly track dependencies, update references on inserts/deletes, handle shared formulas, and avoid corrupting calcChain/calc metadata. The calc engine feature/version metadata in [MS-XLSX] is another area where you can inadvertently force full recalc or create mismatch warnings.
|
|
92
|
-
|
|
93
|
-
**Preservation correctness is harder than parsing correctness.** It’s easy to “read enough to show a grid.” It’s hard to guarantee you won’t drop `extLst`, ignorable namespaces, or parts you didn’t even know existed, especially when reserializing. The architecture must treat preservation as a first-class subsystem, not an afterthought.
|
|
94
|
-
|
|
95
|
-
**ZIP/OPC security and determinism.** Duplicate entries and path confusion can lead to different consumers reading different data. You need strict input validation (reject duplicates after canonicalization; reject `..`; reject odd unicode normalization issues in part names) and deterministic export ordering.
|
|
96
|
-
|
|
97
|
-
**Open question: snapshot persistence strategy.** If snapshots do not preserve the original unknown parts, you cannot guarantee “preserve-only means preserved.” But storing full package bytes in every snapshot may be expensive. You likely need a two-tier persistence model (store base XLSX blob once; store incremental runtime state + a preservation index keyed to the base blob). This is an architectural decision that impacts autosave, collaboration, and storage budgets.
|
|
98
|
-
|
|
99
|
-
## Concrete deliverable in the requested format
|
|
100
|
-
|
|
101
|
-
**File: `docs/specs/spreadsheet-editor-architecture.md`**
|
|
102
|
-
|
|
103
|
-
**Purpose and architectural goals**
|
|
104
|
-
- Deliver a single embeddable React component (`<SpreadsheetEditor />`) that can import XLSX, allow controlled spreadsheet editing, and export XLSX that reopens in modern Excel without repair prompts.
|
|
105
|
-
- Canonical truth lives in a runtime-controlled workbook state model. React is a subscriber/projection layer only.
|
|
106
|
-
- Every mutation flows through `Command → Transaction → Commit`, producing deterministic patches for undo/redo, auditing, and testability.
|
|
107
|
-
- Preservation is mandatory: unsupported but preservable content must not be dropped; it must be retained at the OPC part/relationship level and, where applicable, at XML subtree level inside editor-owned parts.
|
|
108
|
-
- “Response model stays explicit”: preserve, lock, warn, block, fail.
|
|
109
|
-
|
|
110
|
-
**Normative vs observed behavior policy**
|
|
111
|
-
- **Normative sources**: OPC and SpreadsheetML structural rules (package relationships, part naming, basic SpreadsheetML element semantics).
|
|
112
|
-
- **Observed Excel behavior** (treated as correctness constraints for export): Microsoft “standards support” notes and [MS-XLSX] processing restrictions, including pane interpretation, `<v>` typing/length, and various “schema allows but Office forbids” cases.
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
**Public component contract**
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
export type SpreadsheetEditorPhase =
|
|
120
|
-
| "booting"
|
|
121
|
-
| "loading"
|
|
122
|
-
| "ready"
|
|
123
|
-
| "diagnostics"
|
|
124
|
-
| "error";
|
|
125
|
-
|
|
126
|
-
export interface SpreadsheetEditorProps {
|
|
127
|
-
documentId: string;
|
|
128
|
-
|
|
129
|
-
/** Host-supplied user identity for audit/events, not for Excel file authorship unless you implement it */
|
|
130
|
-
currentUser: { id: string; displayName: string };
|
|
131
|
-
|
|
132
|
-
/** Uncontrolled by default: provide initial XLSX bytes or an editor snapshot. */
|
|
133
|
-
initialXlsx?: ArrayBuffer | Uint8Array;
|
|
134
|
-
initialSnapshot?: PersistedSpreadsheetSnapshot;
|
|
135
|
-
|
|
136
|
-
/** If provided, host owns persistence; runtime calls adapter for autosave/export workflows. */
|
|
137
|
-
datastore?: SpreadsheetDatastoreAdapter;
|
|
138
|
-
|
|
139
|
-
/** Runtime config */
|
|
140
|
-
readOnly?: boolean;
|
|
141
|
-
locale?: string; // default: "en-US"
|
|
142
|
-
timeZone?: string; // default: host TZ; used for display only
|
|
143
|
-
featureFlags?: Partial<SpreadsheetFeatureFlags>;
|
|
144
|
-
|
|
145
|
-
/** UI config (projection only) */
|
|
146
|
-
ui?: Partial<SpreadsheetEditorUiConfig>;
|
|
147
|
-
|
|
148
|
-
/** Events are low-volume and semantic (no per-cell keystroke spam). */
|
|
149
|
-
onEvent?: (ev: SpreadsheetEditorEvent) => void;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export interface SpreadsheetEditorRef {
|
|
153
|
-
focus(): void;
|
|
154
|
-
blur(): void;
|
|
155
|
-
|
|
156
|
-
undo(): void;
|
|
157
|
-
redo(): void;
|
|
158
|
-
|
|
159
|
-
/** Programmatic selection (still goes through runtime). */
|
|
160
|
-
setSelection(sel: SelectionSpec): void;
|
|
161
|
-
|
|
162
|
-
/** Export uses runtime-owned state + preserved package graphs. */
|
|
163
|
-
exportXlsx(options?: ExportOptions): Promise<ExportResult>;
|
|
164
|
-
|
|
165
|
-
/** Snapshot includes runtime state + preservation index. */
|
|
166
|
-
getSnapshot(): PersistedSpreadsheetSnapshot;
|
|
167
|
-
|
|
168
|
-
/** Useful for hosts that want to drive commands directly. */
|
|
169
|
-
dispatch(cmd: SpreadsheetCommand): void;
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Contract design notes**
|
|
174
|
-
- The component is “uncontrolled” with respect to workbook content. Host can replace the document only by explicit ref methods or by mounting a new `documentId`.
|
|
175
|
-
- The host API is typed and imperative for correctness: spreadsheets have too many coordinated invariants (references, merge topology, styles) to safely expose “mutable props” patterns.
|
|
176
|
-
- The event model is explicit about diagnostic severity and export gating.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
**Imperative ref API and command surface**
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
export type SpreadsheetCommand =
|
|
184
|
-
| { type: "cell.setValue"; sheetId: SheetId; addr: CellAddr; value: CellInputValue }
|
|
185
|
-
| { type: "cell.setFormula"; sheetId: SheetId; addr: CellAddr; formula: string }
|
|
186
|
-
| { type: "range.paste"; sheetId: SheetId; target: CellAddr; payload: PastePayload }
|
|
187
|
-
| { type: "row.insert"; sheetId: SheetId; rowIndex: number; count: number }
|
|
188
|
-
| { type: "row.delete"; sheetId: SheetId; rowIndex: number; count: number }
|
|
189
|
-
| { type: "col.insert"; sheetId: SheetId; colIndex: number; count: number }
|
|
190
|
-
| { type: "col.delete"; sheetId: SheetId; colIndex: number; count: number }
|
|
191
|
-
| { type: "cells.merge"; sheetId: SheetId; range: A1Range }
|
|
192
|
-
| { type: "cells.unmerge"; sheetId: SheetId; range: A1Range }
|
|
193
|
-
| { type: "sheet.add"; name: string; afterSheetId?: SheetId }
|
|
194
|
-
| { type: "sheet.rename"; sheetId: SheetId; name: string }
|
|
195
|
-
| { type: "sheet.reorder"; sheetId: SheetId; afterSheetId?: SheetId }
|
|
196
|
-
| { type: "sheet.delete"; sheetId: SheetId }
|
|
197
|
-
| { type: "view.freezePanes"; sheetId: SheetId; freeze: { rows: number; cols: number } | null }
|
|
198
|
-
| { type: "comment.setNote"; sheetId: SheetId; addr: CellAddr; note: string | null }
|
|
199
|
-
| { type: "styles.apply"; sheetId: SheetId; range: A1Range; style: StyleDelta };
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
**Command semantics**
|
|
203
|
-
- Commands are the *only* mutation entrypoint.
|
|
204
|
-
- Each command is validated against both runtime invariants and “Excel export invariants” (see validation layer).
|
|
205
|
-
- Commands can be refused with explicit outcomes: preserve/lock/warn/block/fail.
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
**Runtime/controller architecture**
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
export interface WorkbookRuntime {
|
|
213
|
-
/** React uses useSyncExternalStore */
|
|
214
|
-
subscribe(cb: () => void): () => void;
|
|
215
|
-
getRenderSnapshot(): RuntimeRenderSnapshot;
|
|
216
|
-
|
|
217
|
-
/** Commands only */
|
|
218
|
-
dispatch(cmd: SpreadsheetCommand): void;
|
|
219
|
-
|
|
220
|
-
/** Export / persistence */
|
|
221
|
-
exportXlsx(options?: ExportOptions): Promise<ExportResult>;
|
|
222
|
-
getSnapshot(): PersistedSpreadsheetSnapshot;
|
|
223
|
-
|
|
224
|
-
/** Diagnostics */
|
|
225
|
-
getCompatibilityReport(): CompatibilityReport;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export interface RuntimeRenderSnapshot {
|
|
229
|
-
phase: SpreadsheetEditorPhase;
|
|
230
|
-
activeSheetId: SheetId;
|
|
231
|
-
|
|
232
|
-
viewport: {
|
|
233
|
-
topRow: number;
|
|
234
|
-
leftCol: number;
|
|
235
|
-
rowCount: number;
|
|
236
|
-
colCount: number;
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
selection: SelectionState;
|
|
240
|
-
|
|
241
|
-
/** Render-ready cells for the visible region only. */
|
|
242
|
-
visibleCells: RenderCell[][];
|
|
243
|
-
|
|
244
|
-
/** UI-facing derived state */
|
|
245
|
-
canUndo: boolean;
|
|
246
|
-
canRedo: boolean;
|
|
247
|
-
isDirty: boolean;
|
|
248
|
-
|
|
249
|
-
diagnostics: {
|
|
250
|
-
warnings: SpreadsheetWarning[];
|
|
251
|
-
errors: SpreadsheetError[];
|
|
252
|
-
compatibility: CompatibilityReportSummary;
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
**Key architectural constraints enforced**
|
|
258
|
-
- Canonical workbook truth (`WorkbookState`) is runtime-owned.
|
|
259
|
-
- React reads `RuntimeRenderSnapshot` via `useSyncExternalStore`.
|
|
260
|
-
- UI-local state is allowed only for presentation toggles (panel open/closed, theme, active tab), never for workbook truth.
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
**Internal module boundaries**
|
|
265
|
-
|
|
266
|
-
Recommended top-level package boundaries (names are illustrative, align to your repo conventions):
|
|
267
|
-
|
|
268
|
-
- `src/opc/`
|
|
269
|
-
- ZIP ingestion/export, part naming and canonicalization, `[Content_Types].xml` management, relationships graph, deterministic export.
|
|
270
|
-
- **Must** reject unsafe packages (duplicate part names, illegal paths).
|
|
271
|
-
|
|
272
|
-
- `src/xlsx/import/`
|
|
273
|
-
- SpreadsheetML parsing into `WorkbookState` + `PreservationStore`.
|
|
274
|
-
- Part discovery based on relationships, not assumed paths.
|
|
275
|
-
|
|
276
|
-
- `src/xlsx/model/`
|
|
277
|
-
- Canonical workbook/sheet/cell/range state.
|
|
278
|
-
- Row/col metadata, merges, defined names (if supported), styles references, view metadata.
|
|
279
|
-
|
|
280
|
-
- `src/xlsx/formulas/`
|
|
281
|
-
- Lexer/parser → AST; dependency graph; reference rewrite engine for inserts/deletes.
|
|
282
|
-
- Export (string) + import (string) round-trip; shared formula group handling.
|
|
283
|
-
|
|
284
|
-
- `src/xlsx/styles/`
|
|
285
|
-
- Styles table model, number format model (custom + built-in subset), style deduplication, display formatting.
|
|
286
|
-
|
|
287
|
-
- `src/preservation/`
|
|
288
|
-
- Part-level preservation (unknown parts, relationships) + subtree-level preservation inside partially-owned parts.
|
|
289
|
-
- `extLst` + `mc:Ignorable` preservation is explicitly tested.
|
|
290
|
-
|
|
291
|
-
- `src/validation/`
|
|
292
|
-
- Fast runtime invariants + export gate validations.
|
|
293
|
-
- CI-only validation adapters (Open XML SDK / Excel open tests).
|
|
294
|
-
|
|
295
|
-
- `src/runtime/`
|
|
296
|
-
- `WorkbookRuntimeImpl`, command dispatcher, transaction engine, undo/redo journal, snapshot builder, autosave orchestrator.
|
|
297
|
-
|
|
298
|
-
- `src/ui/`
|
|
299
|
-
- Presentational components (grid viewport, sheet tabs, formula bar, status/diagnostics panels).
|
|
300
|
-
- `src/ui/headless/` for selection math, keyboard mapping, pointer-to-cell addressing, clipboard normalization.
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
**Canonical workbook state model**
|
|
305
|
-
|
|
306
|
-
A spreadsheet-native canonical model that can survive large sheets must be sparse and normalized.
|
|
307
|
-
|
|
308
|
-
```ts
|
|
309
|
-
export type WorkbookId = string;
|
|
310
|
-
export type SheetId = string;
|
|
311
|
-
|
|
312
|
-
export interface WorkbookState {
|
|
313
|
-
workbookId: WorkbookId;
|
|
314
|
-
|
|
315
|
-
/** Workbook-level metadata we may preserve but not necessarily edit. */
|
|
316
|
-
metadata: {
|
|
317
|
-
calc: {
|
|
318
|
-
/** If formulas changed and we can't compute accurate cached values, set recalc on load. */
|
|
319
|
-
fullCalcOnLoad: boolean;
|
|
320
|
-
/** Preserve calcId/calcFeatures if present; treat as preserve-only unless explicitly supported. */
|
|
321
|
-
calcId?: number;
|
|
322
|
-
calcFeatures?: string[];
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
/** Sheet order is explicit and stable. */
|
|
326
|
-
sheetOrder: SheetId[];
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
sheets: Record<SheetId, SheetState>;
|
|
330
|
-
|
|
331
|
-
/** Global tables */
|
|
332
|
-
sharedStrings: SharedStringTableState;
|
|
333
|
-
styles: StylesState;
|
|
334
|
-
|
|
335
|
-
/** Preservation of parts and unknown markup. */
|
|
336
|
-
preservation: PreservationStore;
|
|
337
|
-
|
|
338
|
-
/** Diagnostics derived from last import + ongoing edits. */
|
|
339
|
-
compatibility: CompatibilityReport;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export interface SheetState {
|
|
343
|
-
sheetId: SheetId;
|
|
344
|
-
name: string;
|
|
345
|
-
|
|
346
|
-
grid: {
|
|
347
|
-
/** Sparse cell map by numeric row/col key. */
|
|
348
|
-
cells: SparseCellMap;
|
|
349
|
-
rowMeta: RowMetaMap;
|
|
350
|
-
colMeta: ColMetaMap;
|
|
351
|
-
|
|
352
|
-
merges: MergeModel;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
view: SheetViewState;
|
|
356
|
-
|
|
357
|
-
comments: SheetCommentsState;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
export interface CellAddr {
|
|
361
|
-
row: number; // 1-based to match SpreadsheetML and A1 mental model
|
|
362
|
-
col: number; // 1-based
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export type CellValue =
|
|
366
|
-
| { kind: "blank" }
|
|
367
|
-
| { kind: "number"; value: number }
|
|
368
|
-
| { kind: "string"; value: string; storage: "sharedString" | "inlineString" }
|
|
369
|
-
| { kind: "boolean"; value: boolean }
|
|
370
|
-
| { kind: "error"; value: "#NULL!" | "#DIV/0!" | "#VALUE!" | "#REF!" | "#NAME?" | "#NUM!" | "#N/A" }
|
|
371
|
-
| { kind: "date"; iso8601: string }; // support only if safely round-trippable in Excel
|
|
372
|
-
|
|
373
|
-
export interface CellState {
|
|
374
|
-
addr: CellAddr;
|
|
375
|
-
|
|
376
|
-
/** Style index references cellXfs; do not embed large style objects per cell. */
|
|
377
|
-
styleRef?: { xfIndex: number };
|
|
378
|
-
|
|
379
|
-
/** Either value or formula (or both, where value is cached display). */
|
|
380
|
-
value?: CellValue;
|
|
381
|
-
formula?: FormulaState;
|
|
382
|
-
|
|
383
|
-
/** Provenance and preservation */
|
|
384
|
-
origin: "imported" | "runtime";
|
|
385
|
-
preservedXml?: PreservedCellXml; // for unknown attributes/elements like extLst, vm, cm, etc.
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export interface FormulaState {
|
|
389
|
-
text: string; // e.g. "SUM(C4:E4)"
|
|
390
|
-
ast?: FormulaAst; // optional, for editing/rewrites
|
|
391
|
-
kind: "normal" | "shared" | "array" | "dataTable";
|
|
392
|
-
shared?: { si: number; ref?: A1Range }; // when kind === "shared"
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
**Key invariants**
|
|
397
|
-
- Cell values must obey Excel’s typing restrictions on `<v>` based on `t`, and must respect Excel’s string length constraints.
|
|
398
|
-
- Inline strings (`t="inlineStr"`) do not use `<v>`, and must be represented as `<is>` / rich text inline structures.
|
|
399
|
-
- Merged regions store content/format in the top-left cell; runtime must enforce this to avoid generating semantically-invalid merges.
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
**Selection model**
|
|
404
|
-
|
|
405
|
-
Selection must be spreadsheet-native (Excel-like), not text-selection-like.
|
|
406
|
-
|
|
407
|
-
```ts
|
|
408
|
-
export type A1Range = { a1: string; }; // serialized form for API boundaries
|
|
409
|
-
export type NormalizedRange = { r1: number; c1: number; r2: number; c2: number };
|
|
410
|
-
|
|
411
|
-
export interface SelectionState {
|
|
412
|
-
activeCell: CellAddr;
|
|
413
|
-
/** The “primary” selection is what fill-handle / editing uses. */
|
|
414
|
-
primary: NormalizedRange;
|
|
415
|
-
/** Multi-range selections (Ctrl+click) */
|
|
416
|
-
additional: NormalizedRange[];
|
|
417
|
-
mode: "cell" | "row" | "col" | "range";
|
|
418
|
-
isEditingCell: boolean;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
export interface SelectionSpec {
|
|
422
|
-
sheetId: SheetId;
|
|
423
|
-
activeCell: CellAddr;
|
|
424
|
-
primary: NormalizedRange;
|
|
425
|
-
additional?: NormalizedRange[];
|
|
426
|
-
}
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
**Behavioral requirements**
|
|
430
|
-
- Arrow keys move active cell; Shift extends primary range; Ctrl/Command changes navigation granularity depending on platform conventions.
|
|
431
|
-
- Editing state is separate: when `isEditingCell`, keystrokes go to the cell editor overlay; otherwise, they are navigation/commands.
|
|
432
|
-
- Selection is not stored in React; it’s runtime state so that undo/redo and command replay are deterministic.
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
**Command and transaction system**
|
|
437
|
-
|
|
438
|
-
```ts
|
|
439
|
-
export interface Transaction {
|
|
440
|
-
id: string;
|
|
441
|
-
label: string;
|
|
442
|
-
timestamp: number;
|
|
443
|
-
commands: SpreadsheetCommand[];
|
|
444
|
-
/** Atomic patch results */
|
|
445
|
-
patch: WorkbookPatch;
|
|
446
|
-
inversePatch: WorkbookPatch;
|
|
447
|
-
diagnostics: TransactionDiagnostics;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
export interface TransactionDiagnostics {
|
|
451
|
-
warnings: SpreadsheetWarning[];
|
|
452
|
-
errors: SpreadsheetError[];
|
|
453
|
-
/** Explicit export gate */
|
|
454
|
-
exportDisposition: "allow" | "block";
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export interface WorkbookPatch {
|
|
458
|
-
/** Structural ops in a compact, replayable form */
|
|
459
|
-
ops: PatchOp[];
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
export type PatchOp =
|
|
463
|
-
| { op: "cell.upsert"; sheetId: SheetId; cell: CellState }
|
|
464
|
-
| { op: "cell.delete"; sheetId: SheetId; addr: CellAddr }
|
|
465
|
-
| { op: "row.insert"; sheetId: SheetId; rowIndex: number; count: number }
|
|
466
|
-
| { op: "row.delete"; sheetId: SheetId; rowIndex: number; count: number }
|
|
467
|
-
| { op: "col.insert"; sheetId: SheetId; colIndex: number; count: number }
|
|
468
|
-
| { op: "col.delete"; sheetId: SheetId; colIndex: number; count: number }
|
|
469
|
-
| { op: "merge.set"; sheetId: SheetId; merges: MergeModel }
|
|
470
|
-
| { op: "view.set"; sheetId: SheetId; view: SheetViewState }
|
|
471
|
-
| { op: "styles.set"; styles: StylesState }
|
|
472
|
-
| { op: "sharedStrings.set"; sharedStrings: SharedStringTableState }
|
|
473
|
-
| { op: "preservation.update"; delta: PreservationDelta };
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
**Transaction rules**
|
|
477
|
-
- Validate command preconditions before applying.
|
|
478
|
-
- Apply commands to a draft state, computing:
|
|
479
|
-
- reference rewrite deltas (formulas, defined names, charts ranges if owned),
|
|
480
|
-
- merge topology adjustments,
|
|
481
|
-
- style/shared-string table updates.
|
|
482
|
-
- Commit as a single transaction:
|
|
483
|
-
- update canonical state,
|
|
484
|
-
- update derived caches (dependency graph, visible cell projection cache),
|
|
485
|
-
- append transaction to undo journal,
|
|
486
|
-
- publish render snapshot.
|
|
487
|
-
|
|
488
|
-
---
|
|
489
|
-
|
|
490
|
-
**Import pipeline**
|
|
491
|
-
|
|
492
|
-
**Input safety gates (fail fast)**
|
|
493
|
-
- Reject ZIPs with duplicate entry names (after canonicalization), illegal `..` traversal, or ambiguous unicode-normalized paths.
|
|
494
|
-
- Reject packages that cannot be represented as a coherent OPC graph (missing content types or unreadable relationships).
|
|
495
|
-
|
|
496
|
-
**Package parsing**
|
|
497
|
-
- Build `OpcPackage`:
|
|
498
|
-
- `parts: Map<PartName, Uint8Array>`
|
|
499
|
-
- `contentTypes: ContentTypesManifest`
|
|
500
|
-
- `relationships: RelationshipGraph` for package + per-part relationships
|
|
501
|
-
- Discover workbook part via package relationships (do not assume `/xl/workbook.xml`, though it’s typical).
|
|
502
|
-
|
|
503
|
-
**SpreadsheetML parsing into canonical state**
|
|
504
|
-
- Parse workbook.xml: sheet list, sheet ordering, sheet relationship bindings.
|
|
505
|
-
- Parse worksheet parts:
|
|
506
|
-
- `sheetData` rows/cells into sparse grid map
|
|
507
|
-
- merges
|
|
508
|
-
- row/col metadata
|
|
509
|
-
- sheetViews/panes
|
|
510
|
-
- relationships to comments, drawings, tables, etc. (preserve unknown)
|
|
511
|
-
- Parse shared strings: build stable index map; do **not** reorder.
|
|
512
|
-
- Parse styles: `cellXfs`, number formats, and preserve `extLst`.
|
|
513
|
-
|
|
514
|
-
**Preservation capture**
|
|
515
|
-
- Preserve all unknown parts as raw bytes.
|
|
516
|
-
- For editor-owned parts that contain unknown subtrees (extensions, drawings, data validation, conditional formatting, etc.), store preserved XML subtrees with stable re-insertion points.
|
|
517
|
-
|
|
518
|
-
---
|
|
519
|
-
|
|
520
|
-
**Export pipeline**
|
|
521
|
-
|
|
522
|
-
**Export principle**
|
|
523
|
-
- Export regenerates only editor-owned structures and preserves untouched parts and unknown markup/relationships where possible.
|
|
524
|
-
- Export must be deterministic: stable part ordering, stable relationship IDs when feasible, and stable sheet IDs unless deliberately changed.
|
|
525
|
-
|
|
526
|
-
**Owned vs preserved classification**
|
|
527
|
-
- Owned parts (v1 typical):
|
|
528
|
-
- workbook.xml (+ workbook rels if you add/remove sheets)
|
|
529
|
-
- worksheets/sheetN.xml for sheets you touched (but reinsert preserved subtrees)
|
|
530
|
-
- sharedStrings.xml if you touched any shared strings
|
|
531
|
-
- styles.xml if you changed/created styles
|
|
532
|
-
- comments + VML parts only if you fully implement legacy comment editing
|
|
533
|
-
- Preserved parts:
|
|
534
|
-
- any part not explicitly owned, including MS-XLSX extension parts, charts, pivot caches, rich data, etc.
|
|
535
|
-
|
|
536
|
-
**Recalculation policy**
|
|
537
|
-
- If any formula-bearing structure changes and you do not provide Excel-equivalent cached results, set calc recalculation-on-load flags (workbook and/or sheet) to ensure Excel recomputes.
|
|
538
|
-
- If you cannot correctly maintain calcChain semantics, treat calcChain as preserve-only or remove it deliberately and force full calculation on load, but never silently keep a broken calcChain. (This is a release gate item: you must empirically validate with Excel opening behavior.)
|
|
539
|
-
|
|
540
|
-
---
|
|
541
|
-
|
|
542
|
-
**Preservation layer**
|
|
543
|
-
|
|
544
|
-
```ts
|
|
545
|
-
export interface PreservationStore {
|
|
546
|
-
/** Whole-part preservation */
|
|
547
|
-
preservedParts: Record<string /* partName */, PreservedPart>;
|
|
548
|
-
|
|
549
|
-
/** For parts we rewrite but need to keep unknown content */
|
|
550
|
-
preservedSubtrees: Record<string /* partName */, PreservedXmlSubtree[]>;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
export interface PreservedPart {
|
|
554
|
-
partName: string; // e.g. "/xl/drawings/drawing1.xml"
|
|
555
|
-
contentType: string;
|
|
556
|
-
bytes: Uint8Array;
|
|
557
|
-
relationships?: Relationship[];
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export interface PreservedXmlSubtree {
|
|
561
|
-
/** Stable insertion anchor */
|
|
562
|
-
parentPath: string; // e.g. "worksheet"
|
|
563
|
-
beforeChild?: string; // e.g. "sheetData"
|
|
564
|
-
afterChild?: string; // e.g. "sheetData"
|
|
565
|
-
rawXml: string; // exact subtree text
|
|
566
|
-
namespaces: Record<string, string>;
|
|
567
|
-
}
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
**Preservation guarantees**
|
|
571
|
-
- Unknown parts are re-emitted byte-identical unless a spec-required relocation occurs (rare; should be a “warn + test” event).
|
|
572
|
-
- `extLst` subtrees survive intact, including extension URIs.
|
|
573
|
-
- Markup compatibility (`mc:Ignorable`) and ignorable prefixes survive intact.
|
|
574
|
-
|
|
575
|
-
---
|
|
576
|
-
|
|
577
|
-
**Validation layer**
|
|
578
|
-
|
|
579
|
-
Validation exists at three levels:
|
|
580
|
-
|
|
581
|
-
**Runtime invariants (fast, on every transaction)**
|
|
582
|
-
- Cell typing rules (string indices, booleans, errors).
|
|
583
|
-
- Merge topology: no overlaps, top-left ownership enforced.
|
|
584
|
-
- References: any formula rewrite must keep references in valid A1 form, and shared formula group invariants must hold.
|
|
585
|
-
|
|
586
|
-
**Export gate checks (before producing bytes)**
|
|
587
|
-
- OPC graph completeness: content types and relationship parts exist and match emitted parts.
|
|
588
|
-
- Excel behavior checks for known traps:
|
|
589
|
-
- pane/frozen panes attributes written according to Office behavior notes (not just XSD).
|
|
590
|
-
- comment graph correctness if comments are edited (comments part + VML + worksheet rels).
|
|
591
|
-
- Compatibility report must be “exportDisposition=allow” or export is blocked with explicit reasons.
|
|
592
|
-
|
|
593
|
-
**CI gates (slow, external tooling)**
|
|
594
|
-
- Open XML SDK validation in CI (schema/part sanity), used as a gate for PRs/releases.
|
|
595
|
-
- Excel open-and-save smoke tests (manual or automated harness) verifying no repair prompt and no loss of supported features.
|
|
596
|
-
|
|
597
|
-
---
|
|
598
|
-
|
|
599
|
-
**Warning/error model**
|
|
600
|
-
|
|
601
|
-
```ts
|
|
602
|
-
export type ContentDisposition = "supported-roundtrip" | "preserve-only" | "unsupported-fatal";
|
|
603
|
-
|
|
604
|
-
export type EditorResponse = "preserve" | "lock" | "warn" | "block" | "fail";
|
|
605
|
-
|
|
606
|
-
export interface CompatibilityItem {
|
|
607
|
-
id: string;
|
|
608
|
-
disposition: ContentDisposition;
|
|
609
|
-
response: EditorResponse;
|
|
610
|
-
title: string;
|
|
611
|
-
details: string;
|
|
612
|
-
|
|
613
|
-
/** Where it lives */
|
|
614
|
-
location?: { sheetId?: SheetId; rangeA1?: string; partName?: string };
|
|
615
|
-
|
|
616
|
-
/** Whether it blocks export */
|
|
617
|
-
blocksExport: boolean;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
export interface CompatibilityReport {
|
|
621
|
-
items: CompatibilityItem[];
|
|
622
|
-
summary: {
|
|
623
|
-
supportedRoundtripCount: number;
|
|
624
|
-
preserveOnlyCount: number;
|
|
625
|
-
unsupportedFatalCount: number;
|
|
626
|
-
exportBlocked: boolean;
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
export interface SpreadsheetWarning {
|
|
631
|
-
code: string;
|
|
632
|
-
message: string;
|
|
633
|
-
location?: CompatibilityItem["location"];
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
export interface SpreadsheetError {
|
|
637
|
-
code: string;
|
|
638
|
-
message: string;
|
|
639
|
-
location?: CompatibilityItem["location"];
|
|
640
|
-
fatal: boolean;
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
**Policy**
|
|
645
|
-
- Preserve-only content must be surfaced (warn) at least once per document, and export must guarantee preservation.
|
|
646
|
-
- Unsupported-fatal must block export (and often block import), never silently degrade.
|
|
647
|
-
|
|
648
|
-
---
|
|
649
|
-
|
|
650
|
-
**Persistence and autosave**
|
|
651
|
-
|
|
652
|
-
```ts
|
|
653
|
-
export interface PersistedSpreadsheetSnapshot {
|
|
654
|
-
schemaVersion: 1;
|
|
655
|
-
documentId: string;
|
|
656
|
-
createdAt: number;
|
|
657
|
-
|
|
658
|
-
/** Canonical runtime state */
|
|
659
|
-
workbook: WorkbookState;
|
|
660
|
-
|
|
661
|
-
/** Preservation index. Host can store big blobs separately if desired. */
|
|
662
|
-
preservationIndex: {
|
|
663
|
-
baseXlsxFingerprint: string;
|
|
664
|
-
preservedParts: Array<{
|
|
665
|
-
partName: string;
|
|
666
|
-
contentType: string;
|
|
667
|
-
sha256: string;
|
|
668
|
-
/** Either embedded or referenced */
|
|
669
|
-
bytesBase64?: string;
|
|
670
|
-
externalRef?: string;
|
|
671
|
-
}>;
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
export interface SpreadsheetDatastoreAdapter {
|
|
676
|
-
saveSnapshot(docId: string, snapshot: PersistedSpreadsheetSnapshot): Promise<void>;
|
|
677
|
-
loadSnapshot?(docId: string): Promise<PersistedSpreadsheetSnapshot | null>;
|
|
678
|
-
|
|
679
|
-
/** Optional: store base XLSX bytes once, refer by fingerprint in snapshots */
|
|
680
|
-
storeBaseXlsx?(docId: string, bytes: Uint8Array): Promise<{ fingerprint: string }>;
|
|
681
|
-
loadBaseXlsx?(fingerprint: string): Promise<Uint8Array>;
|
|
682
|
-
|
|
683
|
-
/** Optional: export artifact storage */
|
|
684
|
-
storeExport?(docId: string, bytes: Uint8Array): Promise<{ url?: string; id?: string }>;
|
|
685
|
-
}
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
**Autosave behavior**
|
|
689
|
-
- Autosave stores snapshots (small-ish JSON + referenced preserved blobs) on a timer and/or idle boundary, never on every keystroke.
|
|
690
|
-
- Autosave never exports XLSX unless explicitly configured; export is heavier and should be user- or host-triggered.
|
|
691
|
-
|
|
692
|
-
---
|
|
693
|
-
|
|
694
|
-
**Performance strategy**
|
|
695
|
-
|
|
696
|
-
- Parsing:
|
|
697
|
-
- Parse ZIP once on import; do not reparse the full workbook on each edit.
|
|
698
|
-
- For large worksheets, parse `sheetData` into a sparse structure; avoid allocating a 1,048,576×16,384 grid.
|
|
699
|
-
- Rendering:
|
|
700
|
-
- Virtualize viewport: only compute and render visible cells.
|
|
701
|
-
- Use a single overlay input for cell editing to avoid mounting thousands of editable inputs.
|
|
702
|
-
- Computation:
|
|
703
|
-
- Dependency graph updates are incremental: rerun only on impacted formula cells/ranges.
|
|
704
|
-
- Style and shared-string updates are incremental with stable indexing.
|
|
705
|
-
- Export:
|
|
706
|
-
- Only serialize dirty parts.
|
|
707
|
-
- Preserve untouched parts byte-identical.
|
|
708
|
-
|
|
709
|
-
---
|
|
710
|
-
|
|
711
|
-
**Clipboard and paste normalization boundaries**
|
|
712
|
-
|
|
713
|
-
- Support two clipboard tiers:
|
|
714
|
-
- **External clipboard**: plain text and TSV/CSV parsing into a rectangular paste payload.
|
|
715
|
-
- **Internal clipboard**: a custom MIME (e.g., `application/x-editor-grid`) for rich copy/paste within the editor, including formulas and styles, but only when pasted back into the same editor runtime.
|
|
716
|
-
- Paste normalization rules are explicit:
|
|
717
|
-
- Values: normalize numeric parsing by locale (optional), keep raw string if ambiguous.
|
|
718
|
-
- Formulas: only treat leading `=` as formula in “formula-aware” paste mode; otherwise paste literal.
|
|
719
|
-
- Styles: apply only in internal paste mode; external paste ignores formatting unless you explicitly implement HTML clipboard parsing.
|
|
720
|
-
|
|
721
|
-
---
|
|
722
|
-
|
|
723
|
-
**Spreadsheet-specific feature requirements and scope classification**
|
|
724
|
-
|
|
725
|
-
- Workbook/sheet/cell/range-native model: supported-roundtrip.
|
|
726
|
-
- Grid viewport and selection behavior: supported-roundtrip (runtime-owned).
|
|
727
|
-
- Formulas:
|
|
728
|
-
- Parse + rewrite references: supported-roundtrip.
|
|
729
|
-
- Full function evaluation parity with Excel: preserve-only (do not claim otherwise).
|
|
730
|
-
- Recalc-on-load flags: supported-roundtrip.
|
|
731
|
-
- Merged cells: supported-roundtrip.
|
|
732
|
-
- Row/column insertion/deletion: supported-roundtrip, but only if reference rewrite passes fixtures (see tests).
|
|
733
|
-
- Styles and number/date formatting:
|
|
734
|
-
- Preserve all styles: at minimum preserve-only unless you implement editing.
|
|
735
|
-
- Basic editing into `cellXfs` with stable indices: supported-roundtrip when implemented.
|
|
736
|
-
- Date typing must respect Office limitations; treat ambiguous cases as preserve-only.
|
|
737
|
-
- Comments/notes:
|
|
738
|
-
- Legacy notes editing: supported-roundtrip only if multi-part update is implemented and tested.
|
|
739
|
-
- Threaded comments editing: preserve-only.
|
|
740
|
-
- Sheet tabs and workbook metadata: sheet add/rename/reorder supported-roundtrip; deep workbook metadata preserve-only unless modeled.
|
|
741
|
-
- Preserve-only workbook features: charts/pivots/slicers/timelines/rich data models/unknown extensions preserve-only.
|
|
742
|
-
- Large-sheet virtualization: supported-roundtrip at UI level; must be designed in from day one.
|
|
743
|
-
- Frozen panes and view metadata:
|
|
744
|
-
- Preserve existing: supported-roundtrip.
|
|
745
|
-
- Edit freeze/unfreeze: supported-roundtrip only if written to match Office behavior notes.
|
|
746
|
-
|
|
747
|
-
---
|
|
748
|
-
|
|
749
|
-
**Implementation phases**
|
|
750
|
-
|
|
751
|
-
- Phase A: OPC package engine + security gates + deterministic export scaffold.
|
|
752
|
-
- Phase B: Minimal workbook import/export (workbook + one sheet + basic sheetData) + viewport rendering.
|
|
753
|
-
- Phase C: Selection model + keyboard navigation + cell edit overlay + undo/redo journal.
|
|
754
|
-
- Phase D: Formulas (parse + dependency graph + reference rewrite on row/col ops) + recalc-on-load policy wiring.
|
|
755
|
-
- Phase E: Merges + row/col insertion/deletion semantics + export gate checks.
|
|
756
|
-
- Phase F: Styles + number formats (preserve-first, then edit support) + formatting display.
|
|
757
|
-
- Phase G: Comments (legacy notes) if in scope, with rigorous fixtures; otherwise preserve-only with diagnostics UI.
|
|
758
|
-
- Phase H: CI validation gates (Open XML SDK + Excel reopen acceptance suite).
|
|
759
|
-
|
|
760
|
-
---
|
|
761
|
-
|
|
762
|
-
**Non-goals**
|
|
763
|
-
|
|
764
|
-
- Full Excel calculation engine parity (functions, volatile behavior, engine-version semantics). This is not realistic for v1; the product must not claim it.
|
|
765
|
-
- Editing of pivot tables, charts, slicers, timelines, data model, rich values, or other MS-XLSX extension features unless explicitly implemented and validated.
|
|
766
|
-
- Macro-enabled workbooks (.xlsm) unless explicitly supported (not covered here).
|
|
767
|
-
- “Excel ribbon clone” UI: the UI should be workflow-focused, not feature-exhaustive.
|
|
768
|
-
|
|
769
|
-
---
|
|
770
|
-
|
|
771
|
-
**Quality bar**
|
|
772
|
-
|
|
773
|
-
A feature is “supported-roundtrip” only when all are true:
|
|
774
|
-
- It survives import → edit → export → reopen in modern Excel with **no repair prompt**.
|
|
775
|
-
- It does not silently drop related content in any part/relationship.
|
|
776
|
-
- It passes:
|
|
777
|
-
- deterministic unit tests (command → patch/inverse patch),
|
|
778
|
-
- fixture round-trip tests (byte-level preservation for preserve-only parts),
|
|
779
|
-
- CI validation (Open XML SDK),
|
|
780
|
-
- manual or automated Excel reopen gates for representative files.
|
|
781
|
-
|
|
782
|
-
## Sources
|
|
783
|
-
|
|
784
|
-
OPC and SpreadsheetML structure
|
|
785
|
-
- OPC package rules, content types, and relationships part naming:
|
|
786
|
-
- SpreadsheetML workbook/sheet relationship structure:
|
|
787
|
-
- XLSX as “SpreadsheetML in an OOXML/OPC package,” and conformance context (Transitional usage):
|
|
788
|
-
|
|
789
|
-
Cell/value/formula semantics and Excel-specific constraints
|
|
790
|
-
- Cell element structure and inline string behavior:
|
|
791
|
-
- Formula element attributes and shared formula semantics:
|
|
792
|
-
- Excel restrictions on `<v>` values (type-based constraints and 32,767-char limit):
|
|
793
|
-
- Office constraints on formula data tables and related attributes:
|
|
794
|
-
- Calc and recalc semantics (`fullCalcOnLoad`) mappings:
|
|
795
|
-
|
|
796
|
-
Merges, views, comments
|
|
797
|
-
- MergeCells semantics, including top-left ownership of content/format:
|
|
798
|
-
- Office behavior differences for panes (xSplit/ySplit, TopLeftCell, etc.):
|
|
799
|
-
- Comments part rules (one comments part per commented worksheet) and relationship expectations:
|
|
800
|
-
- VML-based visual persistence for legacy comments/notes:
|
|
801
|
-
- Threaded comments part and legacy placeholder behavior for backward compatibility:
|
|
802
|
-
|
|
803
|
-
Extensions and preservation requirements
|
|
804
|
-
- [MS-XLSX] PDF (Excel extensions, extLst usage patterns, calc feature metadata, and extension part ecosystem):
|
|
805
|
-
- [MS-XLSX] introduction statement on normative vs informative sections:
|
|
806
|
-
|
|
807
|
-
Tooling references and security
|
|
808
|
-
- Open XML SDK SpreadsheetDocument class reference (useful for CI validation tooling):
|
|
809
|
-
- ZIP duplicate-entry vulnerability class in OOXML parsing (motivation for strict input validation):
|