Skip to content

feat(templateMark): add rich text editor#878

Draft
mttrbrts wants to merge 3 commits intomainfrom
mr-template-editor
Draft

feat(templateMark): add rich text editor#878
mttrbrts wants to merge 3 commits intomainfrom
mr-template-editor

Conversation

@mttrbrts
Copy link
Copy Markdown
Member

@mttrbrts mttrbrts commented Apr 15, 2026

Closes #

Introduces a TipTap-based rich TemplateMark editor (opt-in “Beta”) alongside the existing Monaco markdown editor, and refactors theme handling to a boolean dark-mode flag while upgrading the Vite/Vitest toolchain.

Changes:

  • Add src/tiptap-editor/ package (components, extensions, serializers, utils) plus wrapper integration into the existing editor container and settings toggle.
  • Refactor theme state from backgroundColor/textColor to isDarkMode and apply Ant Design theming via ConfigProvider.
  • Upgrade build/test tooling (Vite/Vitest, polyfills, coverage) and add new unit + e2e coverage for the rich editor.

Screenshots or Video

image image

Related Issues

  • Issue #
  • Pull Request #

Author Checklist

  • Ensure you provide a DCO sign-off for your commits using the --signoff option of git commit.
  • Vital features and changes captured in unit and/or integration tests
  • Commits messages follow AP format
  • Extend the documentation, if necessary
  • Merging to main from fork:branchname

- Updated ModelManager to use strict mode for better validation in parseMarkdownTemplate.
- Improved error handling in parseMarkdownTemplate to avoid unnecessary logging during editing.
- Modified Vite configuration to set process.browser and process.env for better compatibility.
- Added end-to-end tests for the TipTap Template Editor, covering rich editor features and interactions.
- Introduced theme utilities for managing light/dark mode in the application.
- Created CSS styles for the TipTap Template Editor wrapper, handling layout and error/loading states.
- Defined constants for TemplateMark and CommonMark node classes to avoid typos and improve IDE support.
- Implemented converters for transforming TipTap nodes to TemplateMark format and vice versa.
- Added type guards for runtime type checking of TemplateMark and CommonMark nodes.

Signed-off-by: Matt Roberts <code@rbrts.uk>
@mttrbrts mttrbrts requested a review from a team as a code owner April 15, 2026 10:08
Copilot AI review requested due to automatic review settings April 15, 2026 10:08
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 15, 2026

Deploy Preview for ap-template-playground failed.

Name Link
🔨 Latest commit c6dfd77
🔍 Latest deploy log https://app.netlify.com/projects/ap-template-playground/deploys/69ed1843c8a2bb00082384a8

@mttrbrts mttrbrts marked this pull request as draft April 15, 2026 10:08
@mttrbrts mttrbrts changed the title Mr template editor feat(templateMark): add rich text editor Apr 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a TipTap-based rich TemplateMark editor (opt-in “Beta”) alongside the existing Monaco markdown editor, and refactors theme handling to a boolean dark-mode flag while upgrading the Vite/Vitest toolchain.

Changes:

  • Add src/tiptap-editor/ package (components, extensions, serializers, utils) plus wrapper integration into the existing editor container and settings toggle.
  • Refactor theme state from backgroundColor/textColor to isDarkMode and apply Ant Design theming via ConfigProvider.
  • Upgrade build/test tooling (Vite/Vitest, polyfills, coverage) and add new unit + e2e coverage for the rich editor.

Reviewed changes

