feat(demos): expand contract-templates with Word-authored NDA fixture (SD-3130)#3267
Merged
caio-pizzol merged 12 commits intoMay 13, 2026
Merged
Conversation
There was a problem hiding this comment.
💡 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".
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.
…ce comments (SD-3130)
cc52ec7 to
81cb4ee
Compare
…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.
…ary updates (SD-3130)" This reverts commit f6101fa.
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the markdown-seeded prototype with a real .docx fixture so the contract-templates demo earns its name. SuperDoc imports
public/nda-template.docxat boot, parses its content controls, and the demo reads field values and clause versions straight from the parsed SDTs. Updates flow througheditor.doc.contentControls.*.public/nda-template.docxis 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-encodedw:tagpayload. Three clauses ship behind their latest versions, so the summary line reads "5 fields · 6 clauses · 3 updates available" on first paint.main.tsloses the seed + wrap loops.superdocis configured withdocument: '/nda-template.docx'.readStateFromDocument()populates the UI fromcontentControls.list().superdoc.export({ exportedName, isFinalDoc, triggerDownload }). Raw usesisFinalDoc: falseto preserve controls and tags; clean usesisFinalDoc: trueto flatten controls to final values.selectByTag+replaceContent. No Apply button.replaceContent+patch.superdoc-structured-content-inline/-blockclasses within the painter's existing 1px border / 4px radius slot. No padding or margin changes (painter renders blocks with absolute positioning).contentControls.replaceContentrather thantext.setValue.replaceContentworks 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 13w:sdtelements 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).