diff --git a/packages/match-list/src/answer-area.jsx b/packages/match-list/src/answer-area.jsx index 01ee7b38f9..54c749b965 100644 --- a/packages/match-list/src/answer-area.jsx +++ b/packages/match-list/src/answer-area.jsx @@ -6,9 +6,14 @@ import { isEmpty, isUndefined, reduce } from 'lodash-es'; import Arrow from './arrow'; import DragAndDropAnswer from './answer'; +// matches the min width of the answer entries (see AnswerContainer in ./answer), so the two columns +// give the row an intrinsic min width that the horizontal scroll container can overflow. +const MIN_COLUMN_WIDTH = 200; + const ArrowEntry = styled('div')({ alignItems: 'normal', display: 'flex', + flexShrink: 0, height: 40, margin: '10px 20px', }); @@ -29,6 +34,7 @@ const PromptEntry = styled('div')(({ theme }) => ({ flex: 1, margin: '10px 0', minHeight: 40, + minWidth: MIN_COLUMN_WIDTH, overflow: 'hidden', padding: 10, textAlign: 'center', diff --git a/packages/match-list/src/main.jsx b/packages/match-list/src/main.jsx index b8ba8e9e53..4efd0293fb 100644 --- a/packages/match-list/src/main.jsx +++ b/packages/match-list/src/main.jsx @@ -19,6 +19,20 @@ const MainContainer = styled('div')({ backgroundColor: color.background(), }); +const InteractiveRegion = styled('div')({ + width: '100%', + overflowX: 'auto', + overflowY: 'hidden', +}); + +// A block child of a scroll port is sized to the scroll port, so it has to opt out explicitly for +// the content to be able to overflow. min-content keeps the rows and the pool the same width. +const InteractiveRegionContent = styled('div')({ + display: 'flex', + flexDirection: 'column', + minWidth: 'min-content', +}); + export class Main extends React.Component { static propTypes = { session: PropTypes.object.isRequired, @@ -182,22 +196,26 @@ export class Main extends React.Component { language={language} /> - this.onRemoveAnswer(id)} - disabled={mode !== 'gather'} - showCorrect={showCorrectAnswer} - /> - - this.onRemoveAnswer(id)} - /> + + + this.onRemoveAnswer(id)} + disabled={mode !== 'gather'} + showCorrect={showCorrectAnswer} + /> + + this.onRemoveAnswer(id)} + /> + + {model.correctness && model.feedback && !showCorrectAnswer && ( diff --git a/packages/placement-ordering/package.json b/packages/placement-ordering/package.json index d5f63413ef..fe70979911 100644 --- a/packages/placement-ordering/package.json +++ b/packages/placement-ordering/package.json @@ -8,6 +8,7 @@ }, "dependencies": { "@dnd-kit/core": "6.3.1", + "@dnd-kit/modifiers": "9.0.0", "@emotion/react": "^11.14.0", "@emotion/style": "^0.8.0", "@mui/icons-material": "^7.3.4", diff --git a/packages/placement-ordering/src/placement-ordering.jsx b/packages/placement-ordering/src/placement-ordering.jsx index 0e4777f6cc..f64a447f19 100644 --- a/packages/placement-ordering/src/placement-ordering.jsx +++ b/packages/placement-ordering/src/placement-ordering.jsx @@ -5,6 +5,7 @@ import debug from 'debug'; import { difference, isEqual, uniqueId } from 'lodash-es'; import { styled } from '@mui/material/styles'; import { closestCenter } from '@dnd-kit/core'; +import { restrictToParentElement } from '@dnd-kit/modifiers'; import { Collapsible, color, Feedback, hasMedia, hasText, PreviewPrompt, UiLayout } from '@pie-lib/render-ui'; import { renderMath } from '@pie-lib/math-rendering'; @@ -29,6 +30,26 @@ const PlacementOrderingContainer = styled('div')({ boxSizing: 'border-box', }); +// The interactive region - the choices and answers columns for a vertical item, or the choices and +// answers rows for a horizontal one - scrolls horizontally when it does not fit the available width. +const InteractiveRegion = styled('div')({ + // the ancestors centre their children, which shrink-wraps this box to its content. without a + // definite width it grows with the tiler and the overflow escapes outwards instead of scrolling. + alignSelf: 'stretch', + maxWidth: '100%', + overflowX: 'auto', + // tiles are dragged by transform, which counts towards scrollable overflow, so leaving this axis + // scrollable would pop a vertical scrollbar mid-drag + overflowY: 'hidden', +}); + +// keeps the tiler at its natural width, and centred while it still fits +const InteractiveRegionContent = styled('div')({ + display: 'flex', + justifyContent: 'center', + minWidth: 'min-content', +}); + const StyledPrompt = styled('div')(({ theme }) => ({ paddingBottom: theme.spacing(1), })); @@ -321,10 +342,16 @@ export class PlacementOrdering extends React.Component { flexDirection: 'column', alignItems: 'center', boxSizing: 'border-box', + width: '100%', }; return ( - { }} onDragEnd={this.onDragEnd} collisionDetection={closestCenter}> + { }} + onDragEnd={this.onDragEnd} + collisionDetection={closestCenter} + modifiers={[restrictToParentElement]} + > {showTeacherInstructions && ( @@ -347,18 +374,22 @@ export class PlacementOrdering extends React.Component { language={language} /> - + + + + + {displayNote && }