Copilot reviewed 106 out of 108 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vite.config.ts Switch node polyfill plugin and enable Vitest coverage configuration.
package.json Add TipTap/ProseMirror deps and upgrade Vite/Vitest-related tooling.
.gitignore Ignore coverage output and Dolt database artifacts.
e2e/tiptap-editor.spec.ts Add Playwright coverage for rich editor enabled/disabled flows.
src/store/store.ts Add isDarkMode, useRichEditor, and store modelManager from rebuild.
src/App.tsx Apply Ant Design dark/light algorithms via ConfigProvider; set data-theme.
src/pages/MainContainer.tsx Integrate “Beta” tag display + hide old toolbar when rich editor enabled; adapt to isDarkMode.
src/styles/pages/MainContainer.css Apply typography variables to agreement preview container.
src/components/SettingsModal.tsx Add “Rich Template Editor (Beta)” toggle; migrate to isDarkMode.
src/components/ProblemPanel.tsx Migrate theme usage to isDarkMode and remove inline color styling.
src/components/ErrorBoundary.tsx Migrate theme usage to isDarkMode and simplify inline styling.
src/components/AIChatPanel.tsx Migrate theme usage to isDarkMode and remove inline color styling.
src/components/ResizableContainer.tsx Remove store-driven background color styling.
src/components/FullScreenModal.tsx Remove dynamic style injection based on theme colors.
src/AgreementHtml.tsx Remove inline background/text color styling from preview wrapper.
src/constants/theme.ts Add helper to convert isDarkMode to `'light'
src/editors/editorsContainer/TemplateMarkdown.tsx Route Template editor to TipTap wrapper when useRichEditor enabled.
src/editors/TiptapTemplateEditor.tsx New wrapper syncing markdown string state ↔ TemplateMark JSON, using store modelManager.
src/editors/TiptapTemplateEditor.css Wrapper styles for loading/error states.
src/editors/MarkdownEditor.tsx Migrate editor theme selection to isDarkMode (light/dark Monaco themes).
src/editors/JSONEditor.tsx Migrate editor theme selection to isDarkMode.
src/editors/ConcertoEditor.tsx Migrate editor theme selection to isDarkMode.
src/tests/components/ProblemPanel.test.tsx Update tests for new theme state shape.
src/tests/components/ErrorBoundary.test.tsx Update tests for new theme state shape.
src/tests/tiptap-editor/mocks/styleMock.js Add style mock for TipTap editor test environment.
src/tests/tiptap-editor/helpers/createTestEditor.ts Add headless TipTap editor factory for unit tests.
src/tests/tiptap-editor/utils/serializeTemplate.test.ts Add unit tests for TemplateMark → markdown serialization.
src/tests/tiptap-editor/utils/parseTemplate.test.ts Add unit tests for markdown → TemplateMark parsing helpers.
src/tests/tiptap-editor/utils/generateConcertoModel.test.ts Add unit tests for generating CTO from TemplateMark JSON.
src/tests/tiptap-editor/components/TemplateEditor.test.tsx Add basic render-level tests for the new TemplateEditor component.
src/tests/tiptap-editor/components/conditional-nodeview.test.tsx Add node-level tests for conditional nodes round-tripping.
src/tests/tiptap-editor/components/optional-nodeview.test.tsx Add node-level tests for optional nodes round-tripping.
src/tests/tiptap-editor/components/enum-variable-nodeview.test.tsx Add node-level tests for enum variable nodes round-tripping.
src/tiptap-editor/index.ts Export new editor package API surface (components/hooks/utils/types).
src/tiptap-editor/types/index.ts Define public props + validation error types for the editor package.
src/tiptap-editor/types/TemplateMark.ts Add TemplateMark/CommonMark TS model mirrors for editor logic.
src/tiptap-editor/types/guards.ts Add runtime type guards for TemplateMark/CommonMark nodes.
src/tiptap-editor/constants/nodeClasses.ts Centralize $class string constants for TemplateMark/CommonMark.
src/tiptap-editor/constants/types.ts Add supported type lists + friendly/FQN mapping helpers.
src/tiptap-editor/utils/serializeTemplate.ts Serialize TemplateMark JSON to markdown with UI-prop stripping + formula fixups.
src/tiptap-editor/utils/parseTemplate.ts Parse markdown to TemplateMark JSON using token pass + synthesized CTO.
src/tiptap-editor/utils/generateConcertoModel.ts Generate CTO model from TemplateMark document variable declarations.
src/tiptap-editor/utils/validateTemplate.ts Validate TemplateMark by round-tripping through transformer with generated model.
src/tiptap-editor/utils/branchMarkdown.ts Convert conditional/optional branch JSON ↔ editable markdown strings.
src/tiptap-editor/hooks/useTemplateEditor.ts Create TipTap editor instance with extensions/plugins and external sync behavior.
src/tiptap-editor/hooks/useMarkdownSync.ts Provide rich/markdown view toggle and markdown synchronization.
src/tiptap-editor/hooks/useValidation.ts Debounced validation hook calling TemplateMark validation utility.
src/tiptap-editor/components/TemplateEditor.tsx New editor UI wiring toolbar, rich/markdown view, and validation panel.
src/tiptap-editor/components/ValidationPanel.tsx Display validation errors/warnings in-panel.
src/tiptap-editor/components/dialogs/Popover.tsx Reusable popover component + class-name exports.
src/tiptap-editor/components/dialogs/Modal.tsx Shared modal/branch-modal/insert-dialog UI.
src/tiptap-editor/components/dialogs/index.ts Barrel export for dialog components.
src/tiptap-editor/styles/editor.css Rich editor layout and validation panel styles.
src/tiptap-editor/styles/toolbar.css Toolbar layout styles including responsive breakpoints.
src/tiptap-editor/styles/popover.css Themed popover styles.
src/tiptap-editor/styles/modal.css Themed modal styles.
src/tiptap-editor/extensions/* TipTap node extensions for TemplateMark/CommonMark constructs.
src/tiptap-editor/nodeViews/* React NodeViews for variable/formula/block constructs and editing UI.
src/tiptap-editor/plugins/VariableSyncPlugin.ts ProseMirror plugin to sync variable text within clause scope.
src/tiptap-editor/plugins/FormulaDependencyPlugin.ts ProseMirror decorations for highlighting formula dependencies.
src/tiptap-editor/serializer/nodeConverters.ts Compatibility re-export layer for serializer converter modules.
src/tiptap-editor/serializer/converters/index.ts Barrel export for converter functions.
src/tiptap-editor/serializer/TemplateMarkToTipTap.ts TemplateMark JSON → TipTap JSON conversion entrypoint.
src/tiptap-editor/serializer/TipTapToTemplateMark.ts TipTap JSON → TemplateMark JSON conversion entrypoint.
src/content/intro.md Expand tutorial introduction content and update links/descriptions.
src/content/module1.md Expand Concerto tutorial module content and examples.
src/content/module2.md Expand TemplateMark tutorial module content and examples.

Comment on lines +39 to +48
const switchToRich = useCallback(() => {
if (!editor) { setView('rich'); return; }
const parsed = parseMarkdownTemplate(markdownText, nameRefRef.current.current, modelManagerRef.current);
if (parsed) {
const content = templateMarkToTipTap(parsed);
// emitUpdate=true so onUpdate fires → currentDoc and parent onChange are synced
editor.commands.setContent(content, true);
}
setView('rich');
}, [editor, markdownText]);
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

switchToRich always calls setView('rich') even when parseMarkdownTemplate(...) returns null. This will kick the user back into the rich editor without applying their markdown changes, and makes it hard to fix invalid/partial markdown. Prefer keeping the view in markdown mode (and optionally surface a parse error) when parsing fails.

Copilot uses AI. Check for mistakes.
Comment thread src/store/store.ts
Comment on lines +82 to +86
async function rebuild(template: string, model: string, dataString: string): Promise<{ html: string; modelManager: ModelManager }> {
// Validate inputs before expensive operations
// This fails fast on invalid JSON or CTO syntax without running network calls
await validateBeforeRebuild(template, model, dataString);

Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

rebuild() now returns { html, modelManager }, but not all call sites in this file have been updated. For example, setData still assigns the return value directly to agreementHtml (treating it as a string), which will set agreementHtml to an object and break preview rendering. Update remaining callers to destructure { html, modelManager } and store modelManager consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +16
const { editor, nameRef, currentDoc } = useTemplateEditor(props);
const { view, markdownText, setMarkdownText, toggleView } = useMarkdownSync(editor, nameRef, props.modelManager);
const showValidation = props.showValidation ?? true;
const errors = useValidation(currentDoc.current, showValidation, props.onValidation, props.modelManager);

Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

useValidation is invoked with currentDoc.current, which is a mutable ref. Updating a ref does not trigger a React re-render, so errors can become stale unless the parent re-renders the component on every editor update (e.g., via a controlled value/onChange loop). Consider storing the current TemplateMark document in component state (updated in onUpdate) and passing that state into useValidation, or have useValidation subscribe to editor updates directly.

Copilot uses AI. Check for mistakes.
* fix(editor): retarget pr878 follow-up to mr-template-editor

Retry TipTap template parsing when external sample or shared-link loads receive the rebuilt modelManager, so the rich editor does not get stuck on stale model state.

Also store rebuilt html/modelManager after JSON data edits and split Vitest config from vite.config.ts so CI can load the production Vite config cleanly.

Signed-off-by: Rishabh060105 <rishabhj2005@email.com>

* test(playground): add regression coverage for pr881 fixes

Signed-off-by: Rishabh060105 <rishabhj2005@email.com>

---------

Signed-off-by: Rishabh060105 <rishabhj2005@email.com>
Co-authored-by: Rishabh060105 <rishabhj2005@email.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants