Skip to content

Add the inline choice interaction editor - #6303

Open
AlexVelezLl wants to merge 8 commits into
learningequality:unstablefrom
AlexVelezLl:issue-6182-inline-choice-editor
Open

AlexVelezLl wants to merge 8 commits into
learningequality:unstablefrom
AlexVelezLl:issue-6182-inline-choice-editor

Conversation

@AlexVelezLl

@AlexVelezLl AlexVelezLl commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Adds Inline choice to the question type selector, with its own editor.
  • Adds an options panel for the open dropdown, where authors add, edit, remove and reorder options and mark the correct one.
  • Makes the options panel a modal dialog that traps focus, returns it to the dropdown on Escape or close, and closes when the passage is clicked.
  • Adds a Shuffle setting, as the choice question has, and hides reordering while it's on.
  • Shows validation errors on the option, the dropdown and the passage they belong to.
  • Shows each correct answer in view mode when Show answers is on, and "Choose…" in its place when it's off.
  • Moves the caret past a dropdown instead of selecting it, and removes a dropdown with Backspace or Delete beside it.
  • Returns the caret to the text beside a focused dropdown on Left or Right.
  • Announces to screen readers a dropdown the caret crosses and dropdowns that are removed.
  • Describes the passage editor with its helper text, and names a dropdown that needs attention as such in a preview that hides the answers.
  • Shows an unavailable Insert like the toolbar's other disabled tools, and shrinks it to its icon in a small window.
  • Lets every rich text editor's toolbar scroll sideways as a last resort, when it is still too wide after tools collapse into More, and opens the More menu outside the toolbar, as its Format and Paste menus already do. These two apply to every TipTapEditor, not only the passage.
  • Removes Studio's own text selection colours (Vuetify's ::selection in vuetify.scss), so selected text on every Studio page now uses KDS's selection colour, pale yellow instead of light blue, and a dropdown covered by a selection matches the text around it.
  • Allows uppercase letters in CSS custom property names in .stylelintrc.js, for KDS theme variables such as var(--tokens-fineLine). The rule applies to the whole repo.
  • Documents that an expanded popup keeps the rich text editor open.
  • Adds one helper for reading an editor's stored HTML, used by the editor and the passage.

References

Fixes #6182.
Fixes #6274.

Beyond #6182's scope

#6182 leaves the dropdown chip and Insert to #6181, but this PR also changes the chip. No #6182 acceptance criterion requires these changes; each came up while building, testing or reviewing the editor:

  • Makes a dropdown unselectable, so the caret moves past it, and removes it with Backspace or Delete beside it (InlineChoiceNode.js). The arrow keys stopped on each dropdown to select it before moving past, and Backspace selected it rather than removing it.
  • Returns the caret to the text from a focused dropdown on Left or Right (leaveForText). A dropdown is a focusable button in the text, and the arrow keys did nothing on it.
  • Announces dropdowns the caret crosses and dropdowns that are removed, through KDS's useKLiveRegion, with two new strings. A screen reader said nothing in either case, since a dropdown has no text to read out.
  • Restyles a dropdown covered by a text selection, following the design, since it no longer takes ProseMirror's node selection.
  • Copies a dropdown with its options in an attribute and only its correct answer as text (InlineChoiceNode.js, parse.js). Pasted into another passage it comes back whole; pasted into an editor without dropdowns, such as the question, it is its correct answer, or nothing without one, rather than every option run together. Plain text leaves it out, since a dropdown read as text could set off TipTap's typing shortcuts.

These can move to their own PR if preferred.

Still open: undoing a removal brings the dropdown back without an announcement, while redo announces the removal.

Reviewer guidance

  • Eight commits, each a reviewable unit; the editor is the sixth.
  • Go do the exercise editor, add a new question, set the inline choice question type, and have fun with the new editor!
  • Try possible edge cases: copy/paste, do/redo, make sure IDs are not repeated, make sure keyboard navigation works smoothly, check that resulting XML is compatible with what Kolibri expects.

Demo

Grabacion.de.pantalla.2026-10-07.a.las.4.02.52.p.m.mov

AI usage

Claude Code implemented this from the issue and design screenshots, with tests, then self-reviewed it. I reviewed the changes and steered the design and accessibility decisions.

🤖 Generated with Claude Code

@AlexVelezLl
AlexVelezLl marked this pull request as ready for review October 7, 2026 21:08
@AlexVelezLl
AlexVelezLl requested review from a team, leq-bot and rtibblesbot October 7, 2026 21:08
@rtibblesbot

rtibblesbot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

🟡 Waiting for changes

Outcome: skipped — no new commits since 30149d8

Last updated: 2026-10-23 14:50 UTC

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: the inline choice editor works end to end in manual QA. The type selector, insert flows, options panel, Shuffle, copy/paste ids, save/reopen and view mode all behave as #6182 specifies. CI is passing.

QA ran in the qti-demo shell because the QA server returned Redis 500s. axe found no new violations.

Suggestions, all inline:

  • Options panel focus: clicking non-focusable parts drops focus, and aria-modal while the passage stays editable.
  • Validation goes stale after removing a chip as text.
  • Accessible name for the passage editor.
  • isSupportedBody accepts bodies TipTap can't hold.
  • Chip and announcer changes outside #6182's scope.
  • Toolbar CSS and narrow-width overflow of Insert.
  • Tests that match text anywhere on the page, and focus-trap tests that don't check where focus lands.

Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 18fbfe8 to 6055318 Compare October 8, 2026 15:38

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 6 prior findings are still open; please fix or reply on each thread. 3 new suggestions below. 7 of 14 prior findings are resolved and 1 acknowledged.

CI passes. Manual QA ran 12 scenarios on the qti-demo shell, since Redis MISCONF blocked Django login. Scenarios: insert, options panel, keyboard/screen reader, undo/paste, shuffle, save/reopen, validation, RTL/touch. No regressions.

Still open:

  • aria-modal while the passage stays clickable
  • isSupportedBody accepts bodies TipTap can't hold
  • chip behaviour that #6182 lists as out of scope
  • undo restoring a chip isn't announced
  • chip with options but no correct mark reads "Add answers"
  • Insert overflows the passage toolbar below ~480px without touch. QA: 413px wide in a 301px toolbar at 375px.
  • options use a bare <input>, not the #5927 plain-text row
  • options-problem message shown for NO_CORRECT_ANSWER (nitpick)
Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — clicking heading/padding drops focus; Escape stops closing
UNADDRESSED — InlineChoiceOptions/index.vue:13 — aria-modal while passage stays interactive
RESOLVED — inlineChoice/Editor.vue:95 — validation stale after chip removed/restored
ACKNOWLEDGED — inlineChoice/Editor.vue:84 — passage editor indistinguishable from question field (separate issue under #6103)
UNADDRESSED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
UNADDRESSED — InlineChoiceChip/index.vue:24 — chip behaviour out of scope per #6182
UNADDRESSED — InlineChoiceChip/index.vue:32 — chip with no correct mark reads as "Add answers"
UNADDRESSED — EditorToolbar.vue — Insert pushed off narrow toolbar (styling now via appearanceOverrides)
RESOLVED — inlineChoice/tests/Editor.spec.js — focus-trap tests pass with handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — no-id error test passes wherever it renders
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — duplicates toStoredImageSrcs cases via stub
UNADDRESSED — InlineChoiceOptions/index.vue:97 — bare <input>, not the #5927 plain-text row
UNADDRESSED — inlineChoice/Editor.vue:52 — options-problem message for NO_CORRECT_ANSWER (nitpick)
RESOLVED — InlineChoiceChip/index.vue:14 — green fill on chip with no correct answer
RESOLVED — useInlineChoicePassage.js:75 — praise: live sync keeps editor history


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch 4 times, most recently from 79b7904 to 4ec7055 Compare October 8, 2026 18:44

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: manual QA found two blocking bugs:

  • Clicking another chip can miss when the page is scrolled to its end.
  • Ctrl+Z in an option field types back what it undid.

16 of 17 prior findings are resolved or acknowledged. Please address the open Editor.vue:56 nitpick: its message blames the options for a missing correct answer.

The other comments are smaller. CI pending. QA covered insert, options editing, keyboard, click-outside, chip navigation, undo/copy/paste, shuffle, save/reopen, validation, view mode and RTL. axe found nothing new.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — clicking heading/padding drops focus to <body>
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while the passage stays usable
RESOLVED — inlineChoice/Editor.vue:100 — validation stale after chip removed/restored
ACKNOWLEDGED — inlineChoice/Editor.vue:89 — passage editor indistinguishable from question field
ACKNOWLEDGED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue:24 — chip behaviour changes out of scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:42 — chip without correct mark reads like an option
RESOLVED — EditorToolbar.vue — Insert pushed off the toolbar in narrow windows
RESOLVED — inlineChoice/tests/Editor.spec.js — focus-trap tests pass with handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — no-id error test passes wherever it renders
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — repeats toStoredImageSrcs cases through a stub
ACKNOWLEDGED — InlineChoiceOptions/index.vue:97 — bare <input> instead of plain-text toolbar row
UNADDRESSED — inlineChoice/Editor.vue:56 — message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — green fill on chip with no correct answer
RESOLVED — passageChips.js:45 — invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:69 — helper text not referenced by the passage
RESOLVED — QTIItemEditor.spec.js:599 — findByText for the heading


Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No new commits since my last review (4ec7055).


Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No new commits since my last review (4ec7055).


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 4ec7055 to 79fdd0b Compare October 9, 2026 12:16

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: two new keyboard gaps from routing undo through the passage's history (inline).

17 of 23 prior findings resolved; 6 acknowledged.

CI passing. Manual QA covered authoring, options, shuffle, validation, keyboard (LTR/RTL), screen reader, light dismiss and view mode. Axe found nothing new.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — Clicking the panel's heading or padding drops focus to <body>
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal="true" while the passage stays clickable
RESOLVED — inlineChoice/Editor.vue:97 — Validation goes stale after a chip is removed or restored as text
ACKNOWLEDGED — inlineChoice/Editor.vue:86 — Screen readers can't tell the passage editor from the question field
ACKNOWLEDGED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue:24 — Chip behaviour changes listed as out of scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:42 — Chip with no correct mark reads like an option named "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off the toolbar in narrow windows
RESOLVED — inlineChoice/tests/Editor.spec.js — Focus-trap tests pass with first/last handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — No-id error test passes wherever the error renders
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — Repeats toStoredImageSrcs cases through a stub
ACKNOWLEDGED — InlineChoiceOptions/index.vue:97 — Options use a bare <input>, not the plain-text toolbar row
ACKNOWLEDGED — inlineChoice/Editor.vue:53 — Message blames the options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — Show answers fills a chip with no correct answer green
RESOLVED — inlineChoice/passageChips.js:45 — Invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:66 — Helper text not referenced by the passage
RESOLVED — QTIItemEditor/tests/QTIItemEditor.spec.js:599 — findByText instead of a heading role query
RESOLVED — inlineChoice/Editor.vue — Clicking another chip doesn't open it when scrolled to the end
RESOLVED — InlineChoiceOptions/index.vue:112 — Repeated Ctrl+Z in an option field types the undone text back
ACKNOWLEDGED — InlineChoiceChip/index.vue:33 — Error icon replaces the option count
RESOLVED — EditorToolbar.vue:402 — More menu may be clipped to the toolbar box
RESOLVED — useInlineChoicePassage.spec.js:218 — hasErrors branch of chipMessage untested
RESOLVED — InlineChoiceChip/index.vue — Selected chip doesn't take the selection's colour


Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot
rtibblesbot dismissed their stale review October 9, 2026 14:11

Superseded by my review of 79fdd0b: no blocking findings remain.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 79fdd0b to 0c742cd Compare October 9, 2026 14:26

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: all 25 prior findings are resolved. Two new suggestions on the history shortcut are inline.

CI passes. Manual QA did not run. The UI is unverified.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — Clicking heading/padding drops focus; Escape stops closing
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while the passage stays clickable
RESOLVED — inlineChoice/Editor.vue:97 — Validation goes stale after a chip is removed
RESOLVED — inlineChoice/Editor.vue:86 — Passage editor indistinguishable from question field
RESOLVED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue — Chip behaviour changes outside #6182 scope
RESOLVED — InlineChoiceChip/index.vue:42 — No-correct chip reads like option "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off toolbar in narrow windows
RESOLVED — Editor.spec.js — Focus-trap tests pass with handlers swapped
RESOLVED — Editor.spec.js — No-id error test passes wherever it renders
RESOLVED — imageSrc.spec.js — Repeats toStoredImageSrcs cases through a stub
RESOLVED — InlineChoiceOptions/index.vue:97 — Options use a bare <input>
RESOLVED — inlineChoice/Editor.vue:53 — Message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — Green fill on chip with no correct answer
RESOLVED — passageChips.js:45 — Invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:66 — Helper text not referenced
RESOLVED — QTIItemEditor.spec.js:599 — findByText for card heading
RESOLVED — inlineChoice/Editor.vue — Clicking another chip fails when scrolled to end
RESOLVED — InlineChoiceOptions/index.vue:112 — Repeated Ctrl+Z types undone text back
RESOLVED — InlineChoiceChip/index.vue:33 — Error icon replaces option count
RESOLVED — EditorToolbar.vue:402 — More menu clipped to toolbar box
RESOLVED — useInlineChoicePassage.spec.js:218 — hasErrors branch of chipMessage untested
RESOLVED — InlineChoiceChip/index.vue — Selected chip lacks selection colour
RESOLVED — InlineChoiceOptions/index.vue — Undo/redo deletes focused option, focus to <body>
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing while a chip has focus


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 0c742cd to 4ec4fa0 Compare October 9, 2026 15:42

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: all 27 prior findings resolved or acknowledged; two new suggestions inline.

CI passing. Manual QA did not run, so the UI is unverified.

  • suggestion: On macOS, Ctrl+Z undoes from a chip or the panel but not in the passage. Could the chip and panel reuse ProseMirror's keymap instead of historyShortcut.js?
  • suggestion: The caret test never moves the caret. Could it assert the movement?
Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — clicking heading/padding drops focus to <body>
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage stays clickable
RESOLVED — inlineChoice/Editor.vue:97 — validation stale after chip removed/restored
ACKNOWLEDGED — inlineChoice/Editor.vue:86 — passage editor indistinguishable from question field (separate issue)
ACKNOWLEDGED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold (general issue)
RESOLVED — InlineChoiceChip/index.vue — chip behaviour out of #6182 scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:42 — chip with no correct mark reads like option "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — inlineChoice/tests/Editor.spec.js — focus-trap tests pass with handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — no-id error test passes wherever it renders
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — repeats toStoredImageSrcs cases
ACKNOWLEDGED — InlineChoiceOptions/index.vue:98 — bare <input> instead of plain-text toolbar row
ACKNOWLEDGED — inlineChoice/Editor.vue:53 — message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — green fill on chip with no correct answer
RESOLVED — passageChips.js:45 — invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:66 — helper text not referenced
RESOLVED — QTIItemEditor.spec.js:599 — findByText instead of heading role
RESOLVED — inlineChoice/Editor.vue — clicking another chip fails when scrolled to end
RESOLVED — InlineChoiceOptions/index.vue:112 — repeated Ctrl+Z types undone text back
ACKNOWLEDGED — InlineChoiceChip/index.vue:33 — error icon replaces option count
RESOLVED — EditorToolbar.vue:402 — More menu clipped to toolbar box
RESOLVED — useInlineChoicePassage.spec.js:218 — hasErrors branch of chipMessage untested
RESOLVED — InlineChoiceChip/index.vue — selected chip doesn't take selection colour
RESOLVED — InlineChoiceOptions/index.vue — undo/redo deletes focused option, focus to <body>
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing while chip focused
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z does nothing on panel radios/buttons
RESOLVED — historyShortcut.js — Ctrl+Z on chip fails with non-Latin layout


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 4ec4fa0 to 8d74e78 Compare October 9, 2026 17:43

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 23 of 29 prior findings resolved; 6 acknowledged. One new suggestion inline.

CI passing. Manual QA covered insert/convert, marking, reorder, multiple dropdowns, Shuffle, save/reopen (XSD-valid), undo/redo, copy/paste ids, keyboard/screen reader, view mode and RTL. No new axe AA violations. QA ran the real channel_edit bundle in a static shell because Redis MISCONF blocked login. Server persistence via /api/sync/ was not checked.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — clicking heading/padding drops focus to <body>
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage stays clickable
RESOLVED — inlineChoice/Editor.vue:97 — validation stale after chip removed/restored
ACKNOWLEDGED — inlineChoice/Editor.vue:86 — passage editor indistinguishable from question field
ACKNOWLEDGED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue — chip behaviour changes out of #6182 scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:42 — unmarked chip reads like option "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — inlineChoice/tests/Editor.spec.js — focus-trap tests pass with handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — no-id error test passes wherever it renders
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — repeats toStoredImageSrcs cases
ACKNOWLEDGED — InlineChoiceOptions/index.vue:98 — bare <input> instead of plain-text toolbar
ACKNOWLEDGED — inlineChoice/Editor.vue:53 — message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — green fill on chip with no correct answer
RESOLVED — passageChips.js:45 — invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:66 — helper text not referenced
RESOLVED — QTIItemEditor.spec.js:599 — findByText instead of heading role
RESOLVED — inlineChoice/Editor.vue — clicking another chip fails when scrolled to end
RESOLVED — InlineChoiceOptions/index.vue:112 — repeated Ctrl+Z retypes undone text
ACKNOWLEDGED — InlineChoiceChip/index.vue:33 — error icon replaces option count
RESOLVED — EditorToolbar.vue:402 — More menu clipped
RESOLVED — useInlineChoicePassage.spec.js:218 — hasErrors branch untested
RESOLVED — InlineChoiceChip/index.vue — selected chip lacks selection colour
RESOLVED — InlineChoiceOptions/index.vue — undo/redo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing on focused chip
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios/buttons
RESOLVED — historyShortcut.js — Ctrl+Z fails on non-Latin layout
RESOLVED — historyShortcut.js — macOS Ctrl+Z undoes from chip but not passage
RESOLVED — InlineChoiceChip.spec.js:144 — test never moves the caret


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 8d74e78 to f51a09a Compare October 9, 2026 20:11

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: no new findings. 25 of 31 prior findings are resolved. The maintainer acknowledged the other 6.

Prior-finding status

RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:9 — Clicking heading or padding drops focus to
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:13 — aria-modal while the passage stays clickable
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:97 — Validation goes stale after a chip is removed or restored
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:86 — Passage editor indistinguishable from the question field (separate issue)
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold (general issue)
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Chip behaviour changes outside #6182 scope
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:42 — Chip with no correct mark reads like an "Add answers" option
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue — Insert pushed off the toolbar in narrow windows
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — Focus-trap tests pass with handlers swapped
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — No-id error test passes wherever it renders
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/tests/imageSrc.spec.js — Repeats toStoredImageSrcs cases through a stub
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:98 — Options use a bare
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:53 — Message blames options for NO_CORRECT_ANSWER
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:14 — Green fill on a chip with no correct answer
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/useInlineChoicePassage.js:114 — Live sync keeps editor history (praise)
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/passageChips.js:45 — Invalid chip marked by colour alone
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:66 — Helper text not referenced
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/tests/QTIItemEditor.spec.js:599 — findByText instead of heading role
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue — Clicking another chip fails when scrolled to the end
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:112 — Repeated Ctrl+Z types undone text back
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:33 — Error icon replaces the option count
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue:402 — More menu may be clipped
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/useInlineChoicePassage.spec.js:218 — hasErrors branch of chipMessage untested
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Selected chip lacks the selection colour
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Undo/redo deletes the focused option
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Ctrl+Z does nothing on a focused chip
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Ctrl+Z does nothing on panel radios/buttons
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/historyShortcut.js — Ctrl+Z fails on non-Latin layouts
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/historyShortcut.js — macOS Ctrl+Z works from chip/panel but not the passage
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/InlineChoiceChip.spec.js:144 — Test never moves the caret
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:263 — Ctrl+Z in one panel undoes another chip's edit unseen


Written by rtibblesbot, an LLM-based coding agent.

@AlexVelezLl
AlexVelezLl requested a review from rtibbles October 12, 2026 18:33
@rtibbles rtibbles self-assigned this Oct 14, 2026
@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from f51a09a to bceea4a Compare October 14, 2026 16:48

@rtibbles rtibbles left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

From manual QA; screenshots of the first two in the next comment.

return { label, optionCount, hasAnswer, accessibleName: name({ label, count: optionCount }) };
}

const label = hasAnswer ? correctText : addAnswers$();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The chip says "Add answers" while the panel says "Choose a correct answer". We should make them match.

:aria-label="editQuestionLabel$()"
@click="openPrompt"
>
<TipTapEditor

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Pasting a dropdown here gives satstoodlay. We should strip it, or keep only the correct answer.

idsWith(ValidationError.NO_CORRECT_ANSWER).has(props.dropdown.responseIdentifier),
);

const isOnlyOption = computed(() => props.dropdown.options.length <= 1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A dropdown with one option passes validation. We should report TOO_FEW_CHOICES.

.has-errors & {
background-color: v-bind('$themeTokens.error');
color: var(--tokens-textInverted);
background-color: var(--tokens-correct);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The chip stays green when answers are hidden. We should use neutral colours when isConcealed.

const prevDoc = editor.state.doc;
isSteppingFromOutside = true;
try {
editor.commands[direction]();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Undo from the panel scrolls the page. We should use undoNoScroll/redoNoScroll.

/** Every dropdown in the passage, in document order. */
const dropdowns = computed(() => getDropdowns(state.value.passage));

function setPrompt(html) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A cleared question is saved as <p data-studio-prompt=""/>. We should normalize it with hasRichTextContent.

@rtibbles

Copy link
Copy Markdown
Member

Chip label vs. panel error:

Chip says Add answers, panel says Choose a correct answer

Dropdown pasted into the question:

Pasted dropdown flattened to satstoodlay in the question field

@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from 7be483c to 1c82782 Compare October 19, 2026 16:00

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 30 of 33 prior findings resolved or acknowledged; 3 still open on their threads (out-of-scope chip changes, imageSrc.spec.js duplication, More menu clipping).

CI pending. Manual QA covered all 12 scenarios, including RTL and 375px. Nothing blocking turned up. axe found one new violation (chip name).

  • suggestion: TOO_FEW_CHOICES adds a publish gate that #6180 doesn't specify.
  • suggestion: removing Vuetify's ::selection changes selection colour app-wide.
  • suggestion: opening the panel fires up to two alerts.
  • suggestion: the chip's visible text isn't in its accessible name.
  • suggestion: toolbar Copy leaves out the chip's answer in plain text.

I dropped QA's report that Insert starts out of view at phone widths. The test browser had no touch support. Touch devices get the mobile toolbar.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — panel heading/padding click drops focus
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage clickable (outside click closes the panel)
RESOLVED — Editor.vue:97 — stale validation after chip removed/restored
ACKNOWLEDGED — Editor.vue:86 — passage editor not distinguishable from question field (separate issue under #6103)
ACKNOWLEDGED — Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold (general issue)
UNADDRESSED — InlineChoiceChip/index.vue — chip behaviour changes #6182 lists out of scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:43 — chip with no correct mark reads like "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar (icon-only + overflow-x)
RESOLVED — Editor.spec.js — focus-trap tests pass with first/last swapped
RESOLVED — Editor.spec.js — no-id error test not pinned to passage editor
UNADDRESSED — imageSrc.spec.js — repeats toStoredImageSrcs cases through a stub
ACKNOWLEDGED — InlineChoiceOptions/index.vue:102 — bare input instead of plain-text toolbar
ACKNOWLEDGED — Editor.vue:53 — message blames options for NO_CORRECT_ANSWER (strings review)
RESOLVED — InlineChoiceChip/index.vue:14 — green fill on chip with no correct answer
RESOLVED — useInlineChoicePassage.js:116 — live sync keeps editor history (praise)
RESOLVED — passageChips.js:62 — invalid chip marked by colour alone
RESOLVED — Editor.vue:66 — helper text not referenced
RESOLVED — QTIItemEditor.spec.js:599 — findByText not scoped to heading
RESOLVED — Editor.vue — clicking another chip at page end doesn't open it
RESOLVED — InlineChoiceOptions/index.vue:116 — repeated Ctrl+Z types undone text back
ACKNOWLEDGED — InlineChoiceChip/index.vue:34 — error icon replaces option count
UNADDRESSED — EditorToolbar.vue:402 — More menu may be clipped by overflow-y: hidden
RESOLVED — useInlineChoicePassage.spec.js:225 — hasErrors branch of chipMessage untested
RESOLVED — InlineChoiceChip/index.vue — selected chip colour comment mismatch
RESOLVED — InlineChoiceOptions/index.vue — undo/redo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z inert while chip focused
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z inert on radios/buttons
RESOLVED — historyShortcut.js — non-Latin keyboard layout
RESOLVED — historyShortcut.js — macOS Ctrl+Z in passage
RESOLVED — InlineChoiceChip.spec.js:156 — test never moves the caret
RESOLVED — InlineChoiceOptions/index.vue:265 — Ctrl+Z undoes another chip's edit
RESOLVED — InlineChoiceChip/index.vue — selected chips #b3d4fc blue (Vuetify's ::selection overrode KDS's; see vuetify.scss)
ACKNOWLEDGED — package.json:83 — KDS bump not in PR body (lands after #6317)

After this review: Full code review, then manual QA once the reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js, contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/descriptors.js….
  • Decide whether a one-option dropdown should block publishing (TOO_FEW_CHOICES), since #6180 doesn't specify it.
  • Sign off on removing Vuetify's global ::selection, which changes selection colour and text colour on every Studio page.
  • Check text selection on dark toolbars (channel list, edit modal, settings) for contrast once the selection decision is made.
QA captures (50)

Add a new exercise question and switch it to Inline choice in the type selector — option label and description, card type label, optional question field, passage editor label and helper text, Shuffle setting off by default in the choice editor's settings slot

Step Screenshot
Card collapsed type label Card collapsed type label
Inline choice edit mode Inline choice edit mode
Type dropdown open Type dropdown open
Type selector dialog Type selector dialog
1-switch-to-inline-choice.webm

Insert a blank dropdown with Insert, then convert highlighted passage text into a dropdown — the panel opens on each with focus inside, Insert's look while unavailable (no hover change, not-allowed cursor), the converted text becomes an option, the chip's label and count

Step Screenshot
Blank insert panel open Blank insert panel open
Convert over chip Convert over chip
Converted text panel open Converted text panel open
Insert unavailable hover Insert unavailable hover
2-insert-and-convert.webm

In an open chip's options panel add, edit, remove and reorder options by drag and by move up / move down, and mark the correct one — chip label and count update immediately, the correct mark stays on its option after reorder, the only option's remove control is disabled, removing the correct option gives the dashed "Add answer" chip, the markers act as one labelled single-select group

Step Screenshot
After drag After drag
Correct moved up Correct moved up
Correct option duplicate Correct option duplicate
Correct removed Correct removed
Only option remove disabled Only option remove disabled
Option errors Option errors
Panel initial Panel initial
3-drag-reorder.webm
3-edit-options.webm

Drive the options panel from the keyboard only — Enter / Space on a chip opens it as a labelled role=dialog aria-modal panel, Tab and Shift+Tab stay inside, Escape and the close control return focus to the chip and the next Tab moves on, opening a second chip shows its options, clicking the passage closes the panel, the passage editor stays open while the panel is used

Step Screenshot
Escape focus on chip Escape focus on chip
Panel closed by passage click Panel closed by passage click
Panel open via enter Panel open via enter
Second chip options Second chip options
4-keyboard-options-panel.webm

Turn Shuffle on and off on a question with several dropdowns, then save and reopen — drag handles and move up / move down hidden on every chip's panel while on and back when off, the setting survives reopening, every qti-inline-choice-interaction in the saved XML carries it

Step Screenshot
Shuffle off handles shown Shuffle off handles shown
Shuffle on after reopen Shuffle on after reopen
Shuffle on handles hidden Shuffle on handles hidden
5-shuffle-toggle.webm

Move the caret through a passage with several dropdowns and delete them — arrow keys step past a chip without selecting it, Backspace / Delete beside a chip removes it, Left / Right on a focused chip returns the caret to the text, live-region announcements for crossing and removing chips, a text selection spanning a chip restyles it and selection colours look right

Step Screenshot
Caret after trailing chip Caret after trailing chip
Rtl selection Rtl selection
Select all Select all
Selection spanning chips Selection spanning chips
Three chips deleted Three chips deleted
6-caret-and-delete-chips.webm

Undo and redo option edits and chip removals with the shortcuts in the passage, on a chip and inside the panel, then copy, cut and paste dropdowns within the passage and into the question field — the open panel always matches the chip, pasted chips get fresh unique response and choice identifiers, pasting outside a passage leaves only the correct answer text

Step Screenshot
Pasted chip in passage Pasted chip in passage
Undo in panel opens changed chip Undo in panel opens changed chip

Break an inline choice question in each way validation catches — no dropdown, a dropdown with no correct answer, one option only, an empty option, duplicate options — each error appears on the option row, the chip or the passage as it belongs, the question is marked incomplete, and fixing each clears it

Step Screenshot
All fixed All fixed
Collapsed incomplete Collapsed incomplete
Dropdown removed Dropdown removed
Dropdown restored Dropdown restored
Duplicate options Duplicate options
Empty correct option Empty correct option
Empty option Empty option
New blank errors New blank errors
No dropdown error No dropdown error
One option only One option only
8-fix-and-remove-dropdown.webm

Save an inline choice question with several dropdowns, some without a correct answer, reload the page and reopen it — question, passage, every chip's options and correct answer restored, which chip was open is not saved, the saved XML has response processing only once every dropdown is scorable and no console warning is written

Step Screenshot
After reload reopened After reload reopened
All dropdowns scorable All dropdowns scorable
Before reload chip2 open Before reload chip2 open

Written by rtibblesbot, an LLM-based coding agent.

Comment thread contentcuration/contentcuration/frontend/shared/styles/vuetify.scss
@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch 2 times, most recently from cf5c162 to 65380dc Compare October 19, 2026 20:22

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: the More menu now runs off the viewport, and Add option reads the new field's error twice.

Most prior findings are resolved or acknowledged. New commits landed after these passes ran and are unreviewed.

CI passing. Manual QA covered 12 scenarios. Only the two findings below came up.

  • blocking: the More menu now runs off the viewport (inline).
  • suggestion: Add option reads the new field's error twice (inline).
Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — panel heading/padding click drops focus
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage clickable
RESOLVED — Editor.vue:97 — validation stale while passage open
ACKNOWLEDGED — Editor.vue:86 — passage editor not distinguishable from question field
ACKNOWLEDGED — Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
ACKNOWLEDGED — InlineChoiceChip/index.vue — chip behaviour out of #6182 scope
ACKNOWLEDGED — InlineChoiceChip/index.vue:46 — "Add answers" reads as option name
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — Editor.spec.js — focus-trap tests pass with handlers swapped
RESOLVED — Editor.spec.js — no-id error not pinned to passage editor
RESOLVED — imageSrc.spec.js — repeats toStoredImageSrcs cases
ACKNOWLEDGED — InlineChoiceOptions/index.vue:105 — bare input for options
ACKNOWLEDGED — Editor.vue:53 — message blames options
RESOLVED — InlineChoiceChip/index.vue:14 — green fill with no correct answer
RESOLVED — useInlineChoicePassage.js:116 — live sync keeps history (praise)
RESOLVED — passageChips.js:62 — invalid chip marked by colour alone
RESOLVED — Editor.vue:66 — helper text unreferenced
RESOLVED — QTIItemEditor.spec.js:599 — findByText not scoped to heading
RESOLVED — Editor.vue — clicking another chip at page end
RESOLVED — InlineChoiceOptions/index.vue:119 — repeated Ctrl+Z retypes text
ACKNOWLEDGED — InlineChoiceChip/index.vue:36 — error icon replaces count
RESOLVED — EditorToolbar.vue:404 — More menu clipped (fix regressed; see new blocking finding)
RESOLVED — useInlineChoicePassage.spec.js:225 — hasErrors branch untested
RESOLVED — InlineChoiceChip/index.vue — selected chip colour vs comment
RESOLVED — InlineChoiceOptions/index.vue — undo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z on focused chip
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z on radios/buttons
RESOLVED — historyShortcut.js — non-Latin layouts
RESOLVED — historyShortcut.js — macOS Ctrl+Z
RESOLVED — InlineChoiceChip.spec.js:156 — test never moves caret
RESOLVED — InlineChoiceOptions/index.vue:292 — Ctrl+Z undoes another chip's edit
ACKNOWLEDGED — InlineChoiceChip/index.vue — selected chip blue vs yellow
ACKNOWLEDGED — package.json:83 — KDS bump not in PR body
RESOLVED — validation.js:14 — one-option dropdown fails validation (withdrawn: #6182 lists TOO_FEW_CHOICES)
ACKNOWLEDGED — vuetify.scss:2482 — rule removal affects all pages
RESOLVED — InlineChoiceOptions/index.vue:22 — up to two alerts on open
RESOLVED — InlineChoiceChip/index.vue:106 — accessible name omits badge text
RESOLVED — InlineChoiceNode.js — toolbar Copy drops chip

After this review: Full code review, then manual QA once the reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Confirm the chip behaviour changes beyond #6182's stated scope (chip labels, error icon, selection colour) are wanted product-wide.
  • Confirm removing the vuetify.scss ::selection rule is acceptable across all Studio pages.
  • Re-run the More menu and Add option screen-reader checks once fixed.
QA captures (50)

Add a new question in the exercise editor and switch it to Inline choice — type selector entry, card type label, question field, passage helper text, Insert button in the passage toolbar, Shuffle setting off by default in the settings slot

Step Screenshot
Card collapsed type label Card collapsed type label
Inline choice card initial Inline choice card initial
Passage open insert button Passage open insert button
Type info modal inline choice Type info modal inline choice
Type selector inline choice entry Type selector inline choice entry
1-switch-to-inline-choice.webm

Build a passage with two dropdowns, one inserted blank and one converted from highlighted text, fill each in, then save, close and reopen the item — panel opens on insert, chip labels and counts, correct answers, saved XML has every declaration and no open-chip state

Step Screenshot
Card closed two chips Card closed two chips
Panel open on insert Panel open on insert
Reopened dropdown 2 Reopened dropdown 2
Two dropdowns filled Two dropdowns filled
2-build-save-reopen.webm

Edit one dropdown's options panel end to end — add, type in, remove (last option's remove disabled), reorder by drag and by move up/down, mark correct and move the mark, remove the correct option to reach the dashed Add answer state; chip label and count update after each step

Step Screenshot
Blank options errors Blank options errors
Correct moved to green Correct moved to green
Correct removed no answer Correct removed no answer
Four options blank error Four options blank error
No answer chip closed No answer chip closed
One option delete disabled One option delete disabled
3-drag-reorder.webm

Open one chip, then click another chip, then click into the passage text, then click outside the editor — panel switches to the second chip's options, closes on passage click, rich text editor stays open while the panel is open and closes after

Step Screenshot
Chip1 panel open Chip1 panel open
Chip2 panel switched Chip2 panel switched
Outside click editor closed Outside click editor closed
Outside click with panel open Outside click with panel open
Passage click panel closed Passage click panel closed
Passage open no panel Passage open no panel
4-chip-switch-and-dismiss.webm

Operate the options panel by keyboard only — open a chip with Enter and with Space, focus lands in the list, Tab and Shift+Tab stay trapped, correct markers act as one radio group, move up/down, Escape and the close button return focus to the chip and the next Tab moves on

Step Screenshot
Focus on correct radio Focus on correct radio
Focus on move down Focus on move down
Panel opened by enter focus in list Panel opened by enter focus in list
Panel opened by space dropdown 2 Panel opened by space dropdown 2
5-keyboard-only-panel.webm

Move the caret through a passage with dropdowns using arrow keys, Backspace and Delete, and Left/Right from a focused chip — caret skips over chips, Backspace/Delete beside a chip removes it, chip-to-text return, live region announcements for crossed and removed chips

Step Screenshot
After undo After undo
Backspace removed chip Backspace removed chip
Caret after chip Caret after chip
Rtl passage Rtl passage
6-caret-and-chip-keys.webm

Edit options and remove chips, then undo and redo repeatedly with toolbar buttons and keyboard shortcuts — options panel always matches the passage, the open chip survives or the panel closes when its chip is gone, no stale or duplicated option ids

Step Screenshot
History fully undone History fully undone
Panel after edits Panel after edits
Panel after undo Panel after undo
7-undo-redo-panel-sync.webm

Copy and paste dropdowns — chip into the same passage, into a second inline choice question, and into the question field or another question type's rich text — pasted chip keeps its options with fresh identifiers, plain-text targets get only the correct answer text

Step Screenshot
Question field paste correct answer Question field paste correct answer
Same passage pasted chip panel Same passage pasted chip panel
Second question pasted chip Second question pasted chip
Single choice paste correct answer Single choice paste correct answer
Toolbar and cut paste chips Toolbar and cut paste chips

Toggle Shuffle on and off with several chips, then save and reopen — drag handles and move up/down hide and return on every chip's panel, setting persists, every qti-inline-choice-interaction in the XML carries shuffle

Step Screenshot
Reopened shuffle persisted Reopened shuffle persisted
Shuffle off panel reorderable Shuffle off panel reorderable
Shuffle on panel no reorder Shuffle on panel no reorder
9-shuffle-toggle-save-reopen.webm

Trigger each validation error — empty option text, dropdown with no correct answer, dropdown with one option, passage with no dropdowns — error shown on the option row, chip and panel top, or passage editor; question marked incomplete; Add option does not double-announce the empty error

Step Screenshot
Collapsed cards incomplete Collapsed cards incomplete
Empty option row errors Empty option row errors

Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: the toolbar More menu still opens off-screen on a phone. The other 40 prior findings are resolved or acknowledged.

  • blocking: More menu runs off the viewport at phone width (EditorToolbar.vue:106).
  • CI passing.
  • Manual QA passed insert, options panel, reorder/shuffle, keyboard, undo/redo, paste, validation, save/reload, RTL and selection colour.
  • Commits pushed after these passes ran are not reviewed here.
Prior-finding status

RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:9 — Panel heading/padding click drops focus to body
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:13 — aria-modal while passage is clickable
RESOLVED — QTIEditor/interactions/inlineChoice/Editor.vue:97 — Validation stale after chip removed or restored
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/Editor.vue:86 — Passage editor indistinguishable from question field
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Chip behaviour changes out of scope for #6182 (withdrawn: later changes came from review asks)
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:46 — "Add answers" reads like an option
RESOLVED — TipTapEditor/TipTapEditor/components/EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — Focus-trap tests survive swapped handlers
RESOLVED — QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — No-id error test not tied to passage editor
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — Duplicated toStoredImageSrcs cases
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:105 — Bare input instead of plain-text toolbar
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/Editor.vue:53 — Message blames options for NO_CORRECT_ANSWER
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:14 — Show-answers fill with no correct answer
RESOLVED — QTIEditor/interactions/inlineChoice/passageChips.js:62 — Invalid chip marked by colour alone
RESOLVED — QTIEditor/interactions/inlineChoice/Editor.vue:66 — Helper text unreferenced
RESOLVED — QTIEditor/components/QTIItemEditor/tests/QTIItemEditor.spec.js:751 — findByText not scoped to heading
RESOLVED — QTIEditor/interactions/inlineChoice/Editor.vue — Another chip doesn't open at page end
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:119 — Repeated Ctrl+Z types text back
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:36 — Error icon replaces option count
RESOLVED — TipTapEditor/TipTapEditor/components/EditorToolbar.vue:404 — More menu clipped to toolbar
RESOLVED — QTIEditor/interactions/inlineChoice/tests/useInlineChoicePassage.spec.js:225 — hasErrors branch untested
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Selected chip doesn't take selection colour
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Undo/redo deletes focused option
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Ctrl+Z does nothing on a focused chip
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios/buttons
RESOLVED — QTIEditor/interactions/inlineChoice/historyShortcut.js — Ctrl+Z fails on non-Latin layouts
RESOLVED — QTIEditor/interactions/inlineChoice/historyShortcut.js — macOS Ctrl+Z inconsistent in passage
RESOLVED — QTIEditor/interactions/inlineChoice/tests/InlineChoiceChip.spec.js:156 — Test never moves the caret
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:292 — Ctrl+Z crosses chips
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Selected chips blue vs yellow selection
ACKNOWLEDGED — package.json:84 — KDS bump not in PR body
RESOLVED — QTIEditor/interactions/inlineChoice/validation.js:14 — One-option dropdown fails validation (withdrawn: #6180 rule 8 requires it)
RESOLVED — styles/vuetify.scss:2482 — Removed selection rule changes selection app-wide
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:22 — Two alerts on opening an incomplete chip
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:106 — Accessible name omits count badge text
ACKNOWLEDGED — QTIEditor/interactions/inlineChoice/InlineChoiceNode.js — Toolbar Copy drops chip from plain text
UNADDRESSED — TipTapEditor/TipTapEditor/components/EditorToolbar.vue:106 — More menu runs off viewport
RESOLVED — QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:252 — Add option reads blank error twice

After this review: Full code review, then manual QA once the reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Confirm the shared EditorToolbar changes (Insert icon-only, overflow-x: auto, More menu positioning) suit every TipTap editor, not just the passage.
  • Confirm dropping Vuetify's global ::selection override for KDS's yellow is wanted app-wide.
  • QA the More menu and toolbar on a phone-width window in LTR and RTL once the off-screen fix lands.
QA captures (50)

Add a new exercise question, switch its type to Inline choice, write a question and a passage, insert a blank dropdown and convert highlighted text into a dropdown — question type label, helper text, Insert opening the options panel with focus inside it, the chip label and count after each insert

Step Screenshot
Blank insert panel open Blank insert panel open
Card type label Card type label
Converted chip two options Converted chip two options
Highlight insert panel open Highlight insert panel open
Inline choice selected Inline choice selected
New question default New question default
Panel closed four chips Panel closed four chips
Passage editing Passage editing
Selection spanning chip Selection spanning chip
Sun highlighted Sun highlighted
Type dropdown open Type dropdown open
Type picker Type picker
1-insert-flow.webm

Fill a dropdown's options in its panel: add options, edit their text, mark one correct then mark another, remove the correct one, try removing the last remaining option — chip label and count update live, single-select correct markers, disabled remove on the only option, dashed "Add answer" state after removing the correct option

Step Screenshot
Correct option emptied Correct option emptied
Correct removed chip needs answer Correct removed chip needs answer
Only option remove disabled Only option remove disabled
Option1 correct chip blue Option1 correct chip blue
Option2 correct single select Option2 correct single select
Panel opened one blank option Panel opened one blank option
View mode chip no correct View mode chip no correct
2-options-panel-flow.webm

Reorder a dropdown's options with drag and drop and with move up / move down, then turn Shuffle on and off — correct mark follows its option, Shuffle checkbox sits where the choice question's does and starts off, handles and move controls hide on every chip's panel while Shuffle is on and return when off

Step Screenshot
Choice question shuffle reference Choice question shuffle reference
Dragged blue to last Dragged blue to last
Initial blue correct Initial blue correct
Moved blue to top Moved blue to top
Moved up blue first Moved up blue first
Shuffle off default Shuffle off default
Shuffle off handles back Shuffle off handles back
Shuffle on dropdown2 no handles Shuffle on dropdown2 no handles
Shuffle on handles hidden Shuffle on handles hidden
3-reorder-shuffle-flow.webm

Operate the options panel by keyboard only: Tab to a chip, open it with Enter and with Space, Tab and Shift+Tab around the panel, mark correct and reorder by keyboard, close with Escape and with the close control, open a second chip while one is open — focus trapped in the dialog, dialog role/aria-modal/label naming the dropdown, focus returns to the chip and the next Tab moves on, the second chip's options replace the first's

Step Screenshot
Marked correct and moved Marked correct and moved
Panel open by enter Panel open by enter
Second chip replaces first Second chip replaces first
4-keyboard-panel-flow.webm

Move the caret through a passage with several dropdowns using arrow keys, delete a dropdown with Backspace and with Delete beside it, press Left/Right on a focused chip, then click the passage while a panel is open — caret skips chips rather than selecting them, chip removed in one keystroke, caret returns to the text, panel closes on passage click while the editor stays open, screen reader live-region announcements for crossed and removed dropdowns

Step Screenshot
Caret before chip Caret before chip
Panel closed after passage click Panel closed after passage click
Panel open Panel open
5-caret-delete-flow.webm

Edit options, insert and delete dropdowns, then undo and redo each step with keyboard shortcuts and the toolbar history buttons — the open panel's list always matches the chip after every undo/redo, no stale panel for a removed chip, each edit is one undo step

Step Screenshot
Start Start
Undo switches panel to changed chip Undo switches panel to changed chip
6-insert-delete-undo-redo.webm

Copy passage text holding dropdowns with Ctrl+C and with the toolbar Copy, paste it back into the passage, into the question field, into a hint and as plain text — pasted chips come back whole with fresh identifiers (check saved XML for duplicate ids), the question gets only the correct answer text or nothing without one, plain-text paste drops the dropdown

Step Screenshot
Ctrl v hint correct answer text Ctrl v hint correct answer text
Ctrl v passage chips whole Ctrl v passage chips whole
Ctrl v question correct answer text Ctrl v question correct answer text
Passage after pastes Passage after pastes
Plain paste hint drops dropdown Plain paste hint drops dropdown
Plain paste passage drops dropdown Plain paste passage drops dropdown
Toolbar paste passage chips whole Toolbar paste passage chips whole

Leave an inline choice question with validation problems — no dropdown in the passage, a dropdown with no correct answer, a dropdown with too few options, an option with empty text — each error shows on the passage, the chip and the panel top, or the option row as appropriate, the question is marked incomplete, and errors clear once fixed

Step Screenshot
Blank dropdown errors Blank dropdown errors

Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 38 of 41 prior findings resolved or acknowledged; 3 still open.

  • suggestion (vuetify.scss:2482 thread): removing Vuetify's global ::selection rule recolours text selection on every Studio page. Vuetify's #b3d4fc overrode KDS's, hence the bluish selection on unstable. Get design sign-off, or scope it to the editor.
  • suggestion (EditorToolbar.vue:106, both threads): the More menu still runs off the viewport in narrow non-touch windows. Downgraded from blocking: touch devices get the mobile toolbar. Fix it, or get a maintainer to defer it to KDS.
  • Withdrawn: chip changes outside #6182's scope; I requested most.
  • Withdrawn: the one-option dropdown validation finding. #6182 names TOO_FEW_CHOICES.

CI passing. Manual QA did not run.

Prior-finding status

RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:9 — Panel heading click drops focus
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:13 — aria-modal while the passage is clickable
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:97 — Stale validation after a chip is removed
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:86 — Passage editor indistinguishable from question field
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Chip behaviour outside #6182 scope (withdrawn)
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:46 — Chip with no correct mark reads like an option
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — Focus-trap tests pass with handlers swapped
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/Editor.spec.js — No-id error test not tied to passage editor
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/tests/imageSrc.spec.js — Duplicate toStoredImageSrcs cases
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:105 — Options use a bare <input>
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:53 — Message blames options for NO_CORRECT_ANSWER
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:14 — Green fill on chip with no correct answer
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/useInlineChoicePassage.js:116 — Praise: live sync keeps history
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/passageChips.js:62 — Invalid chip marked by colour alone
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue:66 — Helper text not referenced
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/tests/QTIItemEditor.spec.js:751 — findByText for card label
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/Editor.vue — Clicking another chip fails at page end
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:119 — Repeated Ctrl+Z types undone text back
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:36 — Error icon replaces option count
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue:404 — More menu clipped to toolbar box
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/useInlineChoicePassage.spec.js:225 — hasErrors branch untested
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Selected chip doesn't take selection colour
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Undo/redo deletes the focused option
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Ctrl+Z does nothing on a focused chip
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios/buttons
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/historyShortcut.js — Ctrl+Z on non-Latin layouts
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/historyShortcut.js — macOS Ctrl+Z in the passage
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/tests/InlineChoiceChip.spec.js:156 — Test never moves the caret
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:300 — Ctrl+Z undoes another chip's edit
ACKNOWLEDGED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue — Selected chips #b3d4fc blue
ACKNOWLEDGED — package.json:84 — KDS bump not in PR body
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/validation.js:14 — One-option dropdown fails validation (withdrawn)
UNADDRESSED — contentcuration/contentcuration/frontend/shared/views/../styles/vuetify.scss:2482 — Global ::selection rule removed
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:22 — Up to two alerts on opening an incomplete chip
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue:106 — Accessible name lacks visible text
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/InlineChoiceNode.js — Toolbar Copy drops chip from plain text
RESOLVED — contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceOptions/index.vue:254 — Add option announces blank error twice
CONTESTED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue:106 — More menu runs off the viewport
CONTESTED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue:106 — More menu opens above the viewport on a phone

After this review: Full code review, then manual QA once the reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Decide whether dropping Vuetify's global ::selection rule, which recolours text selection across Studio, is acceptable.
  • Decide whether the More menu running off the viewport in narrow non-touch windows can wait for a KDS fix.
  • In the running app, check the chip and options panel with keyboard, screen reader and Ctrl+Z, because manual QA did not run.

Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot
rtibblesbot dismissed stale reviews from themself October 20, 2026 01:17

Superseded by my review of b3705ba: no blocking findings remain.

@AlexVelezLl
AlexVelezLl requested a review from rtibbles October 20, 2026 21:18
AlexVelezLl and others added 5 commits October 22, 2026 08:31
An item with several responses gets no response processing while any of
them has nothing to score it by, such as an inline choice dropdown with
no correct answer yet. That is an unfinished item, which validation
already reports to the author, so it is not logged as well.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An unavailable action now fades as the toolbar's disabled buttons do,
with a not-allowed cursor, and no longer changes on hover or press as if
it could be used. In a small window it shows only its icon, keeping its
name for assistive technology, since its full label ran past the
toolbar's edge in a narrow window or at a high zoom. As a last resort,
a toolbar still too wide for its editor scrolls.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The editor stays open on a click outside it while any trigger inside it
has aria-haspopup and aria-expanded="true". The toolbar's menus rely on
that, and so does a node view that opens a panel beside the editor, such
as the inline choice chip's options. It is now stated in the consumer
docs and tested for a popup opened from the content, so a change to the
check cannot silently close the editor while such a panel is in use.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A chip is not a place to type, and its button is how the keyboard
reaches its options, so it is no longer selectable as a node: the arrow
keys move past it rather than onto it. ProseMirror leaves Backspace and
Delete beside such a node to the browser, which handles them unevenly,
so they remove the chip themselves, in one undoable step.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The stored form of an editor's HTML, with images back to their stored
filenames, is now `storedHTML` in `utils/imageSrc.js`. `TipTapEditor`
reads its content out through it, and so can a consumer that reads an
editor directly, without repeating how that form is made.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from b3705ba to f144867 Compare October 22, 2026 13:35

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 31 of 41 prior findings are resolved and 8 acknowledged. The More menu placement (2 threads) is still open, now as a suggestion.

CI passing. Manual QA covered create/save/reopen, option editing, validation, keyboard, undo/redo, copy/paste, view mode, RTL, the toolbar and legacy items. The saved XML passes the QTI 3 XSD. axe found only pre-existing violations.

  • suggestion: More menu opens off-screen (inline).
  • suggestion: Add option still sets off a section-level alert (inline).
Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — Clicking panel padding drops focus
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while the passage is clickable
RESOLVED — Editor.vue:97 — Validation stale after a chip is removed
ACKNOWLEDGED — Editor.vue:86 — Passage editor indistinguishable from question field
ACKNOWLEDGED — Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue — Chip changes out of #6182's scope (withdrawn: later rounds asked for most of them)
ACKNOWLEDGED — InlineChoiceChip/index.vue:46 — "Add answers" reads like an option
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — Editor.spec.js — Focus-trap tests pass with handlers swapped
RESOLVED — Editor.spec.js — No-id error not pinned to passage editor
RESOLVED — imageSrc.spec.js — Repeats toStoredImageSrcs cases
ACKNOWLEDGED — InlineChoiceOptions/index.vue:105 — Bare input instead of plain-text toolbar
ACKNOWLEDGED — Editor.vue:53 — Message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — Green fill on chip with no correct answer
ACKNOWLEDGED — useInlineChoicePassage.js:116 — Live sync keeps history (praise)
RESOLVED — passageChips.js:62 — Invalid chip marked by colour alone
RESOLVED — Editor.vue:66 — Helper text not referenced
RESOLVED — QTIItemEditor.spec.js:751 — findByText instead of heading role
RESOLVED — Editor.vue — Chip click fails when scrolled to page end
RESOLVED — InlineChoiceOptions/index.vue:119 — Repeated Ctrl+Z retypes undone text
ACKNOWLEDGED — InlineChoiceChip/index.vue:36 — Error icon replaces option count
RESOLVED — EditorToolbar.vue:404 — More menu clipped to toolbar box
RESOLVED — useInlineChoicePassage.spec.js:225 — hasErrors branch untested
RESOLVED — InlineChoiceChip/index.vue — Selected chip ignores selection colour
RESOLVED — InlineChoiceOptions/index.vue — Undo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing on a chip
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios/buttons
RESOLVED — historyShortcut.js — Non-Latin layout
RESOLVED — historyShortcut.js — macOS Ctrl+Z in passage
RESOLVED — InlineChoiceChip.spec.js:156 — Test never moves the caret
RESOLVED — InlineChoiceOptions/index.vue:300 — Undo touches another chip's edit
RESOLVED — InlineChoiceChip/index.vue — Selected chips blue (the removed vuetify.scss rule was the blue; chips now take KDS's yellow)
ACKNOWLEDGED — package.json:84 — KDS bump not in PR body
RESOLVED — validation.js:14 — One-option dropdown fails validation (withdrawn: #6182 lists TOO_FEW_CHOICES)
RESOLVED — vuetify.scss:2482 — Global selection change (withdrawn: every page now uses KDS's selection colour)
RESOLVED — InlineChoiceOptions/index.vue:22 — Two alerts on open
RESOLVED — InlineChoiceChip/index.vue:106 — Accessible name lacks badge text
RESOLVED — InlineChoiceNode.js — Plain-text copy drops chip (withdrawn: #6274 specifies it)
RESOLVED — InlineChoiceOptions/index.vue:254 — Add option double announcement
CONTESTED — EditorToolbar.vue:106 — More menu runs off the viewport (now suggestion)
CONTESTED — EditorToolbar.vue:106 — More menu opens above the viewport on a phone (now suggestion)

Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Decide whether the off-viewport More menu at small window widths can wait on a KDS change.
  • The vuetify.scss removal changes text selection colour on every Studio page; confirm that is wanted.
  • Check the chip, panel and toolbar against the Figma spec in a running app before release.
QA captures (50)

Create an inline choice question from scratch in the exercise editor — pick Inline choice in the question type selector, write an optional question and a passage, insert a blank dropdown and one converted from highlighted text, add options, mark the correct one, close the panel, save, then reopen the item and check the dropdowns, options and correct answers persisted and the saved XML is valid QTI with unique identifiers

Step Screenshot
Blank dropdown options correct Blank dropdown options correct
Blank dropdown panel Blank dropdown panel
Converted dropdown panel Converted dropdown panel
Highlighted text before convert Highlighted text before convert
Inline choice selected Inline choice selected
Passage before insert Passage before insert
Passage two dropdowns Passage two dropdowns
Reopened dropdown 2 panel Reopened dropdown 2 panel
Reopened item Reopened item
Type selector open Type selector open
1-create-inline-choice.webm

Edit options in the dropdown's options panel — add, edit, delete and reorder options, change the correct answer, then turn Shuffle on and check reordering is hidden and the setting persists after save and reopen

Step Screenshot
Panel after edits Panel after edits
Panel initial Panel initial
Reopened shuffle persisted Reopened shuffle persisted
Shuffle on no reorder Shuffle on no reorder
2-edit-options-and-shuffle.webm

Validation on an inline choice question — a passage with no dropdown, a dropdown with no correct answer, one with fewer than 2 options, duplicate options; check each error shows on the option, the chip (error icon in place of the count) and the passage, clears when fixed, and an incomplete question is flagged in the exercise

Step Screenshot
After recording reload After recording reload
After stop recording reload After stop recording reload
All errors cleared All errors cleared
Blank dropdown errors Blank dropdown errors
Dropdown deleted error back Dropdown deleted error back
Duplicate options Duplicate options
Exercise flags incomplete Exercise flags incomplete
New question no dropdown New question no dropdown
Too few options Too few options
3-fix-errors-one-by-one.webm

Options panel as a modal dialog with the keyboard — open a chip with Enter, Tab stays inside the panel, Escape and the close button return focus to the chip, clicking in the passage closes it, and messages are not all read out as alerts on open

Step Screenshot
Panel open by enter Panel open by enter
Panel open dropdown 2 Panel open dropdown 2
Panel reopened with errors Panel reopened with errors
4-keyboard-modal-flow.webm

Keyboard caret movement around dropdown chips in the passage — arrow keys move past a chip without selecting it, Left/Right from a focused chip return the caret beside it (also in an RTL language), Backspace and Delete beside a chip remove it in one step, and screen reader live-region announcements for crossed and removed chips

Step Screenshot
Caret beside chip Caret beside chip
Rtl caret after chip Rtl caret after chip
5-backspace-delete-chip.webm
5-rtl-arabic-passage-arrows.webm

Undo and redo in an inline choice question — undo/redo option edits from inside the options panel and on a focused chip, undo a chip removal and redo it; check the panel and validation follow each step and the page does not scroll away

Step Screenshot
Blank option error Blank option error
Chip removal undone Chip removal undone
Chip removed Chip removed
Panel before edit Panel before edit
Redo removes open chip Redo removes open chip
Undo switches to chip 2 Undo switches to chip 2
Undo while scrolled Undo while scrolled
6-undo-redo-flow.webm

Copy and paste dropdown chips — copy a chip within a passage and into another inline choice question (comes back whole with options and new unique ids), into the question field or another rich text editor (only its correct answer, nothing without one), and as plain text

Step Screenshot
Chip copied within passage Chip copied within passage
Chip pasted into question field Chip pasted into question field
Chips pasted into other question Chips pasted into other question
Plain text paste drops chips Plain text paste drops chips

View mode of an inline choice question in the exercise list/preview — with Show answers on each chip shows its correct answer, with it off each shows "Choose…" in neutral colours, and a chip needing attention is named as such

Step Screenshot
Needs attention answers off Needs attention answers off
Needs attention answers on Needs attention answers on
Rtl answers off Rtl answers off
Rtl answers on Rtl answers on

Written by rtibblesbot, an LLM-based coding agent.

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: 40 of 43 prior findings resolved; 3 acknowledged, none open.

The two More-menu threads at EditorToolbar.vue:106 are no longer blocking. Only narrow non-touch windows hit them; touch devices get the mobile toolbar. The fix is deferred to KDS #1384.

Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — panel heading or padding click drops focus
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage is clickable
RESOLVED — inlineChoice/Editor.vue:103 — validation stale after chip removed
RESOLVED — inlineChoice/Editor.vue:92 — passage editor indistinguishable from question field
RESOLVED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue — chip behaviour changes out of scope
RESOLVED — InlineChoiceChip/index.vue:46 — "Add answers" reads like an option
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — inlineChoice/tests/Editor.spec.js — focus-trap tests pass if handlers swapped
RESOLVED — inlineChoice/tests/Editor.spec.js — no-id error not tied to passage editor
RESOLVED — TipTapEditor/tests/imageSrc.spec.js — repeats toStoredImageSrcs cases
RESOLVED — InlineChoiceOptions/index.vue:105 — bare <input> for options
RESOLVED — inlineChoice/Editor.vue — message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — green fill with no correct answer
RESOLVED — inlineChoice/useInlineChoicePassage.js:116 — praise: live sync keeps history
RESOLVED — inlineChoice/passageChips.js:62 — invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:72 — helper text not referenced
RESOLVED — QTIItemEditor/tests/QTIItemEditor.spec.js:751 — findByText not scoped to heading
RESOLVED — inlineChoice/Editor.vue — clicking another chip at page end doesn't open it
RESOLVED — InlineChoiceOptions/index.vue:119 — repeated Ctrl+Z types undone text back
RESOLVED — InlineChoiceChip/index.vue:36 — error icon replaces option count
RESOLVED — EditorToolbar.vue:404 — More menu clipped to toolbar box
RESOLVED — inlineChoice/tests/useInlineChoicePassage.spec.js:225 — hasErrors branch untested
RESOLVED — InlineChoiceChip/index.vue — selected chip doesn't take selection colour
RESOLVED — InlineChoiceOptions/index.vue — undo or redo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing with chip focused
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios or buttons
RESOLVED — inlineChoice/historyShortcut.js — non-Latin layout
RESOLVED — inlineChoice/historyShortcut.js — macOS Ctrl+Z in passage
RESOLVED — inlineChoice/tests/InlineChoiceChip.spec.js:156 — test never moves caret
RESOLVED — InlineChoiceOptions/index.vue:305 — Ctrl+Z undoes another chip's edit
RESOLVED — InlineChoiceChip/index.vue — selected chips #b3d4fc blue
RESOLVED — package.json:84 — KDS bump not in PR body
RESOLVED — inlineChoice/validation.js:14 — one-option dropdown fails validation
RESOLVED — shared/styles/vuetify.scss:2482 — removed ::selection rule is global
RESOLVED — InlineChoiceOptions/index.vue:22 — incomplete chip fires two alerts
RESOLVED — InlineChoiceChip/index.vue:106 — accessible name omits badge text
RESOLVED — inlineChoice/InlineChoiceNode.js — toolbar Copy drops chip from plain text
RESOLVED — InlineChoiceOptions/index.vue:257 — Add option reads "Answer cannot be blank" twice
RESOLVED — inlineChoice/Editor.vue — Add option fires role="alert"
ACKNOWLEDGED — EditorToolbar.vue:106 — More menu runs off the viewport (severity withdrawn; KDS #1384)
ACKNOWLEDGED — EditorToolbar.vue:106 — More menu opens above the viewport on a phone (severity withdrawn; KDS #1384)
ACKNOWLEDGED — EditorToolbar.vue:106 — More menu partly off-screen (KDS #1384)

Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Removing Vuetify's ::selection rule in vuetify.scss changes the text-selection colour on every Studio page.
  • EditorToolbar.vue sets :constrainToScrollParent="false", which pushes the More menu off-screen in every rich text editor at narrow non-touch widths until KDS #1384 lands.
  • The KDS bump in package.json assumes this merges after #6317.
QA captures (50)

Add a new question in the exercise editor and switch it to Inline choice — type selector offers it, card label, optional question field, passage editor with helper text and the prominent Insert button (unavailable look, hover, tooltip), Shuffle setting off by default

Step Screenshot
Card collapsed type label Card collapsed type label
Inline choice card edit mode Inline choice card edit mode
Insert available hover Insert available hover
Insert unavailable hover Insert unavailable hover
Insert unavailable multiline selection Insert unavailable multiline selection
Response type help lists inline choice Response type help lists inline choice
Type selector offers inline choice Type selector offers inline choice

Write a passage, insert a blank dropdown and convert highlighted text into a dropdown — the panel opens on insert with focus inside, add/edit/remove options, remove disabled on the last option, mark the correct option and see the chip label and count update, removing the correct option leaves the dashed "Add answer" chip

Step Screenshot
Correct option marked Correct option marked
Correct option removed Correct option removed
Highlight converted Highlight converted
Panel closed no correct Panel closed no correct
Panel opens on insert Panel opens on insert
2-options-add-mark-remove.webm

Build a passage with two or more dropdowns and switch between them — clicking or Enter/Space on another chip shows that chip's options, panel dialog label names the dropdown, clicking the passage closes the panel, no duplicated option or response identifiers across chips

Step Screenshot
Click switches to dropdown 2 Click switches to dropdown 2
Passage click closes panel Passage click closes panel
Pasted chip own ids Pasted chip own ids
Space opens dropdown 4 Space opens dropdown 4
Three chips dropdown 2 open Three chips dropdown 2 open
3-switch-between-dropdowns.webm

Reorder options in a dropdown with drag and drop and with move up / move down — correct mark stays on the same option, then turn Shuffle on and confirm handles and move controls disappear on every chip's panel, and return when it is turned off

Step Screenshot
After drag correct follows After drag correct follows
After move up correct follows After move up correct follows
Panel before reorder Panel before reorder
Shuffle off handles return Shuffle off handles return
Shuffle on chip1 no handles Shuffle on chip1 no handles
Shuffle on chip4 no handles Shuffle on chip4 no handles
4-drag-reorder.webm

Drive the options panel by keyboard only — open a chip with Enter and Space, Tab/Shift+Tab stay trapped in the panel, correct-answer markers act as a single-select group with option names, Escape and the close control return focus to the chip and the next Tab moves on

Step Screenshot
Close control focused Close control focused
Panel opened by enter Panel opened by enter
Panel opened by space Panel opened by space
5-keyboard-panel-flow.webm

Move the caret through a passage with dropdowns using the arrow keys, Backspace and Delete — caret steps past chips without selecting them, Left/Right from a focused chip return to the text, Backspace/Delete beside a chip removes it, screen reader live-region announcements for crossed and removed chips, selected text over a chip uses the pale yellow KDS selection colour

Step Screenshot
Rtl selection over chips Rtl selection over chips
Selection over chips Selection over chips
6-caret-past-chips.webm

Undo and redo options edits, chip insertions and chip removals in the passage — the open panel's list always matches the chip, toolbar and Ctrl+Z/Ctrl+Y both work, removal announcements on redo

Step Screenshot
Redo removed chip Redo removed chip
Undo switches panel to changed chip Undo switches panel to changed chip
7-undo-redo-options-and-chips.webm

Copy passage text containing dropdowns and paste it into the same passage, another inline choice question's passage, and the question field — whole dropdowns with fresh ids in passages, only the correct answer (or nothing) in the question field, toolbar Copy and plain-text paste leave the chip out

Step Screenshot
Pasted into question field Pasted into question field
Pasted into same passage Pasted into same passage
Pasted into second question passage Pasted into second question passage

Leave an inline choice question incomplete in each way (no dropdown, a dropdown with no correct answer, too few options, an empty option) — errors appear on the option row, the chip and the panel top or the passage editor, and the question is marked incomplete; fix each and see it clear

Step Screenshot
All errors cleared All errors cleared
Blank dropdown all errors Blank dropdown all errors
Chip error panel closed Chip error panel closed
Collapsed card incomplete Collapsed card incomplete
Correct option blanked Correct option blanked
Fixed card closed Fixed card closed
No dropdown error No dropdown error
Only no correct answer Only no correct answer
9-fix-too-few-options.webm

Finish an inline choice question with several dropdowns and Shuffle on, close the editor and view it — view mode shows the question and passage with correct answers when Show answers is on and "Choose…" when off; reopen and confirm question, passage, every chip's options, correct answers and Shuffle are restored, and the saved XML puts shuffle on every dropdown and no open-chip state

Step Screenshot
Reopened panel dropdown 3 Reopened panel dropdown 3
Rtl view show answers on Rtl view show answers on

Written by rtibblesbot, an LLM-based coding agent.

AlexVelezLl and others added 3 commits October 23, 2026 08:07
Turns on the Inline choice question type: an optional question, the
passage holding the dropdown chips, and a modal options panel for the
open chip, trapping focus with KFocusTrap and returning it to the chip on
close. A press in the passage closes it, as the passage is then in use.
Option edits go through the chip node's commands, so each is one
step of the passage's history, and the passage is synced while a chip is
open so the panel always matches the saved state. A change to the chips
syncs it too, so validation follows a chip removed or restored without
waiting for the passage to lose focus. A dropdown needs a correct
answer and at least two options, and its panel lists what it lacks.
Shuffle is the choice interaction's AnswerSettings, and hides reordering
while on.

The chips follow the design, and take the selection colour as a whole
when a selection covers them. A preview without Show answers shows
"Choose…" in neutral colours in place of each answer. A copied chip pastes
into another passage whole, and into an editor without chips as its
correct answer alone. A cleared question is saved as no question. The descriptor accepts any item body,
since parse() splits every body into question and passage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Left and Right on a focused chip put the caret back in the passage
  beside it, following the text direction, as they move past the chip
  there.
- A chip the caret crosses is announced by its accessible name, since a
  screen reader reads out the text the caret crosses and a chip has
  none. Removing chips is announced too. Both use KDS's assertive live
  region, so they are read as a crossed character would be.
- A chip that needs attention shows the error icon in place of its
  option count, as an option row does, so colour is not all that marks
  it. Its name says so in a preview that hides the answers too.
- The passage editor is described by its helper text.
- A chip without a correct answer shows what its options panel says is
  missing, such as "Choose a correct answer", so the two always match.
  A chip with one shows it, its error icon saying if it needs work.
- Undo and redo from the options panel or a focused chip don't scroll
  the page away from the panel.
- The options panel's messages are no alerts, which would all be read
  at once each time it opens. Those it opens with describe the dialog
  and its fields; one that appears while it is open is announced once,
  through KDS's live region.
- A chip's count badge is hidden from assistive technology, which hears
  the count in its name, so that the name starts with the text it shows.

The chip's label and accessible name move to passageChips.js, so the
chip and the announcements name it the same way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AlexVelezLl
AlexVelezLl force-pushed the issue-6182-inline-choice-editor branch from f3ca0f9 to 30149d8 Compare October 23, 2026 13:10

@rtibblesbot rtibblesbot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6303: the More menu still runs off the viewport (blocking, inline at EditorToolbar.vue:106).

41 of 43 prior findings are resolved. The 2 contested ones are both this menu.

CI pending. Manual QA ran 11 scenarios across the inline choice editor. Only the More menu regression comes from this PR.

  • blocking: More menu off-viewport at desktop widths (inline, EditorToolbar.vue:106).
  • pre-existing: InlineChoiceChip/index.vue:263 — chips are cut off without an ellipsis at 360px.
    • The label's max-width: 20em is wider than the 254px passage.
    • Set max-width: min(20em, 100%) so the label truncates.
      Chip clipped at 360px
Prior-finding status

RESOLVED — InlineChoiceOptions/index.vue:9 — Panel click drops focus, Escape stops working
RESOLVED — InlineChoiceOptions/index.vue:13 — aria-modal while passage is clickable
RESOLVED — inlineChoice/Editor.vue:103 — Validation stale while passage is open
RESOLVED — inlineChoice/Editor.vue:92 — Passage editor indistinguishable from question field
RESOLVED — inlineChoice/Descriptor.js:43 — isSupportedBody accepts bodies TipTap can't hold
RESOLVED — InlineChoiceChip/index.vue — Chip behaviour changes out of #6182 scope
RESOLVED — InlineChoiceChip/index.vue:46 — Options but no correct mark reads like "Add answers"
RESOLVED — EditorToolbar.vue — Insert pushed off narrow toolbar
RESOLVED — tests/Editor.spec.js — Focus-trap tests pass with handlers swapped
RESOLVED — tests/Editor.spec.js — No-id error test passes wherever it renders
RESOLVED — tests/imageSrc.spec.js — Repeats toStoredImageSrcs cases through a stub
RESOLVED — InlineChoiceOptions/index.vue:105 — Bare input instead of plain-text toolbar row
RESOLVED — inlineChoice/Editor.vue — Message blames options for NO_CORRECT_ANSWER
RESOLVED — InlineChoiceChip/index.vue:14 — Green fill on chip with no correct answer
RESOLVED — useInlineChoicePassage.js:116 — Live sync keeps editor history (praise)
RESOLVED — passageChips.js:63 — Invalid chip marked by colour alone
RESOLVED — inlineChoice/Editor.vue:72 — Helper text not referenced
RESOLVED — QTIItemEditor.spec.js:751 — findByText instead of heading role
RESOLVED — inlineChoice/Editor.vue — Clicking another chip fails when scrolled to end
RESOLVED — InlineChoiceOptions/index.vue:119 — Repeated Ctrl+Z types undone text back
RESOLVED — InlineChoiceChip/index.vue:36 — Error icon replaces option count
RESOLVED — EditorToolbar.vue:404 — More menu clipped to toolbar box
RESOLVED — useInlineChoicePassage.spec.js:225 — hasErrors branch of chipMessage untested
RESOLVED — InlineChoiceChip/index.vue — Selected chip doesn't take selection colour
RESOLVED — InlineChoiceOptions/index.vue — Undo/redo deletes focused option
RESOLVED — InlineChoiceChip/index.vue — Ctrl+Z does nothing on a focused chip
RESOLVED — InlineChoiceOptions/index.vue — Ctrl+Z does nothing on radios/buttons
RESOLVED — historyShortcut.js — Ctrl+Z fails on non-Latin layouts
RESOLVED — historyShortcut.js — macOS Ctrl+Z mismatch with passage
RESOLVED — InlineChoiceChip.spec.js:156 — Caret test never moves the caret
RESOLVED — InlineChoiceOptions/index.vue:305 — Ctrl+Z silently undoes another chip's edit
RESOLVED — InlineChoiceChip/index.vue — Selected chips still #b3d4fc blue
RESOLVED — package.json:84 — KDS bump not in PR body
RESOLVED — inlineChoice/validation.js — One-option dropdown fails validation
RESOLVED — styles/vuetify.scss:2482 — Removed ::selection rule affects every page
RESOLVED — InlineChoiceOptions/index.vue:22 — Opening incomplete chip fires extra alerts
RESOLVED — InlineChoiceChip/index.vue:106 — Accessible name omits visible badge text
RESOLVED — inlineChoice/InlineChoiceNode.js — Toolbar Copy drops chip from plain text
RESOLVED — InlineChoiceOptions/index.vue:257 — Add option announces blank error twice
RESOLVED — EditorToolbar.vue:106 — More menu partly off-screen (suggestion)
RESOLVED — inlineChoice/Editor.vue — Add option fires role=alert while focus moves
CONTESTED — EditorToolbar.vue:106 — More menu runs off the viewport (blocking, re-raised)
CONTESTED — EditorToolbar.vue:106 — More menu opens above the viewport on a phone (blocking, re-raised)

Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.

  • User-visible files changed: .stylelintrc.js, contentcuration/contentcuration/frontend/shared/styles/vuetify.scss, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue, contentcuration/contentcuration/frontend/shared/views/QTIEditor/composables/useInlineChoiceInteraction.js….
  • Decide whether the More menu running off-screen below 600px can wait on kolibri-design-system#1384 or must be fixed before merge.
  • The toolbar changes (icon-only Insert, overflow-x: auto, unconstrained More) reach every TipTap editor, not just inline choice.
  • Run the inline choice editor end to end, especially undo/redo across the panel, chips and passage.
QA captures (50)

Add a new question in the exercise editor, switch its type to Inline choice, write a question and a passage, insert a blank dropdown with Insert and convert highlighted text into a second one — the question field, passage helper text, the options panel opening on insert, the card's Inline choice type label

Step Screenshot
Blank dropdown panel open Blank dropdown panel open
Closed card type label Closed card type label
Converted dropdown panel open Converted dropdown panel open
Highlighted text Highlighted text
Inline choice empty Inline choice empty
Insert over selection with chips Insert over selection with chips
Passage open toolbar Passage open toolbar
1-create-inline-choice.webm

Build a dropdown's options in its panel — Add option, edit option text, mark one correct then move the mark, remove options down to the last (remove disabled), remove the correct one (chip goes to dashed "Add answer"), move up / move down and drag reorder keeping the correct mark; chip label and count update after each edit

Step Screenshot
After drag correct last After drag correct last
Correct removed chip Correct removed chip
Last option remove disabled Last option remove disabled
Move button focused Move button focused
New dropdown panel New dropdown panel
Three options correct marked Three options correct marked
2-build-options.webm
2-reorder-keeps-correct.webm

Open one dropdown, then another, then delete the open dropdown from the passage — the panel switches to the other chip's options, closes when its chip is gone with focus back in the editor, and closes when the passage is clicked

Step Screenshot
First chip open First chip open
Open chip deleted Open chip deleted
Passage click closes panel Passage click closes panel
Switched to second chip Switched to second chip
3-switch-then-delete-open-chip.webm

Edit a dropdown's options, then undo and redo with the toolbar and Ctrl+Z / Ctrl+Shift+Z — the options list and the chip label match the passage after each step, and removing a dropdown with Backspace or Delete beside it undoes cleanly

Step Screenshot
After edits After edits
After redo After redo
Chip removed backspace Chip removed backspace
Chip restored undo Chip restored undo
Panel open initial Panel open initial
Undo opens other chip Undo opens other chip
4-undo-redo.webm

Toggle Shuffle on an inline choice question, save, close and reopen the exercise — Shuffle sits where the choice question's does and starts off, drag handles and move up / move down vanish on every dropdown while on and return when off, and the setting survives the reopen

Step Screenshot
Shuffle click with panel open Shuffle click with panel open
Shuffle off again handles back Shuffle off again handles back
Shuffle off initial Shuffle off initial
Shuffle off panel handles Shuffle off panel handles
Shuffle on panel no handles Shuffle on panel no handles
5-shuffle-toggle-handles.webm

Save an inline choice question with several dropdowns, close and reopen it, and inspect the saved raw_data via the sync API — question, passage, every dropdown's options, correct answers and shuffle restored; no open-chip state and no duplicate identifiers in the XML

Step Screenshot
Closed card four dropdowns Closed card four dropdowns
Passage three dropdowns Passage three dropdowns
Reopened after reload Reopened after reload

Leave validation errors on an inline choice question (no dropdown, a dropdown with no correct answer, an empty option) and close the card — each error shows on the passage, the chip, the panel top or the option row, and the question is marked incomplete; fix each and see it clear

Step Screenshot
Blank dropdown panel errors Blank dropdown panel errors
Closed blank dropdown Closed blank dropdown
Closed empty option Closed empty option
Closed fixed Closed fixed
Closed no dropdown Closed no dropdown
Dropdown removed open Dropdown removed open
Empty option open Empty option open
New empty question New empty question
New question no dropdown New question no dropdown
Only no correct left Only no correct left
7-fix-errors.webm

Close the editing card of a filled inline choice question and toggle Show answers — view mode shows the question and the passage with each chip's correct answer when on and "Choose…" when off, and a chip needing attention is named as such

Step Screenshot
Filled question answers on Filled question answers on
8-close-card-toggle-show-answers.webm

Written by rtibblesbot, an LLM-based coding agent.

<!-- Not kept inside the toolbar, which scrolls when too narrow, as its other menus -->
<KDropdownMenu
:options="flatOverflowOptions(overflowItems)"
:constrainToScrollParent="false"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: The More menu still runs off the viewport, and not only on phones. My :404 suggestion caused this. :constrainToScrollParent="false" fixed the clipping but lets the menu overflow the viewport.

  • New since the author's reply: it happens at 599×800 on a non-touch window. The menu spans y −278 to 284. Copy, Paste, Paste without formatting, Align right, Clear formatting and Bullet list are unreachable. The page doesn't scroll.
  • At 360px, ArrowDown focuses "Italic" at y −334. Keyboard users lose sight of focus.
  • A legacy answer editor and RTL fail the same way. Every TipTap editor regresses, not just the passage.
  • With this prop false, UiPopover.vue:170-172 turns off popper's overflow prevention entirely. KDS has no viewport-boundary option; kolibri-design-system#1384 tracks that.

Drop this prop and keep the More button outside the overflow-x: auto box, so its scroll parent is the dialog, as on unstable. Or hold merge until #1384 lands. A maintainer can accept the regression instead. The author's reply alone doesn't settle a blocking regression.

More menu at 599px, top items off-screen
More menu at 360px, clipped top and right
RTL More menu at 599px
Answer editor More menu at 360px

11-more-menu-offscreen-360.webm

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This will be fixed when learningequality/kolibri-design-system#1384 is implemented. I just assigned that issue, so it will be in the next KDS release.

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.

[QTI] A dropdown pasted into the inline choice question becomes its options' text run together [QTI] Inline choice interaction editor

3 participants