Skip to content

Commit

Permalink
Updated typings
Browse files Browse the repository at this point in the history
  • Loading branch information
fraincs committed Sep 19, 2024
1 parent 2afe0d0 commit 3f4a075
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 33 deletions.
22 changes: 22 additions & 0 deletions .changeset/giant-rules-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@igloo-ui/action-menu": minor
"@igloo-ui/alert": minor
"@igloo-ui/button": minor
"@igloo-ui/combobox": minor
"@igloo-ui/filter": minor
"@igloo-ui/icon-button": minor
"@igloo-ui/list": minor
"@igloo-ui/select": minor
"@igloo-ui/stepper": minor
"@igloo-ui/toaster": minor
"@igloo-ui/datepicker": minor
"@igloo-ui/dialog": minor
"@igloo-ui/modal": minor
"@igloo-ui/popover": minor
"@igloo-ui/stacked-bar": minor
"@igloo-ui/tag": minor
"@igloo-ui/tag-picker": minor
"@igloo-ui/text-editor": minor
---

Updated typings
21 changes: 21 additions & 0 deletions packages/ActionMenu/src/ActionMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,25 @@ describe('ActionMenu', () => {
}
expect(selected).toBeTruthy();
});

test('It calls the onClick of the option even with an eventHandler', () => {
let selected = false;
setup({
...actionMenuProps, options: [
{
label: 'Add Item',
value: 'add',
onClick: (e) => {
e.preventDefault();
selected = true;
}
},
]
});
const listItem = screen.getByText('Add Item');
if (listItem) {
fireEvent.click(listItem);
}
expect(selected).toBeTruthy();
});
});
11 changes: 9 additions & 2 deletions packages/ActionMenu/src/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface ActionMenuOption extends Omit<Option, "type"> {
/** Whether or not the action menu should close when an option is selected */
closeOnSelect?: boolean | ((option: OptionType) => boolean);
/** Callback when an option is selected */
onClick?: () => void;
onClick?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
}

