Skip to content

Commit

Permalink
Stepper prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
lilywuyanru committed May 6, 2024
1 parent 7c93793 commit 0627ee9
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-points-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': major
---

Stepper prototype
66 changes: 50 additions & 16 deletions polaris-react/src/components/TextField/TextField.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
fill: var(--p-color-icon-secondary);
}

.disabledSpinnerButton svg {
fill: var(--p-color-icon-disabled);
}

/* only show the clear button when focused within the textfield */
&:focus-within {
.ClearButton {
Expand Down Expand Up @@ -525,6 +529,20 @@
}
}

.MobileStepper {
/* stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY */
z-index: var(--pc-text-field-contents);
margin: var(--p-space-100);
color: var(--p-color-icon);
visibility: visible;
display: flex;
align-self: stretch;
cursor: pointer;
flex-direction: row-reverse;
width: 90px;
gap: var(--p-space-100);
}

.Spinner {
/* stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY */
z-index: var(--pc-text-field-contents);
Expand Down Expand Up @@ -580,43 +598,59 @@
}

.Segment {
background: var(--p-color-bg-fill-tertiary);
border-radius: var(--p-border-radius-100);
background: var(--p-color-bg-fill-secondary);
border-radius: var(--p-border-radius-200);
display: flex;
flex: 1 1 0%;
justify-content: center;
align-items: center;
appearance: none;
border: none;

&:hover {
background: var(--p-color-bg-fill-tertiary-hover);
@media (--p-breakpoints-md-up) {
background: var(--p-color-bg-fill-tertiary);
border-radius: var(--p-border-radius-100);
}

&:focus {
outline: none;
}

&:active {
background: var(--p-color-bg-fill-tertiary-active);
background: var(--p-color-bg-fill-secondary-active);
}

&:first-child {
margin-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
@media (--p-breakpoints-md-up) {
&:hover {
background: var(--p-color-bg-fill-tertiary-hover);
}
&:active {
background: var(--p-color-bg-fill-tertiary-active);
}
&:first-child {
margin-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}

&:last-child {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
&:last-child {
border-top-left-radius: 0;
border-top-right-radius: 0;
}

&:not(:first-child) {
margin-top: 0;
&:not(:first-child) {
margin-top: 0;
}
}
}

.disabledSpinnerButton {
background: var(--p-color-bg-fill-disabled);
color: var(--pc-button-color_disabled);
user-select: none;
pointer-events: none;
}

.monospaced {
font-family: var(--p-font-family-mono);
}
12 changes: 12 additions & 0 deletions polaris-react/src/components/TextField/TextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export const Number = {
value={value}
onChange={handleChange}
autoComplete="off"
min={1}
max={5}
/>
<TextField
label="Second Quantity"
Expand All @@ -124,6 +126,16 @@ export const Number = {
onChange={handleChange1}
autoComplete="off"
/>
<TextField
label="Third Quantity"
labelHidden
type="number"
value={value}
onChange={handleChange}
autoComplete="off"
min={1}
max={5}
/>
</LegacyStack>
);
},
Expand Down
10 changes: 10 additions & 0 deletions polaris-react/src/components/TextField/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {useIsMobileFormsInline} from '../../utilities/use-is-mobile-forms-inline
import {Resizer, Spinner} from './components';
import type {SpinnerProps} from './components';
import styles from './TextField.module.css';
import {useSpinner} from './components/Spinner/useSpinner';

type Type =
| 'text'
Expand Down Expand Up @@ -335,6 +336,13 @@ export function TextField({
const isNumericType = type === 'number' || type === 'integer';
const iconPrefix = React.isValidElement(prefix) && prefix.type === Icon;

const {canDecrement, canIncrement} = useSpinner({
value: isNumericType ? Number(value) : null,
minValue: min ? Number(min) : undefined,
maxValue: max ? Number(max) : undefined,
disabled,
});

const prefixMarkup = prefix ? (
<div
className={classNames(styles.Prefix, iconPrefix && styles.PrefixIcon)}
Expand Down Expand Up @@ -487,6 +495,8 @@ export function TextField({
const spinnerMarkup =
isNumericType && step !== 0 && !disabled && !readOnly ? (
<Spinner
canIncrement={canIncrement}
canDecrement={canDecrement}
onClick={handleClickChild}
onChange={handleNumberChange}
onMouseDown={handleSpinnerButtonPress}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React from 'react';
import {ChevronDownIcon, ChevronUpIcon} from '@shopify/polaris-icons';
import {
ChevronDownIcon,
ChevronUpIcon,
MinusIcon,
PlusIcon,
} from '@shopify/polaris-icons';

import {Icon} from '../../../Icon';
import styles from '../../TextField.module.css';
import {useBreakpoints} from '../../../../utilities/breakpoints';
import {classNames} from '../../../../utilities/css';

type HandleStepFn = (step: number) => void;

export interface SpinnerProps {
canIncrement: boolean;
canDecrement: boolean;
onChange: HandleStepFn;
onClick?(event: React.MouseEvent): void;
onMouseDown(onChange: HandleStepFn): void;
Expand All @@ -15,7 +24,18 @@ export interface SpinnerProps {
}

export const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
function Spinner({onChange, onClick, onMouseDown, onMouseUp, onBlur}, ref) {
function Spinner(
{
canDecrement,
canIncrement,
onChange,
onClick,
onMouseDown,
onMouseUp,
onBlur,
},
ref,
) {
function handleStep(step: number) {
return () => onChange(step);
}
Expand All @@ -27,32 +47,49 @@ export const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
};
}

const {mdDown} = useBreakpoints();
const increaseIconSource = mdDown ? PlusIcon : ChevronUpIcon;
const decreaseIconSource = mdDown ? MinusIcon : ChevronDownIcon;
const isIncrementDisabled = mdDown && !canIncrement;
const isDecrementDisabled = mdDown && !canDecrement;

return (
<div className={styles.Spinner} onClick={onClick} aria-hidden ref={ref}>
<div
className={mdDown ? styles.MobileStepper : styles.Spinner}
onClick={onClick}
aria-hidden
ref={ref}
>
<div
role="button"
className={styles.Segment}
className={classNames(
styles.Segment,
isIncrementDisabled && styles.disabledSpinnerButton,
)}
tabIndex={-1}
onClick={handleStep(1)}
onMouseDown={handleMouseDown(handleStep(1))}
onMouseUp={onMouseUp}
onBlur={onBlur}
>
<div className={styles.SpinnerIcon}>
<Icon source={ChevronUpIcon} />
<Icon source={increaseIconSource} />
</div>
</div>
<div
role="button"
className={styles.Segment}
className={classNames(
styles.Segment,
isDecrementDisabled && styles.disabledSpinnerButton,
)}
tabIndex={-1}
onClick={handleStep(-1)}
onMouseDown={handleMouseDown(handleStep(-1))}
onMouseUp={onMouseUp}
onBlur={onBlur}
>
<div className={styles.SpinnerIcon}>
<Icon source={ChevronDownIcon} />
<Icon source={decreaseIconSource} />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
interface Props {
value: number | null;
minValue?: number;
maxValue?: number;
disabled?: boolean;
}

interface Value {
canDecrement: boolean;
canIncrement: boolean;
}

export function useSpinner({
value,
minValue,
maxValue,
disabled,
}: Props): Value {
const isDisabled = disabled === true || value === null;

const canDecrement = isDisabled ? false : value > (minValue ?? -Infinity);
const canIncrement = isDisabled ? false : value < (maxValue ?? Infinity);

return {
canDecrement,
canIncrement,
};
}

0 comments on commit 0627ee9

Please sign in to comment.