From c01b10762eb551141abc6adffb4c240c096d7cb4 Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Tue, 3 Oct 2023 16:13:54 +1100 Subject: [PATCH] [IndexFilters] Loading spinner moved to be a suffix within the search box. --- .changeset/sixty-fishes-grin.md | 5 ++ .../src/components/Filters/Filters.scss | 9 ---- .../src/components/Filters/Filters.tsx | 19 ++------ .../components/SearchField/SearchField.scss | 24 ++++++++-- .../components/SearchField/SearchField.tsx | 46 +++++++++++++------ .../IndexFilters/IndexFilters.stories.tsx | 25 +++++++++- 6 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 .changeset/sixty-fishes-grin.md diff --git a/.changeset/sixty-fishes-grin.md b/.changeset/sixty-fishes-grin.md new file mode 100644 index 00000000000..c56b4f1e39f --- /dev/null +++ b/.changeset/sixty-fishes-grin.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': patch +--- + +[IndexFilters] Loading spinner moved to be a suffix within the search box. diff --git a/polaris-react/src/components/Filters/Filters.scss b/polaris-react/src/components/Filters/Filters.scss index dc445d3b28c..9d12b514c0e 100644 --- a/polaris-react/src/components/Filters/Filters.scss +++ b/polaris-react/src/components/Filters/Filters.scss @@ -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; diff --git a/polaris-react/src/components/Filters/Filters.tsx b/polaris-react/src/components/Filters/Filters.tsx index 0b98b65c6d3..332fd9bec75 100644 --- a/polaris-react/src/components/Filters/Filters.tsx +++ b/polaris-react/src/components/Filters/Filters.tsx @@ -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'; @@ -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'; @@ -280,17 +279,6 @@ export function Filters({ const shouldShowAddButton = filters.some((filter) => !filter.pinned); - const additionalContent = useMemo(() => { - return ( - <> -
- {loading ? : null} -
- {children} - - ); - }, [loading, children]); - const containerSpacing: { paddingBlockStart: BoxProps['paddingBlockStart']; paddingBlockEnd: BoxProps['paddingBlockEnd']; @@ -335,9 +323,10 @@ export function Filters({ focused={focused} disabled={disabled || disableQueryField} borderlessQueryField={borderlessQueryField} + loading={loading} /> - {additionalContent} + {children} @@ -454,7 +443,7 @@ export function Filters({ md: '300', }} > - {additionalContent} + {children} ) : null} diff --git a/polaris-react/src/components/Filters/components/SearchField/SearchField.scss b/polaris-react/src/components/Filters/components/SearchField/SearchField.scss index 3d8e23e8c85..c8041f1a366 100644 --- a/polaris-react/src/components/Filters/components/SearchField/SearchField.scss +++ b/polaris-react/src/components/Filters/components/SearchField/SearchField.scss @@ -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); @@ -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 { @@ -54,19 +57,32 @@ outline-offset: var(--p-space-025); } -.ClearButton { +.Suffix { 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; + } +} diff --git a/polaris-react/src/components/Filters/components/SearchField/SearchField.tsx b/polaris-react/src/components/Filters/components/SearchField/SearchField.tsx index edb5e3d1df5..d8abf95b977 100644 --- a/polaris-react/src/components/Filters/components/SearchField/SearchField.tsx +++ b/polaris-react/src/components/Filters/components/SearchField/SearchField.tsx @@ -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'; @@ -19,6 +21,8 @@ export interface SearchFieldProps { placeholder?: string; disabled?: boolean; borderlessQueryField?: boolean; + /** Show a loading spinner to the right of the input */ + loading?: boolean; } export function SearchField({ @@ -31,6 +35,7 @@ export function SearchField({ placeholder, disabled, borderlessQueryField, + loading, }: SearchFieldProps) { const i18n = useI18n(); const id = useId(); @@ -72,21 +77,32 @@ export function SearchField({ placeholder={placeholder} disabled={disabled} /> - {value !== '' && ( - handleClear()} - disabled={disabled} - > - - {i18n.translate('Polaris.Common.clear')} - - - - )} + {loading || value !== '' ? ( +
+ + {loading ? ( +
+ +
+ ) : null} + {value !== '' ? ( + handleClear()} + disabled={disabled} + > + + {i18n.translate('Polaris.Common.clear')} + + + + ) : null} +
+
+ ) : null} ); } diff --git a/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx b/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx index 0f4f3d943b0..d9782cab155 100644 --- a/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx +++ b/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx @@ -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 { @@ -224,6 +224,23 @@ function BasicExample( const [moneySpent, setMoneySpent] = useState(null); const [taggedWith, setTaggedWith] = useState(''); const [queryValue, setQueryValue] = useState(''); + const [uncontrolledLoading, setLoading] = useState(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), @@ -344,7 +361,7 @@ function BasicExample( ; } +export function WithLoading() { + return ; +} + export function WithPinnedFilters() { const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));