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

Dkilgore eightfold/select improvements #384

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
4 changes: 2 additions & 2 deletions src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, {
useState,
} from 'react';
import { DropdownProps } from './Dropdown.types';
import { autoUpdate, shift, useFloating } from '@floating-ui/react-dom';
import { autoUpdate, flip, shift, useFloating } from '@floating-ui/react-dom';
import { offset as fOffset } from '@floating-ui/core';
import {
ConditionalWrapper,
Expand Down Expand Up @@ -71,7 +71,7 @@ export const Dropdown: FC<DropdownProps> = React.memo(
useFloating({
placement,
strategy: positionStrategy,
middleware: [fOffset(offset), shift()],
middleware: [flip(), fOffset(offset), shift()],
});

const toggle: Function =
Expand Down
19 changes: 15 additions & 4 deletions src/components/Pills/Pill.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { FC, Ref } from 'react';
import React, { FC, Ref, useContext } from 'react';
import { PillProps, PillSize, PillType } from './Pills.types';
import { mergeClasses } from '../../shared/utilities';
import { Icon, IconName, IconSize } from '../Icon';
import DisabledContext, { Disabled } from '../ConfigProvider/DisabledContext';

import styles from './pills.module.scss';
import { ButtonSize, DefaultButton } from '../Button';
Expand All @@ -11,6 +12,11 @@ export const Pill: FC<PillProps> = React.forwardRef(
{
classNames,
color,
configContextProps = {
noDisabledContext: false,
noSizeContext: false,
},
disabled = false,
label,
iconProps,
theme = 'blue',
Expand All @@ -19,12 +25,16 @@ export const Pill: FC<PillProps> = React.forwardRef(
closeButtonProps,
pillButtonProps,
type = PillType.default,
size = PillSize.Large,
size = PillSize.Medium,
style,
...rest
},
ref: Ref<HTMLDivElement>
) => {
const contextuallyDisabled: Disabled = useContext(DisabledContext);
const mergedDisabled: boolean = configContextProps.noDisabledContext
? disabled
: contextuallyDisabled || disabled;
const pillSizeToButtonSizeMap = new Map<PillSize, ButtonSize>([
[PillSize.Large, ButtonSize.Medium],
[PillSize.Medium, ButtonSize.Small],
Expand Down Expand Up @@ -59,6 +69,7 @@ export const Pill: FC<PillProps> = React.forwardRef(
{ [styles.violetRed]: theme === 'violetRed' },
{ [styles.grey]: theme === 'grey' },
{ [styles.xsmall]: size === PillSize.XSmall },
{ [styles.tagPillsDisabled]: mergedDisabled },
]);
return (
<div
Expand All @@ -78,7 +89,7 @@ export const Pill: FC<PillProps> = React.forwardRef(
{type === PillType.withButton && (
<DefaultButton
{...pillButtonProps}
onClick={onClick}
onClick={!mergedDisabled ? onClick : null}
size={pillSizeToButtonSizeMap.get(size)}
classNames={styles.button}
/>
Expand All @@ -87,7 +98,7 @@ export const Pill: FC<PillProps> = React.forwardRef(
<DefaultButton
{...closeButtonProps}
iconProps={{ path: IconName.mdiClose }}
onClick={onClose}
onClick={!mergedDisabled ? onClose : null}
size={pillSizeToButtonSizeMap.get(size)}
classNames={styles.closeButton}
/>
Expand Down
5 changes: 5 additions & 0 deletions src/components/Pills/Pills.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ const pillArgs: Object = {
size: PillSize.Large,
type: PillType.default,
label: 'Pill label',
disabled: false,
configContextProps: {
noDisabledContext: false,
noSizeContext: false,
},
closeButtonProps: {
ariaLabel: 'Close',
},
Expand Down
12 changes: 11 additions & 1 deletion src/components/Pills/Pills.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IconProps } from '../Icon';
import { OcThemeNames } from '../ConfigProvider';
import { ButtonProps } from '../Button';
import { OcBaseProps } from '../OcBase';
import { ConfigContextProps } from '../ConfigProvider';

export enum PillType {
default = 'default',
Expand Down Expand Up @@ -43,6 +44,15 @@ export interface PillProps extends OcBaseProps<HTMLElement> {
* Custom color for the pill
*/
color?: string;
/**
* Configure how contextual props are consumed
*/
configContextProps?: ConfigContextProps;
/**
* The pill disabled state
* @default false
*/
disabled?: boolean;
/**
* Icon shown before the label
*/
Expand All @@ -66,7 +76,7 @@ export interface PillProps extends OcBaseProps<HTMLElement> {
pillButtonProps?: pillButtonProps;
/**
* Size of the pill
* @default PillType.Large
* @default PillType.Medium
*/
size?: PillSize;
/**
Expand Down
7 changes: 6 additions & 1 deletion src/components/Pills/pills.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
--hover-bg: var(--grey-color-30);
}

&:hover {
&:hover:not(.tag-pills-disabled) {
--bg: var(--hover-bg);
--label: var(--hover-label);
}
Expand Down Expand Up @@ -136,4 +136,9 @@
.icon {
margin-right: $space-xxs;
}

&-disabled {
cursor: not-allowed;
opacity: $disabled-alpha-value;
}
}
5 changes: 3 additions & 2 deletions src/components/Select/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ const Wrapper: FC<SelectProps> = ({ children }) => {

const DynamicSelect: FC<SelectProps> = (args) => {
const timer = useRef<ReturnType<typeof setTimeout>>(null);
const [options, setOptions] = useState([]);
const [options, setOptions] = useState(defaultOptions);
const [isLoading, setIsLoading] = useState(false);
const loadOptions = (searchString: string) => {
setIsLoading(true);
Expand Down Expand Up @@ -159,15 +159,16 @@ export const Basic: SelectStory = Basic_Story.bind({});
export const Dynamic_Width: SelectStory = Basic_Story.bind({});
export const With_DefaultValue: SelectStory = Basic_Story.bind({});
export const Disabled: SelectStory = Basic_Story.bind({});
export const Options_Disabled: SelectStory = Basic_Story.bind({});
export const With_Clear: SelectStory = Basic_Story.bind({});
export const Options_Disabled: SelectStory = Basic_Story.bind({});
export const Filterable: SelectStory = Basic_Story.bind({});
export const Multiple: SelectStory = Basic_Story.bind({});
export const Multiple_With_NoFilter: SelectStory = Basic_Story.bind({});
export const Dynamic: SelectStory = Dynamic_Story.bind({});

const SelectArgs: SelectProps = {
classNames: 'octuple-select-class',
disabled: false,
'data-test-id': 'octuple-select-test-id',
shape: SelectShape.Rectangle,
size: SelectSize.Medium,
Expand Down
89 changes: 83 additions & 6 deletions src/components/Select/Select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React from 'react';
import Enzyme, { mount } from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import MatchMediaMock from 'jest-matchmedia-mock';
import { SelectSize } from './Select.types';
import { SelectShape, SelectSize } from './Select.types';
import { Select, SelectOption } from './';
import { fireEvent, render } from '@testing-library/react';
import { sleep } from '../../tests/Utilities';

Enzyme.configure({ adapter: new Adapter() });

Expand Down Expand Up @@ -33,8 +34,15 @@ describe('Select', () => {
matchMedia.clear();
});

test('Select clearable', () => {
const defaultOptions: SelectOption[] = [
async function change(container: HTMLElement, value: string) {
fireEvent.change(container.querySelector('.select-input'), {
target: { value },
});
await sleep();
}

test('Select clearable', async () => {
let defaultOptions: SelectOption[] = [
{
text: 'School',
value: 'school',
Expand All @@ -50,6 +58,7 @@ describe('Select', () => {
}}
/>
);
await change(container, 'School');
expect(
(container.querySelector('.select-input') as HTMLInputElement).value
).toBe('School');
Expand All @@ -59,18 +68,86 @@ describe('Select', () => {
).toBe('');
});

test('Select backspace clearable', async () => {
const backspace = (element: HTMLInputElement) => {
let actuallyTyped: string = element.value;

const backspaceKey = {
key: 'Backspace',
code: 8,
inputType: 'deleteContentBackward',
};

const sharedEventConfig = {
key: backspaceKey.key,
charCode: backspaceKey.code,
keyCode: backspaceKey.code,
which: backspaceKey.code,
};
const downEvent = fireEvent.keyDown(element, sharedEventConfig);

if (downEvent) {
actuallyTyped = actuallyTyped.slice(0, -1);

fireEvent.input(element, {
target: { value: actuallyTyped },
inputType: backspaceKey.inputType,
bubbles: true,
cancelable: true,
});
}

fireEvent.keyUp(element, sharedEventConfig);
};
const defaultOptions: SelectOption[] = [
{
text: 'School',
value: 'school',
},
];
const { container } = render(<Select options={defaultOptions} />);
await change(container, 'School');
expect(
(container.querySelector('.select-input') as HTMLInputElement).value
).toBe('School');
let count = 6;
do {
backspace(
container.querySelector('.select-input') as HTMLInputElement
);
} while (count--);
expect(
(container.querySelector('.select-input') as HTMLInputElement).value
).toBe('');
});

test('Select is large', () => {
const wrapper = mount(<Select size={SelectSize.Large} />);
expect(wrapper.find('.select-large')).toBeTruthy();
expect(wrapper.render()).toMatchSnapshot();
});

test('Select is medium', () => {
const wrapper = mount(<Select size={SelectSize.Medium} />);
expect(wrapper.find('.select-medium')).toBeTruthy();
expect(wrapper.render()).toMatchSnapshot();
});

test('Select is small', () => {
const wrapper = mount(<Select size={SelectSize.Small} />);
expect(wrapper.find('.select-small')).toBeTruthy();
expect(wrapper.render()).toMatchSnapshot();
});

test('Select is rectangle shaped', () => {
const wrapper = mount(<Select shape={SelectShape.Rectangle} />);
expect(wrapper.render()).toMatchSnapshot();
});

test('Select is pill shaped', () => {
const wrapper = mount(<Select shape={SelectShape.Pill} />);
expect(wrapper.render()).toMatchSnapshot();
});

test('Select is underline shaped', () => {
const wrapper = mount(<Select shape={SelectShape.Underline} />);
expect(wrapper.render()).toMatchSnapshot();
});
});
Loading