feat(apollo-wind): add PromptEditor component [MST-10659]#784
feat(apollo-wind): add PromptEditor component [MST-10659]#784fikewa-olatunji wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Ports a Lexical-based PromptEditor into @uipath/apollo-wind as a reusable component, including token-pill rendering, $-triggered variable autocomplete, formatting toolbar, and a sanitized markdown preview mode.
Changes:
- Added
PromptEditorpublic exports (+ supporting types) and integrated Lexical-based editor with token nodes + plugins. - Implemented toolbar actions, token copy/paste serialization,
$-autocomplete menu, validation, and rename-on-options-change behavior. - Added markdown preview rendering via
marked+dompurify, plus Storybook + unit tests; updated dependencies/lockfile.
Reviewed changes
Copilot reviewed 35 out of 36 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Locks new Lexical + markdown preview dependencies and transitive graph. |
| packages/apollo-wind/package.json | Adds Lexical + marked + dompurify runtime deps for the new component. |
| packages/apollo-wind/src/index.ts | Exports PromptEditor + types from the package root. |
| packages/apollo-wind/src/components/ui/prompt-editor/index.ts | Local barrel export for PromptEditor and its public types. |
| packages/apollo-wind/src/components/ui/prompt-editor/types.ts | Defines token/types API and token color/label helpers. |
| packages/apollo-wind/src/components/ui/prompt-editor/prompt-editor.tsx | Main component wiring Lexical composer, plugins, toolbar, preview, and imperative ref API. |
| packages/apollo-wind/src/components/ui/prompt-editor/prompt-editor.test.tsx | Unit tests for rendering, toolbar/preview toggling, and malformed-prop tolerance. |
| packages/apollo-wind/src/components/ui/prompt-editor/prompt-editor.stories.tsx | Storybook coverage for common modes (toolbar, autocomplete, preview, controlled, etc.). |
| packages/apollo-wind/src/components/ui/prompt-editor/utils/index.ts | Barrel export for prompt-editor utilities. |
| packages/apollo-wind/src/components/ui/prompt-editor/utils/serialization.ts | Token ↔ Lexical state conversion + clipboard string serialization/parsing + selection token extraction. |
| packages/apollo-wind/src/components/ui/prompt-editor/utils/insert-token.ts | Inserts token nodes at cursor / selection. |
| packages/apollo-wind/src/components/ui/prompt-editor/utils/comparison.ts | Token-array deep equality helper. |
| packages/apollo-wind/src/components/ui/prompt-editor/utils/autocomplete-segments.ts | $ trigger helpers (type inference, regex, dismissed-trigger sentinel). |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/ValueSyncPlugin.tsx | Controlled-value sync into Lexical state with focus-aware selection preservation. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/ValidateTokensPlugin.tsx | Marks token pills invalid if not present in autocomplete option set. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/RenameTokensPlugin.tsx | Renames token values when option-path trees indicate a rename. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/AutocompletePlugin.tsx | Drives $ trigger detection and commits selected/free-form variables as token pills. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/CopyPastePlugin.tsx | Custom copy/cut/paste integrating token clipboard format and Lexical mime payload. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/EditorRefPlugin.tsx | Exposes Lexical editor instance to parent wiring. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/MultilinePlugin.tsx | Enforces single-line vs multiline behavior (enter suppression, newline stripping). |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/NodeSelectionFixPlugin.tsx | Keyboard/cursor management for inline DecoratorNode “pill” selection. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/ToolbarActionsPlugin.tsx | Implements formatting actions by inserting markdown markers/prefixes. |
| packages/apollo-wind/src/components/ui/prompt-editor/plugins/shared/token-nodes.ts | Shared traversal helpers for finding token nodes in editor state. |
| packages/apollo-wind/src/components/ui/prompt-editor/nodes/index.ts | Barrel export for the custom Lexical token nodes. |
| packages/apollo-wind/src/components/ui/prompt-editor/nodes/InputTokenNode.tsx | Input token DecoratorNode implementation. |
| packages/apollo-wind/src/components/ui/prompt-editor/nodes/OutputTokenNode.tsx | Output token DecoratorNode implementation. |
| packages/apollo-wind/src/components/ui/prompt-editor/nodes/StateTokenNode.tsx | State token DecoratorNode implementation. |
| packages/apollo-wind/src/components/ui/prompt-editor/nodes/ResourceTokenNode.tsx | Resource token DecoratorNode implementation. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/EditorToolbar.tsx | Toolbar UI (edit/preview toggle + formatting buttons). |
| packages/apollo-wind/src/components/ui/prompt-editor/components/PromptEditorAutocompleteMenu.tsx | Caret-anchored command menu for variable selection. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/MarkdownPreview.tsx | Markdown preview rendering + sanitization + token-pill HTML injection. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/markdown-preview.css | Styles for preview output and token pills in sanitized HTML. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPill.tsx | Visual pill rendering (icons, remove button, selected outline). |
| packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPillWithTooltip.tsx | Adds tooltips + NodeSelection mouse handling to token pills. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/token-icon-markup.ts | Inline lucide SVG markup builder for preview-mode token icons. |
| packages/apollo-wind/src/components/ui/prompt-editor/components/token-icon-markup.test.ts | Tests for SVG markup builder output. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
b5f8a7a to
9168e44
Compare
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Dependency License Review
License distribution
Excluded packages
|
9168e44 to
7fc6691
Compare
7fc6691 to
10b1152
Compare
10b1152 to
645a2fb
Compare
645a2fb to
676ed08
Compare
676ed08 to
d64f988
Compare
d64f988 to
b30a8cb
Compare
e1dd32d to
b47504a
Compare
CalinaCristian
left a comment
There was a problem hiding this comment.
PR #784 review — PromptEditor extraction
Overall: correct, intentional decoupling — not a strict 1-to-1 but a well-executed port. Core Lexical engine, plugin architecture, serialization, and public API surface are faithfully preserved. Several real bugs from the flow-workbench original were fixed along the way (empty-array controlled value, minRows/maxRows clamping, Lexical state corruption in insertVariableToken, $-prefix on free-typed chip paths, NodeSelection crash guard, borderless text color). No data-loss or crash bugs found in the new code.
Severity legend: 🟡 medium = worth landing before merge · 🔵 low = follow-up is fine
✅ Bug fixes shipped in this extraction (all genuine improvements)
| Fix | Location |
|---|---|
root.append(tokenNode) → wrap in $createParagraphNode() |
insert-token.ts |
!value → value === undefined — empty array now clears a controlled editor |
ValueSyncPlugin.tsx |
isEmpty init seeds from initialValue ?? value — fixes controlled-only usage |
prompt-editor.tsx |
effectiveMinRows = Math.min(minRows, maxRows) — max-height no longer silently overridden |
prompt-editor.tsx |
borderless ? 'inherit' : 'var(--color-foreground)' — correct text color in parent-provided chrome |
prompt-editor.tsx |
$isRangeSelection guard — insertRawText can't throw on a NodeSelection |
prompt-editor.tsx |
Free-typed chip path: $vars.foo → vars.foo — matches menu-selected chips for validation |
AutocompletePlugin.tsx |
closeMenu(explicit) flag — auto-close no longer suppresses re-opening at the same $ position |
AutocompletePlugin.tsx |
target removed from DOMPurify allowlist — closes tabnabbing vector in markdown preview |
MarkdownPreview.tsx |
CSS inlined in JS — self-contained bundle, no unresolved .css import next to published JS |
MarkdownPreview.tsx |
Inline comments below cover the two 🟡 medium and one 🔵 low observations.
e1e2aea to
368ac01
Compare
📦 Dev Packages
|
Port the Lexical-based PromptEditor from flow-workbench into apollo-wind as a reusable, prop-driven component (value / onChange / autoCompleteOptions). It renders inline token pills (input/output/state/resource), a formatting toolbar, a markdown preview mode, and a $-triggered variable autocomplete rebuilt on apollo-wind Command/Popover/Tooltip — decoupled from flow-workbench's variables, schema, i18n, and theme systems. Adds lexical, @lexical/react, @lexical/utils, @lexical/clipboard, marked and dompurify. Token/option props are normalized to arrays so malformed input can't crash the editor, and token colors map to apollo-wind design tokens. Exports PromptEditor and its public types from the package root, with unit tests and Storybook stories. Refs: MST-10659
- Honor `borderless` in preview mode: drop the editor's own border/background there too, so borderless behaves consistently between edit and preview. - Remove dead `data-invalid` style rule + allowed attribute in MarkdownPreview (preview no longer emits it). - Fix stale lucide version reference (0.555.0 -> 0.577.0) in token-icon-markup.
apollo-react pins lexical 0.16.0 (its ApRichTextEditor); apollo-wind's PromptEditor requires lexical 0.42.0 (React 19 support + 0.42-only APIs). The two design-system packages intentionally track different lexical majors, so ignore the lexical/@lexical/* family in the consistency check rather than force-aligning and breaking one of the editors.
…focus, preview styles, exports) - PromptEditorAutocompleteMenu: preventDefault on container pointerdown so focus can't leave the editor before commit (review M1) - Move markdown-preview styles from an inline <style> into the shared package stylesheet (tailwind.utilities.css) consumers already import - Remove unused PromptEditorHighlightLocator/Item types (review M2) - Export prompt-editor from the components/ui barrel - Document the no-$ token value convention and that preview is visual-only re: validity
…lity + scope dep exemption - Narrow the dependency-consistency exemption from the repo-wide lexical family to just @uipath/apollo-wind, so lexical drift elsewhere is still caught (review) - Add unit tests for clipboard token serialization round-trip, free-form path type inference + VARIABLE_PATH_REGEX, dismissed-trigger suppression, and token equality (the extraction-risky logic; Lexical interaction paths stay limited under jsdom)
Deployed apollo-design Storybook already themes the autodocs story background, so the borderless PromptEditor preview is readable without this override. Reverts preview-head.html to match main (review).
…mption Bumps apollo-react's lexical + @lexical/* from 0.16.0 to 0.42.0 to match apollo-wind, so the dependency-version-consistency check passes without any ignore workaround (review). Fixes the one resulting breakage: LexicalErrorBoundary is a named export in 0.42, not default. apollo-react editor typechecks clean and its 18 tests pass on 0.42.
Adds a native HTML5 drag-drop VariableDropPlugin + `mapVarDropToToken` prop: a consumer's drag source sets the variable path on dataTransfer (VARIABLE_DRAG_MIME, now exported), and the editor inserts a token at the drop point (falling back to the end of the content when the drop caret can't be resolved). Only the custom MIME is handled, so ordinary text drops aren't hijacked. Wired through PromptEditor → EditorInner, with a WithVariableDragDrop story and tests.
- Free-form $path commit now happens in the picker (an 'Insert <path>' item) so Enter commits it, instead of an editor handler the focused menu never received. - VARIABLE_PATH_REGEX accepts state/resource namespaces; inferTokenTypeFromPath falls back to the leading namespace (state.*→state, resource.*→resource) so free-form chips get the correct node type. - wrapSelectionWithMarkers normalizes selection.isBackward() so right-to-left selections wrap correctly. - RenameTokensPlugin groups renames by type once (O(1) per-node lookup).
a479f0f to
6ba21a9
Compare
📊 Coverage + size by packagePer-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.
"Coverage" is each package's own |
Jira: MST-10659
Summary
Ports the Lexical-based PromptEditor from flow-workbench into
@uipath/apollo-windas a reusable, fully prop-driven component. It renders inline variable token pills (input / output / state / resource), a formatting toolbar, a markdown preview mode, and a$-triggered variable autocomplete.The port deliberately decouples the editor from flow-workbench-specific systems that don't exist in a design system:
Command/Popover/Tooltip), driven by theautoCompleteOptionsprop — no flowVariablePickeror schema services.react-i18next).VariableDropPlugin+mapVarDropToTokenprop (the consumer owns the drag source and sets the path ondataTransferunder the exportedVARIABLE_DRAG_MIME) — no dnd-kit dependency, unlike flow-workbench's version.Public API
PromptEditor+ types (PromptEditorProps,PromptEditorRef,PromptEditorToken,PromptEditorTokenType,PromptEditorAutoCompleteOption,PromptEditorMode) exported from the package root. Controlled (value/onChange) and uncontrolled (initialValue) usage,multiline,minRows/maxRows,placeholder,disabled,showToolbar,mode/onModeChange,borderless,fillHeight, and an imperativeeditorRef.Dependencies added (apollo-wind only)
lexical,@lexical/react,@lexical/utils,@lexical/clipboard(0.42.0),marked,dompurify. No other package uses them (version-consistency safe); they introduce no new audit findings.Robustness
Token/option props are normalized to arrays so malformed input (e.g. a Storybook "Set object"
{}) can't crash the editor or preview.maxRowscaps the visible height and scrolls (clamped so it isn't overridden whenmaxRows ≤ minRows).Testing
vitest: 19 unit tests for PromptEditor (rendering, toolbar, preview, mode toggle, autocomplete mount, malformed-input tolerance) — full apollo-wind suite passes (928 tests).biome format/lintclean,test:coveragepasses, fullpnpm build(all 8 packages) succeeds, frozen lockfile in sync.$-autocomplete, chip insertion, light/dark, height capping) verified end-to-end in a headless browser.