Skip to content

Commit

Permalink
Merge branch 'next-release'
Browse files Browse the repository at this point in the history
  • Loading branch information
mucahit committed Mar 11, 2022
2 parents 4b76992 + 0e3309f commit 648a555
Show file tree
Hide file tree
Showing 21 changed files with 21,495 additions and 37,120 deletions.
57,684 changes: 20,606 additions & 37,078 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hipo/react-ui-toolkit",
"version": "1.0.0-alpha.5.3.1",
"version": "1.0.0-beta",
"description": "React based UI toolkit.",
"main": "dist/index.js",
"scripts": {
Expand Down Expand Up @@ -58,6 +58,7 @@
"@types/react": "17.0.5",
"@types/react-dom": "17.0.4",
"@types/react-test-renderer": "17.0.1",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "4.23.0",
"@typescript-eslint/parser": "4.23.0",
"axe-core": "4.2.0",
Expand Down Expand Up @@ -101,7 +102,8 @@
},
"dependencies": {
"classnames": "2.3.1",
"react-textarea-autosize": "8.3.2"
"react-textarea-autosize": "8.3.2",
"uuid": "8.3.2"
},
"peerDependencies": {
"react": "17.0.2",
Expand Down
5 changes: 2 additions & 3 deletions src/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ export type ButtonProps = Omit<
shouldPreventDefault?: boolean;
shouldStopPropagation?: boolean;
shouldFocus?: boolean;
ref?: React.RefObject<HTMLButtonElement>;
shouldDisplaySpinner?: boolean;
customClassName?: string;
};

