Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/sixty-fishes-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': patch
---

[IndexFilters] Loading spinner moved to be a suffix within the search box.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[IndexFilters] Loading spinner moved to be a suffix within the search box.
Moved the `Filters` loading spinner to the suffix of the query filter

9 changes: 0 additions & 9 deletions polaris-react/src/components/Filters/Filters.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,6 @@
flex: 1;
}

.Spinner {
width: var(--p-space-500);
transform: translateX(var(--p-space-100));

svg {
display: block;
}
}

.FiltersWrapper {
border-bottom: var(--p-border-width-025) solid var(--p-color-border-secondary);
height: 53px;
Expand Down
19 changes: 4 additions & 15 deletions polaris-react/src/components/Filters/Filters.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useState, useRef, useEffect, useMemo} from 'react';
import React, {useState, useRef, useEffect} from 'react';
import type {ReactNode} from 'react';
import {PlusMinor} from '@shopify/polaris-icons';
import type {TransitionStatus} from 'react-transition-group';
Expand All @@ -18,7 +18,6 @@ import type {
import {InlineStack} from '../InlineStack';
import type {BoxProps} from '../Box';
import {Box} from '../Box';
import {Spinner} from '../Spinner';
import {Button} from '../Button';

import {FilterPill, SearchField} from './components';
Expand Down Expand Up @@ -280,17 +279,6 @@ export function Filters({

const shouldShowAddButton = filters.some((filter) => !filter.pinned);

const additionalContent = useMemo(() => {
return (
<>
<div className={styles.Spinner}>
{loading ? <Spinner size="small" /> : null}
</div>
{children}
</>
);
}, [loading, children]);

const containerSpacing: {
paddingBlockStart: BoxProps['paddingBlockStart'];
paddingBlockEnd: BoxProps['paddingBlockEnd'];
Expand Down Expand Up @@ -335,9 +323,10 @@ export function Filters({
focused={focused}
disabled={disabled || disableQueryField}
borderlessQueryField={borderlessQueryField}
loading={loading}
/>
</div>
{additionalContent}
{children}
</InlineStack>
</Box>
</div>
Expand Down Expand Up @@ -454,7 +443,7 @@ export function Filters({
md: '300',
}}
>
{additionalContent}
{children}
</InlineStack>
</Box>
) : null}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@import '../../../../styles/common';

.SearchField {
// stylelint-disable-next-line -- Polaris component custom properties
--pc-indexfilter-search-padding-inline: var(--p-space-150);
position: relative;
display: flex;
padding-block: var(--p-space-025);
Expand All @@ -19,7 +21,8 @@
border: var(--p-border-width-025) solid var(--p-color-input-border);
border-radius: var(--p-border-radius-100);
border-color: var(--p-color-input-border);
padding-inline: var(--p-space-150);
// stylelint-disable-next-line -- Polaris component custom properties
padding-inline: var(--pc-indexfilter-search-padding-inline);
width: 100%;

&:hover {
Expand Down Expand Up @@ -54,19 +57,32 @@
outline-offset: var(--p-space-025);
}

.ClearButton {
.Suffix {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

position: absolute;
top: 50%;
right: 0;
// stylelint-disable-next-line -- Polaris component custom properties
right: var(--pc-indexfilter-search-padding-inline);
transform: translateY(-50%);
}

.ClearButton {
background: none;
border: none;
transform: translateY(-50%);
opacity: 0;
transition: opacity var(--p-motion-duration-150) var(--p-motion-ease-in-out);
cursor: pointer;
padding: 0;
}

.ClearButton-focused {
opacity: 1;
pointer-events: auto;
}

.Spinner {
width: var(--p-space-500);

svg {
display: block;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, {useEffect, useRef, useId} from 'react';
import {CircleCancelMinor} from '@shopify/polaris-icons';

import {InlineStack} from '../../../InlineStack';
import {Spinner} from '../../../Spinner';
import {Text} from '../../../Text';
import {classNames} from '../../../../utilities/css';
import {Icon} from '../../../Icon';
Expand All @@ -19,6 +21,8 @@ export interface SearchFieldProps {
placeholder?: string;
disabled?: boolean;
borderlessQueryField?: boolean;
/** Show a loading spinner to the right of the input */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** Show a loading spinner to the right of the input */
/** Show a loading spinner to the right of the input value */

loading?: boolean;
}

export function SearchField({
Expand All @@ -31,6 +35,7 @@ export function SearchField({
placeholder,
disabled,
borderlessQueryField,
loading,
}: SearchFieldProps) {
const i18n = useI18n();
const id = useId();
Expand Down Expand Up @@ -72,21 +77,32 @@ export function SearchField({
placeholder={placeholder}
disabled={disabled}
/>
{value !== '' && (
<UnstyledButton
className={classNames(
styles.ClearButton,
focused && styles['ClearButton-focused'],
)}
onClick={() => handleClear()}
disabled={disabled}
>
<Text as="span" visuallyHidden>
{i18n.translate('Polaris.Common.clear')}
</Text>
<Icon source={CircleCancelMinor} tone="subdued" />
</UnstyledButton>
)}
{loading || value !== '' ? (
<div className={styles.Suffix}>
<InlineStack gap="200">
{loading ? (
<div className={styles.Spinner}>
<Spinner size="small" />
</div>
) : null}
{value !== '' ? (
<UnstyledButton
className={classNames(
styles.ClearButton,
focused && styles['ClearButton-focused'],
)}
onClick={() => handleClear()}
disabled={disabled}
>
<Text as="span" visuallyHidden>
{i18n.translate('Polaris.Common.clear')}
</Text>
<Icon source={CircleCancelMinor} tone="subdued" />
</UnstyledButton>
) : null}
</InlineStack>
</div>
Comment on lines +80 to +104
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the markup for each of the suffix items into variables so there aren't conditionals in the return.

const loadingMarkup = loading
  ? (
    <div className={styles.Spinner}>
      <Spinner size="small" />
    </div>
  ) : null;

const clearButtonMarkup = value !== ''
  ? (
    <UnstyledButton
      onClick={() => handleClear()}
      disabled={disabled}
      className={classNames(
        styles.ClearButton,
        focused && styles['ClearButton-focused'],
      )}
    >
      <Text as="span" visuallyHidden>
        {i18n.translate('Polaris.Common.clear')}
      </Text>
      <Icon source={CircleCancelMinor} tone="subdued" />
    </UnstyledButton>
) : null

const suffixMarkup = loading || value !== '' 
  ? (
    <div className={styles.Suffix}>
      <InlineStack gap="200">
        {loadingMarkup}
        {clearButtonMarkup}
      </InlineStack>
    </div>
  ) : null;
  
  
  ....
  ....
  

{suffixMarkup}

) : null}
</div>
);
}
25 changes: 23 additions & 2 deletions polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useState, useCallback} from 'react';
import React, {useState, useCallback, useEffect} from 'react';
import type {ComponentMeta} from '@storybook/react';
import type {TabProps} from '@shopify/polaris';
import {
Expand Down Expand Up @@ -224,6 +224,23 @@ function BasicExample(
const [moneySpent, setMoneySpent] = useState(null);
const [taggedWith, setTaggedWith] = useState('');
const [queryValue, setQueryValue] = useState('');
const [uncontrolledLoading, setLoading] = useState<boolean>(false);
const loadingIsControlled = typeof props.loading !== 'undefined';
const loading = loadingIsControlled ? props.loading : uncontrolledLoading;

// Psuedo-loading state transitions
useEffect(() => {
if (loadingIsControlled) {
return;
}
if (queryValue !== '') {
setLoading(true);
}
const timeoutId = setTimeout(() => {
setLoading(false);
}, 1500);
return () => clearTimeout(timeoutId);
}, [loadingIsControlled, queryValue]);

const handleAccountStatusChange = useCallback(
(value) => setAccountStatus(value),
Expand Down Expand Up @@ -344,7 +361,7 @@ function BasicExample(
<Card padding="0">
<IndexFilters
{...props}
loading={queryValue !== ''}
loading={loading}
sortOptions={sortOptions}
sortSelected={sortSelected}
queryValue={queryValue}
Expand Down Expand Up @@ -407,6 +424,10 @@ export function WithoutKeyboardShortcuts() {
return <BasicExample disableKeyboardShortcuts />;
}

export function WithLoading() {
return <BasicExample loading />;
}

export function WithPinnedFilters() {
const sleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
Expand Down