PT-4020 Backspace confirmation#2480
Conversation
…-backspace-confirmation
…-backspace-confirmation
- Match shadcn destructive affordance: 10% --destructive tint in light themes, 20% under .dark for legibility on the darker editor surface - Switch color-mix to the oklab color space (repo convention) - Propagate .verse-selected rule to the Storybook demo usj-nodes.css copy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Session-URL: <session URL>
…-backspace-confirmation
Add caret-like glow-underline blink (gated on .verse-delete-armed root class), roomier padding with compensating negative margin, and a destructive keystroke tooltip. Bind to live theme tokens (--destructive, --popover) for light/dark, with a reduced-motion static fallback. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
katherinejensen00
left a comment
There was a problem hiding this comment.
I like how clear the colors and highlighting are. Great work, Jolie! One note, when this and the related Editor PR pass, Claude suggested checking the following scenario: When the upstream class-application lands, worth verifying ordinary text selection isn't painted destructive-red. Per the block comment, only the blink is gated on .verse-delete-armed — the destructive background + red text apply to any verse marker inside a normal range selection. That's likely fine, but once the behavior is live it'd be good to eyeball that selecting a paragraph doesn't make every contained verse marker read as "armed for deletion."
@katherinejensen00 reviewed 2 files and all commit messages, and made 1 comment.
Reviewable status:complete! all files reviewed, all discussions resolved.
Replace the bespoke .verse-delete-tooltip CSS with a VerseDeleteTooltipOverlay component that renders the destructive "press again" hint via a vetted ShadCN Tooltip, with localized (en/es) copy. The overlay observes the editor's data-verse-delete-* attributes and verse-selected marker to arm/anchor the hint. Also gate the two-step delete on isProtectionActive so it stays off in power mode, wiring isStructureProtectionActive into the editor options. Co-authored-by: Claude <noreply@anthropic.com>
…-backspace-confirmation
katherinejensen00
left a comment
There was a problem hiding this comment.
Great additions! Just a couple of small things to consider and you are all set. I went ahead and approved the changes since the suggestions are so small
@katherinejensen00 reviewed 6 files and all commit messages, and made 3 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on jolierabideau).
extensions/src/platform-scripture-editor/src/verse-delete-tooltip/verse-delete-tooltip-overlay.component.tsx line 125 at r2 (raw file):
}} /> <TooltipContent side="bottom" align="start" showArrow={false}>
NIT Claude Suggestion that seemed like a good idea. I didn't know you could do something like this.
This hint gates a destructive action but is visual-only, so screen-reader users get no warning before deleting a verse marker. The trigger is aria-hidden="true" / tabIndex={-1} and the "press again" copy lives entirely in TooltipContent, so nothing is announced when the delete is armed. This pattern was fine to copy from ParagraphMarkerTooltipOverlay (a passive hover hint), but a destructive-action confirmation has a higher a11y bar. Consider mirroring the armed state into an aria-live="polite" (or assertive) region so the "Backspace again to delete selection" message is spoken when it arms.
extensions/src/platform-scripture-editor/src/verse-delete-tooltip/verse-delete-tooltip-overlay.component.tsx line 128 at r2 (raw file):
{armed ? ( <> <kbd>{confirmingKey(armed.intent)}</kbd> {message}
NIT Claude Finding
Nice improvement localizing the copy — one gap: the key label stays English and the word order is hard-coded, so Spanish reads "Backspace de nuevo para eliminar la selección." The <kbd> value comes from confirmingKey (always English "Backspace"/"Delete") and the JSX bakes in key-first ordering that not every language will want. If that's a deliberate call to leave physical key names untranslated, all good — otherwise consider a single localized string with a {key} placeholder so translators own both the word and its position.
Co-Authored-By: Claude <noreply@anthropic.com>
The editor's EditorOptions replaced the isStructureProtected/isStructureProtectionActive booleans with a single structureProtectionMode: "off" | "guarded" | "protected", but this call site still passed the removed boolean fields (silently ignored — useMemo's generic callback pattern doesn't trigger TS's excess-property check, so this wasn't caught by typecheck). Locked (by admin, personal preference, or both) now maps to "protected"; Simple mode while unlocked maps to "guarded" (two-step delete confirm); Power mode always maps to "off". Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
- Wrap the formatReplacementStringToArray interpolation result in keyed Fragments (mirroring about-dialog.component.tsx) so React doesn't warn about missing keys on the tooltip's array children every time it arms. - Remove the stale .verse-delete-tooltip CSS block from the Storybook demo copy of usj-nodes.css — the extension's _usj-nodes.scss already dropped it in favor of the ShadCN tooltip overlay, but the demo copy was never updated to match, leaving dead, unreferenced CSS. Also drops the now-unused --popover mention from both files' shared header comment. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Screen.Recording.2026-07-01.at.12.21.20.PM.mov
Code Review Summary
Branch: pt-4020-backspace-confirmation
Base: origin/main
Date: 2026-06-30
Review model: Claude Opus 4.8
Files changed: 1 (original branch) → 2 (after in-review changes)
Overview
This PR adds the styling half of a two-step intentional-delete affordance for verse markers in the scripture editor. The goal is to prevent verse markers from being deleted too easily via the keyboard: the first Backspace/Delete "arms" the marker (selects it and gives it destructive styling), and a second Backspace/Delete actually removes it.
The deletion logic lives in a coordinated upstream PR in the external
@eten-tech-foundation/platform-editorpackage (~/dev/scripture-editors, branchpt-4020-backspace-confirmation), whereImmutableVerseNodeapplies a.verse-selectedclass on the armed state. This paranext-core PR supplies the theme-aware styling for that class, overriding the package's default hardcoded#dc2626rule with the platform's--destructivetheme token — exactly as the upstream package's own comment directs ("see paranext-core's _usj-nodes.scss").During review the styling was refined to match shadcn's destructive affordance (10% tint in light themes, 20% under
.dark), switched to the repo's standardcolor-mix(in oklab, …)color space, and propagated to the Storybook demo copy.API Changes
None. The only changed files are CSS/SCSS stylesheets. No exports, type signatures, command names, or
@papi/surfaces were added, modified, or removed.Findings
Critical — Must address before merge
None.
Important — Should address before merge
Rule placed in(Dismissed — placement is correct and matches the established convention._usj-nodes.scss(the verbatim "Copied from upstream" file) rather than the dedicated_editor-overrides.scss..verse-selectedis a per-node USJ style maintained upstream inusj-nodes.cssalongside.verse/.chapter; the file already hosts theme-token deviations from upstream (16var(--…)usages, e.g.--scripture-accent,--muted-foreground); upstream's own comment explicitly points the--destructiveoverride to_usj-nodes.scss; and_editor-overrides.scssis reserved for editor chrome —.editor-container,.toolbar,::selection, focus rings — not per-node USJ styles.)color: var(--destructive)text on a 15% tint of the same dark-red token risked low contrast in dark themes (fixed during review: matched shadcn'sdestructivebutton affordance —color-mix(… --destructive 10%)in light themes, bumped to20%under.dark .verse-selected, with a comment citing the button variant it mirrors.)lib/platform-bible-react/src/components/demo/scripture-editor/usj-nodes.cssdid not contain.verse-selected, so the demo would not reflect the armed-for-delete styling (fixed during review: added the equivalent rule with avar(--destructive, #dc2626)fallback so it renders even where the theme token is absent, plus the matching.darksplit.)[Author response: Finding 1 dismissed with a strong rationale grounded in the upstream repo's conventions (verified against
~/dev/scripture-editors). Findings 2 and 3 were fixed in-review at the author's direction.]Minor — Consider
Comment-style nit: the file mixes(Moot — was only relevant if the rule moved to/* */and//comments._editor-overrides.scss, which uses//. The rule correctly stayed in_usj-nodes.scss, which uses/* */.)Semantic color-pairing: design guide nudges toward(Resolved — the rule now matches shadcn's own vettedbackground+-foregroundpairing rather than same-token-on-same-token.destructivecomponent pattern exactly.)color-mix(in srgb, …)mixed an OKLCH-authored token in sRGB, which can look muddier thanin oklab(fixed during review: switched both files tocolor-mix(in oklab, …), matching the repo's dominant convention — 15 existingin oklabusages vs the 4 newin srgbones, including the nearest precedent in the editor's owneditor-overrides.css.)Third sibling copy(Dismissed — it is a partial/divergent copy, and enhanced-resources is a read-only resource viewer where verse deletion cannot occur, so the rule is intentionally out of scope.)extensions/src/platform-enhanced-resources/src/_usj-nodes.scsslacks the rule.[Author response: Author confirmed the dispositions; the one actionable item (oklab) was fixed in-review.]
Template Propagation
Shared Regions Modified
None. The changed files contain no
#region shared with …markers.Extension Config Changes
extensions/src/platform-scripture-editor/src/_usj-nodes.scss— extension source stylesheet, not a config/build file. No template propagation required.lib/platform-bible-react/src/components/demo/scripture-editor/usj-nodes.css— Storybook demo asset, not a config/build file. No template propagation required.Positive Observations
--destructivetheme token instead of the package's hardcoded#dc2626, so the armed state is theme- and dark-mode-aware — exactly the override the upstream package documents and requests.Interview Notes
~/dev/scripture-editors, branchpt-4020-backspace-confirmation— whereImmutableVerseNodeapplies the.verse-selectedclass (latest commit guardsImmutableVerseNode.isSelectedagainst a Lexical element-point throw). The styling and behavior need to land together._usj-nodes.scss, not the overrides file) and that the destructive theming was copied from the shadcn theme — both of which checked out against the upstream repo andlib/platform-bible-react. No areas were deferred to AI; no uncertainty expressed.In-Review Quality Check
All checks pass after the in-review changes:
npm run typecheck— passed cleanlynpm run lint— passed (0 errors; 2 pre-existingno-consolewarnings in an unrelated TS hook, untouched)npm test— passed (8 files, 191 tests)Note: the required
build:platform-bible-reactstep regeneratedlib/platform-bible-react/dist/artifacts, but those were a 10,852-line minifier-identifier-churn diff containing zeroverse-selectedreferences (the demo CSS is not bundled intodist). They were unrelated build drift from a differently-built committeddist, so they were reverted and excluded from this PR.Suggested Review Focus
Prioritized areas for the author-reviewer meeting:
@eten-tech-foundation/platform-editorversion that ships the delete behavior (and applies.verse-selected) is the one this repo pins/installs —package.jsonrequests~0.8.14, installed is0.8.15. Ensure the styling PR and the editor-behavior PR merge together so neither ships half a feature./10→/20split.usj-nodes.css(using#dc2626) so the two copies stay aligned.AI-assisted — session
This change is