Skip to content
This repository was archived by the owner on Sep 30, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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