@pautena/react-design-system 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/enhanced-select/enhanced-select.d.ts +15 -0
- package/dist/cjs/types/components/enhanced-select/index.d.ts +1 -0
- package/dist/cjs/types/components/index.d.ts +1 -0
- package/dist/esm/index.js +5 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/enhanced-select/enhanced-select.d.ts +15 -0
- package/dist/esm/types/components/enhanced-select/index.d.ts +1 -0
- package/dist/esm/types/components/index.d.ts +1 -0
- package/dist/index.d.ts +15 -1
- package/package.json +1 -1
- package/src/components/enhanced-select/enhanced-select.stories.tsx +70 -0
- package/src/components/enhanced-select/enhanced-select.test.tsx +90 -0
- package/src/components/enhanced-select/enhanced-select.tsx +84 -0
- package/src/components/enhanced-select/index.ts +1 -0
- package/src/components/index.ts +1 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { SelectInputProps } from "@mui/material/Select/SelectInput";
|
|
3
|
+
declare type EnhancedSelectSize = "small" | "medium";
|
|
4
|
+
export interface EnhancedSelectProps<T> {
|
|
5
|
+
label: string;
|
|
6
|
+
value: T;
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
fetching?: boolean;
|
|
9
|
+
size?: EnhancedSelectSize;
|
|
10
|
+
fullWidth?: boolean;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
13
|
+
}
|
|
14
|
+
export declare const EnhancedSelect: <T extends React.ReactNode>({ label, value, loading, fetching, size, fullWidth, children, onChange, }: EnhancedSelectProps<T>) => JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./enhanced-select";
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { LinkProps } from 'react-router-dom';
|
|
|
8
8
|
import * as _emotion_styled from '@emotion/styled';
|
|
9
9
|
import * as _mui_system from '@mui/system';
|
|
10
10
|
import { BasicModelInstance as BasicModelInstance$1 } from '~/generators';
|
|
11
|
+
import { SelectInputProps } from '@mui/material/Select/SelectInput';
|
|
11
12
|
|
|
12
13
|
declare type HeaderPreset = PropTypes.Color | "transparent";
|
|
13
14
|
declare type HeaderActionVariant = "text" | "outlined" | "contained";
|
|
@@ -457,6 +458,19 @@ declare type ContentElement = ReactElement<ContentElement, ContentComponent>;
|
|
|
457
458
|
|
|
458
459
|
declare const Content: ({ children }: ContentProps) => JSX.Element;
|
|
459
460
|
|
|
461
|
+
declare type EnhancedSelectSize = "small" | "medium";
|
|
462
|
+
interface EnhancedSelectProps<T> {
|
|
463
|
+
label: string;
|
|
464
|
+
value: T;
|
|
465
|
+
loading?: boolean;
|
|
466
|
+
fetching?: boolean;
|
|
467
|
+
size?: EnhancedSelectSize;
|
|
468
|
+
fullWidth?: boolean;
|
|
469
|
+
children?: ReactNode;
|
|
470
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
471
|
+
}
|
|
472
|
+
declare const EnhancedSelect: <T extends React__default.ReactNode>({ label, value, loading, fetching, size, fullWidth, children, onChange, }: EnhancedSelectProps<T>) => JSX.Element;
|
|
473
|
+
|
|
460
474
|
declare const newArrayWithSize: <T>(size: number, fillValue: T) => any[];
|
|
461
475
|
declare const getRandomItem: <T>(items: T[]) => {
|
|
462
476
|
index: number;
|
|
@@ -716,4 +730,4 @@ declare type TabProviderProps = PropsWithChildren<{
|
|
|
716
730
|
}>;
|
|
717
731
|
declare const TabProvider: ({ children, initialValue }: TabProviderProps) => JSX.Element;
|
|
718
732
|
|
|
719
|
-
export { AppBarComponent, AppBarElement, AppBarProfile, AppBarProps, AppBarWithDrawerLayout, AppBarWithDrawerLayoutProps, BasicModelInstance, Bullet, BulletProps, BulletVariant, CenterContainer, CenterContainerProps, Content, ContentComponent, ContentElement, ContentProps, Drawer, DrawerComponent, DrawerContent, DrawerContentComponent, DrawerContentElement, DrawerContentProps, DrawerContext, DrawerContextProps, DrawerElement, DrawerItem, DrawerItemProps, DrawerProps, DrawerProvider, DrawerSection, DrawerSectionProps, EnhancedRemoteTable, EnhancedTable, EnhancedTableHead, GroupField, GroupValueCard, GroupValueCardProps, GroupValueItem, GroupValueItemComponent, GroupValueItemElement, GroupValueItemProps, HeadCell, Header, HeaderAction, HeaderActionVariant, HeaderBreadcrumb, HeaderComponent, HeaderElement, HeaderLayout, HeaderPreset, HeaderProps, HeaderTab, IdleRequest, Label, LabelProps, LabelVariant, Link, LinkBehaviour, LoadingRequest, MiniAppBar, MiniDrawer, Model, ModelField, ModelFieldTypes, ModelForm, ModelFormProps, ModelRouter, ModelRouterProps, Nav, NavItem, NavItemAvatar, NavItemBullet, NavItemLabel, NavSection, Notification, NotificationCenterContext, NotificationCenterProps, NotificationCenterProvider, NotificationCenterProviderProps, NotificationCenterProviderUndefinedError, NotifyWhenValueChangesOptions, ObjectDetails, ObjectDetailsProps, Order, Placeholder, PlaceholderAction, PlaceholderIconArgs, PlaceholderProps, QueryContainer, QueryContainerError, QueryContainerProps, QueryContainerSuccess, RequestState, SignIn, SnackbarActionType, SnackbarContentType, SuccessRequest, TabCard, TabContext, TabContextProvider, TabPanel, TabProvider, TableList, TableListProps, TableRowOption, UndefinedProvider, ValueBoolean, ValueBooleanProps, ValueCard, ValueCardProps, ValueDatetime, ValueDatetimeProps, ValueText, ValueTextProps, bulletClasses, getRandomItem, groupValueItemClasses, labelClasses, newArrayWithSize, useDrawer, useGetDefaultThemeColor, useNotificationCenter, useNotifyWhenValueChanges, useTab };
|
|
733
|
+
export { AppBarComponent, AppBarElement, AppBarProfile, AppBarProps, AppBarWithDrawerLayout, AppBarWithDrawerLayoutProps, BasicModelInstance, Bullet, BulletProps, BulletVariant, CenterContainer, CenterContainerProps, Content, ContentComponent, ContentElement, ContentProps, Drawer, DrawerComponent, DrawerContent, DrawerContentComponent, DrawerContentElement, DrawerContentProps, DrawerContext, DrawerContextProps, DrawerElement, DrawerItem, DrawerItemProps, DrawerProps, DrawerProvider, DrawerSection, DrawerSectionProps, EnhancedRemoteTable, EnhancedSelect, EnhancedSelectProps, EnhancedTable, EnhancedTableHead, GroupField, GroupValueCard, GroupValueCardProps, GroupValueItem, GroupValueItemComponent, GroupValueItemElement, GroupValueItemProps, HeadCell, Header, HeaderAction, HeaderActionVariant, HeaderBreadcrumb, HeaderComponent, HeaderElement, HeaderLayout, HeaderPreset, HeaderProps, HeaderTab, IdleRequest, Label, LabelProps, LabelVariant, Link, LinkBehaviour, LoadingRequest, MiniAppBar, MiniDrawer, Model, ModelField, ModelFieldTypes, ModelForm, ModelFormProps, ModelRouter, ModelRouterProps, Nav, NavItem, NavItemAvatar, NavItemBullet, NavItemLabel, NavSection, Notification, NotificationCenterContext, NotificationCenterProps, NotificationCenterProvider, NotificationCenterProviderProps, NotificationCenterProviderUndefinedError, NotifyWhenValueChangesOptions, ObjectDetails, ObjectDetailsProps, Order, Placeholder, PlaceholderAction, PlaceholderIconArgs, PlaceholderProps, QueryContainer, QueryContainerError, QueryContainerProps, QueryContainerSuccess, RequestState, SignIn, SnackbarActionType, SnackbarContentType, SuccessRequest, TabCard, TabContext, TabContextProvider, TabPanel, TabProvider, TableList, TableListProps, TableRowOption, UndefinedProvider, ValueBoolean, ValueBooleanProps, ValueCard, ValueCardProps, ValueDatetime, ValueDatetimeProps, ValueText, ValueTextProps, bulletClasses, getRandomItem, groupValueItemClasses, labelClasses, newArrayWithSize, useDrawer, useGetDefaultThemeColor, useNotificationCenter, useNotifyWhenValueChanges, useTab };
|
package/package.json
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { MenuItem } from "@mui/material";
|
|
2
|
+
import { ComponentMeta } from "@storybook/react";
|
|
3
|
+
import React, { ReactNode } from "react";
|
|
4
|
+
import { createTemplate, withContainer } from "../../storybook";
|
|
5
|
+
import { EnhancedSelect, EnhancedSelectProps } from "./enhanced-select";
|
|
6
|
+
import { faker } from "@faker-js/faker";
|
|
7
|
+
|
|
8
|
+
const baseArgs = {
|
|
9
|
+
label: "Car model",
|
|
10
|
+
value: faker.vehicle.model(),
|
|
11
|
+
size: "medium",
|
|
12
|
+
fetching: false,
|
|
13
|
+
loading: false,
|
|
14
|
+
fullWidth: true,
|
|
15
|
+
options: faker.definitions.vehicle?.model || [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
title: "Input/EnhancedSelect",
|
|
20
|
+
component: EnhancedSelect,
|
|
21
|
+
decorators: [withContainer({ width: 200 })],
|
|
22
|
+
parameters: {
|
|
23
|
+
layout: "centered",
|
|
24
|
+
},
|
|
25
|
+
} as ComponentMeta<typeof EnhancedSelect>;
|
|
26
|
+
|
|
27
|
+
interface TemplateProps<T extends ReactNode> extends EnhancedSelectProps<T> {
|
|
28
|
+
options: T[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const Template = createTemplate(<T extends string>({ options, ...rest }: TemplateProps<T>) => {
|
|
32
|
+
return (
|
|
33
|
+
<EnhancedSelect {...rest}>
|
|
34
|
+
{options.map((option) => (
|
|
35
|
+
<MenuItem key={option} value={option}>
|
|
36
|
+
{option}
|
|
37
|
+
</MenuItem>
|
|
38
|
+
))}
|
|
39
|
+
</EnhancedSelect>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const WithoutFullWidth = Template.bind({});
|
|
44
|
+
WithoutFullWidth.args = {
|
|
45
|
+
...baseArgs,
|
|
46
|
+
fullWidth: false,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const EnhancedSelectLoaded = Template.bind({});
|
|
50
|
+
EnhancedSelectLoaded.args = {
|
|
51
|
+
...baseArgs,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Loading = Template.bind({});
|
|
55
|
+
Loading.args = {
|
|
56
|
+
...baseArgs,
|
|
57
|
+
loading: true,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const Fetching = Template.bind({});
|
|
61
|
+
Fetching.args = {
|
|
62
|
+
...baseArgs,
|
|
63
|
+
fetching: true,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const SizeSmall = Template.bind({});
|
|
67
|
+
SizeSmall.args = {
|
|
68
|
+
...baseArgs,
|
|
69
|
+
size: "small",
|
|
70
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EnhancedSelectLoaded } from "./enhanced-select.stories";
|
|
3
|
+
import { render, screen } from "../../tests";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
|
|
6
|
+
describe("EnhancedSelect", () => {
|
|
7
|
+
const renderComponent = ({
|
|
8
|
+
label = EnhancedSelectLoaded.args.label,
|
|
9
|
+
loading = false,
|
|
10
|
+
fetching = false,
|
|
11
|
+
} = {}) => {
|
|
12
|
+
render(
|
|
13
|
+
<EnhancedSelectLoaded
|
|
14
|
+
{...EnhancedSelectLoaded.args}
|
|
15
|
+
label={label}
|
|
16
|
+
loading={loading}
|
|
17
|
+
fetching={fetching}
|
|
18
|
+
/>,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
options: EnhancedSelectLoaded.args.options as string[],
|
|
23
|
+
value: EnhancedSelectLoaded.args.value as string,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
it("would render a select with a label", () => {
|
|
28
|
+
renderComponent({ label: "Lorem ipsum" });
|
|
29
|
+
|
|
30
|
+
expect(screen.getByRole("button", { name: /lorem ipsum/i })).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("would render the value", () => {
|
|
34
|
+
const { value } = renderComponent();
|
|
35
|
+
|
|
36
|
+
expect(screen.getByText(value)).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("when is loading", () => {
|
|
40
|
+
it("would render a progress indicator", () => {
|
|
41
|
+
renderComponent({ loading: true });
|
|
42
|
+
|
|
43
|
+
expect(screen.getByRole("progressbar")).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("would render the value", () => {
|
|
47
|
+
const { value } = renderComponent({ loading: true });
|
|
48
|
+
|
|
49
|
+
expect(screen.getByText(value)).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("when is fetching", () => {
|
|
54
|
+
it("would render a progress indicator", () => {
|
|
55
|
+
renderComponent({ fetching: true });
|
|
56
|
+
|
|
57
|
+
expect(screen.getByRole("progressbar")).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("wouldn't render the value", () => {
|
|
61
|
+
const { value } = renderComponent({ fetching: true });
|
|
62
|
+
|
|
63
|
+
expect(screen.queryByText(value)).not.toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("when is fetching and loading", () => {
|
|
68
|
+
it("would render a progress indicator", () => {
|
|
69
|
+
renderComponent({ fetching: true, loading: true });
|
|
70
|
+
|
|
71
|
+
expect(screen.getByRole("progressbar")).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("wouldn't render the value", () => {
|
|
75
|
+
const { value } = renderComponent({ fetching: true, loading: true });
|
|
76
|
+
|
|
77
|
+
expect(screen.queryByText(value)).not.toBeInTheDocument();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("would render a menu item for each option", async () => {
|
|
82
|
+
const { options } = renderComponent({ label: "Lorem ipsum" });
|
|
83
|
+
|
|
84
|
+
await userEvent.click(screen.getByRole("button", { name: /lorem ipsum/i }));
|
|
85
|
+
|
|
86
|
+
options.forEach((option) => {
|
|
87
|
+
expect(screen.getByRole("option", { name: option })).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { ReactNode, useId } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
CircularProgress,
|
|
5
|
+
FormControl,
|
|
6
|
+
InputLabel,
|
|
7
|
+
LinearProgress,
|
|
8
|
+
Select,
|
|
9
|
+
} from "@mui/material";
|
|
10
|
+
import { CenterContainer } from "../center-container";
|
|
11
|
+
import { SelectInputProps } from "@mui/material/Select/SelectInput";
|
|
12
|
+
|
|
13
|
+
type EnhancedSelectSize = "small" | "medium";
|
|
14
|
+
|
|
15
|
+
export interface EnhancedSelectProps<T> {
|
|
16
|
+
label: string;
|
|
17
|
+
value: T;
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
fetching?: boolean;
|
|
20
|
+
size?: EnhancedSelectSize;
|
|
21
|
+
fullWidth?: boolean;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ProgressSize: Record<EnhancedSelectSize, number> = {
|
|
27
|
+
small: 15,
|
|
28
|
+
medium: 20,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const EnhancedSelect = <T extends ReactNode>({
|
|
32
|
+
label,
|
|
33
|
+
value,
|
|
34
|
+
loading = false,
|
|
35
|
+
fetching = false,
|
|
36
|
+
size = "medium",
|
|
37
|
+
fullWidth = false,
|
|
38
|
+
children,
|
|
39
|
+
onChange,
|
|
40
|
+
}: EnhancedSelectProps<T>) => {
|
|
41
|
+
const id = useId();
|
|
42
|
+
|
|
43
|
+
const renderValue = (value: T): ReactNode => {
|
|
44
|
+
if (fetching) {
|
|
45
|
+
return (
|
|
46
|
+
<CenterContainer centerVertical centerHorizontal>
|
|
47
|
+
<CircularProgress color="inherit" size={ProgressSize[size]} />
|
|
48
|
+
</CenterContainer>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (loading) {
|
|
53
|
+
return (
|
|
54
|
+
<Box display="flex" flexDirection="column">
|
|
55
|
+
{value}
|
|
56
|
+
<LinearProgress
|
|
57
|
+
color="inherit"
|
|
58
|
+
sx={{ position: "absolute", left: 0, right: 0, bottom: 0 }}
|
|
59
|
+
/>
|
|
60
|
+
</Box>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return value;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<FormControl fullWidth={fullWidth}>
|
|
69
|
+
<InputLabel id={id}>{label}</InputLabel>
|
|
70
|
+
<Select
|
|
71
|
+
labelId={id}
|
|
72
|
+
id={id}
|
|
73
|
+
value={value}
|
|
74
|
+
label={label}
|
|
75
|
+
onChange={onChange}
|
|
76
|
+
disabled={fetching}
|
|
77
|
+
size={size}
|
|
78
|
+
renderValue={renderValue}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</Select>
|
|
82
|
+
</FormControl>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./enhanced-select";
|
package/src/components/index.ts
CHANGED