Skip to content

Commit

Permalink
[WB-1814.2] Refactor TextField and TextArea to use semantic colors (#…
Browse files Browse the repository at this point in the history
…2440)

## Summary:

- Form: Migrated `color` instances to use `semanticColor` internally in
TextField and TextArea.

- Tokens: Added `border.focus` semantic color token to use for the focus outline


Issue: WB-1814

## Test plan:

Navigate to the Storybook for `TextField` and `TextArea` components and verify
that the colors are looking as expected.

- /?path=/docs/packages-form-textarea--docs
- /?path=/docs/packages-form-textfield--docs

Author: jandrade

Reviewers: beaesguerra, jandrade

Required Reviewers:

Approved By: beaesguerra

Checks: ✅ Chromatic - Get results on regular PRs (ubuntu-latest, 20.x), ✅ Test / Test (ubuntu-latest, 20.x, 2/2), ✅ Test / Test (ubuntu-latest, 20.x, 1/2), ✅ Lint / Lint (ubuntu-latest, 20.x), ✅ Check build sizes (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Chromatic - Build and test on regular PRs / chromatic (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ⏭️  Chromatic - Skip on Release PR (changesets), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 20.x), ✅ gerald, ⏭️  dependabot

Pull Request URL: #2440
  • Loading branch information
jandrade authored Jan 28, 2025
1 parent bd7c9bf commit c162abb
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-radios-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-blocks-form": patch
---

Migrate color instances to use semanticColor internally on TextField and TextArea
5 changes: 5 additions & 0 deletions .changeset/spicy-grapes-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-blocks-tokens": minor
---

Add `border.focus` semantic color token to use for the focus outline
6 changes: 1 addition & 5 deletions __docs__/wonder-blocks-form/text-area-variants.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import {LabeledField} from "@khanacademy/wonder-blocks-labeled-field";
*/
export default {
title: "Packages / Form / TextArea / All Variants",
parameters: {
docs: {
autodocs: false,
},
},
tags: ["!autodocs"],
} as Meta;

type StoryComponentType = StoryObj<typeof TextArea>;
Expand Down
8 changes: 4 additions & 4 deletions __docs__/wonder-blocks-form/text-area.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TextArea} from "@khanacademy/wonder-blocks-form";
import packageConfig from "../../packages/wonder-blocks-form/package.json";

import ComponentInfo from "../components/component-info";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens";
import Button from "@khanacademy/wonder-blocks-button";
import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
import {Strut} from "@khanacademy/wonder-blocks-layout";
Expand Down Expand Up @@ -50,12 +50,12 @@ type ControlledStoryComponentType = StoryObj<typeof ControlledTextArea>;

const styles = StyleSheet.create({
customField: {
backgroundColor: color.darkBlue,
color: color.white,
backgroundColor: semanticColor.status.notice.background,
color: semanticColor.status.notice.foreground,
border: "none",
maxWidth: 250,
"::placeholder": {
color: color.white64,
color: semanticColor.text.secondary,
},
},
});
Expand Down
8 changes: 4 additions & 4 deletions __docs__/wonder-blocks-form/text-field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {Meta, StoryObj} from "@storybook/react";

import {PropsFor, View} from "@khanacademy/wonder-blocks-core";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens";
import Button from "@khanacademy/wonder-blocks-button";
import {LabelLarge, Body} from "@khanacademy/wonder-blocks-typography";

