diff --git a/.changeset/sharp-maps-leave.md b/.changeset/sharp-maps-leave.md new file mode 100644 index 000000000..62d05264d --- /dev/null +++ b/.changeset/sharp-maps-leave.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-form": patch +--- + +Improve `LabeledTextField` styling when the `light` prop is `true`. This improves the color contrast of the label, required indicator, description, and error message when the component is used on dark backgrounds. diff --git a/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx b/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx index 3212d2a24..f2830e4a9 100644 --- a/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx +++ b/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx @@ -3,8 +3,7 @@ import {StyleSheet} from "aphrodite"; import type {Meta, StoryObj} from "@storybook/react"; import {View} from "@khanacademy/wonder-blocks-core"; -import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography"; -import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; +import {spacing} from "@khanacademy/wonder-blocks-tokens"; import {Strut} from "@khanacademy/wonder-blocks-layout"; import Button from "@khanacademy/wonder-blocks-button"; import Link from "@khanacademy/wonder-blocks-link"; @@ -436,6 +435,15 @@ export const Error: StoryComponentType = { render: ErrorRender, }; +/** + * The `light` prop is intended to be used on a dark background. When the + * `light` prop is set to `true`: + * - the underlying `TextField` will have a light border when focused + * - a specific light styling is used for the error state, as seen in the + * `ErrorLight` story + * - the text in the component (label, required indicator, description, and + * error message) are modified to work on the dark background + */ export const Light: StoryComponentType = (args: any) => { const [value, setValue] = React.useState(""); @@ -446,24 +454,17 @@ export const Light: StoryComponentType = (args: any) => { }; return ( - - Name - } - description={ - - Please enter your name - - } - value={value} - onChange={setValue} - placeholder="Name" - light={true} - onKeyDown={handleKeyDown} - /> - + ); }; @@ -472,17 +473,15 @@ Light.args = { }; Light.parameters = { - docs: { - description: { - story: `If the \`light\` prop is set to true, the - underlying \`TextField\` will have a light border when focused. - This is intended to be used on a dark background. There is also a - specific light styling for the error state, as seen in the - \`ErrorLight\` story.`, - }, + backgrounds: { + default: "darkBlue", }, }; +/** + * If an input value fails validation and the `light` prop is true, + * `TextField` will have light error styling. + */ export const ErrorLight: StoryComponentType = (args: any) => { const [value, setValue] = React.useState("khan"); @@ -500,26 +499,19 @@ export const ErrorLight: StoryComponentType = (args: any) => { }; return ( - - Email - } - description={ - - Please provide your personal email - - } - type="email" - value={value} - light={true} - onChange={setValue} - placeholder="Email" - validate={validate} - onKeyDown={handleKeyDown} - /> - + ); }; @@ -528,11 +520,8 @@ ErrorLight.args = { }; ErrorLight.parameters = { - docs: { - description: { - story: `If an input value fails validation and the - \`light\` prop is true, \`TextField\` will have light error styling.`, - }, + backgrounds: { + default: "darkBlue", }, }; @@ -766,16 +755,6 @@ AutoComplete.parameters = { }; const styles = StyleSheet.create({ - darkBackground: { - background: color.darkBlue, - padding: `${spacing.medium_16}px`, - }, - whiteColor: { - color: color.white, - }, - offWhiteColor: { - color: color.white64, - }, button: { maxWidth: 150, }, diff --git a/packages/wonder-blocks-form/src/components/field-heading.tsx b/packages/wonder-blocks-form/src/components/field-heading.tsx index 56553b929..b8198fe49 100644 --- a/packages/wonder-blocks-form/src/components/field-heading.tsx +++ b/packages/wonder-blocks-form/src/components/field-heading.tsx @@ -42,6 +42,10 @@ type Props = { * Optional test ID for e2e testing. */ testId?: string; + /** + * Change the field’s sub-components to fit a dark background. + */ + light?: boolean; }; const StyledSpan = addStyle("span"); @@ -52,10 +56,13 @@ const StyledSpan = addStyle("span"); */ export default class FieldHeading extends React.Component { renderLabel(): React.ReactNode { - const {label, id, required, testId} = this.props; + const {label, id, required, testId, light} = this.props; const requiredIcon = ( - + {" "} * @@ -64,7 +71,7 @@ export default class FieldHeading extends React.Component { return ( { } maybeRenderDescription(): React.ReactNode | null | undefined { - const {description, testId} = this.props; + const {description, testId, light} = this.props; if (!description) { return null; @@ -87,7 +94,7 @@ export default class FieldHeading extends React.Component { return ( {description} @@ -98,7 +105,7 @@ export default class FieldHeading extends React.Component { } maybeRenderError(): React.ReactNode | null | undefined { - const {error, id, testId} = this.props; + const {error, id, testId, light} = this.props; if (!error) { return null; @@ -108,7 +115,7 @@ export default class FieldHeading extends React.Component { { id={uniqueId} testId={testId} style={style} + light={light} field={