export interface ActionMenuProps extends React.ComponentProps<"div"> {
Expand Down Expand Up @@ -125,7 +125,14 @@ const ActionMenu: React.FunctionComponent<ActionMenuProps> = ({
);
const onOptionSelect = actionMenuOption?.onClick;
if (onOptionSelect) {
onOptionSelect();
if (onOptionSelect.length > 0) {
// eslint-disable-next-line max-len
const syntheticEvent = new MouseEvent("click") as unknown as React.MouseEvent<HTMLButtonElement>;
onOptionSelect(syntheticEvent);
} else {
// Call the function without arguments if it doesn't expect any
(onOptionSelect as () => void)();
}
}

if (closeMenuOnSelect(option)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/Alert/src/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type Appearance = "card" | "inline" | "horizontal";

export interface AlertButton {
label: React.ReactNode;
onClick: () => void;
onClick: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
}

export interface AlertProps extends Omit<React.ComponentProps<"div">, "title"> {
Expand Down
2 changes: 1 addition & 1 deletion packages/Button/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export interface ButtonOwnProps {
/** Display only the icon in mobile */
showOnlyIconOnMobile?: boolean;
/** Callback when clicked */
onClick?: () => void;
onClick?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
/** Optional prop to specify the type of the Button */
type?: "button" | "reset" | "submit";
/** Add a data-intercom-target with unique id to link a
Expand Down
58 changes: 46 additions & 12 deletions packages/Combobox/src/Combobox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ const smallOptionList: ComboboxOption[] = [
},
];

const NodeLabelOptionList: ComboboxOption[] = [
{
label: <span>Text option</span>,
value: 'text',
},
{
label: <span>Disabled option</span>,
value: 'disabled',
disabled: true,
},
{
label: <span>Text option with icon</span>,
value: 'icon',
icon: <Happiness size="small" />,
},
];

const largeOptionList: ComboboxOption[] = [
{
label: 'Text 1',
Expand Down Expand Up @@ -154,21 +171,38 @@ const listWithAction: ComboboxOption[] = [
type Story = StoryObj<typeof Combobox>;

export const Overview: Story = {
args: {
children: comboboxPlaceholder,
options: smallOptionList,
},
args: {
children: comboboxPlaceholder,
options: smallOptionList,
},

play: async ({ canvasElement }) => {
const body = canvasElement.ownerDocument.body;
const canvas = within(body);
play: async ({ canvasElement }) => {
const body = canvasElement.ownerDocument.body;
const canvas = within(body);

await userEvent.click(canvas.getByRole('button'));
const firstOption = await canvas.findByText('Text option');
await userEvent.click(canvas.getByRole('button'));
const firstOption = await canvas.findByText('Text option');

await expect(firstOption).toBeInTheDocument();
},
};
await expect(firstOption).toBeInTheDocument();
},
};

export const Nodes: Story = {
args: {
children: comboboxPlaceholder,
options: NodeLabelOptionList,
},

play: async ({ canvasElement }) => {
const body = canvasElement.ownerDocument.body;
const canvas = within(body);

await userEvent.click(canvas.getByRole('button'));
const firstOption = await canvas.findByText('Text option');

await expect(firstOption).toBeInTheDocument();
},
};

export const Sizes: Story = {
render: () => (
Expand Down
15 changes: 15 additions & 0 deletions packages/Combobox/src/Combobox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ describe('Combobox', () => {
expect(comboboxOptions.length).toBe(options.length);
});

test('It should support react nodes', () => {
const options: ComboboxOption[] = [
{ label: <span>1</span>, value: 1 },
{ label: <span>2</span>, value: 2 },
{ label: <span>3</span>, value: 3 },
{ label: <span>4</span>, value: 4 },
];

setup({ isOpen: true }, options);
const combobox = screen.getByTestId('combobox1');
const comboboxOptions = combobox.querySelectorAll('.ids-list-item');

expect(comboboxOptions.length).toBe(options.length);
});

test("It should put the option label in the header after it's clicked", () => {
const options = [{ label: '1', value: 1 }];

Expand Down
2 changes: 1 addition & 1 deletion packages/Combobox/src/Combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const Combobox: React.FunctionComponent<ComboboxProps> = ({
}
}, [comboboxOptions]);

const optionText = (option: OptionType | undefined): string | undefined => {
const optionText = (option: OptionType | undefined): React.ReactNode | undefined => {
if (option?.type === "member") {
return option?.member;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/Filter/src/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface FilterProps extends React.ComponentProps<"button"> {
/** True if the filter should be disabled */
disabled?: boolean;
/** Add an event for when the filter is clicked */
onClick?: () => void;
onClick?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
/** True if the tag is selected */
selected?: boolean;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/IconButton/src/IconButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
* @jest-environment jsdom
*/
import React from 'react';

import { render, screen } from '@testing-library/react';
import Plus from '@igloo-ui/icons/dist/Plus';

import IconButton from './IconButton';

const setUp = (props = {}) => {
return render(
return render(
<IconButton
icon={<Plus size="small" />}
dataTest="ids-icon-btn"
Expand Down
2 changes: 1 addition & 1 deletion packages/IconButton/src/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface IconButtonProps extends Omit<ButtonOwnProps, "size"> {
icon: React.ReactNode;
/** Callback function that will be called
* when the user clicks on the button */
onClick?: () => void;
onClick?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
/** True if the control is disabled and shows a disabled state.
* The user cannot click on the button */
disabled?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions packages/List/src/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface Option extends ListItem {
/** Whether or not the option is disabled */
disabled?: boolean;
/** The option label */
label: string;
label: React.ReactNode;
/** The option type */
type: "list";
}
Expand Down Expand Up @@ -195,7 +195,7 @@ const ListItem: React.FunctionComponent<ListItemProps> = ({
<span className="ids-list-item__text-member">
{option?.member}
{option?.manager && (
isWorkleap ?
isWorkleap ?
<UserIcon size="sm" className="ids-list-item__manager" /> :
<UserSolid size="small" className="ids-list-item__manager" />
)}
Expand Down
2 changes: 1 addition & 1 deletion packages/Select/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const Select: React.FunctionComponent<SelectProps> = ({
React.useState(selectedOption);
const [showMenu, setShowMenu] = React.useState(isOpen);

const optionText = (option: OptionType | undefined): string | undefined => {
const optionText = (option: OptionType | undefined): React.ReactNode | undefined => {
if (option?.type === "member") {
return option?.member;
}
Expand Down
29 changes: 26 additions & 3 deletions packages/Stepper/src/Stepper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,38 @@ describe('Stepper', () => {
}
});

test('It should accept React.MouseEventHandler<HTMLButtonElement> as onClick prop', () => {
const mockOnClick: React.MouseEventHandler<HTMLButtonElement> = jest.fn();

const steps = [
{ title: 'Step 1', onClick: mockOnClick },
{ title: 'Step 2' },
{ title: 'Step 3' },
];

const currentStep = 1;
const {container} = setup({steps: steps, currentStep: currentStep, clickableNextSteps: false});

const props: StepperProps = {
steps: steps,
currentStep: 0,
};

render(<Stepper {...props} />);

const stepElements = container.querySelectorAll('.ids-step');
fireEvent.click(stepElements[0]);

expect(mockOnClick).toHaveBeenCalled();
});

test('Enables steps after the current step if clickableNextSteps is true', () => {
const currentStep = 1;

const {container} = setup({steps: steps, currentStep: currentStep, clickableNextSteps: true});
const stepElements = container.querySelectorAll('.ids-step');
for (let i = currentStep + 1; i < stepElements.length; i++) {
expect(stepElements[i]).not.toBeDisabled();
}
});


});
12 changes: 10 additions & 2 deletions packages/Stepper/src/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import * as React from "react";
import cx from "classnames";
import type { PressEvent } from "react-aria";

import Step from "./Step";

import "./stepper.scss";

export interface Step {
/** The callback function that is called when the step is clicked */
onClick?: (index: number) => void;
onClick?: ((index: number) => void) | React.MouseEventHandler<HTMLButtonElement>;
/** The title for the step */
title: string;
}
Expand Down Expand Up @@ -54,7 +55,14 @@ const Stepper: React.FunctionComponent<StepperProps> = ({
isComplete={isComplete}
isCurrent={isCurrent}
disabled={disabled}
onPress={() => step.onClick?.(index)}
onPress={(event: PressEvent) => {
if (typeof step.onClick === "function") {
(step.onClick as (index: number) => void)(index);
} else if (step.onClick) {
// eslint-disable-next-line max-len
(step.onClick as React.MouseEventHandler<HTMLButtonElement>)(event as unknown as React.MouseEvent<HTMLButtonElement>);
}
}}
/>
{index < steps.length - 1 && (
<div
Expand Down
15 changes: 14 additions & 1 deletion packages/Toaster/src/Toaster.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,17 @@ export const ErrorToast = () => {
<Toaster />
</ChromaticWrapper>
);
};
};


export const NodeMessageSuccessToast = () => {

return (
<ChromaticWrapper>
<Button appearance="secondary" onClick={() => toast.success(<span>Andrew's <em>profile</em> has been deleted</span>)}>
Remove profile
</Button>
<Toaster />
</ChromaticWrapper>
);
};
8 changes: 4 additions & 4 deletions packages/Toaster/src/Toaster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "./toaster.scss";
export interface ToastArgs {
isClosable?: boolean;
status?: "success" | "error";
message: string;
message: React.ReactNode;
}

export interface ToastQueueOptionsProps {
Expand All @@ -20,8 +20,8 @@ export interface ToastQueueOptionsProps {
}

export interface ToastQueueProps {
success: (message: string, options?: ToastQueueOptionsProps) => void;
error: (message: string, options?: ToastQueueOptionsProps) => void;
success: (message: React.ReactNode, options?: ToastQueueOptionsProps) => void;
error: (message: React.ReactNode, options?: ToastQueueOptionsProps) => void;
}

const TOAST_DURATION = 4000 as const;
Expand Down Expand Up @@ -66,7 +66,7 @@ const useActiveToastContainer = (): unknown => {
};

const addToast = (
message: string,
message: React.ReactNode,
status: "success" | "error",
duration: number | "infinite",
isClosable: boolean
Expand Down

0 comments on commit 3f4a075

Please sign in to comment.