Skip to content

feat(demos): expand contract-templates with Word-authored NDA fixture (SD-3130)#3267

Merged
caio-pizzol merged 12 commits into
mainfrom
caio-pizzol/SD-3130-expand-contract-templates
May 13, 2026
Merged

feat(demos): expand contract-templates with Word-authored NDA fixture (SD-3130)#3267
caio-pizzol merged 12 commits into
mainfrom
caio-pizzol/SD-3130-expand-contract-templates

Conversation

@caio-pizzol
Copy link
Copy Markdown
Contributor

@caio-pizzol caio-pizzol commented May 13, 2026

Replaces the markdown-seeded prototype with a real .docx fixture so the contract-templates demo earns its name. SuperDoc imports public/nda-template.docx at boot, parses its content controls, and the demo reads field values and clause versions straight from the parsed SDTs. Updates flow through editor.doc.contentControls.*.

  • public/nda-template.docx is the starting document. It contains 13 plain-text content controls: seven inline smart fields across five field keys (Receiving party and Purpose each appear twice — once in the header sentence and once nested inside the Permitted Use clause) plus six block clauses, each with a JSON-encoded w:tag payload. Three clauses ship behind their latest versions, so the summary line reads "5 fields · 6 clauses · 3 updates available" on first paint.
  • main.ts loses the seed + wrap loops. superdoc is configured with document: '/nda-template.docx'. readStateFromDocument() populates the UI from contentControls.list().
  • Sidebar with Fields and Clauses tabs, a summary line, and top-right Export raw DOCX / Export clean DOCX buttons wired to superdoc.export({ exportedName, isFinalDoc, triggerDownload }). Raw uses isFinalDoc: false to preserve controls and tags; clean uses isFinalDoc: true to flatten controls to final values.
  • Smart fields are reactive: each input debounces ~250ms and fans the new value to every occurrence of that tag via selectByTag + replaceContent. No Apply button.
  • Clauses tab uses a library-review pattern: stale clauses surface as "Update available" with a one-line summary of the change. Click Review to expand the card and see the in-document clause text alongside the library version, then "Replace with library clause" to apply via replaceContent + patch.
  • Local CSS overlays color the visible superdoc-structured-content-inline / -block classes within the painter's existing 1px border / 4px radius slot. No padding or margin changes (painter renders blocks with absolute positioning).
  • Field updates use contentControls.replaceContent rather than text.setValue. replaceContent works regardless of how the control's type is detected on import.

Browser-smoke verified: fixture loads with 13 content controls discoverable by tag; typing in a field input updates every occurrence live (verified on receivingParty -> "NORTHSTAR HEALTH", both header + nested occurrences); Review expands the clause card showing current vs library text; Replace swaps the body and bumps the tag from v1 to v2; summary line decrements correctly; Export raw DOCX produces a DOCX with 13 w:sdt elements and JSON smartField/reusableSection tags preserved; Export clean DOCX flattens to zero SDTs with visible values intact.

Related: IT-1046, SD-3123, SD-3124, SD-3131, SD-3132 (tracked-changes review for clause replacement, follow-up).

@caio-pizzol caio-pizzol requested a review from a team as a code owner May 13, 2026 17:39
@linear
Copy link
Copy Markdown

linear Bot commented May 13, 2026

SD-3130

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 430eb1b0ee

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread demos/contract-templates/src/main.ts Outdated
Base automatically changed from caio-pizzol/IT-1046-content-controls-demo to main May 13, 2026 17:48
… (SD-3130)

Replaces the markdown-seeded prototype with a real Word-authored .docx fixture imported at boot. The demo now opens an NDA template with five inline smart fields and six versioned clauses already authored as Word content controls, then reads field values and clause versions straight from the parsed SDTs and drives updates through the Document API.

- public/nda-template.docx is generated by public/nda-template.generate.ps1 via Word COM (eleven w:sdt elements with JSON-encoded w:tag payloads).
- main.ts removes the seed+wrap loops, loads the fixture as document=, and reads initial state from contentControls.list.
- Sidebar with Fields and Clauses tabs, summary line, per-clause Update to v2 CTAs, Export button using superdoc.export.
- Local CSS overlay colorizes the visible DomPainter SDT classes (superdoc-structured-content-inline / -block) within the painter's existing 1px border slots; no box-size changes.
- Field updates use contentControls.replaceContent rather than text.setValue because Word-authored plain-text controls currently surface as controlType: 'unknown' (filed as follow-up).
- README documents the fixture, the generation script, and the limits.
…130)

The PowerShell generator was only useful for internal regeneration of the fixture. Public repo readers don't need it, and shipping it in the demo invites questions we don't want to answer. The .docx fixture remains; regeneration is an internal workflow.
@caio-pizzol caio-pizzol force-pushed the caio-pizzol/SD-3130-expand-contract-templates branch from cc52ec7 to 81cb4ee Compare May 13, 2026 17:52
…n export status (SD-3130)

Refreshes the fixture so 'Receiving party' and 'Purpose' each appear twice: once in the header sentence and once nested inside the Permitted Use block clause. Demonstrates selectByTag fan-out across the document including inside managed clauses, which is the contract-template behavior the customer reference shows.

Permitted Use is in the no-upgrade set, so the nested fields never collide with replaceContent (which would otherwise flatten the inner SDTs). The upgradeable clauses (Confidentiality, Governing Law, Limitation of Liability) stay field-free.

Also sharpens the export status from 'Exported' to 'Exported Mutual NDA.docx' so the workflow finish is concrete.

Verified: fixture loads with 13 SDTs (was 11), receivingParty and purpose return 2 occurrences each via selectByTag, editing one input + Apply updates both occurrences, export status reads 'Exported Mutual NDA.docx'.
Replaces the engineering-flavored 'Update to v2' button with a clause-library review pattern that matches the customer's mental model.

- Drops category headers (each category contained one clause anyway).
- Current clauses muted with 'Current · Document v1'. Stale clauses surface as 'Update available' with a one-line summary of what the upgrade does (e.g. 'Extends survival period from 2 years to 5 years.').
- Review button on stale cards expands the card in place, showing the in-document clause text alongside the library clause text plus a 'Replace with library clause' CTA.
- Version numbers stay as secondary metadata ('Document v1 · Library v2'), not primary UI.
- After replace, card collapses to Current, summary line drops the update count.

Implementation: adds 'summary' field to each upgrade entry, state.expandedClause for one-at-a-time review, applyClauseVersion unchanged (drawer is pure UI on top of the same Document API calls).
Drops the 'Apply fields' button. Each input listener debounces ~250ms and pushes the value to every occurrence of that field's tag via selectByTag + replaceContent. The mutation skips the run() wrapper so the status bar doesn't flash on every keystroke. Clause Review / Replace stays explicit because it's a real review action.

Effect on video: typing 'NORTHSTAR HEALTH' in the Receiving party input updates both occurrences live (header sentence + nested inside Permitted Use), without a click.

Also cleans up stale wording from earlier iterations:
- README and main.ts JSDoc: 'Five inline content controls' -> 'Seven inline content controls across five field keys' (after nested fields).
- README and main.ts JSDoc: 'Update CTA' -> 'Review CTA' to match the redesigned Clauses tab.
- README run instructions: dropped 'click Apply' since the field flow is reactive.
…tes (SD-3130)

Replaces the inline before/after review with a proper pending-review lifecycle that uses SuperDoc's track-changes engine. The SDT tag is no longer patched optimistically when the user clicks update; it bumps only after the tracked change is accepted, so a rejection leaves both the body and the tag at v1.

Flow:
1. Stale clause cards show 'Library update available' with a Suggest library update button.
2. Click Suggest -> doc.replace with changeMode: 'tracked' against the clause body (located via query.match against the SDT's current text). Tracked entity ids are captured by diffing trackedChanges before/after. The SDT tag stays at v1. Card moves to 'Pending review' with Accept / Reject buttons.
3. Accept -> doc.trackChanges.decide({ target: { id }, decision: 'accept' }) for each captured entity, then contentControls.patch bumps the tag to v2.
4. Reject -> doc.trackChanges.decide(..., 'reject') for each entity. Body reverts. Tag stays v1.

Rationale: contentControls.replaceContent doesn't accept changeMode: 'tracked' today (engine rejects anything but 'direct'), and the document state would lie if the tag bumped before acceptance (user rejects body but tag still says v2). Using doc.replace on the inner text via query.match plus sidebar-driven accept/reject keeps the lifecycle correct without engine changes. Properly closing this on content-control-aware tracked replacement is filed as SD-3132.

Verified end-to-end: Suggest leaves tag at v1 and adds tracked changes; Reject reverts body and tag stays v1; Accept resolves tracked changes and patches tag to v2; summary line tracks pending review separately from update-available count.
Replaces the two-box 'In your document / From library' panel with a single 'Proposed change' preview that shows the diff inline using semantic <del> / <ins> markup. Reviewer sees the change in context without having to compare two full-text blocks.

Each upgrade now ships a hand-authored preview: PreviewSegment[] (same/insert/delete tuples) alongside summary and body. Rendered as escaped text in <del>/<ins>/<span>. Liability includes both the cap change and the appended carve-outs sentence so the preview doesn't undersell the upgrade.

CSS: red strikethrough on <del>, green-tinted background on <ins>. Painter layout untouched.

Deliberately not a real text diff. The label says 'Proposed change', not 'Redline' or 'Diff', because we're not computing one. For three controlled clause updates, hand-authoring is correct.

Verified: each stale clause's expanded card renders the three sentences with the expected insert/delete markup; Replace still works the same (direct contentControls.replaceContent + patch).
…SD-3130)

Pushed state used isFinalDoc: true, which strips SDT wrappers, but the
README claimed controls were preserved. Splits export into two buttons:
raw DOCX uses isFinalDoc: false and preserves controls/tags for future
template/library updates; clean DOCX uses isFinalDoc: true and flattens
controls so the filled values are in place.
@caio-pizzol caio-pizzol merged commit 72c4712 into main May 13, 2026
23 checks passed
@caio-pizzol caio-pizzol deleted the caio-pizzol/SD-3130-expand-contract-templates branch May 13, 2026 19:46
msviderok pushed a commit to msviderok/superdoc that referenced this pull request May 16, 2026
… (SD-3130) (superdoc-dev#3267)

* feat(demos): expand contract-templates with Word-authored NDA fixture (SD-3130)

Replaces the markdown-seeded prototype with a real Word-authored .docx fixture imported at boot. The demo now opens an NDA template with five inline smart fields and six versioned clauses already authored as Word content controls, then reads field values and clause versions straight from the parsed SDTs and drives updates through the Document API.

- public/nda-template.docx is generated by public/nda-template.generate.ps1 via Word COM (eleven w:sdt elements with JSON-encoded w:tag payloads).
- main.ts removes the seed+wrap loops, loads the fixture as document=, and reads initial state from contentControls.list.
- Sidebar with Fields and Clauses tabs, summary line, per-clause Update to v2 CTAs, Export button using superdoc.export.
- Local CSS overlay colorizes the visible DomPainter SDT classes (superdoc-structured-content-inline / -block) within the painter's existing 1px border slots; no box-size changes.
- Field updates use contentControls.replaceContent rather than text.setValue because Word-authored plain-text controls currently surface as controlType: 'unknown' (filed as follow-up).
- README documents the fixture, the generation script, and the limits.

* chore(demos): drop nda-template.generate.ps1 from public assets (SD-3130)

The PowerShell generator was only useful for internal regeneration of the fixture. Public repo readers don't need it, and shipping it in the demo invites questions we don't want to answer. The .docx fixture remains; regeneration is an internal workflow.

* docs(demos): drop "Word-authored" framing from public README and source comments (SD-3130)

* docs(demos): align top-of-file comment with replaceContent path (SD-3130)

* feat(demos): nest smart fields inside Permitted Use clause and sharpen export status (SD-3130)

Refreshes the fixture so 'Receiving party' and 'Purpose' each appear twice: once in the header sentence and once nested inside the Permitted Use block clause. Demonstrates selectByTag fan-out across the document including inside managed clauses, which is the contract-template behavior the customer reference shows.

Permitted Use is in the no-upgrade set, so the nested fields never collide with replaceContent (which would otherwise flatten the inner SDTs). The upgradeable clauses (Confidentiality, Governing Law, Limitation of Liability) stay field-free.

Also sharpens the export status from 'Exported' to 'Exported Mutual NDA.docx' so the workflow finish is concrete.

Verified: fixture loads with 13 SDTs (was 11), receivingParty and purpose return 2 occurrences each via selectByTag, editing one input + Apply updates both occurrences, export status reads 'Exported Mutual NDA.docx'.

* docs(demos): correct fixture SDT count after nested fields (SD-3130)

* feat(demos): redesign Clauses tab around clause-library review (SD-3130)

Replaces the engineering-flavored 'Update to v2' button with a clause-library review pattern that matches the customer's mental model.

- Drops category headers (each category contained one clause anyway).
- Current clauses muted with 'Current · Document v1'. Stale clauses surface as 'Update available' with a one-line summary of what the upgrade does (e.g. 'Extends survival period from 2 years to 5 years.').
- Review button on stale cards expands the card in place, showing the in-document clause text alongside the library clause text plus a 'Replace with library clause' CTA.
- Version numbers stay as secondary metadata ('Document v1 · Library v2'), not primary UI.
- After replace, card collapses to Current, summary line drops the update count.

Implementation: adds 'summary' field to each upgrade entry, state.expandedClause for one-at-a-time review, applyClauseVersion unchanged (drawer is pure UI on top of the same Document API calls).

* feat(demos): reactive smart fields + clean up stale wording (SD-3130)

Drops the 'Apply fields' button. Each input listener debounces ~250ms and pushes the value to every occurrence of that field's tag via selectByTag + replaceContent. The mutation skips the run() wrapper so the status bar doesn't flash on every keystroke. Clause Review / Replace stays explicit because it's a real review action.

Effect on video: typing 'NORTHSTAR HEALTH' in the Receiving party input updates both occurrences live (header sentence + nested inside Permitted Use), without a click.

Also cleans up stale wording from earlier iterations:
- README and main.ts JSDoc: 'Five inline content controls' -> 'Seven inline content controls across five field keys' (after nested fields).
- README and main.ts JSDoc: 'Update CTA' -> 'Review CTA' to match the redesigned Clauses tab.
- README run instructions: dropped 'click Apply' since the field flow is reactive.

* feat(demos): tracked-changes review lifecycle for clause library updates (SD-3130)

Replaces the inline before/after review with a proper pending-review lifecycle that uses SuperDoc's track-changes engine. The SDT tag is no longer patched optimistically when the user clicks update; it bumps only after the tracked change is accepted, so a rejection leaves both the body and the tag at v1.

Flow:
1. Stale clause cards show 'Library update available' with a Suggest library update button.
2. Click Suggest -> doc.replace with changeMode: 'tracked' against the clause body (located via query.match against the SDT's current text). Tracked entity ids are captured by diffing trackedChanges before/after. The SDT tag stays at v1. Card moves to 'Pending review' with Accept / Reject buttons.
3. Accept -> doc.trackChanges.decide({ target: { id }, decision: 'accept' }) for each captured entity, then contentControls.patch bumps the tag to v2.
4. Reject -> doc.trackChanges.decide(..., 'reject') for each entity. Body reverts. Tag stays v1.

Rationale: contentControls.replaceContent doesn't accept changeMode: 'tracked' today (engine rejects anything but 'direct'), and the document state would lie if the tag bumped before acceptance (user rejects body but tag still says v2). Using doc.replace on the inner text via query.match plus sidebar-driven accept/reject keeps the lifecycle correct without engine changes. Properly closing this on content-control-aware tracked replacement is filed as SD-3132.

Verified end-to-end: Suggest leaves tag at v1 and adds tracked changes; Reject reverts body and tag stays v1; Accept resolves tracked changes and patches tag to v2; summary line tracks pending review separately from update-available count.

* Revert "feat(demos): tracked-changes review lifecycle for clause library updates (SD-3130)"

This reverts commit f6101fa.

* feat(demos): inline proposed-change preview on clause Review (SD-3130)

Replaces the two-box 'In your document / From library' panel with a single 'Proposed change' preview that shows the diff inline using semantic <del> / <ins> markup. Reviewer sees the change in context without having to compare two full-text blocks.

Each upgrade now ships a hand-authored preview: PreviewSegment[] (same/insert/delete tuples) alongside summary and body. Rendered as escaped text in <del>/<ins>/<span>. Liability includes both the cap change and the appended carve-outs sentence so the preview doesn't undersell the upgrade.

CSS: red strikethrough on <del>, green-tinted background on <ins>. Painter layout untouched.

Deliberately not a real text diff. The label says 'Proposed change', not 'Redline' or 'Diff', because we're not computing one. For three controlled clause updates, hand-authoring is correct.

Verified: each stale clause's expanded card renders the three sentences with the expected insert/delete markup; Replace still works the same (direct contentControls.replaceContent + patch).

* feat(demos): split contract-templates export into raw + clean paths (SD-3130)

Pushed state used isFinalDoc: true, which strips SDT wrappers, but the
README claimed controls were preserved. Splits export into two buttons:
raw DOCX uses isFinalDoc: false and preserves controls/tags for future
template/library updates; clean DOCX uses isFinalDoc: true and flattens
controls so the filled values are in place.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant