Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1ce498c
Add basic reorder buttons to parsons questions
sjd210 Jun 19, 2026
e03ce3d
Reformat dragging buttons visually
sjd210 Jun 19, 2026
6165c4c
Merge branch 'main' into feature/reorder-question-accessibility
sjd210 Jun 19, 2026
32401b0
Disable buttons at top and bottom of list
sjd210 Jun 19, 2026
b15427f
Correctly center indent controls
sjd210 Jun 23, 2026
73aa993
Allow reorder arrows to be indented
sjd210 Jun 24, 2026
1f1f73a
Combine reorder buttons logic into component
sjd210 Jun 24, 2026
f2a769c
Move border to only cover indented region
sjd210 Jun 24, 2026
5792761
Maintain item shape while dragging
sjd210 Jun 24, 2026
6d8e1b4
Clean up code layout and classnames
sjd210 Jun 24, 2026
8183ff3
Style focus outlines correctly for each element
sjd210 Jun 24, 2026
4b19a92
Merge branch 'main' into feature/reorder-question-accessibility
sjd210 Jun 24, 2026
0c20cb2
Maintain current indent when non-drag moving items
sjd210 Jun 24, 2026
22fe476
Allow indent controls to appear for keyboard nav
sjd210 Jun 24, 2026
37efa8b
Style focus outline correctly for scrollable pre
sjd210 Jun 25, 2026
16d58f8
Simplify indent button z-index styling
sjd210 Jun 25, 2026
2874566
Clean up redundant styling and bootstrap classes
sjd210 Jun 25, 2026
2e600a1
Deduplicate Draggable logic with shared component
sjd210 Jun 25, 2026
47a6aa3
Simplify props used in new components
sjd210 Jun 25, 2026
d88d974
Reuse Parsons Draggable item for Reorder questions
sjd210 Jun 26, 2026
640125b
Update VRT baselines
actions-user Jun 26, 2026
7e86541
Remove check from always truthy items
sjd210 Jun 26, 2026
bc27349
Merge pull request #2227 from isaacphysics/vrt/feature/reorder-questi…
sjd210 Jun 26, 2026
3615771
Update onDragEnd code to a more generic format
sjd210 Jun 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
401 changes: 231 additions & 170 deletions src/app/components/content/IsaacParsonsQuestion.tsx

Large diffs are not rendered by default.

37 changes: 7 additions & 30 deletions src/app/components/content/IsaacReorderQuestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,16 @@ import React, {useEffect, useState} from "react";
import {IsaacContentValueOrChildren} from "./IsaacContentValueOrChildren";
import {IsaacReorderQuestionDTO, ItemChoiceDTO, ItemDTO} from "../../../IsaacApiTypes";
import {Col, Row} from "reactstrap";
import {DragDropContext, Draggable, Droppable, DropResult} from "@hello-pangea/dnd";
import {DragDropContext, Droppable, DropResult} from "@hello-pangea/dnd";
import _differenceBy from "lodash/differenceBy";
import {useCurrentQuestionAttempt} from "../../services";
import {IsaacQuestionProps} from "../../../IsaacAppTypes";
import classNames from "classnames";
import {Markup} from "../elements/markup";
import {Immutable} from "immer";

