Skip to content

Commit

Permalink
[Prototype] Mobile Inline Input labels
Browse files Browse the repository at this point in the history
  • Loading branch information
ssetem committed May 9, 2024
1 parent 9833c5d commit c98a085
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/sweet-donkeys-shake.md
@@ -0,0 +1,5 @@
---
'@shopify/polaris': major
---

Introduce Inline Labels for Mobile to TextField & Select
19 changes: 16 additions & 3 deletions polaris-react/src/components/Label/Label.tsx
@@ -1,7 +1,8 @@
import React from 'react';

import {Text} from '../Text';
import {classNames} from '../../utilities/css';
import type {TextProps} from '../Text';
import {Text} from '../Text';

import styles from './Label.module.css';

Expand All @@ -14,13 +15,25 @@ export interface LabelProps {
hidden?: boolean;
/** Visual required indicator for the label */
requiredIndicator?: boolean;
/** Text variant */
variant?: TextProps['variant'];

/** Text tone*/
tone?: TextProps['tone'];
}

export function labelID(id: string) {
return `${id}Label`;
}

export function Label({children, id, hidden, requiredIndicator}: LabelProps) {
export function Label({
children,
id,
hidden,
requiredIndicator,
variant = 'bodyMd',
tone,
}: LabelProps) {
const className = classNames(styles.Label, hidden && styles.hidden);

return (
Expand All @@ -33,7 +46,7 @@ export function Label({children, id, hidden, requiredIndicator}: LabelProps) {
requiredIndicator && styles.RequiredIndicator,
)}
>
<Text as="span" variant="bodyMd">
<Text as="span" variant={variant} tone={tone}>
{children}
</Text>
</label>
Expand Down
20 changes: 20 additions & 0 deletions polaris-react/src/components/Labelled/Labelled.module.css
Expand Up @@ -26,6 +26,26 @@
margin-bottom: var(--p-space-100);
}

.LabelInside,
.LabelInsidePlaceholder {
position: relative;
.LabelWrapper {
position: absolute;
left: var(--p-space-300);
margin-bottom: 0;
z-index: var(--p-z-index-2);
}
}

.LabelInside .LabelWrapper {
top: var(--p-space-150);
}

.LabelInsidePlaceholder .LabelWrapper {
top: 50%;
transform: translateY(-50%);
}

.HelpText {
margin-top: var(--p-space-100);
}
Expand Down
8 changes: 8 additions & 0 deletions polaris-react/src/components/Labelled/Labelled.tsx
Expand Up @@ -33,6 +33,10 @@ export interface LabelledProps {
disabled?: boolean;
/** Labels signify a readOnly control */
readOnly?: boolean;

labelPosition?: 'Outside' | 'InsidePlaceholder' | 'Inside';

labelInline?: boolean;
}

export function Labelled({
Expand All @@ -46,9 +50,11 @@ export function Labelled({
requiredIndicator,
disabled,
readOnly,
labelPosition,
...rest
}: LabelledProps) {
const className = classNames(
labelPosition && styles[`Label${labelPosition}`],
labelHidden && styles.hidden,
disabled && styles.disabled,
readOnly && styles.readOnly,
Expand Down Expand Up @@ -85,6 +91,8 @@ export function Labelled({
requiredIndicator={requiredIndicator}
{...rest}
hidden={false}
variant={labelPosition === 'Inside' ? 'bodyXs' : undefined}
tone={labelPosition?.startsWith('Inside') ? 'subdued' : undefined}
>
{label}
</Label>
Expand Down
12 changes: 12 additions & 0 deletions polaris-react/src/components/Select/Select.module.css
Expand Up @@ -93,6 +93,18 @@
text-overflow: ellipsis;
}

.tallSelect {
.SelectedOption {
padding-block: var(--p-space-100);
}
&.labelInside {
.SelectedOption,
.Prefix {
padding-block-start: calc(var(--p-space-150) + var(--p-space-400));
}
}
}

.Prefix {
padding-right: var(--p-space-100);
}
Expand Down
9 changes: 8 additions & 1 deletion polaris-react/src/components/Select/Select.tsx
Expand Up @@ -9,6 +9,7 @@ import {Icon} from '../Icon';
import {Text} from '../Text';
import type {Error} from '../../types';
import {useToggle} from '../../utilities/use-toggle';
import {useBreakpoints} from '../../utilities/breakpoints';

import styles from './Select.module.css';

Expand Down Expand Up @@ -102,13 +103,18 @@ export function Select({
tone,
}: SelectProps) {
const {value: focused, toggle: toggleFocused} = useToggle(false);

const {mdDown: tallerInlineSelect} = useBreakpoints();
const uniqId = useId();
const id = idProp ?? uniqId;
const isTallSelect = tallerInlineSelect;
const labelHidden = labelInline ? true : labelHiddenProp;
const labelInsideOptOut = labelHidden || labelAction || labelInline;
const labelInside = isTallSelect && !labelInsideOptOut;

const className = classNames(
styles.Select,
isTallSelect && styles.tallSelect,
labelInside && styles.labelInside,
error && styles.error,
tone && styles[variationName('tone', tone)],
disabled && styles.disabled,
Expand Down Expand Up @@ -198,6 +204,7 @@ export function Select({
error={error}
action={labelAction}
labelHidden={labelHidden}
labelPosition={labelInside ? 'Inside' : undefined}
helpText={helpText}
requiredIndicator={requiredIndicator}
disabled={disabled}
Expand Down
18 changes: 18 additions & 0 deletions polaris-react/src/components/TextField/TextField.module.css
Expand Up @@ -322,6 +322,24 @@
}
}

.tallInput {
.Input {
padding-block: 10px;
}

&.labelInside .Input {
padding-block: 19px;
}

&.labelInside.hasValue {
.Input,
.Prefix {
padding-block-start: 28px;
padding-block-end: 10px;
}
}
}

.borderless {
.Input,
.Backdrop {
Expand Down
19 changes: 18 additions & 1 deletion polaris-react/src/components/TextField/TextField.tsx
@@ -1,3 +1,4 @@
/* eslint-disable no-nested-ternary */
import React, {
createElement,
useState,
Expand All @@ -20,6 +21,7 @@ import {Icon} from '../Icon';
import {Text} from '../Text';
import {Spinner as LoadingSpinner} from '../Spinner';
import {useEventListener} from '../../utilities/use-event-listener';
import {useBreakpoints} from '../../utilities/breakpoints';

import {Resizer, Spinner} from './components';
import type {SpinnerProps} from './components';
Expand Down Expand Up @@ -262,6 +264,11 @@ export function TextField({
const [height, setHeight] = useState<number | null>(null);
const [focus, setFocus] = useState(Boolean(focused));
const isAfterInitial = useIsAfterInitialMount();
const {mdDown: tallerInlineInputs} = useBreakpoints();
const isTallInput = tallerInlineInputs && !verticalContent;
const inlineLabelOptOut = labelHidden || labelAction || connectedLeft;
const labelInside = isTallInput && !inlineLabelOptOut;

const uniqId = useId();
const id = idProp ?? uniqId;

Expand Down Expand Up @@ -308,6 +315,8 @@ export function TextField({

const className = classNames(
styles.TextField,
isTallInput && styles.tallInput,
labelInside && styles.labelInside,
Boolean(normalizedValue) && styles.hasValue,
disabled && styles.disabled,
readOnly && styles.readOnly,
Expand Down Expand Up @@ -484,6 +493,13 @@ export function TextField({
/>
) : null;

// TODO: cleanup
const labelPosition = labelInside
? value.length > 0 || spinnerMarkup
? 'Inside'
: 'InsidePlaceholder'
: 'Outside';

const style =
multiline && height
? {
Expand Down Expand Up @@ -574,7 +590,7 @@ export function TextField({
role,
autoFocus,
value: normalizedValue,
placeholder,
placeholder: labelInside ? undefined : placeholder,
style,
autoComplete,
className: inputClassName,
Expand Down Expand Up @@ -666,6 +682,7 @@ export function TextField({
error={error}
action={labelAction}
labelHidden={labelHidden}
labelPosition={labelPosition}
helpText={helpText}
requiredIndicator={requiredIndicator}
disabled={disabled}
Expand Down

0 comments on commit c98a085

Please sign in to comment.