const Button = React.forwardRef<HTMLButtonElement, Record<string, any>>(
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
// eslint-disable-next-line prefer-arrow-callback
function ButtonComponent(props: ButtonProps, ref) {
function ButtonComponent(props, ref) {
const {
testid,
type = "button",
Expand Down
11 changes: 3 additions & 8 deletions src/button/file-upload/FileUploadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,17 @@ import classNames from "classnames";

import FileInput, {FileInputProps} from "../../form/input/file/FileInput";

export type FileUploadButtonProps = Omit<
FileInputProps,
"children" | "onChange" | "children"
> & {
children: React.ReactNode;
customClassName?: string;
export type FileUploadButtonProps = Omit<FileInputProps, "onChange"> & {
customLabelClassName?: string;
ref?: React.RefObject<HTMLLabelElement>;
onFileSelect?: (
files: React.SyntheticEvent<HTMLInputElement>["currentTarget"]["files"]
) => void;
};

const FileUploadButton = React.forwardRef<HTMLLabelElement, Record<string, any>>(
const FileUploadButton = React.forwardRef<HTMLLabelElement, FileUploadButtonProps>(
// eslint-disable-next-line prefer-arrow-callback
function FileUploadButtonComponent(props: FileUploadButtonProps, ref) {
function FileUploadButtonComponent(props, ref) {
const {
onFileSelect,
children,
Expand Down
1 change: 1 addition & 0 deletions src/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ function Dropdown<OptionIdShape extends string>({
onMouseUp={handleMouseUp}
onClick={toggleDropdown}
tabIndex={-1}
// @ts-ignore
aria-haspopup={role}
aria-expanded={isMenuOpen}
shouldFocus={shouldFocusOnHeaderButton}>
Expand Down
6 changes: 0 additions & 6 deletions src/dropdown/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ $dropdown-header-horizontal-padding: 8px;
}
}

.dropdown--has-selected-option {
svg {
display: none;
}
}

.dropdown__header-button {
/* stylelint-disable color-no-hex */
--button-bg: #ebebeb;
Expand Down
5 changes: 3 additions & 2 deletions src/form/input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
let caret = event.currentTarget.selectionStart || 0;

if (
String(value).length === finalEventValue.length + 1 ||
String(value).length === finalEventValue.length - 1
finalEventValue &&
(String(value).length === finalEventValue.length + 1 ||
String(value).length === finalEventValue.length - 1)
) {
if (prevValueThousandthsSeparatorCount === thousandthsSeparatorCount + 1) {
caret -= 1;
Expand Down
9 changes: 6 additions & 3 deletions src/form/input/file/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ export interface FileInputProps {
customLabelClassName?: string;
acceptedFileTypes?: string;
ref?: React.RefObject<HTMLLabelElement>;
isMultiple?: boolean;
}

const FileInput = React.forwardRef<HTMLLabelElement, Record<string, any>>(
const FileInput = React.forwardRef<HTMLLabelElement, FileInputProps>(
// eslint-disable-next-line prefer-arrow-callback
function FileInputComponent(props: FileInputProps, ref) {
function FileInputComponent(props, ref) {
const {
onChange,
children,
Expand All @@ -35,7 +36,8 @@ const FileInput = React.forwardRef<HTMLLabelElement, Record<string, any>>(
customClassName,
customLabelClassName,
isPending,
isDisabled
isDisabled,
isMultiple
} = props;
const containerClassName = classNames("file-input__container", customClassName);
const isInputDisabled = isPending || isDisabled;
Expand All @@ -58,6 +60,7 @@ const FileInput = React.forwardRef<HTMLLabelElement, Record<string, any>>(
id={htmlFor}
disabled={isInputDisabled}
accept={acceptedFileTypes}
multiple={isMultiple}
/>

<label
Expand Down
49 changes: 48 additions & 1 deletion src/form/input/typeahead/typeahead-input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import {render} from "@testing-library/react";
import {render, screen} from "@testing-library/react";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";

import {testA11y} from "../../../core/utils/test/testUtils";
import TypeaheadInput, {TypeaheadInputProps} from "./TypeaheadInput";
Expand All @@ -22,4 +23,50 @@ describe("<TypeaheadInput />", () => {

await testA11y(container);
});

it("should update value on change", () => {
render(<TypeaheadInput {...defaultTypeaheadInputProps} />);

const typeaheadInput = screen.getByRole("textbox");

userEvent.type(typeaheadInput, "test");

expect(typeaheadInput).toHaveValue("test");
});

it("should render left and right icons correctly", () => {
const iconContent = <p data-testid={"icon"}>{"Test"}</p>;

const {rerender, container} = render(
<TypeaheadInput leftIcon={iconContent} {...defaultTypeaheadInputProps} />
);

const leftIcon = screen.getByText("Test");

expect(container).toContainElement(leftIcon);

rerender(<TypeaheadInput rightIcon={iconContent} {...defaultTypeaheadInputProps} />);

const rightIcon = screen.getByText("Test");

expect(container).toContainElement(rightIcon);
});

it("should run onQueryChange when value is changed", () => {
const handleQueryChange = jest.fn();

render(
<TypeaheadInput {...defaultTypeaheadInputProps} onQueryChange={handleQueryChange} />
);

handleQueryChange("test");

expect(handleQueryChange).toHaveBeenCalled();
});

it("should add placeholder correctly", () => {
render(<TypeaheadInput {...defaultTypeaheadInputProps} />);

expect(screen.getByRole("textbox")).toHaveAttribute("placeholder", "typeahead input");
});
});
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ import {
} from "./dropdown/list/item/DropdownListItem";
import List, {ListProps as ListComponentProps} from "./list/List";
import ListItem, {ListItemProps as ListItemComponentProps} from "./list/item/ListItem";
import DescriptionTerm, {
DescriptionTermProps as DescriptionTermComponentProps
} from "./list/description-term/DescriptionTerm";
import Button, {ButtonProps as ButtonComponentProps} from "./button/Button";
import FileUploadButton, {
FileUploadButtonProps as FileUploadButtonComponentProps
Expand Down Expand Up @@ -71,6 +74,7 @@ export {
Dropdown,
List,
ListItem,
DescriptionTerm,
Button,
FileUploadButton,
Spinner,
Expand Down Expand Up @@ -125,6 +129,7 @@ export type DropdownSelectedOption<
> = DropdownSelectedComponentOption<Id, Context>;
export type ListProps<Item = any> = ListComponentProps<Item>;
export type ButtonProps = ButtonComponentProps;
export type DescriptionTermProps = DescriptionTermComponentProps;
export type FileUploadButtonProps = FileUploadButtonComponentProps;
export type SpinnerProps = SpinnerComponentProps;
export type TabItem = TabComponentItem;
Expand Down
43 changes: 28 additions & 15 deletions src/list/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import "./_list.scss";
import React, {Fragment} from "react";
import classNames from "classnames";

import {generateListItemKey} from "./util/listUtils";

export interface ListProps<Item = any> {
items: Item[];
children: (item: Item, testid: string, index?: number) => JSX.Element;
Expand All @@ -18,6 +20,7 @@ export interface ListProps<Item = any> {
shouldDisplayEmptyState: boolean;
emptyState: React.ReactNode;
};
type?: "unordered" | "ordered" | "description";
}

function List<Item extends any>({
Expand All @@ -28,35 +31,45 @@ function List<Item extends any>({
role,
listItemKeyGenerator,
placeholderProps,
emptyStateProps
emptyStateProps,
type = "unordered"
}: ListProps<Item>) {
const listClassName = classNames("list", customClassName);
let ListTypeElement: Extract<keyof JSX.IntrinsicElements, "ul" | "ol" | "dl">;

switch (type) {
case "ordered":
ListTypeElement = "ol";
break;

case "description":
ListTypeElement = "dl";
break;

default:
ListTypeElement = "ul";
break;
}

return (
<ul className={listClassName} role={role} data-testid={testid}>
<ListTypeElement className={listClassName} role={role} data-testid={testid}>
{items.map((item: Item, index: number) => {
const listItemTestId = `${testid}.item-${index}`;
let key = listItemTestId;

// @ts-ignore
if (item && typeof item === "object" && item.id) {
// @ts-ignore
key = item.id;
}

if (listItemKeyGenerator) {
key = listItemKeyGenerator(item, listItemTestId);
}

return <Fragment key={key}>{children(item, listItemTestId, index)}</Fragment>;
return (
<Fragment
key={generateListItemKey({listItemKeyGenerator, listItemTestId, item})}>
{children(item, listItemTestId, index)}
</Fragment>
);
})}

{placeholderProps?.shouldDisplayPlaceholder && placeholderProps.placeholder}

{!placeholderProps?.shouldDisplayPlaceholder &&
emptyStateProps?.shouldDisplayEmptyState &&
emptyStateProps.emptyState}
</ul>
</ListTypeElement>
);
}

Expand Down
40 changes: 40 additions & 0 deletions src/list/description-term/DescriptionTerm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import "./_description-term.scss";

import React from "react";
import classNames from "classnames";

export interface DescriptionTermProps {
title: string;
description: React.ReactNode;
id?: string;
customClassNames?: {container?: string; title?: string; description?: string};
role?: string;
testid?: string;
}

const DescriptionTerm = React.forwardRef<HTMLDivElement, DescriptionTermProps>(
({id, title, description, customClassNames, testid, role}, ref) => {
const {
container: containerClassName,
title: titleClassName,
description: descriptionClassName
} = customClassNames || {};

return (
<div
ref={ref}
className={containerClassName}
data-testid={testid}
id={id}
role={role}>
<dt className={classNames("description-term__title", titleClassName)}>{title}</dt>

<dd className={classNames("description-term__description", descriptionClassName)}>
{description}
</dd>
</div>
);
}
);

export default DescriptionTerm;
9 changes: 9 additions & 0 deletions src/list/description-term/_description-term.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.description-term__title {
font-weight: 600;
}

.description-term__description {
margin: 0;

padding: 4px 0 8px;
}
29 changes: 29 additions & 0 deletions src/list/util/listUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {v4 as uuidv4} from "uuid";

import {ListProps} from "../List";

function generateListItemKey<Item = any>({
listItemKeyGenerator,
listItemTestId,
item
}: {
listItemKeyGenerator: ListProps["listItemKeyGenerator"];
listItemTestId: string;
item: Item;
}) {
let key;

if (listItemKeyGenerator) {
key = listItemKeyGenerator(item, listItemTestId);
// @ts-ignore
} else if (item && typeof item === "object" && item.id) {
// @ts-ignore
key = item.id;
} else {
key = uuidv4();
}

return key;
}

export {generateListItemKey};
1 change: 1 addition & 0 deletions src/select/typeahead/TypeaheadSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ function TypeaheadSelect({

return (
<Dropdown
testid={testid}
customClassName={typeaheadSelectClassName}
headerWithoutButton={dropdownHeader}
role={"listbox"}
Expand Down
Loading

0 comments on commit 648a555

Please sign in to comment.