const ReorderDraggableItem = ({item, index, inAvailableItems, readonly}: {item: Immutable<ItemDTO>; index: number; inAvailableItems?: boolean; readonly?: boolean}) => {
return <Draggable
key={item.id}
draggableId={`${item.id || index}|reorder-item-choice`}
index={index}
isDragDisabled={readonly}
>
{(provided) => {
return <div
id={`${item.id || index}|reorder-item-${inAvailableItems ? "available" : "choice"}`}
className={`reorder-item`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={provided.draggableProps.style}
>
<Markup trusted-markup-encoding={"html"}>
{item?.value ?? ""}
</Markup>
</div>;
}}
</Draggable>;
};
import { ParsonsDraggableItem } from "./IsaacParsonsQuestion";

const IsaacReorderQuestion = ({doc, questionId, readonly} : IsaacQuestionProps<IsaacReorderQuestionDTO>) => {

const {currentAttempt, dispatchSetCurrentAttempt} = useCurrentQuestionAttempt<ItemChoiceDTO>(questionId);

const [availableItems, setAvailableItems] = useState<Immutable<ItemDTO>[]>([...doc.items ?? []]);

const moveItem = (src: Immutable<ItemDTO>[] | undefined, fromIndex: number, dst: Immutable<ItemDTO>[] | undefined, toIndex: number) => {
Expand Down Expand Up @@ -139,7 +113,8 @@ const IsaacReorderQuestion = ({doc, questionId, readonly} : IsaacQuestionProps<I
className={classNames("parsons-items", {"empty": !(availableItems && availableItems.length > 0), "drag-over": snapshot.isDraggingOver})}
>
{availableItems && availableItems.map((item, index) =>
<ReorderDraggableItem key={item.id} item={item} index={index} inAvailableItems readonly={readonly}/>)}
<ParsonsDraggableItem key={item.id} currentItem={item} index={index} inAvailableItems readonly={readonly}
setItems={setAvailableItems} items={availableItems}/>)}
{(!availableItems || availableItems.length === 0)
? <div>&nbsp;</div>
: provided.placeholder}
Expand All @@ -155,7 +130,9 @@ const IsaacReorderQuestion = ({doc, questionId, readonly} : IsaacQuestionProps<I
className={classNames("parsons-items", {"empty": !(currentAttempt && currentAttempt.items && currentAttempt.items.length > 0), "drag-over": snapshot.isDraggingOver})}
>
{currentAttempt && currentAttempt.items && currentAttempt.items.map((item, index) =>
<ReorderDraggableItem key={item.id} item={item} index={index} readonly={readonly}/>)}
<ParsonsDraggableItem key={item.id} currentItem={item} index={index} readonly={readonly}
setItems={(items: Immutable<ItemDTO>[]) => dispatchSetCurrentAttempt({...currentAttempt, items})}
items={(currentAttempt?.items || []) as Immutable<ItemDTO>[]}/>)}
{(!currentAttempt || currentAttempt?.items?.length === 0)
? <div className="text-muted text-center">
{readonly ? "No answer entered" : "Drag items across to build your answer"}
Expand Down
115 changes: 61 additions & 54 deletions src/scss/common/questions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ figure .inline-container {

.parsons-question {
.parsons-items {
border: solid 1px #00000021;
border: solid 1px $gray-136;
padding: 0 0.5em;

&.empty {
Expand All @@ -363,23 +363,6 @@ figure .inline-container {
}
}

.parsons-item > pre {
margin: 0.5rem 0;
padding: 0.5em 1em;
cursor: grab; // Doesn't work?
}

.reorder-item {
> * {
overflow-x: auto;
margin: 0.5rem 0;
padding: 0.5em 1em;
cursor: grab;
background: var(--color-neutral-white, white);
border: solid 1px #00000021;
}
}

// REMINDER: If you change the PARSONS_MAX_INDENT and PARSONS_INDENT_STEP
// constants, you also have to change these two in here.
$parsons-max-indent: 3;
Expand All @@ -392,50 +375,74 @@ figure .inline-container {
}
}

position: relative;
.indent-buttons {
display: flex;
align-items: center;

.controls {
display: none;
}
button {
display: grid;
position: relative;
justify-content: center;
align-content: center;

.show-controls {
.controls {
position: absolute;
right: 0.5rem;
top: 0.5rem;
display: block;

button {
display: inline-block;
width: 20px;
height: 20px;
padding: 0;
background: $gray-120;

&.show:hover {
background-color: $primary !important;
}

&.hide {
opacity: 0.2;
cursor: default;
}

&.show {
opacity: 1.0;
}
width: 20px;
height: 20px;
padding: 0;
background-color: $gray-120;

&.show:hover {
background-color: $primary;
}

&.hide {
opacity: 0.2;
cursor: default;
}

&.show {
opacity: 1.0;
}
}

// Use negative z-index rather than `display: none` to hide buttons so they can still be selected using keyboard controls
&:not(:has(:focus)) button {
z-index: -999;
}
&:has(:focus) button {
z-index: 2;
}
}
}

// The fixed position of a selected parsons-item causes the box-shadow to be drawn in the wrong place,
// so we need to apply it to the correctly positioned child instead
.parsons-item, .reorder-item {
&:focus-visible:focus-visible {
box-shadow: none;
> * {
@include focus-outline;
display: flex;
align-items: center;
position: relative;
border: solid 1px $gray-136;
margin: 0.5rem 0;
background: var(--color-neutral-white, white);

pre {
margin: 0.25em 0.5em;
padding: 0.25em 0;
border: none;
background: none;
}

.reorder-buttons {
display: flex;
flex-direction: column;
align-items: center;

button {
display: grid;
justify-content: center;
}
}

&:hover, &:focus-within {
.indent-buttons button {
z-index: 2;
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/scss/cs/questions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,11 @@
margin-top: 0.7rem;
}
}

.parsons-question {
.parsons-item, .reorder-item {
.reorder-buttons button.disabled {
opacity: 0.5;
}
}
}
1 change: 0 additions & 1 deletion src/scss/phy/typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pre {
background: var(--color-neutral-white);
padding: 1rem;
font-weight: 400;
border: solid 1px #00000021;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.875rem;

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading