diff --git a/package.json b/package.json index 9a4532f..056c01f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openstax/assessment-components", - "version": "1.0.0", + "version": "1.1.0", "license": "MIT", "source": "./src/index.ts", "types": "./dist/src/index.d.ts", diff --git a/src/components/Answer.tsx b/src/components/Answer.tsx index d90dadd..912ede1 100644 --- a/src/components/Answer.tsx +++ b/src/components/Answer.tsx @@ -10,7 +10,7 @@ import { colors } from '../theme'; const StyledAnswerIndicator = styled.div<{ state: boolean }>` color: ${props => props.state ? colors.answer.correct : colors.answer.incorrect}; text-transform: uppercase; - font-size: 1.1rem; + font-size: calc(1.1rem * var(--content-text-scale)); font-weight: bold; `; diff --git a/src/components/Card.tsx b/src/components/Card.tsx index 6143a0b..5fff851 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -145,7 +145,7 @@ StepCardHeader.displayName = 'StepCardHeader'; const StepCardQuestion = styled.div<{ unpadded?: boolean }>` .step-card-body { ${mixins.stepCardPadding()} - + overflow: auto; background: ${colors.card.body.background}; &.exercise-stimulus { diff --git a/src/components/CompletionStatus.tsx b/src/components/CompletionStatus.tsx index 774fe84..8e9cb50 100644 --- a/src/components/CompletionStatus.tsx +++ b/src/components/CompletionStatus.tsx @@ -1,17 +1,24 @@ -import styled from "styled-components"; +import styled, { createGlobalStyle } from "styled-components"; import { InnerStepCard } from "./Card"; import Button from "./Button"; +const GlobalStyle = createGlobalStyle` + :root { + --content-text-scale: 1; + } +`; + export interface CompletionStatusProps { numberOfQuestions: number; numberCompleted: number; handleClick: () => void; + className?: string; } const CompletionStatusCard = styled(InnerStepCard)` padding: 88px 72px; - font-size: 1.8rem; - line-height: 3rem; + font-size: calc(1.8rem * var(--content-text-scale)); + line-height: calc(3rem * var(--content-text-scale)); display: block; button { @@ -25,27 +32,28 @@ const CompletionStatusCard = styled(InnerStepCard)` `; const CompletionHeader = styled.h2` - font-size: 2.4rem; + font-size: calc(2.4rem * var(--content-text-scale)); margin: 0; `; -export const CompletionStatus = ({ - numberOfQuestions, numberCompleted, handleClick +export const CompletionStatus = styled(({ + numberOfQuestions, numberCompleted, handleClick, className }: CompletionStatusProps) => { - + const allCompleted = numberOfQuestions === numberCompleted; const someCompleted = numberCompleted > 0; const buttonText = allCompleted ? 'Next' : ( someCompleted ? 'Continue' : 'Start' ); - return ( - + return <> + + {allCompleted ? 'You are done.' : (someCompleted ? 'Quiz is partially complete.' : 'No questions have been answered.')}

{allCompleted ? 'Great job answering all the questions.' : (someCompleted ? `You've completed ${numberCompleted} of ${numberOfQuestions} questions.` : 'Begin working on the quiz.')}

-
- ) -}; + +})``; diff --git a/src/components/Exercise.stories.tsx b/src/components/Exercise.stories.tsx index 29be734..d1aeb86 100644 --- a/src/components/Exercise.stories.tsx +++ b/src/components/Exercise.stories.tsx @@ -1,6 +1,7 @@ -import { useState } from 'react'; +import React, { useState } from 'react'; import { Exercise, ExerciseWithStepDataProps, ExerciseWithQuestionStatesProps } from './Exercise'; import { Answer } from '../types'; +import styled from 'styled-components'; const exerciseWithStepDataProps: ExerciseWithStepDataProps = { exercise: { @@ -131,6 +132,38 @@ const exerciseWithQuestionStatesProps = (): ExerciseWithQuestionStatesProps => { }, }}; +type TextResizerValue = -2 | -1 | 0 | 1 | 2 | 3; +const textResizerScales = [0.75, 0.9, 1, 1.25, 1.5, 2]; +const textResizerValues: TextResizerValue[] = [-2, -1, 0, 1, 2, 3]; +const textResizerValueMap = new Map(textResizerValues.map((v, i) => [v, textResizerScales[i]])); + +const ExerciseWrapper = styled.div<{ textSize: TextResizerValue }>` + ${(props: { textSize: TextResizerValue }) => ` + --content-text-scale: ${textResizerValueMap.get(props.textSize)}; + `} +`; + +const TextResizerProvider = ({ children }: { children: React.ReactNode }) => { + const [index, setIndex] = useState(2); + + const increase = () => setIndex(Math.min(index + 1, textResizerValues.length - 1)); + const decrease = () => setIndex(Math.max(index - 1, 0)); + + return ( + +
+

Text Size

+ + + {textResizerScales[index]} + + +
+ {children} +
+ ); +}; + export const Default = () => { const [selectedAnswerId, setSelectedAnswerId] = useState(0); const [apiIsPending, setApiIsPending] = useState(false) @@ -144,7 +177,8 @@ export const Default = () => { setSelectedAnswerId(a.id) }} onAnswerSave={() => setApiIsPending(true)} - />) + /> + ) }; export const DeprecatedStepData = () => ; @@ -173,7 +207,7 @@ export const CompleteWithFeedback = () => { } }; - return ; + return ; }; export const IncorrectWithFeedbackAndSolution = () => { @@ -197,7 +231,7 @@ export const IncorrectWithFeedbackAndSolution = () => { apiIsPending: false } }; - return ; + return ; }; export const IncorrectWithFeedbackAndSolutionWrappingText = () => { @@ -223,7 +257,7 @@ export const IncorrectWithFeedbackAndSolutionWrappingText = () => { }; props.exercise.questions[0].answers[0].content_html = 'A very long correct answer to observe line wrapping at mobile sizes'; props.exercise.questions[0].answers[1].content_html = 'A very long incorrect answer to observe line wrapping at mobile sizes'; - return ; + return ; }; export const MultiPartHalfComplete = () => { @@ -325,7 +359,7 @@ export const MultiPartHalfComplete = () => { } }; - return ; + return ; }; export const Icons = () => { @@ -341,20 +375,20 @@ export const Icons = () => { }; return ; }; @@ -506,7 +540,7 @@ bitterness. The discriminant could perhaps a }; return ( - <> + & { id: number, question_id: number }) => { setSelectedAnswerId(a.id) @@ -516,6 +550,6 @@ bitterness. The discriminant could perhaps a }} /> - + ); }; diff --git a/src/components/Exercise.tsx b/src/components/Exercise.tsx index 0c4030e..2df0332 100644 --- a/src/components/Exercise.tsx +++ b/src/components/Exercise.tsx @@ -1,6 +1,6 @@ import React from 'react'; import scrollToElement from 'scroll-to-element'; -import styled, { css } from 'styled-components'; +import styled, { createGlobalStyle, css } from 'styled-components'; import { Answer, ExerciseData, ID, QuestionState, StepBase, StepWithData } from '../../src/types'; import { InnerStepCard, OuterStepCard, TaskStepCard, TaskStepCardProps } from './Card'; import { Content } from './Content'; @@ -12,8 +12,14 @@ import { ExerciseHeaderIcons } from './ExerciseHeaderIcons'; import { TypesetMathContext } from '../hooks/useTypesetMath'; const StyledTaskStepCard = styled(TaskStepCard)` - font-size: 1.8rem; - line-height: 2.8rem; + font-size: calc(1.8rem * var(--content-text-scale)); + line-height: calc(2.8rem * var(--content-text-scale)); +`; + +const GlobalStyle = createGlobalStyle` + :root { + --content-text-scale: 1; + } `; const ToolbarWrapper = styled.div<{ @@ -151,9 +157,9 @@ export interface ExerciseWithQuestionStatesProps extends ExerciseBaseProps { onAnswerChange: (answer: Omit & { id: number, question_id: number }) => void; } -export const Exercise = ({ +export const Exercise = styled(({ numberOfQuestions, questionNumber, step, exercise, show_all_feedback, scrollToQuestion, exerciseIcons, ...props -}: ExerciseWithStepDataProps | ExerciseWithQuestionStatesProps) => { +}: { className?: string } & (ExerciseWithStepDataProps | ExerciseWithQuestionStatesProps)) => { const legacyStepRender = 'feedback_html' in step; const questionsRef = React.useRef>([]); const container = React.useRef(null); @@ -175,6 +181,7 @@ export const Exercise = ({ const mobileToolbarEnabled = Object.values(exerciseIcons || {}).some(({ location }) => location?.toolbar?.mobile); return +
@@ -217,4 +225,5 @@ export const Exercise = ({
; -}; +})` +`; diff --git a/src/components/Question.tsx b/src/components/Question.tsx index 9042ea6..64109bf 100644 --- a/src/components/Question.tsx +++ b/src/components/Question.tsx @@ -13,7 +13,7 @@ const StyledQuestion = styled.div` &.openstax-question { border-top: 1px solid ${colors.palette.pale}; - font-size: 1.8rem; + font-size: calc(1.8rem * var(--content-text-scale)); .detailed-solution { margin-bottom: 1rem; @@ -42,8 +42,8 @@ const StyledQuestion = styled.div` .answers-table { margin-bottom: 20px; - font-size: 1.6rem; - line-height: 2rem; + font-size: calc(1.6rem * var(--content-text-scale)); + line-height: calc(2rem * var(--content-text-scale)); } .instructions { diff --git a/src/components/StepCardFooter.tsx b/src/components/StepCardFooter.tsx index a5a127d..886eb94 100644 --- a/src/components/StepCardFooter.tsx +++ b/src/components/StepCardFooter.tsx @@ -6,9 +6,10 @@ export const StepCardFooter = styled.div` display: flex; flex-wrap: wrap; justify-content: space-between; - font-size: 1.4rem; - line-height: 2rem; + font-size: calc(1.4rem * var(--content-text-scale)); + line-height: calc(2rem * var(--content-text-scale)); background: ${colors.card.body.background}; + overflow: auto; > * { flex-grow: 1; diff --git a/src/components/__snapshots__/Answer.spec.tsx.snap b/src/components/__snapshots__/Answer.spec.tsx.snap index 0bec985..4a4de30 100644 --- a/src/components/__snapshots__/Answer.spec.tsx.snap +++ b/src/components/__snapshots__/Answer.spec.tsx.snap @@ -141,7 +141,7 @@ exports[`Answer renders a correct answer 1`] = ` className="answer-answer" >
Correct Answer @@ -194,7 +194,7 @@ exports[`Answer renders an incorrect answer 1`] = ` className="answer-answer" >
Incorrect Answer @@ -320,7 +320,7 @@ exports[`Answer renders teacher preview 1`] = ` className="answer-answer" >
Correct Answer diff --git a/src/components/__snapshots__/AnswersTable.spec.tsx.snap b/src/components/__snapshots__/AnswersTable.spec.tsx.snap index 8e7aa02..bb9b0d2 100644 --- a/src/components/__snapshots__/AnswersTable.spec.tsx.snap +++ b/src/components/__snapshots__/AnswersTable.spec.tsx.snap @@ -141,7 +141,7 @@ exports[`AnswersTable renders all feedback 1`] = ` className="answer-answer" >
Incorrect Answer @@ -212,7 +212,7 @@ exports[`AnswersTable renders all feedback 1`] = ` className="answer-answer" >
Correct Answer @@ -281,7 +281,7 @@ exports[`AnswersTable renders correct answer feedback 1`] = ` className="answer-answer" >
Correct Answer @@ -397,7 +397,7 @@ exports[`AnswersTable renders incorrect answer feedback 1`] = ` className="answer-answer" >
Incorrect Answer @@ -468,7 +468,7 @@ exports[`AnswersTable renders incorrect answer feedback 1`] = ` className="answer-answer" >
Correct Answer diff --git a/src/components/__snapshots__/Card.spec.tsx.snap b/src/components/__snapshots__/Card.spec.tsx.snap index 78a8933..6f9a8b9 100644 --- a/src/components/__snapshots__/Card.spec.tsx.snap +++ b/src/components/__snapshots__/Card.spec.tsx.snap @@ -39,7 +39,7 @@ exports[`StepCard matches snapshot 1`] = `
Question content
@@ -92,7 +92,7 @@ exports[`StepCard matches snapshot with more than one question 1`] = `
Question content
@@ -133,7 +133,7 @@ exports[`TaskStepCard can optionally provide task 1`] = `
@@ -172,7 +172,7 @@ exports[`TaskStepCard can optionally provide type 1`] = `
@@ -211,7 +211,7 @@ exports[`TaskStepCard matches snapshot 1`] = `
diff --git a/src/components/__snapshots__/CompletionStatus.spec.tsx.snap b/src/components/__snapshots__/CompletionStatus.spec.tsx.snap index ba4906a..00c3d30 100644 --- a/src/components/__snapshots__/CompletionStatus.spec.tsx.snap +++ b/src/components/__snapshots__/CompletionStatus.spec.tsx.snap @@ -2,10 +2,10 @@ exports[`CompletionStatus matches snapshot 1`] = `

No questions have been answered.

@@ -24,10 +24,10 @@ exports[`CompletionStatus matches snapshot 1`] = ` exports[`CompletionStatus matches snapshot with all questions completed 1`] = `

You are done.

@@ -46,10 +46,10 @@ exports[`CompletionStatus matches snapshot with all questions completed 1`] = ` exports[`CompletionStatus matches snapshot with some questions completed 1`] = `

Quiz is partially complete.

diff --git a/src/components/__snapshots__/Exercise.spec.tsx.snap b/src/components/__snapshots__/Exercise.spec.tsx.snap index 5efa557..d05a3e6 100644 --- a/src/components/__snapshots__/Exercise.spec.tsx.snap +++ b/src/components/__snapshots__/Exercise.spec.tsx.snap @@ -9,7 +9,7 @@ exports[`Exercise using step data matches snapshot 1`] = ` data-task-step-id={1} >
@@ -169,7 +169,7 @@ exports[`Exercise using step data matches snapshot 1`] = `
@@ -365,7 +365,7 @@ exports[`Exercise with question state data matches snapshot 1`] = `
@@ -701,7 +701,7 @@ exports[`Exercise with question state data renders header icons with multiple ch
@@ -1077,7 +1077,7 @@ exports[`Exercise with question state data renders header icons with two-step ex
@@ -1273,7 +1273,7 @@ exports[`Exercise with question state data shows a detailed solution 1`] = `
@@ -118,7 +118,7 @@ exports[`ExerciseQuestion matches snapshot 1`] = `
@@ -255,7 +255,7 @@ exports[`ExerciseQuestion renders Re-submit button 1`] = ` className="answer-answer" >
Incorrect Answer @@ -275,7 +275,7 @@ exports[`ExerciseQuestion renders Re-submit button 1`] = `
@@ -413,7 +413,7 @@ exports[`ExerciseQuestion renders Save button 1`] = ` className="answer-answer" >
Incorrect Answer @@ -433,7 +433,7 @@ exports[`ExerciseQuestion renders Save button 1`] = `
@@ -585,7 +585,7 @@ exports[`ExerciseQuestion renders all attempts remaining 1`] = `
@@ -729,7 +729,7 @@ exports[`ExerciseQuestion renders continue button (unused?) 1`] = ` className="answer-answer" >
Incorrect Answer @@ -749,7 +749,7 @@ exports[`ExerciseQuestion renders continue button (unused?) 1`] = `
@@ -830,7 +830,7 @@ exports[`ExerciseQuestion renders detailed solution and published comments 1`] = className="answer-answer" >
Correct Answer @@ -874,7 +874,7 @@ exports[`ExerciseQuestion renders detailed solution and published comments 1`] = className="answer-answer" >
Incorrect Answer @@ -894,7 +894,7 @@ exports[`ExerciseQuestion renders detailed solution and published comments 1`] =
@@ -1069,7 +1069,7 @@ exports[`ExerciseQuestion renders free response 1`] = `
@@ -1206,7 +1206,7 @@ exports[`ExerciseQuestion renders no attempts remaining 1`] = ` className="answer-answer" >
Incorrect Answer @@ -1226,7 +1226,7 @@ exports[`ExerciseQuestion renders no attempts remaining 1`] = `
@@ -1363,7 +1363,7 @@ exports[`ExerciseQuestion renders some attempts remaining 1`] = ` className="answer-answer" >
Incorrect Answer @@ -1383,7 +1383,7 @@ exports[`ExerciseQuestion renders some attempts remaining 1`] = `
@@ -118,7 +118,7 @@ exports[`Question defaults QuestionHtml html 1`] = ` exports[`Question defaults collaborator_solutions 1`] = `
@@ -234,7 +234,7 @@ exports[`Question defaults collaborator_solutions 1`] = ` exports[`Question defaults formats 1`] = `
@@ -359,7 +359,7 @@ exports[`Question defaults formats 1`] = ` exports[`Question matches snapshot 1`] = `
@@ -475,7 +475,7 @@ exports[`Question matches snapshot 1`] = ` exports[`Question renders exercise uid 1`] = `
@@ -596,7 +596,7 @@ exports[`Question renders exercise uid 1`] = ` exports[`Question renders formats 1`] = `
@@ -724,7 +724,7 @@ exports[`Question renders formats 1`] = ` exports[`Question renders solutions 1`] = `
diff --git a/src/theme.ts b/src/theme.ts index c3b3899..dd33048 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -208,7 +208,7 @@ export const mixins = { margin: calc(${layouts.popover.arrow.height} - 14px) 0 ${layouts.answer.horizontalSpacing} 8px; box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1); color: ${colors.palette.neutralThin}; - font-size: 1.4rem; + font-size: calc(1.4rem * var(--content-text-scale)); .arrow { position: absolute;