Fix answer box styling. TNL-10333 (#197)

* fix: use feedback icon with correct hover color

* fix: problem answer layout squishes delete button background

* fix: remove borders from textarea

* fix: textarea resize

* refactor: remove renderThing-antipattern in answer option

* fix: answer option feedback color

* fix: add second feedback box to all problem types

* refactor: move extra components out of answer option file

* fix: icon disappearing on hover when active

* fix: update snapshot

* fix: lint

* fix: add tests

* fix: add tests

* fix: snapshots

* Update src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.jsx

Co-authored-by: Kristin Aoki <42981026+KristinAoki@users.noreply.github.com>

* fix: resolve discussions from PR

Co-authored-by: Kristin Aoki <42981026+KristinAoki@users.noreply.github.com>
This commit is contained in:
Jesper Hodge
2023-01-13 17:00:56 -05:00
committed by GitHub
parent 95ae45cce8
commit b7c24d1e1a
16 changed files with 549 additions and 321 deletions

2
src/colors.scss Normal file
View File

@@ -0,0 +1,2 @@
$white: #fff;
$black: #000;

View File

@@ -2,57 +2,18 @@ import React, { memo } from 'react';
import { connect, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import {
Col, Collapsible, Icon, IconButton, Form, Row,
Collapsible, Icon, IconButton, Form,
} from '@edx/paragon';
import { AddComment, Delete } from '@edx/paragon/icons';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Feedback, Delete } from '@edx/paragon/icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import { selectors } from '../../../../../data/redux';
import { answerOptionProps } from '../../../../../data/services/cms/types';
import { ProblemTypeKeys } from '../../../../../data/constants/problem';
import Checker from './components/Checker';
import { FeedbackBox } from './components/Feedback';
import * as hooks from './hooks';
const Checker = ({
hasSingleAnswer, answer, setAnswer,
}) => {
let CheckerType = Form.Checkbox;
if (hasSingleAnswer) {
CheckerType = Form.Radio;
}
return (
<CheckerType
className="pl-4 mt-3"
value={answer.id}
onChange={(e) => setAnswer({ correct: e.target.checked })}
checked={answer.correct}
>
{answer.id}
</CheckerType>
);
};
const FeedbackControl = ({
feedback, onChange, labelMessage, labelMessageBoldUnderline, key, answer, intl,
}) => (
<Form.Group key={key}>
<Form.Label className="mb-3">
<FormattedMessage
{...labelMessage}
values={{
answerId: answer.id,
boldunderline: <b><u><FormattedMessage {...labelMessageBoldUnderline} /></u></b>,
}}
/>
</Form.Label>
<Form.Control
placeholder={intl.formatMessage(messages.feedbackPlaceholder)}
value={feedback}
onChange={onChange}
/>
</Form.Group>
);
export const AnswerOption = ({
answer,
hasSingleAnswer,
@@ -66,91 +27,56 @@ export const AnswerOption = ({
const setAnswer = hooks.setAnswer({ answer, hasSingleAnswer, dispatch });
const { isFeedbackVisible, toggleFeedback } = hooks.prepareFeedback(answer);
const displayFeedbackControl = (answerObject) => {
if (problemType !== ProblemTypeKeys.MULTISELECT) {
return FeedbackControl({
key: `feedback-${answerObject.id}`,
feedback: answerObject.selectedFeedback,
onChange: (e) => setAnswer({ selectedFeedback: e.target.value }),
labelMessage: messages.selectedFeedbackLabel,
labelMessageBoldUnderline: messages.selectedFeedbackLabelBoldUnderlineText,
answer: answerObject,
intl,
});
}
return [
FeedbackControl({
key: `selectedfeedback-${answerObject.id}`,
feedback: answerObject.selectedFeedback,
onChange: (e) => setAnswer({ selectedFeedback: e.target.value }),
labelMessage: messages.selectedFeedbackLabel,
labelMessageBoldUnderline: messages.selectedFeedbackLabelBoldUnderlineText,
answer: answerObject,
intl,
}),
FeedbackControl({
key: `unselectedfeedback-${answerObject.id}`,
feedback: answerObject.unselectedFeedback,
onChange: (e) => setAnswer({ unselectedFeedback: e.target.value }),
labelMessage: messages.unSelectedFeedbackLabel,
labelMessageBoldUnderline: messages.unSelectedFeedbackLabelBoldUnderlineText,
answer: answerObject,
intl,
}),
];
};
return (
<Collapsible.Advanced
open={isFeedbackVisible}
onToggle={toggleFeedback}
className="collapsible-card"
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
>
<Row className="my-2">
<Col xs={1}>
<Checker
hasSingleAnswer={hasSingleAnswer}
<div className="answer-option-flex-item-1 mr-1 d-flex align-items-center">
<Checker
hasSingleAnswer={hasSingleAnswer}
answer={answer}
setAnswer={setAnswer}
/>
</div>
<div className="answer-option-flex-item-2 ml-1">
<Form.Control
as="textarea"
className="answer-option-textarea text-gray-500 small"
autoResize
rows={1}
value={answer.title}
onChange={(e) => { setAnswer({ title: e.target.value }); }}
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}
/>
<Collapsible.Body>
<FeedbackBox
problemType={problemType}
answer={answer}
setAnswer={setAnswer}
intl={intl}
/>
</Col>
<Col xs={10}>
<Form.Control
as="textarea"
rows={1}
value={answer.title}
onChange={(e) => { setAnswer({ title: e.target.value }); }}
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}
/>
<Collapsible.Body>
<div className="bg-dark-100 p-4 mt-3">
{displayFeedbackControl(answer)}
</div>
</Collapsible.Body>
</Col>
<Col xs={1} className="d-inline-flex mt-1">
<Collapsible.Trigger>
<IconButton
src={AddComment}
iconAs={Icon}
alt={intl.formatMessage(messages.feedbackToggleIconAltText)}
variant="primary"
/>
</Collapsible.Trigger>
</Collapsible.Body>
</div>
<div className="answer-option-flex-item-3 d-flex flex-row flex-nowrap">
<Collapsible.Trigger>
<IconButton
src={Delete}
src={Feedback}
className="feedback-icon-button"
iconAs={Icon}
alt={intl.formatMessage(messages.answerDeleteIconAltText)}
onClick={removeAnswer}
alt={intl.formatMessage(messages.feedbackToggleIconAltText)}
variant="primary"
/>
</Col>
</Row>
</Collapsible.Trigger>
<IconButton
src={Delete}
iconAs={Icon}
alt={intl.formatMessage(messages.answerDeleteIconAltText)}
onClick={removeAnswer}
variant="primary"
/>
</div>
</Collapsible.Advanced>
);
};
@@ -164,22 +90,6 @@ AnswerOption.propTypes = {
problemType: PropTypes.string.isRequired,
};
FeedbackControl.propTypes = {
feedback: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
labelMessage: PropTypes.string.isRequired,
labelMessageBoldUnderline: PropTypes.string.isRequired,
key: PropTypes.string.isRequired,
answer: answerOptionProps.isRequired,
intl: intlShape.isRequired,
};
Checker.propTypes = {
hasSingleAnswer: PropTypes.bool.isRequired,
answer: answerOptionProps.isRequired,
setAnswer: PropTypes.func.isRequired,
};
export const mapStateToProps = (state) => ({
problemType: selectors.problem.problemType(state),
});

View File

@@ -2,17 +2,40 @@
exports[`AnswerOption render snapshot: renders correct option with feedback 1`] = `
<Advanced
className="collapsible-card"
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
onToggle={[Function]}
open={false}
>
<Row
className="my-2"
<div
className="answer-option-flex-item-1 mr-1 d-flex align-items-center"
>
<Col
xs={1}
>
<Checker
<Checker
answer={
Object {
"correct": true,
"id": "A",
"selectedFeedback": "some feedback",
"title": "Answer 1",
}
}
hasSingleAnswer={false}
setAnswer={[Function]}
/>
</div>
<div
className="answer-option-flex-item-2 ml-1"
>
<Form.Control
as="textarea"
autoResize={true}
className="answer-option-textarea text-gray-500 small"
onChange={[Function]}
placeholder="Enter an answer"
rows={1}
value="Answer 1"
/>
<Body>
<injectIntl(ShimmedIntlComponent)
answer={
Object {
"correct": true,
@@ -21,94 +44,74 @@ exports[`AnswerOption render snapshot: renders correct option with feedback 1`]
"title": "Answer 1",
}
}
hasSingleAnswer={false}
intl={
Object {
"formatMessage": [Function],
}
}
problemType="multiplechoiceresponse"
setAnswer={[Function]}
/>
</Col>
<Col
xs={10}
>
<Form.Control
as="textarea"
onChange={[Function]}
placeholder="Enter an answer"
rows={1}
value="Answer 1"
/>
<Body>
<div
className="bg-dark-100 p-4 mt-3"
>
<Form.Group
key="feedback-A"
>
<Form.Label
className="mb-3"
>
<FormattedMessage
defaultMessage="Show following feedback when {answerId} {boldunderline}:"
description="Label text for feedback if option is selected"
id="authoring.answerwidget.feedback.selected.label"
values={
Object {
"answerId": "A",
"boldunderline": <b>
<u>
<FormattedMessage
defaultMessage="is selected"
description="Bold & underlined text for feedback if option is selected"
id="authoring.answerwidget.feedback.selected.label.boldunderline"
/>
</u>
</b>,
}
}
/>
</Form.Label>
<Form.Control
onChange={[Function]}
placeholder="Feedback message"
value="some feedback"
/>
</Form.Group>
</div>
</Body>
</Col>
<Col
className="d-inline-flex mt-1"
xs={1}
>
<Trigger>
<IconButton
alt="Toggle feedback"
iconAs="Icon"
variant="primary"
/>
</Trigger>
</Body>
</div>
<div
className="answer-option-flex-item-3 d-flex flex-row flex-nowrap"
>
<Trigger>
<IconButton
alt="Delete answer"
alt="Toggle feedback"
className="feedback-icon-button"
iconAs="Icon"
onClick={[Function]}
variant="primary"
/>
</Col>
</Row>
</Trigger>
<IconButton
alt="Delete answer"
iconAs="Icon"
onClick={[Function]}
variant="primary"
/>
</div>
</Advanced>
`;
exports[`AnswerOption render snapshot: renders correct option with selected unselected feedback 1`] = `
<Advanced
className="collapsible-card"
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
onToggle={[Function]}
open={false}
>
<Row
className="my-2"
<div
className="answer-option-flex-item-1 mr-1 d-flex align-items-center"
>
<Col
xs={1}
>
<Checker
<Checker
answer={
Object {
"correct": true,
"id": "A",
"selectedFeedback": "selected feedback",
"title": "Answer 1",
"unselectedFeedback": "unselected feedback",
}
}
hasSingleAnswer={false}
setAnswer={[Function]}
/>
</div>
<div
className="answer-option-flex-item-2 ml-1"
>
<Form.Control
as="textarea"
autoResize={true}
className="answer-option-textarea text-gray-500 small"
onChange={[Function]}
placeholder="Enter an answer"
rows={1}
value="Answer 1"
/>
<Body>
<injectIntl(ShimmedIntlComponent)
answer={
Object {
"correct": true,
@@ -118,109 +121,33 @@ exports[`AnswerOption render snapshot: renders correct option with selected unse
"unselectedFeedback": "unselected feedback",
}
}
hasSingleAnswer={false}
intl={
Object {
"formatMessage": [Function],
}
}
problemType="choiceresponse"
setAnswer={[Function]}
/>
</Col>
<Col
xs={10}
>
<Form.Control
as="textarea"
onChange={[Function]}
placeholder="Enter an answer"
rows={1}
value="Answer 1"
/>
<Body>
<div
className="bg-dark-100 p-4 mt-3"
>
<Form.Group
key="selectedfeedback-A"
>
<Form.Label
className="mb-3"
>
<FormattedMessage
defaultMessage="Show following feedback when {answerId} {boldunderline}:"
description="Label text for feedback if option is selected"
id="authoring.answerwidget.feedback.selected.label"
values={
Object {
"answerId": "A",
"boldunderline": <b>
<u>
<FormattedMessage
defaultMessage="is selected"
description="Bold & underlined text for feedback if option is selected"
id="authoring.answerwidget.feedback.selected.label.boldunderline"
/>
</u>
</b>,
}
}
/>
</Form.Label>
<Form.Control
onChange={[Function]}
placeholder="Feedback message"
value="selected feedback"
/>
</Form.Group>
<Form.Group
key="unselectedfeedback-A"
>
<Form.Label
className="mb-3"
>
<FormattedMessage
defaultMessage="Show following feedback when {answerId} {boldunderline}:"
description="Label text for feedback if option is not selected"
id="authoring.answerwidget.feedback.unselected.label"
values={
Object {
"answerId": "A",
"boldunderline": <b>
<u>
<FormattedMessage
defaultMessage="is not selected"
description="Bold & underlined text for feedback if option is not selected"
id="authoring.answerwidget.feedback.unselected.label.boldunderline"
/>
</u>
</b>,
}
}
/>
</Form.Label>
<Form.Control
onChange={[Function]}
placeholder="Feedback message"
value="unselected feedback"
/>
</Form.Group>
</div>
</Body>
</Col>
<Col
className="d-inline-flex mt-1"
xs={1}
>
<Trigger>
<IconButton
alt="Toggle feedback"
iconAs="Icon"
variant="primary"
/>
</Trigger>
</Body>
</div>
<div
className="answer-option-flex-item-3 d-flex flex-row flex-nowrap"
>
<Trigger>
<IconButton
alt="Delete answer"
alt="Toggle feedback"
className="feedback-icon-button"
iconAs="Icon"
onClick={[Function]}
variant="primary"
/>
</Col>
</Row>
</Trigger>
<IconButton
alt="Delete answer"
iconAs="Icon"
onClick={[Function]}
variant="primary"
/>
</div>
</Advanced>
`;

View File

@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Checker component with multiple answers 1`] = `
<Form.Checkbox
checked={true}
className="pl-4"
onChange={[Function]}
value="A"
>
A
</Form.Checkbox>
`;
exports[`Checker component with single answer 1`] = `
<Radio
checked={true}
className="pl-4"
onChange={[Function]}
value="A"
>
A
</Radio>
`;

View File

@@ -0,0 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Form } from '@edx/paragon';
const Checker = ({
hasSingleAnswer, answer, setAnswer,
}) => {
let CheckerType = Form.Checkbox;
if (hasSingleAnswer) {
CheckerType = Form.Radio;
}
return (
<CheckerType
className="pl-4"
value={answer.id}
onChange={(e) => setAnswer({ correct: e.target.checked })}
checked={answer.correct}
>
{answer.id}
</CheckerType>
);
};
Checker.propTypes = {
hasSingleAnswer: PropTypes.bool.isRequired,
answer: PropTypes.shape({
correct: PropTypes.bool,
id: PropTypes.number,
}).isRequired,
setAnswer: PropTypes.func.isRequired,
};
export default Checker;

View File

@@ -0,0 +1,22 @@
import { shallow } from 'enzyme';
import Checker from '.';
const props = {
hasSingleAnswer: true,
answer: {
id: 'A',
title: 'Answer 1',
correct: true,
selectedFeedback: 'some feedback',
},
setAnswer: jest.fn(),
};
describe('Checker component', () => {
test('with single answer', () => {
expect(shallow(<Checker {...props} />)).toMatchSnapshot();
});
test('with multiple answers', () => {
expect(shallow(<Checker {...props} hasSingleAnswer={false} />)).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { answerOptionProps } from '../../../../../../../data/services/cms/types';
import FeedbackControl from './FeedbackControl';
import { messages } from './messages';
export const FeedbackBox = ({
answer, setAnswer, intl,
}) => {
const props = {
onChange: (e) => setAnswer({ selectedFeedback: e.target.value }),
answer,
intl,
};
return (
<div className="bg-light-300 p-4 mt-3">
<FeedbackControl
key={`selectedfeedback-${answer.id}`}
feedback={answer.selectedFeedback}
labelMessage={messages.selectedFeedbackLabel}
labelMessageBoldUnderline={messages.selectedFeedbackLabelBoldUnderlineText}
{...props}
/>
<FeedbackControl
key={`unselectedfeedback-${answer.id}`}
feedback={answer.unselectedFeedback}
labelMessage={messages.unSelectedFeedbackLabel}
labelMessageBoldUnderline={messages.unSelectedFeedbackLabelBoldUnderlineText}
{...props}
/>
</div>
);
};
FeedbackBox.propTypes = {
answer: answerOptionProps.isRequired,
setAnswer: PropTypes.func.isRequired,
intl: intlShape.isRequired,
};
export default injectIntl(FeedbackBox);

View File

@@ -0,0 +1,22 @@
import { shallow } from 'enzyme';
import { FeedbackBox } from './FeedbackBox';
const answerWithFeedback = {
id: 'A',
title: 'Answer 1',
correct: true,
selectedFeedback: 'some feedback',
unselectedFeedback: 'unselectedFeedback',
};
const props = {
answer: answerWithFeedback,
intl: {},
setAnswer: jest.fn(),
};
describe('FeedbackBox component', () => {
test('renders', () => {
expect(shallow(<FeedbackBox {...props} />)).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, intlShape } from '@edx/frontend-platform/i18n';
import { Form } from '@edx/paragon';
import { answerOptionProps } from '../../../../../../../data/services/cms/types';
import messages from './messages';
const FeedbackControl = ({
feedback, onChange, labelMessage, labelMessageBoldUnderline, answer, intl,
}) => (
<Form.Group>
<Form.Label className="mb-3">
<FormattedMessage
{...labelMessage}
values={{
answerId: answer.id,
boldunderline: <b><u><FormattedMessage {...labelMessageBoldUnderline} /></u></b>,
}}
/>
</Form.Label>
<Form.Control
placeholder={intl.formatMessage(messages.feedbackPlaceholder)}
value={feedback}
onChange={onChange}
/>
</Form.Group>
);
FeedbackControl.propTypes = {
feedback: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
labelMessage: PropTypes.string.isRequired,
labelMessageBoldUnderline: PropTypes.string.isRequired,
answer: answerOptionProps.isRequired,
intl: intlShape.isRequired,
};
export default FeedbackControl;

View File

@@ -0,0 +1,26 @@
import { shallow } from 'enzyme';
import FeedbackControl from './FeedbackControl';
const answerWithFeedback = {
id: 'A',
title: 'Answer 1',
correct: true,
selectedFeedback: 'some feedback',
unselectedFeedback: 'unselectedFeedback',
};
const props = {
answer: answerWithFeedback,
intl: { formatMessage: jest.fn() },
setAnswer: jest.fn(),
feedback: 'feedback',
onChange: jest.fn(),
labelMessage: 'msg',
labelMessageBoldUnderline: 'msg',
};
describe('FeedbackControl component', () => {
test('renders', () => {
expect(shallow(<FeedbackControl {...props} />)).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,66 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`FeedbackBox component renders 1`] = `
<div
className="bg-light-300 p-4 mt-3"
>
<FeedbackControl
answer={
Object {
"correct": true,
"id": "A",
"selectedFeedback": "some feedback",
"title": "Answer 1",
"unselectedFeedback": "unselectedFeedback",
}
}
feedback="some feedback"
intl={Object {}}
key="selectedfeedback-A"
labelMessage={
Object {
"defaultMessage": "Show following feedback when {answerId} {boldunderline}:",
"description": "Label text for feedback if option is selected",
"id": "authoring.answerwidget.feedback.selected.label",
}
}
labelMessageBoldUnderline={
Object {
"defaultMessage": "is selected",
"description": "Bold & underlined text for feedback if option is selected",
"id": "authoring.answerwidget.feedback.selected.label.boldunderline",
}
}
onChange={[Function]}
/>
<FeedbackControl
answer={
Object {
"correct": true,
"id": "A",
"selectedFeedback": "some feedback",
"title": "Answer 1",
"unselectedFeedback": "unselectedFeedback",
}
}
feedback="unselectedFeedback"
intl={Object {}}
key="unselectedfeedback-A"
labelMessage={
Object {
"defaultMessage": "Show following feedback when {answerId} {boldunderline}:",
"description": "Label text for feedback if option is not selected",
"id": "authoring.answerwidget.feedback.unselected.label",
}
}
labelMessageBoldUnderline={
Object {
"defaultMessage": "is not selected",
"description": "Bold & underlined text for feedback if option is not selected",
"id": "authoring.answerwidget.feedback.unselected.label.boldunderline",
}
}
onChange={[Function]}
/>
</div>
`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`FeedbackControl component renders 1`] = `
<Form.Group>
<Form.Label
className="mb-3"
>
<FormattedMessage
0="m"
1="s"
2="g"
values={
Object {
"answerId": "A",
"boldunderline": <b>
<u>
<FormattedMessage
0="m"
1="s"
2="g"
/>
</u>
</b>,
}
}
/>
</Form.Label>
<Form.Control
onChange={[MockFunction]}
value="feedback"
/>
</Form.Group>
`;

View File

@@ -0,0 +1,2 @@
export { default as FeedbackBox } from './FeedbackBox';
export { default as FeedbackControl } from './FeedbackControl';

View File

@@ -0,0 +1,34 @@
export const messages = {
feedbackPlaceholder: {
id: 'authoring.answerwidget.feedback.placeholder',
defaultMessage: 'Feedback message',
description: 'Placeholder text for feedback text',
},
feedbackToggleIconAltText: {
id: 'authoring.answerwidget.feedback.icon.alt',
defaultMessage: 'Toggle feedback',
description: 'Alt text for feedback toggle icon',
},
selectedFeedbackLabel: {
id: 'authoring.answerwidget.feedback.selected.label',
defaultMessage: 'Show following feedback when {answerId} {boldunderline}:',
description: 'Label text for feedback if option is selected',
},
selectedFeedbackLabelBoldUnderlineText: {
id: 'authoring.answerwidget.feedback.selected.label.boldunderline',
defaultMessage: 'is selected',
description: 'Bold & underlined text for feedback if option is selected',
},
unSelectedFeedbackLabel: {
id: 'authoring.answerwidget.feedback.unselected.label',
defaultMessage: 'Show following feedback when {answerId} {boldunderline}:',
description: 'Label text for feedback if option is not selected',
},
unSelectedFeedbackLabelBoldUnderlineText: {
id: 'authoring.answerwidget.feedback.unselected.label.boldunderline',
defaultMessage: 'is not selected',
description: 'Bold & underlined text for feedback if option is not selected',
},
};
export default messages;

View File

@@ -1,11 +1,59 @@
.problem-answer {
padding: 12px;
color: #00262B;
.problem-answer-title {
font-weight: bold;
}
@import '../../../../../../colors.scss';
.problem-answer-description {
font-size: 0.9rem;
}
.problem-answer {
padding: 12px;
.problem-answer-title {
font-weight: bold;
}
.problem-answer-description {
font-size: 0.9rem;
}
}
.answer-option {
// The paragon icon path is missing "fill: currentColor"
.feedback-icon-button {
&:hover {
&:not(:focus) {
svg {
path {
fill: $white;
}
}
}
}
}
.answer-option-flex-item-1 {
flex-basis: 8.33%;
}
.answer-option-flex-item-2 {
flex-basis: 83.34%;
}
.answer-option-flex-item-3 {
flex-basis: 8.33%;
}
.answer-option-textarea {
textarea {
border: none;
resize: none;
&:active, &:hover, &:focus, &:focus-visible {
border: none;
border-right: none;
border-left: none;
border-radius: 0;
box-shadow: none;
}
&:focus, &:hover {
border-bottom: 1px solid $black;
}
}
}
}

View File

@@ -1 +1 @@
/* styles go here */
@import './colors.scss';