Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow any icon prop to also pass partial iconProps #1104

Merged
merged 7 commits into from
Jul 16, 2024
23 changes: 23 additions & 0 deletions packages/snap-preact-demo/tests/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ Cypress.Commands.add('snapController', (controllerId = 'search', options) => {
});
});

Cypress.Commands.add('snapController', (controllerId = 'search', options) => {
const defaultOptions = {
delay: 300,
};

const mergedOptions = { ...defaultOptions, ...options };
return cy.wait(mergedOptions.delay).then(() => {
return cy.window().then((window) => {
return new Cypress.Promise((resolve) => {
const checkTimeout = 150;
const interval = setInterval(() => {
if (window.searchspring?.controller && window.searchspring.controller[controllerId]) {
if (!window.searchspring.controller[controllerId].store.loading) {
clearInterval(interval);
resolve(window.searchspring.controller[controllerId]);
}
}
}, checkTimeout);
});
});
});
});

Cypress.Commands.add('waitForBundle', () => {
return cy.window().then((window) => {
return new Cypress.Promise((resolve) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ComponentProps, StylingCSS } from '../../../types';
import { Theme, useTheme, CacheProvider } from '../../../providers';
import { useA11y } from '../../../hooks/useA11y';
import { defined, mergeProps } from '../../../utilities';
import { Icon, IconProps } from '../Icon';
import { Icon, IconProps, IconType } from '../Icon';

const CSS = {
button: ({ color, backgroundColor, borderColor, theme }: Partial<ButtonProps>) =>
Expand Down Expand Up @@ -93,13 +93,13 @@ export const Button = observer((properties: ButtonProps): JSX.Element => {
<button {...elementProps}>
{content}
{children}
{icon && <Icon icon={icon} {...subProps.icon} />}
{icon && <Icon {...subProps.icon} {...(typeof icon == 'string' ? { icon: icon } : (icon as Partial<IconProps>))} />}
</button>
) : (
<div {...(!disableA11y ? a11yProps : {})} {...elementProps} role={'button'} aria-disabled={disabled}>
{content}
{children}
{icon && <Icon icon={icon} {...subProps.icon} />}
{icon && <Icon {...subProps.icon} {...(typeof icon == 'string' ? { icon: icon } : (icon as Partial<IconProps>))} />}
</div>
)}
</CacheProvider>
Expand All @@ -116,7 +116,7 @@ export interface ButtonProps extends ComponentProps {
backgroundColor?: string;
borderColor?: string;
color?: string;
icon?: string;
icon?: IconType | Partial<IconProps>;
content?: string | JSX.Element;
children?: ComponentChildren;
disabled?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function Icon(properties: IconProps): JSX.Element {

const { color, icon, path, children, size, width, height, viewBox, disableStyles, className, style, styleScript, ...otherProps } = props;

const iconPath = iconPaths[icon as keyof typeof iconPaths] || path;
const iconPath = iconPaths[icon as IconType] || path;
const pathType = typeof iconPath;
const styling: { css?: StylingCSS } = {};
const stylingProps = props;
Expand Down Expand Up @@ -79,7 +79,7 @@ export type SVGPathElement = {

export interface IconProps extends ComponentProps {
color?: string;
icon?: IconType | string;
icon?: IconType;
path?: string | SVGPathElement[];
children?: ComponentChildren;
size?: string | number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { observer } from 'mobx-react';
import { ComponentProps, StylingCSS } from '../../../types';
import { defined, mergeProps } from '../../../utilities';
import { Theme, useTheme, CacheProvider } from '../../../providers';
import { Icon, IconProps } from '../../Atoms/Icon';
import { Icon, IconProps, IconType } from '../../Atoms/Icon';
import { useA11y } from '../../../hooks/useA11y';

const CSS = {
Expand Down Expand Up @@ -142,7 +142,11 @@ export const Checkbox = observer((properties: CheckboxProps): JSX.Element => {
role="checkbox"
aria-checked={checkedState}
>
{checkedState ? <Icon {...subProps.icon} /> : <span className="ss__checkbox__empty" />}
{checkedState ? (
<Icon {...subProps.icon} {...(typeof icon == 'string' ? { icon: icon } : (icon as Partial<IconProps>))} />
) : (
<span className="ss__checkbox__empty" />
)}
</span>
)}
</CacheProvider>
Expand All @@ -156,7 +160,7 @@ export interface CheckboxProps extends ComponentProps {
checked?: boolean;
color?: string;
disabled?: boolean;
icon?: string;
icon?: IconType | Partial<IconProps>;
iconColor?: string;
onClick?: (e: React.MouseEvent<HTMLInputElement | HTMLSpanElement, MouseEvent>) => void;
size?: string | number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { defined, mergeProps } from '../../../utilities';
import { Theme, useTheme, CacheProvider } from '../../../providers';
import { ComponentProps, StylingCSS } from '../../../types';
import { Button, ButtonProps } from '../../Atoms/Button';
import { Icon, IconProps } from '../../Atoms/Icon';
import { Icon, IconProps, IconType } from '../../Atoms/Icon';
import type { Filter as FilterType } from '@searchspring/snap-store-mobx';
import type { UrlManager } from '@searchspring/snap-url-manager';

Expand Down Expand Up @@ -97,7 +97,7 @@ export const Filter = observer((properties: FilterProps): JSX.Element => {
href={link?.href}
>
<Button {...subProps.button} disableA11y={true}>
<Icon {...subProps.icon} />
<Icon {...subProps.icon} {...(typeof icon == 'string' ? { icon: icon } : (icon as Partial<IconProps>))} />
{!hideFacetLabel && (
<span className="ss__filter__label">
{label}
Expand All @@ -120,7 +120,7 @@ export interface FilterProps extends ComponentProps {
url?: UrlManager;
hideFacetLabel?: boolean;
onClick?: (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
icon?: string;
icon?: IconType | Partial<IconProps>;
separator?: string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,7 @@ export function List(properties: ListProps): JSX.Element {
{!hideOptionCheckboxes && <Checkbox {...subProps.checkbox} checked={selected} disableA11y={true} />}

{option.icon && !hideOptionIcons && (
<Icon
{...subProps.icon}
{...(typeof option.icon == 'string' ? { icon: option.icon as string } : (option.icon as Partial<IconProps>))}
/>
<Icon {...subProps.icon} {...(typeof option.icon == 'string' ? { icon: option.icon } : (option.icon as Partial<IconProps>))} />
)}

{!hideOptionLabels && (option.label || !option.icon) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useIntersection } from '../../../hooks';
import type { SearchPaginationStore } from '@searchspring/snap-store-mobx';
import type { SearchController } from '@searchspring/snap-controller';
import { Button, ButtonProps } from '../../Atoms/Button';
import { Icon, IconProps } from '../../Atoms/Icon';
import { Icon, IconProps, IconType } from '../../Atoms/Icon';
import { useFuncDebounce } from '../../../hooks';

const CSS = {
Expand Down Expand Up @@ -252,10 +252,16 @@ export const LoadMore = observer((properties: LoadMoreProps): JSX.Element => {
{...subProps.button}
>
{loadMoreText}
{loadingIcon && isLoading && loadingLocation === 'button' ? <Icon icon={loadingIcon} {...subProps.icon}></Icon> : <Fragment></Fragment>}
{loadingIcon && isLoading && loadingLocation === 'button' ? (
<Icon {...subProps.icon} {...(typeof loadingIcon == 'string' ? { icon: loadingIcon } : (loadingIcon as Partial<IconProps>))} />
) : (
<Fragment></Fragment>
)}
</Button>

{loadingLocation === 'outside' && isLoading && <Icon icon={loadingIcon} {...subProps.icon}></Icon>}
{loadingIcon && isLoading && loadingLocation === 'outside' && (
<Icon {...subProps.icon} {...(typeof loadingIcon == 'string' ? { icon: loadingIcon } : (loadingIcon as Partial<IconProps>))} />
)}
</Fragment>
)}

Expand Down Expand Up @@ -325,7 +331,7 @@ export interface LoadMoreProps extends ComponentProps {
progressIndicatorSize?: string;
hideProgressIndicator?: boolean;
hideProgressText?: boolean;
loadingIcon?: string;
loadingIcon?: IconType | Partial<IconProps>;
loadingLocation?: 'button' | 'outside';
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite';
import { ComponentProps, StylingCSS } from '../../../types';
import { defined, mergeProps } from '../../../utilities';
import { Theme, useTheme, CacheProvider } from '../../../providers';
import { Icon, IconProps } from '../../Atoms/Icon';
import { Icon, IconProps, IconType } from '../../Atoms/Icon';
import { useA11y } from '../../../hooks/useA11y';

const CSS = {
Expand Down Expand Up @@ -47,6 +47,8 @@ export const Radio = observer((properties: RadioProps): JSX.Element => {
size: '20px',
startChecked: false,
disableA11y: false,
checkedIcon: 'bullet',
unCheckedIcon: 'bullet-o',
};

const props = mergeProps('radio', globalTheme, defaultProps, properties);
Expand All @@ -72,7 +74,6 @@ export const Radio = observer((properties: RadioProps): JSX.Element => {
activeIcon: {
// default props
className: 'ss__radio__icon--active',
icon: checkedIcon || 'bullet',
// global theme
...globalTheme?.components?.icon,
// inherited props
Expand All @@ -87,7 +88,6 @@ export const Radio = observer((properties: RadioProps): JSX.Element => {
inactiveIcon: {
// default props
className: 'ss__radio__icon--inactive',
icon: unCheckedIcon || 'bullet-o',
// global theme
...globalTheme?.components?.icon,
// inherited props
Expand Down Expand Up @@ -162,9 +162,17 @@ export const Radio = observer((properties: RadioProps): JSX.Element => {
aria-checked={checkedState}
>
{checkedState ? (
<Icon {...subProps.activeIcon} name="ss__radio__icon--active" />
<Icon
{...subProps.activeIcon}
name="ss__radio__icon--active"
{...(typeof checkedIcon == 'string' ? { icon: checkedIcon } : (checkedIcon as Partial<IconProps>))}
/>
) : (
<Icon {...subProps.inactiveIcon} name="ss__radio__icon--inactive" />
<Icon
{...subProps.inactiveIcon}
name="ss__radio__icon--inactive"
{...(typeof unCheckedIcon == 'string' ? { icon: unCheckedIcon } : (unCheckedIcon as Partial<IconProps>))}
/>
)}
</span>
)}
Expand All @@ -180,8 +188,8 @@ export interface RadioProps extends ComponentProps {
checked?: boolean;
color?: string;
disabled?: boolean;
checkedIcon?: string;
unCheckedIcon?: string;
checkedIcon?: IconType | Partial<IconProps>;
unCheckedIcon?: IconType | Partial<IconProps>;
onClick?: (e: React.MouseEvent<HTMLInputElement | HTMLSpanElement, MouseEvent>) => void;
size?: string;
startChecked?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,7 @@ export function RadioList(properties: RadioListProps): JSX.Element {
{!hideOptionRadios && <Radio {...subProps.Radio} checked={selected} disableA11y={true} />}

{option.icon && !hideOptionIcons && (
<Icon
{...subProps.Icon}
{...(typeof option.icon == 'string' ? { icon: option.icon as string } : (option.icon as Partial<IconProps>))}
/>
<Icon {...subProps.Icon} {...(typeof option.icon == 'string' ? { icon: option.icon } : (option.icon as Partial<IconProps>))} />
)}

{!hideOptionLabels && (option.label || !option.icon) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
import { Theme, useTheme, CacheProvider } from '../../../providers';
import { ComponentProps, StylingCSS } from '../../../types';
import { defined, mergeProps } from '../../../utilities';
import { Icon, IconProps } from '../../Atoms/Icon';
import { Icon, IconProps, IconType } from '../../Atoms/Icon';

const CSS = {
rating: ({}: Partial<RatingProps>) =>
Expand Down Expand Up @@ -55,7 +55,6 @@ export const Rating = observer((properties: RatingProps): JSX.Element => {
const subProps: RatingSubProps = {
fullIcon: {
// default props
icon: fullIcon,
// global theme
...globalTheme?.components?.icon,
// inherited props
Expand All @@ -67,7 +66,6 @@ export const Rating = observer((properties: RatingProps): JSX.Element => {
},
emptyIcon: {
// default props
icon: emptyIcon,
color: '#ccc',
// global theme
...globalTheme?.components?.icon,
Expand Down Expand Up @@ -113,7 +111,11 @@ export const Rating = observer((properties: RatingProps): JSX.Element => {
<div className="ss__rating__stars ss__rating__stars--empty">
{[...Array(5)].map(() => (
<span className="ss__rating__stars__star ss__rating__stars__star--empty">
<Icon name={'ss__rating__stars__star--empty'} {...subProps.emptyIcon} />
<Icon
name={'ss__rating__stars__star--empty'}
{...subProps.emptyIcon}
{...(typeof emptyIcon == 'string' ? { icon: emptyIcon } : (emptyIcon as Partial<IconProps>))}
/>
</span>
))}
</div>
Expand All @@ -127,7 +129,11 @@ export const Rating = observer((properties: RatingProps): JSX.Element => {

return (
<span className="ss__rating__stars__star ss__rating__stars__star--full" style={{ width: `${width}%` }}>
<Icon name={'ss__rating__stars__star--full'} {...subProps.fullIcon} />
<Icon
name={'ss__rating__stars__star--full'}
{...subProps.fullIcon}
{...(typeof fullIcon == 'string' ? { icon: fullIcon } : (fullIcon as Partial<IconProps>))}
/>
</span>
);
})}
Expand All @@ -154,6 +160,6 @@ export interface RatingProps extends ComponentProps {
text?: string;
alwaysRender?: boolean;
disablePartialFill?: boolean;
fullIcon?: string;
emptyIcon?: string;
fullIcon?: IconType | Partial<IconProps>;
emptyIcon?: IconType | Partial<IconProps>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,20 @@ export const Select = observer((properties: SelectProps): JSX.Element => {
<Icon
{...subProps.icon}
className="ss__select__selection__icon"
{...(typeof selection.icon == 'string' ? { icon: selection.icon as string } : (selection.icon as Partial<IconProps>))}
{...(typeof selection.icon == 'string' ? { icon: selection.icon } : (selection.icon as Partial<IconProps>))}
/>
)}
{!hideOptionLabels && <span className="ss__select__selection">{selection?.label}</span>}
</>
)}
{!hideIcon && <Icon {...subProps.icon} icon={open ? iconClose : iconOpen} />}
{!hideIcon && (
<Icon
{...subProps.icon}
{...(open
? { ...(typeof iconClose == 'string' ? { icon: iconClose } : (iconClose as Partial<IconProps>)) }
: { ...(typeof iconOpen == 'string' ? { icon: iconOpen } : (iconOpen as Partial<IconProps>)) })}
/>
)}
</Button>
}
>
Expand All @@ -304,7 +311,7 @@ export const Select = observer((properties: SelectProps): JSX.Element => {
<Icon
{...subProps.icon}
className="ss__select__select__option__icon"
{...(typeof option.icon == 'string' ? { icon: option.icon as string } : (option.icon as Partial<IconProps>))}
{...(typeof option.icon == 'string' ? { icon: option.icon } : (option.icon as Partial<IconProps>))}
/>
)}
{!hideOptionLabels && <span>{option.label}</span>}
Expand Down Expand Up @@ -336,8 +343,8 @@ export interface SelectProps extends ComponentProps {
disabled?: boolean;
hideLabelOnSelection?: boolean;
iconColor?: string;
iconClose?: IconType | string;
iconOpen?: IconType | string;
iconClose?: IconType | Partial<IconProps>;
iconOpen?: IconType | Partial<IconProps>;
label?: string | JSX.Element;
native?: boolean;
onSelect?: (e: React.ChangeEvent<HTMLSelectElement> | React.MouseEvent<HTMLElement>, option?: ListOption) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const VariantSelection = observer((properties: VariantSelectionProps): JS
className: 'ss__variant-selection__list',
multiSelect: false,
hideOptionCheckboxes: true,
onSelect: (e, option) => selection.select(option.value as string),
onSelect: (e, option) => selection.select(option.value),
selected: selection.selected,

// global theme
Expand All @@ -123,7 +123,7 @@ export const VariantSelection = observer((properties: VariantSelectionProps): JS
swatches: {
name: `ss__variant-selection__swatches--${selection.field}`,
className: 'ss__variant-selection__swatches',
onSelect: (e, option) => selection.select(option.value as string),
onSelect: (e, option) => selection.select(option.value),
selected: selection.selected,
// global theme
...globalTheme?.components?.swatches,
Expand Down
Loading
Loading