@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
178 lines (161 loc) • 5.68 kB
JavaScript
/** @jsx jsx */
import {Component} from 'react'
import PropTypes from 'prop-types'
import {IconButton} from '@instructure/ui-buttons'
import {IconDragHandleLine} from '@instructure/ui-icons'
import {ScreenReaderContent, PresentationContent} from '@instructure/ui-a11y-content'
import {Text} from '@instructure/ui-text'
import {jsx} from '@instructure/emotion'
import {RichContentRenderer} from '@instructure/quiz-rce/components/RichContentRenderer/index'
import Card from '../../../common/components/Card'
import generateStyle from './styles'
import generateComponentTheme from './theme'
import t from '@instructure/quiz-i18n/format-message'
import {v4 as uuid} from 'uuid'
import {TextInput} from '@instructure/quiz-common/components/TextInput/index'
import {withStyleOverrides} from '@instructure/quiz-common/util/withStyleOverrides'
(generateStyle, generateComponentTheme)
export default class OrderGroup extends Component {
static displayName = 'OrderGroup'
static componentId = `Quizzes${this.displayName}`
static propTypes = {
bottomLabel: PropTypes.string,
topLabel: PropTypes.string,
choiceOrder: PropTypes.arrayOf(PropTypes.string).isRequired,
choices: PropTypes.shape({
itemBody: RichContentRenderer.propTypes.content,
}).isRequired,
actionsContent: PropTypes.func,
displayAnswersParagraph: PropTypes.bool,
includeLabels: PropTypes.bool,
onMoveChoice: PropTypes.func,
readOnly: PropTypes.bool,
styles: PropTypes.object,
makeStyles: PropTypes.func,
}
static defaultProps = {
bottomLabel: void 0,
topLabel: void 0,
actionsContent: void 0,
displayAnswersParagraph: void 0,
includeLabels: void 0,
onMoveChoice: void 0,
readOnly: false,
}
componentDidMount() {
this.props.makeStyles()
}
componentDidUpdate() {
this.props.makeStyles()
}
takeId = uuid()
// ===========
// RENDER
// ===========
renderActions = (choiceId, isFinalChoice, isFirstChoice, choicePosition) => {
if (this.props.actionsContent) {
return this.props.actionsContent(choiceId, isFinalChoice, isFirstChoice, choicePosition)
}
return (
// We need to wrap the button in a div for drag-and-drop to work in IE11 and Firefox
<div>
<IconButton
size="small"
withBackground={false}
withBorder={false}
readOnly={this.props.readOnly}
renderIcon={IconDragHandleLine}
screenReaderLabel={t('Reorder Choice')}
/>
</div>
)
}
renderChoice = (choiceId, index) => {
const choicePosition = index + 1
const isFirstChoice = index === 0
const isFinalChoice = choicePosition === this.props.choiceOrder.length
return (
<div key={choiceId} css={this.props.styles.choiceContainer} data-testid="choice-cointainer">
<div css={this.props.styles.choiceContainerContent}>
{!this.props.displayAnswersParagraph && (
<div css={this.props.styles.choicePosition}>
<ScreenReaderContent>
{t('position {position, number}', {position: choicePosition})}
</ScreenReaderContent>
<PresentationContent>
<Text color="primary">{t.number(choicePosition)}</Text>
</PresentationContent>
</div>
)}
<div css={this.props.styles.printedPositionInput}>
<TextInput
width="3rem"
defaultValue={this.props.readOnly ? t.number(choicePosition) : ''}
renderLabel=""
readOnly
/>
</div>
<div css={this.props.styles.choice} className="fs-mask">
{this.renderActions(choiceId, isFinalChoice, isFirstChoice, choicePosition)}
<RichContentRenderer
customStyles={this.props.styles.choiceBody}
content={this.props.choices[choiceId.split('_')[0]].itemBody}
/>
</div>
</div>
</div>
)
}
renderChoicesContainer() {
if (this.props.readOnly) {
return (
<div css={this.props.styles.container}>{this.props.choiceOrder.map(this.renderChoice)}</div>
)
}
return (
<div css={this.props.styles.container}>
{this.props.choiceOrder.map((choiceId, i) => {
const id = `${choiceId}_${this.takeId}`
return (
<Card
key={choiceId}
index={i}
id={id}
choices={this.props.choices}
moveCard={this.props.onMoveChoice}
>
{this.renderChoice(id, i)}
</Card>
)
})}
</div>
)
}
render() {
return (
<div>
{this.props.includeLabels && (
<div css={this.props.styles.topLabel} data-automation="sdk-ordering-toplabel">
<ScreenReaderContent>
{t('Top label: {label}', {label: this.props.topLabel})}
</ScreenReaderContent>
<PresentationContent>
<Text color="primary">{this.props.topLabel}</Text>
</PresentationContent>
</div>
)}
{this.renderChoicesContainer()}
{this.props.includeLabels && (
<div css={this.props.styles.bottomLabel} data-automation="sdk-ordering-bottomlabel">
<ScreenReaderContent>
{t('Bottom label: {label}', {label: this.props.bottomLabel})}
</ScreenReaderContent>
<PresentationContent>
<Text color="primary">{this.props.bottomLabel}</Text>
</PresentationContent>
</div>
)}
</div>
)
}
}