Skip to content

Commit

Permalink
[TextField, Radio, Checkbox] Add styles for AI generated values (#10819)
Browse files Browse the repository at this point in the history
<!--
  ☝️How to write a good PR title:
- Prefix it with [ComponentName] (if applicable), for example: [Button]
  - Start with a verb, for example: Add, Delete, Improve, Fix…
  - Give as much context as necessary and as little as possible
  - Prefix it with [WIP] while it’s a work in progress
-->

### WHY are these changes introduced?

This PR introduces a new `tone` prop with a possible value "magic" for
determining the values in the component have been generated by AI. It
uses the `--p-color-text-magic` color token and serves as an example for
how the rest of styles in this and other components should be
implemented.

References #10152

### WHAT is this pull request doing?

This follows the pattern suggested by the Polaris team. After
considering applying the styles with a `data-ai-generated` attribute so
it could be modified via DOM manipulation I discarded that option.

![Screenshot 2023-10-23 at 9 33 27
AM](https://github.com/Shopify/polaris/assets/36676/a1c51eb0-e0f7-4c21-9c15-c2aa4c22d0f9)

Radio in web

![Screenshot 2023-10-24 at 1 13 51
PM](https://github.com/Shopify/polaris/assets/36676/3bf9bbee-569a-4e1e-b281-8049d0f02ebe)

Checkbox
<img width="571" alt="Screenshot 2023-10-26 at 11 03 40 AM"
src="https://github.com/Shopify/polaris/assets/36676/0d5e197a-488b-418b-b698-7d4ad14771b4">

hover
<img width="570" alt="Screenshot 2023-10-26 at 11 10 51 AM"
src="https://github.com/Shopify/polaris/assets/36676/eb37c2df-1545-45b8-a1a4-83f51cd5c1cb">

checked
<img width="573" alt="Screenshot 2023-10-26 at 11 03 59 AM"
src="https://github.com/Shopify/polaris/assets/36676/20360362-effe-4982-b382-1a1f70670932">


### How to 🎩

🖥 [Local development
instructions](https://github.com/Shopify/polaris/blob/main/README.md#local-development)
🗒 [General tophatting
guidelines](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md)
📄 [Changelog
guidelines](https://github.com/Shopify/polaris/blob/main/.github/CONTRIBUTING.md#changelog)

- Added a new story in Storybook for showing the variant.

### 🎩 checklist

- [x] Tested on
[mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing)
- [x] Tested on [multiple
browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers)
- [x] Tested for
[accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md)
- [ ] N/A Updated the component's `README.md` with documentation changes
- [x] [Tophatted
documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md)
changes in the style guide
  • Loading branch information
matallo authored Nov 1, 2023
1 parent 54dcc98 commit 460c48c
Show file tree
Hide file tree
Showing 15 changed files with 243 additions and 12 deletions.
7 changes: 7 additions & 0 deletions .changeset/fair-eggs-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@shopify/polaris': minor
---

- Added `tone` prop with `magic` value to `TextField`
- Added `tone` prop with `magic` value to `ChoiceList`
- Added `tone` prop with `magic` value to `Checkbox`
38 changes: 33 additions & 5 deletions polaris-react/src/components/Checkbox/Checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
box-shadow: inset 0 0 0 var(--p-space-050) var(--p-color-bg-fill-brand);
}

// stylelint-disable selector-max-specificity, selector-max-class -- Much easier to read the rules when written like this
// stylelint-disable selector-max-specificity, selector-max-class, selector-max-combinators, max-nesting-depth -- Much easier to read the rules when written like this
.Input {
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
@include visually-hidden;
Expand Down Expand Up @@ -62,7 +62,6 @@
transform var(--p-motion-duration-150) var(--p-motion-ease-out);
opacity: 1;

/* stylelint-disable-next-line selector-max-combinators -- need to target svg from icons package */
svg {
fill: var(--p-color-text-brand-on-bg-fill);
}
Expand All @@ -88,7 +87,6 @@
}
}

// stylelint-disable-next-line selector-max-combinators -- target disabled icon color
~ .Icon svg {
color: var(--p-color-checkbox-icon-disabled);
}
Expand All @@ -104,7 +102,37 @@
}
}
}
// stylelint-enable selector-max-specificity, selector-max-class

&.toneMagic {
+ .Backdrop {
background-color: var(--p-color-bg-surface-magic);
box-shadow: inset 0 0 0 var(--p-border-width-0165)
var(--p-color-border-magic-secondary);

.ChoiceLabel:hover & {
background-color: var(--p-color-bg-surface-magic-hover);
box-shadow: inset 0 0 0 var(--p-border-width-0165)
var(--p-color-border-magic-secondary-hover);
}
}

&:checked,
&.Input-indeterminate {
+ .Backdrop {
border-color: var(--p-color-bg-fill-magic);
background-color: var(--p-color-bg-fill-magic);
box-shadow: inset 0 0 0 var(--p-space-800) var(--p-color-bg-fill-magic);

.ChoiceLabel:hover & {
border-color: var(--p-color-bg-fill-magic);
background-color: var(--p-color-bg-fill-magic);
box-shadow: inset 0 0 0 var(--p-space-800)
var(--p-color-bg-fill-magic);
}
}
}
}
// stylelint-enable selector-max-specificity, selector-max-class, selector-max-combinators, max-nesting-depth
}