Expand Down Expand Up @@ -828,12 +828,12 @@ AutoComplete.parameters = {

const styles = StyleSheet.create({
customField: {
backgroundColor: color.darkBlue,
color: color.white,
backgroundColor: semanticColor.status.notice.background,
color: semanticColor.status.notice.foreground,
border: "none",
maxWidth: 250,
"::placeholder": {
color: color.white64,
color: semanticColor.text.secondary,
},
},
button: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {StyleSheet} from "aphrodite";
import type {Meta, StoryObj} from "@storybook/react";

import {View} from "@khanacademy/wonder-blocks-core";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {spacing} from "@khanacademy/wonder-blocks-tokens";
import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
import SearchField from "@khanacademy/wonder-blocks-search-field";
import {LabeledField} from "@khanacademy/wonder-blocks-labeled-field";
Expand Down Expand Up @@ -123,9 +123,6 @@ export const Active: StoryComponentType = {
};

const styles = StyleSheet.create({
darkDefault: {
backgroundColor: color.darkBlue,
},
statesContainer: {
padding: spacing.medium_16,
},
Expand Down
10 changes: 5 additions & 5 deletions packages/wonder-blocks-form/src/components/field-heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {StyleSheet} from "aphrodite";

import {View, addStyle, StyleType} from "@khanacademy/wonder-blocks-core";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens";
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";

type Props = {
Expand Down Expand Up @@ -136,15 +136,15 @@ export default class FieldHeading extends React.Component<Props> {

const styles = StyleSheet.create({
label: {
color: color.offBlack,
color: semanticColor.text.primary,
},
description: {
color: color.offBlack64,
color: semanticColor.text.secondary,
},
error: {
color: color.red,
color: semanticColor.status.critical.foreground,
},
required: {
color: color.red,
color: semanticColor.status.critical.foreground,
},
});
68 changes: 48 additions & 20 deletions packages/wonder-blocks-form/src/components/text-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import {
addStyle,
View,
} from "@khanacademy/wonder-blocks-core";
import {border, color, font, spacing} from "@khanacademy/wonder-blocks-tokens";
import {
border,
font,
semanticColor,
spacing,
} from "@khanacademy/wonder-blocks-tokens";
import {styles as typographyStyles} from "@khanacademy/wonder-blocks-typography";
import {useId} from "react";
import {useFieldValidation} from "../hooks/use-field-validation";
Expand Down Expand Up @@ -299,6 +304,27 @@ const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(

const VERTICAL_SPACING_PX = 10;

// The different states that the component can be in.
const states = {
// Resting state
default: {
border: semanticColor.border.strong,
background: semanticColor.surface.primary,
foreground: semanticColor.text.primary,
},
disabled: {
border: semanticColor.border.primary,
background: semanticColor.action.disabled.secondary,
foreground: semanticColor.text.secondary,
},
// Form validation error state
error: {
border: semanticColor.status.critical.foreground,
background: semanticColor.status.critical.background,
foreground: semanticColor.text.primary,
},
};

const styles = StyleSheet.create({
textarea: {
borderRadius: border.radius.medium_4,
Expand All @@ -312,45 +338,47 @@ const styles = StyleSheet.create({
}px`,
},
default: {
background: color.white,
border: `1px solid ${color.offBlack50}`,
color: color.offBlack,
background: states.default.background,
border: `${border.width.hairline}px solid ${states.default.border}`,
color: states.default.foreground,
"::placeholder": {
color: color.offBlack64,
color: semanticColor.text.secondary,
},
},
defaultFocus: {
":focus-visible": {
borderColor: color.blue,
outline: `1px solid ${color.blue}`,
borderColor: semanticColor.border.focus,
outline: `${border.width.hairline}px solid ${semanticColor.border.focus}`,
// Negative outline offset so it focus outline is not cropped off if
// an ancestor element has overflow: hidden
outlineOffset: "-2px",
outlineOffset: -2,
},
},
disabled: {
background: color.offWhite,
border: `1px solid ${color.offBlack16}`,
color: color.offBlack64,
background: states.disabled.background,
border: `${border.width.hairline}px solid ${states.disabled.border}`,
color: states.disabled.foreground,
"::placeholder": {
color: color.offBlack64,
color: states.disabled.foreground,
},
cursor: "not-allowed",
":focus-visible": {
outline: `2px solid ${color.offBlack32}`,
outlineOffset: "-3px",
// TODO(WB-1856): Verify if we can use the global focus color
outline: `${border.width.thin}px solid ${semanticColor.action.disabled.default}`,
outlineOffset: -3,
},
},
error: {
background: color.fadedRed8,
border: `1px solid ${color.red}`,
color: color.offBlack,
background: states.error.background,
border: `${border.width.hairline}px solid ${states.error.border}`,
color: states.error.foreground,
"::placeholder": {
color: color.offBlack64,
color: semanticColor.text.secondary,
},
":focus-visible": {
outlineColor: color.red,
borderColor: color.red,
// TODO(WB-1856): Verify if we can use the global focus color
outlineColor: states.error.border,
borderColor: states.error.border,
},
},
});
Expand Down
67 changes: 47 additions & 20 deletions packages/wonder-blocks-form/src/components/text-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import * as React from "react";
import {StyleSheet} from "aphrodite";

import {Id, addStyle} from "@khanacademy/wonder-blocks-core";
import {border, color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {
border,
semanticColor,
spacing,
} from "@khanacademy/wonder-blocks-tokens";
import {styles as typographyStyles} from "@khanacademy/wonder-blocks-typography";

import type {StyleType, AriaProps} from "@khanacademy/wonder-blocks-core";
Expand Down Expand Up @@ -258,6 +262,27 @@ const TextField = (props: PropsWithForwardRef) => {
);
};

// The different states that the component can be in.
const states = {
// Resting state
default: {
border: semanticColor.border.strong,
background: semanticColor.surface.primary,
foreground: semanticColor.text.primary,
},
disabled: {
border: semanticColor.border.primary,
background: semanticColor.action.disabled.secondary,
foreground: semanticColor.text.secondary,
},
// Form validation error state
error: {
border: semanticColor.status.critical.foreground,
background: semanticColor.status.critical.background,
foreground: semanticColor.text.primary,
},
};

const styles = StyleSheet.create({
input: {
width: "100%",
Expand All @@ -268,45 +293,47 @@ const styles = StyleSheet.create({
margin: 0,
},
default: {
background: color.white,
border: `1px solid ${color.offBlack50}`,
color: color.offBlack,
background: states.default.background,
border: `${border.width.hairline}px solid ${states.default.border}`,
color: states.default.foreground,
"::placeholder": {
color: color.offBlack64,
color: semanticColor.text.secondary,
},
},
defaultFocus: {
":focus-visible": {
borderColor: color.blue,
outline: `1px solid ${color.blue}`,
borderColor: semanticColor.border.focus,
outline: `${border.width.hairline}px solid ${semanticColor.border.focus}`,
// Negative outline offset so it focus outline is not cropped off if
// an ancestor element has overflow: hidden
outlineOffset: "-2px",
outlineOffset: -2,
},
},
error: {
background: color.fadedRed8,
border: `1px solid ${color.red}`,
color: color.offBlack,
background: states.error.background,
border: `${border.width.hairline}px solid ${states.error.border}`,
color: states.error.foreground,
"::placeholder": {
color: color.offBlack64,
color: semanticColor.text.secondary,
},
":focus-visible": {
outlineColor: color.red,
borderColor: color.red,
// TODO(WB-1856): Verify if we can use the global focus color
outlineColor: states.error.border,
borderColor: states.error.border,
},
},
disabled: {
background: color.offWhite,
border: `1px solid ${color.offBlack16}`,
color: color.offBlack64,
background: states.disabled.background,
border: `${border.width.hairline}px solid ${states.disabled.border}`,
color: states.disabled.foreground,
"::placeholder": {
color: color.offBlack64,
color: states.disabled.foreground,
},
cursor: "not-allowed",
":focus-visible": {
outline: `2px solid ${color.offBlack32}`,
outlineOffset: "-3px",
// TODO(WB-1856): Verify if we can use the global focus color
outline: `${border.width.thin}px solid ${semanticColor.action.disabled.default}`,
outlineOffset: -3,
},
},
});
Expand Down
1 change: 1 addition & 0 deletions packages/wonder-blocks-tokens/src/tokens/semantic-color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const border = {
primary: color.fadedOffBlack16,
subtle: color.fadedOffBlack8,
strong: color.fadedOffBlack50,
focus: color.blue,
inverse: color.white,
};

Expand Down

0 comments on commit c162abb

Please sign in to comment.