Skip to content

Commit

Permalink
Merge branch 'main' into FCT-1186-data-table-manager-custom-configura…
Browse files Browse the repository at this point in the history
…tions-story
  • Loading branch information
ddouglasz authored Oct 9, 2024
2 parents 877a0cc + 9ab30bc commit 8f6c687
Show file tree
Hide file tree
Showing 14 changed files with 1,047 additions and 36 deletions.
1 change: 1 addition & 0 deletions design-system/materials/custom-properties.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
--shadow-16: 0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25),
-0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25);
--shadow-17: 0 1px 5px 0 rgba(0, 0, 0, 0.05);
--shadow-18: 0 5px 30px 0px rgba(0, 0, 0, 0.1);
--constraint-scale: 100%;
--constraint-1: 42px;
--constraint-2: 84px;
Expand Down
1 change: 1 addition & 0 deletions design-system/materials/custom-properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
"--shadow-15": "0 2px 2px rgba(0, 0, 0, 0.24), 0 1px 4.75px rgba(0, 0, 0, 0.12)",
"--shadow-16": "0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25), -0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25)",
"--shadow-17": "0 1px 5px 0 rgba(0, 0, 0, 0.05)",
"--shadow-18": "0 5px 30px 0px rgba(0, 0, 0, 0.1)",
"--constraint-scale": "100%",
"--constraint-1": "42px",
"--constraint-2": "84px",
Expand Down
1 change: 1 addition & 0 deletions design-system/materials/custom-properties_default.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
--shadow-16: 0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25),
-0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25);
--shadow-17: 0 1px 5px 0 rgba(0, 0, 0, 0.05);
--shadow-18: 0 5px 30px 0px rgba(0, 0, 0, 0.1);
--constraint-scale: 100%;
--constraint-1: 42px;
--constraint-2: 84px;
Expand Down
1 change: 1 addition & 0 deletions design-system/materials/internals/definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ choiceGroupsByTheme:
shadow-15: '0 2px 2px rgba(0, 0, 0, 0.24), 0 1px 4.75px rgba(0, 0, 0, 0.12)'
shadow-16: '0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25), -0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25)'
shadow-17: '0 1px 5px 0 rgba(0, 0, 0, 0.05)'
shadow-18: '0 5px 30px 0px rgba(0, 0, 0, 0.1)'
constraints:
label: Constraints
prefix: constraint
Expand Down
2 changes: 2 additions & 0 deletions design-system/src/design-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export const themes = {
shadow16:
'0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25), -0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25)',
shadow17: '0 1px 5px 0 rgba(0, 0, 0, 0.05)',
shadow18: '0 5px 30px 0px rgba(0, 0, 0, 0.1)',
constraintScale: '100%',
constraint1: '42px',
constraint2: '84px',
Expand Down Expand Up @@ -396,6 +397,7 @@ const designTokens = {
shadow16:
'var(--shadow-16, 0.5px 1.5px 4px 1px rgba(0, 0, 0, 0.25), -0.5px -0.5px 4px 1px rgba(0, 0, 0, 0.25))',
shadow17: 'var(--shadow-17, 0 1px 5px 0 rgba(0, 0, 0, 0.05))',
shadow18: 'var(--shadow-18, 0 5px 30px 0px rgba(0, 0, 0, 0.1))',
constraintScale: 'var(--constraint-scale, 100%)',
constraint1: 'var(--constraint-1, 42px)',
constraint2: 'var(--constraint-2, 84px)',
Expand Down
4 changes: 4 additions & 0 deletions packages/components/filters/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
"dependencies": {
"@babel/runtime": "^7.20.13",
"@babel/runtime-corejs3": "^7.20.13",
"@commercetools-uikit/constraints": "workspace:^",
"@commercetools-uikit/design-system": "workspace:^",
"@commercetools-uikit/dropdown-menu": "workspace:^",
"@commercetools-uikit/icons": "workspace:^",
"@commercetools-uikit/secondary-icon-button": "workspace:^",
"@commercetools-uikit/utils": "workspace:^",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@radix-ui/react-popover": "^1.1.2",
"prop-types": "15.8.1",
"react-intl": "^6.3.2"
},
Expand Down
36 changes: 28 additions & 8 deletions packages/components/filters/src/filter-menu/filter-menu.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
import { screen, render } from '../../../../../test/test-utils';
import FilterMenu from './filter-menu';
import FilterMenu, { type TFilterMenuProps } from './filter-menu';

/**
* THIS IS A PLACEHOLDER, PLEASE UPDATE IT
*/
describe('FilterMenu FilterMenu', () => {
it('should render the filter-menu', async () => {
await render(<FilterMenu label="filter menu" />);
await screen.findByText('filter menu');
const mockRenderMenuBody = jest.fn(() => <div>im the body</div>);
const mockOnRemoveRequest = jest.fn();

const getDefaultProps = (custom?: Partial<TFilterMenuProps>) => ({
filterKey: 'test',
label: 'filter menu',
renderMenuBody: mockRenderMenuBody,
appliedFilterValues: [{ label: 'hello', value: 'hello' }],
mockOnRemoveRequest: mockOnRemoveRequest,
...custom,
});

describe('FilterMenu component', () => {
it('should render the FilterMenu label', async () => {
const props = getDefaultProps();
await render(<FilterMenu {...props} />);
await screen.findByText('filter menu:');
});
it('should open the menu body when defaultOpen is true', async () => {
const props = getDefaultProps({ defaultOpen: true });
await render(<FilterMenu {...props} />);
await screen.findByText('im the body');
});
it('should not open the menu body when isDisabled and defaultOpen are true', async () => {
const props = getDefaultProps({ defaultOpen: true, isDisabled: true });
await render(<FilterMenu {...props} />);
expect(screen.queryByText('im the body')).not.toBeInTheDocument();
});
});
100 changes: 93 additions & 7 deletions packages/components/filters/src/filter-menu/filter-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,106 @@
import DropdownMenu from '@commercetools-uikit/dropdown-menu';
import { type ReactNode } from 'react';
import { css } from '@emotion/react';
import Constraints from '@commercetools-uikit/constraints';
import { designTokens } from '@commercetools-uikit/design-system';
import * as Popover from '@radix-ui/react-popover';
import { Footer } from './footer';
import { Header } from './header';
import { TriggerButton } from './trigger-button';

export type TAppliedFilterValue = {
value: string;
label: ReactNode;
};

export type TFilterMenuProps = {
/**
* This is a stub prop!
* unique identifier for the filter
*/
filterKey: string;
/**
* formatted message to display the filter's name
*/
label: string;
label: ReactNode;
/**
* the input in which the user selects values for the filter
*/
renderMenuBody: () => ReactNode;
/**
* the input in which the user can select which operator should be used for this filter
*/
renderOperatorsInput?: () => ReactNode;
/**
* the values applied to this filter by the user
*/
appliedFilterValues: TAppliedFilterValue[] | undefined | null;
/**
* indicates whether FilterMenu can be removed from the filtersList
*/
isPersistent?: boolean;
/**
* whether or not the filter is disabled
*/
isDisabled?: boolean;
/**
* controls whether `x` in Trigger Button is displayed - required if `isPersistent` is `false`
*/
onRemoveRequest?: Function;
/**
* optional button that allows the user to apply selected filter values
*/
renderApplyButton?: () => ReactNode;
/**
* controls whether `clear` button in Menu Body Footer is displayed
*/
onClearRequest?: Function;
/**
* controls whether `sort` button in Menu Body Header is displayed
*/
onSortRequest?: Function;
/**
* controls whether menu is open on initial render
*/
defaultOpen?: boolean;
};

const menuStyles = css`
display: flex;
flex-direction: column;
align-items: flex-start;
gap: ${designTokens.spacing30};
width: ${Constraints.getMaxPropTokenValue(6)};
padding: ${designTokens.spacing20} ${designTokens.spacing30};
background-color: ${designTokens.colorSurface};
border: 1px solid ${designTokens.colorSurface};
border-radius: ${designTokens.borderRadius8};
box-shadow: ${designTokens.shadow18};
animation-duration: ${designTokens.transitionStandard};
will-change: 'transform, opacity';
margin-top: ${designTokens.spacing10};
position: relative;
z-index: 5;
`;
function FilterMenu(props: TFilterMenuProps) {
return (
<DropdownMenu triggerElement={<TriggerButton label={props.label} />}>
<Header />
<Footer />
</DropdownMenu>
<Popover.Root defaultOpen={props.isDisabled ? false : props.defaultOpen}>
<Popover.Trigger asChild>
<TriggerButton
filterKey={props.filterKey}
label={props.label}
appliedFilterValues={props.appliedFilterValues}
isDisabled={props.isDisabled}
isPersistent={props.isPersistent}
onRemoveRequest={props.onRemoveRequest}
/>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content side="bottom" align="start" css={menuStyles}>
<Header />
<div>{props.renderMenuBody()}</div>
<Footer />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,92 @@
import { screen, render } from '../../../../../../test/test-utils';
import TriggerButton from './trigger-button';
import { screen, render, fireEvent } from '../../../../../../test/test-utils';
import TriggerButton, {
type TFilterMenuTriggerButtonProps,
} from './trigger-button';

const mockOnRemoveRequest = jest.fn();

const getDefaultProps = (custom?: Partial<TFilterMenuTriggerButtonProps>) => ({
filterKey: 'test-key',
label: 'test',
appliedFilterValues: [{ label: 'cool test phrase', value: 'testPhrase' }],
onRemoveRequest: mockOnRemoveRequest,
...custom,
});

/**
* THIS IS A PLACEHOLDER, PLEASE UPDATE IT
*/
describe('FilterMenu Trigger Button', () => {
it('should render the trigger button', async () => {
await render(<TriggerButton label="trigger button" />);
await screen.findByText(/trigger button/i);
it('should render the label', async () => {
const props = getDefaultProps();
await render(<TriggerButton {...props} />);
await screen.findByLabelText(/test:/i);
});

describe('when there are no applied filter values', () => {
it('should render the CaretDownIcon', async () => {
const props = getDefaultProps({ appliedFilterValues: undefined });
await render(<TriggerButton {...props} />);
await screen.findByLabelText('toggle filter menu icon');
});
it('should render the CaretDownIcon if isPersistent is true', async () => {
const props = getDefaultProps({
appliedFilterValues: undefined,
isPersistent: true,
});
await render(<TriggerButton {...props} />);
await screen.findByLabelText('toggle filter menu icon');
});
it('should not render a remove button', async () => {
const props = getDefaultProps({ appliedFilterValues: undefined });
await render(<TriggerButton {...props} />);
await screen.findByLabelText(/test:/i);
expect(
screen.queryByRole('button', { name: 'remove test filter' })
).not.toBeInTheDocument();
});
});

describe('when there are applied filter values', () => {
it('should not render the CaretDownIcon', async () => {
const props = getDefaultProps();
await render(<TriggerButton {...props} />);
await screen.findByLabelText(/test:/i);
expect(
screen.queryByLabelText('toggle filter menu icon')
).not.toBeInTheDocument();
});
it('should render a remove button', async () => {
const props = getDefaultProps();
await render(<TriggerButton {...props} />);
await screen.findByRole('button', { name: 'remove test filter' });
});
it('should call onRemoveRequest when remove button is clicked', async () => {
const props = getDefaultProps();
await render(<TriggerButton {...props} />);
const removeButton = await screen.findByRole('button', {
name: 'remove test filter',
});
fireEvent.click(removeButton);
expect(mockOnRemoveRequest).toHaveBeenCalled();
});
it('should not render a remove button if isPersistent is true', async () => {
const props = getDefaultProps({ isPersistent: true });
await render(<TriggerButton {...props} />);
await screen.findByLabelText(/test:/i);
expect(
screen.queryByRole('button', { name: 'remove test filter' })
).not.toBeInTheDocument();
});
});

describe('when disabled', () => {
it('should apply the proper attributes to the main action (overlay) button', async () => {
const props = getDefaultProps({ isDisabled: true });
await render(<TriggerButton {...props} />);
const overlayButton = await screen.findByRole('button', {
name: 'test:',
});
expect(overlayButton).toHaveAttribute('disabled');
expect(overlayButton).toHaveAttribute('readonly');
expect(overlayButton).toHaveAttribute('tabindex', '-1');
});
});
});
Loading

0 comments on commit 8f6c687

Please sign in to comment.