.Backdrop {
Expand Down Expand Up @@ -207,7 +235,7 @@
}
}
}
// stylelint-enable selector-max-specificity, selector-max-class, selector-max-combinators, selector-max-compound-selectors
// stylelint-enable selector-max-specificity, selector-max-class, selector-max-combinators

// stylelint-disable-next-line selector-max-combinators, selector-max-type -- override
.animated svg > path {
Expand Down
14 changes: 14 additions & 0 deletions polaris-react/src/components/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ export function Error() {
);
}

export function Magic() {
const [checked, setChecked] = useState<CheckboxState>();
const handleChange = useCallback((newChecked) => setChecked(newChecked), []);

return (
<Checkbox
label="Magic checkbox"
checked={checked}
onChange={handleChange}
tone="magic"
/>
);
}

export function WithBleedAndFill() {
const [checked1, setChecked1] = useState<CheckboxState>(false);
const [checked2, setChecked2] = useState<CheckboxState>(false);
Expand Down
7 changes: 6 additions & 1 deletion polaris-react/src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React, {
} from 'react';
import {MinusMinor} from '@shopify/polaris-icons';

import {classNames} from '../../utilities/css';
import {classNames, variationName} from '../../utilities/css';
import type {ResponsiveProp} from '../../utilities/css';
import type {ChoiceBleedProps} from '../Choice';
import {Choice, helpTextID} from '../Choice';
Expand Down Expand Up @@ -51,6 +51,8 @@ export interface CheckboxProps extends ChoiceBleedProps {
helpText?: React.ReactNode;
/** Display an error message */
error?: Error | boolean;
/** Indicates the tone of the checkbox */
tone?: 'magic';
}

export const Checkbox = forwardRef<CheckboxHandles, CheckboxProps>(
Expand All @@ -77,6 +79,7 @@ export const Checkbox = forwardRef<CheckboxHandles, CheckboxProps>(
bleedBlockEnd,
bleedInlineStart,
bleedInlineEnd,
tone,
}: CheckboxProps,
ref,
) {
Expand Down Expand Up @@ -153,6 +156,7 @@ export const Checkbox = forwardRef<CheckboxHandles, CheckboxProps>(
const inputClassName = classNames(
styles.Input,
isIndeterminate && styles['Input-indeterminate'],
tone && styles[variationName('tone', tone)],
);

const extraChoiceProps = {
Expand All @@ -173,6 +177,7 @@ export const Checkbox = forwardRef<CheckboxHandles, CheckboxProps>(
disabled={disabled}
labelClassName={classNames(styles.ChoiceLabel, labelClassName)}
fill={fill}
tone={tone}
{...extraChoiceProps}
>
<span className={wrapperClassName}>
Expand Down
4 changes: 4 additions & 0 deletions polaris-react/src/components/Choice/Choice.scss
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@
}
}

.toneMagic > .Label {
color: var(--p-color-text-magic);
}

.disabled + .Descriptions {
// the <Text/> component in the HelpText markup in Choice.tsx is set to `undefined` when the disabled prop is true
// Which tells it to inherit whatever color we specify here.
Expand Down
5 changes: 5 additions & 0 deletions polaris-react/src/components/Choice/Choice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getResponsiveValue,
classNames,
sanitizeCustomProperties,
variationName,
} from '../../utilities/css';
import type {ResponsiveProp} from '../../utilities/css';
import type {Error} from '../../types';
Expand Down Expand Up @@ -70,6 +71,8 @@ interface ChoiceProps extends ChoiceBleedProps {
error?: Error | boolean;
/** Additional text to aide in use. Will add a wrapping <div> */
helpText?: React.ReactNode;
/** Indicates the tone of the choice */
tone?: 'magic';
}

export function Choice({
Expand All @@ -88,11 +91,13 @@ export function Choice({
bleedBlockEnd,
bleedInlineStart,
bleedInlineEnd,
tone,
}: ChoiceProps) {
const className = classNames(
styles.Choice,
labelHidden && styles.labelHidden,
disabled && styles.disabled,
tone && styles[variationName('tone', tone)],
labelClassName,
);

Expand Down
50 changes: 50 additions & 0 deletions polaris-react/src/components/ChoiceList/ChoiceList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ export function WithError() {
);
}

export function Magic() {
const [selected, setSelected] = useState(['hidden']);

const handleChange = useCallback((value) => setSelected(value), []);

return (
<ChoiceList
title="Company name"
choices={[
{label: 'Hidden', value: 'hidden'},
{label: 'Optional', value: 'optional'},
{label: 'Required', value: 'required'},
]}
selected={selected}
onChange={handleChange}
tone="magic"
/>
);
}

export function WithMultiChoice() {
const [selected, setSelected] = useState(['hidden']);

Expand Down Expand Up @@ -74,6 +94,36 @@ export function WithMultiChoice() {
);
}

export function MagicWithMultiChoice() {
const [selected, setSelected] = useState(['hidden']);

const handleChange = useCallback((value) => setSelected(value), []);

return (
<ChoiceList
allowMultiple
title="While the customer is checking out"
choices={[
{
label: 'Use the shipping address as the billing address by default',
value: 'shipping',
helpText:
'Reduces the number of fields required to check out. The billing address can still be edited.',
},
{
label: 'Require a confirmation step',
value: 'confirmation',
helpText:
'Customers must review their order details before purchasing.',
},
]}
selected={selected}
onChange={handleChange}
tone="magic"
/>
);
}

export function WithChildrenContent() {
const [selected, setSelected] = useState(['none']);
const [textFieldValue, setTextFieldValue] = useState('');
Expand Down
4 changes: 4 additions & 0 deletions polaris-react/src/components/ChoiceList/ChoiceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export interface ChoiceListProps {
disabled?: boolean;
/** Callback when the selected choices change */
onChange?(selected: string[], name: string): void;
/** Indicates the tone of the choice list */
tone?: 'magic';
}

export function ChoiceList({
Expand All @@ -58,6 +60,7 @@ export function ChoiceList({
error,
disabled = false,
name: nameProp,
tone,
}: ChoiceListProps) {
// Type asserting to any is required for TS3.2 but can be removed when we update to 3.3
// see https://github.com/Microsoft/TypeScript/issues/28768
Expand Down Expand Up @@ -119,6 +122,7 @@ export function ChoiceList({
ariaDescribedBy={
error && describedByError ? errorTextID(finalName) : null
}
tone={tone}
/>
{children}
</Bleed>
Expand Down
15 changes: 15 additions & 0 deletions polaris-react/src/components/RadioButton/RadioButton.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@
}
}

&.toneMagic:checked:not([disabled]) + .Backdrop {
&,
.ChoiceLabel:hover & {
background-color: var(--p-color-bg-fill-magic);
border-color: var(--p-color-bg-fill-magic);
}

&::before {
&,
.ChoiceLabel:hover & {
background-color: var(--p-color-text-magic-on-bg-fill);
}
}
}

+ .Backdrop {
.ChoiceLabel:hover & {
cursor: pointer;
Expand Down
32 changes: 32 additions & 0 deletions polaris-react/src/components/RadioButton/RadioButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,38 @@ export function DisabledRadio() {
);
}

export function Magic() {
const [value, setValue] = useState('disabled');

const handleChange = useCallback(
(_checked, newValue) => setValue(newValue),
[],
);

return (
<LegacyStack vertical>
<RadioButton
label="Accounts are disabled"
helpText="Customers will only be able to check out as guests."
checked={value === 'disabled'}
id="disabled"
name="accounts"
onChange={handleChange}
tone="magic"
/>
<RadioButton
label="Accounts are optional"
helpText="Customers will be able to check out with a customer account or as a guest."
id="optional"
name="accounts"
checked={value === 'optional'}
onChange={handleChange}
tone="magic"
/>
</LegacyStack>
);
}

export function WithBleed() {
const [value1, setValue1] = useState('disabled');
const [value2, setValue2] = useState('disabled2');
Expand Down
11 changes: 9 additions & 2 deletions polaris-react/src/components/RadioButton/RadioButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {useRef, useId} from 'react';

import {classNames} from '../../utilities/css';
import {classNames, variationName} from '../../utilities/css';
import type {ResponsiveProp} from '../../utilities/css';
import {Choice, helpTextID} from '../Choice';
import type {ChoiceBleedProps} from '../Choice';
Expand Down Expand Up @@ -34,6 +34,8 @@ export interface RadioButtonProps extends ChoiceBleedProps {
fill?: ResponsiveProp<boolean>;
/** Additional text to aide in use */
helpText?: React.ReactNode;
/** Indicates the tone of the text field */
tone?: 'magic';
}

export function RadioButton({
Expand All @@ -55,6 +57,7 @@ export function RadioButton({
bleedBlockEnd,
bleedInlineStart,
bleedInlineEnd,
tone,
}: RadioButtonProps) {
const uniqId = useId();
const id = idProp ?? uniqId;
Expand All @@ -80,7 +83,10 @@ export function RadioButton({
? describedBy.join(' ')
: undefined;

const inputClassName = classNames(styles.Input);
const inputClassName = classNames(
styles.Input,
tone && styles[variationName('tone', tone)],
);

const extraChoiceProps = {
helpText,
Expand All @@ -100,6 +106,7 @@ export function RadioButton({
labelClassName={styles.ChoiceLabel}
fill={fill}
{...extraChoiceProps}
{...(checked ? {tone} : {})}
>
<span className={styles.RadioButton}>
<input
Expand Down
Loading

0 comments on commit 460c48c

Please sign in to comment.