@pautena/react-design-system 0.3.0 → 0.4.1
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 +5 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/enhanced-select/enhanced-select.d.ts +16 -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/cjs/types/generators/model-router/model-router.types.d.ts +1 -0
- package/dist/cjs/types/generators/model-router/screens/details-screen.d.ts +1 -1
- package/dist/cjs/types/hooks/index.d.ts +1 -0
- package/dist/cjs/types/hooks/routing/index.d.ts +1 -0
- package/dist/cjs/types/hooks/routing/routing.hooks.d.ts +5 -0
- package/dist/cjs/types/providers/notification-center/index.d.ts +1 -0
- package/dist/cjs/types/providers/notification-center/notification-center.hooks.d.ts +6 -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 +16 -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/esm/types/generators/model-router/model-router.types.d.ts +1 -0
- package/dist/esm/types/generators/model-router/screens/details-screen.d.ts +1 -1
- package/dist/esm/types/hooks/index.d.ts +1 -0
- package/dist/esm/types/hooks/routing/index.d.ts +1 -0
- package/dist/esm/types/hooks/routing/routing.hooks.d.ts +5 -0
- package/dist/esm/types/providers/notification-center/index.d.ts +1 -0
- package/dist/esm/types/providers/notification-center/notification-center.hooks.d.ts +6 -0
- package/dist/index.d.ts +23 -1
- package/package.json +1 -1
- package/src/components/enhanced-select/enhanced-select.stories.tsx +99 -0
- package/src/components/enhanced-select/enhanced-select.test.tsx +90 -0
- package/src/components/enhanced-select/enhanced-select.tsx +110 -0
- package/src/components/enhanced-select/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/generators/model-router/model-router.test.tsx +246 -20
- package/src/generators/model-router/model-router.types.ts +4 -0
- package/src/generators/model-router/screens/add-screen.tsx +16 -20
- package/src/generators/model-router/screens/details-screen.tsx +3 -2
- package/src/generators/model-router/screens/list-screen.tsx +17 -0
- package/src/generators/model-router/screens/update-screen.tsx +22 -13
- package/src/hooks/index.ts +1 -0
- package/src/hooks/routing/index.ts +1 -0
- package/src/hooks/routing/routing.hooks.ts +23 -0
- package/src/hooks/routing/routing.test.tsx +83 -0
- package/src/providers/notification-center/index.ts +1 -0
- package/src/providers/notification-center/notification-center.hooks.ts +23 -0
- package/src/providers/notification-center/notification-center.test.tsx +87 -1
- package/src/tests/assertions.ts +5 -0
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
color?: string;
|
|
11
|
+
fullWidth?: boolean;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
14
|
+
}
|
|
15
|
+
export declare const EnhancedSelect: <T extends React.ReactNode>({ label, value, loading, fetching, size, fullWidth, color, children, onChange, }: EnhancedSelectProps<T>) => JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./enhanced-select";
|
|
@@ -17,4 +17,4 @@ export interface DetailsScreenProps<T extends BasicModelInstance> extends BaseSc
|
|
|
17
17
|
*/
|
|
18
18
|
detailsItem?: T;
|
|
19
19
|
}
|
|
20
|
-
export declare const DetailsScreen: <T extends BasicModelInstance>({ model, modelName, onRequestItem, itemRequest, detailsItem, }: DetailsScreenProps<T>) => JSX.Element;
|
|
20
|
+
export declare const DetailsScreen: <T extends BasicModelInstance>({ model, modelName, basePath, onRequestItem, itemRequest, detailsItem, }: DetailsScreenProps<T>) => JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./routing";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./routing.hooks";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Notification } from "./notification-center.context";
|
|
2
|
+
export interface NotifyWhenValueChangesOptions<T> {
|
|
3
|
+
from: T;
|
|
4
|
+
to: T;
|
|
5
|
+
}
|
|
6
|
+
export declare const useNotifyWhenValueChanges: <T>(notification: Notification, value: T | undefined, { from, to }: NotifyWhenValueChangesOptions<T>) => void;
|
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,20 @@ 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
|
+
color?: string;
|
|
469
|
+
fullWidth?: boolean;
|
|
470
|
+
children?: ReactNode;
|
|
471
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
472
|
+
}
|
|
473
|
+
declare const EnhancedSelect: <T extends React__default.ReactNode>({ label, value, loading, fetching, size, fullWidth, color, children, onChange, }: EnhancedSelectProps<T>) => JSX.Element;
|
|
474
|
+
|
|
460
475
|
declare const newArrayWithSize: <T>(size: number, fillValue: T) => any[];
|
|
461
476
|
declare const getRandomItem: <T>(items: T[]) => {
|
|
462
477
|
index: number;
|
|
@@ -554,6 +569,7 @@ interface RequestState {
|
|
|
554
569
|
}
|
|
555
570
|
declare const IdleRequest: RequestState;
|
|
556
571
|
declare const LoadingRequest: RequestState;
|
|
572
|
+
declare const SuccessRequest: RequestState;
|
|
557
573
|
|
|
558
574
|
interface BaseScreenProps {
|
|
559
575
|
/**
|
|
@@ -700,6 +716,12 @@ interface NotificationCenterProps {
|
|
|
700
716
|
declare const NotificationCenterContext: React__default.Context<NotificationCenterProps | undefined>;
|
|
701
717
|
declare const useNotificationCenter: () => NotificationCenterProps;
|
|
702
718
|
|
|
719
|
+
interface NotifyWhenValueChangesOptions<T> {
|
|
720
|
+
from: T;
|
|
721
|
+
to: T;
|
|
722
|
+
}
|
|
723
|
+
declare const useNotifyWhenValueChanges: <T>(notification: Notification, value: T | undefined, { from, to }: NotifyWhenValueChangesOptions<T>) => void;
|
|
724
|
+
|
|
703
725
|
declare const TabContext: React.Context<[number, Dispatch<SetStateAction<number>>]>;
|
|
704
726
|
declare const TabContextProvider: React.Provider<[number, Dispatch<SetStateAction<number>>]>;
|
|
705
727
|
declare const useTab: () => [number, Dispatch<SetStateAction<number>>];
|
|
@@ -709,4 +731,4 @@ declare type TabProviderProps = PropsWithChildren<{
|
|
|
709
731
|
}>;
|
|
710
732
|
declare const TabProvider: ({ children, initialValue }: TabProviderProps) => JSX.Element;
|
|
711
733
|
|
|
712
|
-
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, ObjectDetails, ObjectDetailsProps, Order, Placeholder, PlaceholderAction, PlaceholderIconArgs, PlaceholderProps, QueryContainer, QueryContainerError, QueryContainerProps, QueryContainerSuccess, RequestState, SignIn, SnackbarActionType, SnackbarContentType, 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, useTab };
|
|
734
|
+
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,99 @@
|
|
|
1
|
+
import { Box, MenuItem, PropTypes, useTheme } 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
|
+
};
|
|
71
|
+
|
|
72
|
+
type WithBackgroundProps<T extends ReactNode> = TemplateProps<T> & { bgcolor: PropTypes.Color };
|
|
73
|
+
|
|
74
|
+
export const WithBackground = <T extends string>({
|
|
75
|
+
options,
|
|
76
|
+
bgcolor: bgcolorProp,
|
|
77
|
+
...rest
|
|
78
|
+
}: WithBackgroundProps<T>) => {
|
|
79
|
+
const { palette } = useTheme();
|
|
80
|
+
const bgcolor = palette[bgcolorProp].main;
|
|
81
|
+
const selectColor = palette.getContrastText(bgcolor);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<Box bgcolor={bgcolor} padding={3}>
|
|
85
|
+
<EnhancedSelect {...rest} color={selectColor}>
|
|
86
|
+
{options.map((option) => (
|
|
87
|
+
<MenuItem key={option} value={option}>
|
|
88
|
+
{option}
|
|
89
|
+
</MenuItem>
|
|
90
|
+
))}
|
|
91
|
+
</EnhancedSelect>
|
|
92
|
+
</Box>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
WithBackground.args = {
|
|
97
|
+
bgcolor: "secondary",
|
|
98
|
+
...baseArgs,
|
|
99
|
+
};
|
|
@@ -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,110 @@
|
|
|
1
|
+
import React, { ReactNode, useId } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
CircularProgress,
|
|
5
|
+
FormControl,
|
|
6
|
+
InputLabel,
|
|
7
|
+
LinearProgress,
|
|
8
|
+
useTheme,
|
|
9
|
+
Select,
|
|
10
|
+
Typography,
|
|
11
|
+
styled,
|
|
12
|
+
} from "@mui/material";
|
|
13
|
+
import { CenterContainer } from "../center-container";
|
|
14
|
+
import { SelectInputProps } from "@mui/material/Select/SelectInput";
|
|
15
|
+
|
|
16
|
+
type EnhancedSelectSize = "small" | "medium";
|
|
17
|
+
|
|
18
|
+
export interface EnhancedSelectProps<T> {
|
|
19
|
+
label: string;
|
|
20
|
+
value: T;
|
|
21
|
+
loading?: boolean;
|
|
22
|
+
fetching?: boolean;
|
|
23
|
+
size?: EnhancedSelectSize;
|
|
24
|
+
color?: string;
|
|
25
|
+
fullWidth?: boolean;
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
onChange?: SelectInputProps<T>["onChange"];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const ProgressSize: Record<EnhancedSelectSize, number> = {
|
|
31
|
+
small: 15,
|
|
32
|
+
medium: 20,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const EnhancedSelect = <T extends ReactNode>({
|
|
36
|
+
label,
|
|
37
|
+
value,
|
|
38
|
+
loading = false,
|
|
39
|
+
fetching = false,
|
|
40
|
+
size = "medium",
|
|
41
|
+
fullWidth = false,
|
|
42
|
+
color,
|
|
43
|
+
children,
|
|
44
|
+
onChange,
|
|
45
|
+
}: EnhancedSelectProps<T>) => {
|
|
46
|
+
const id = useId();
|
|
47
|
+
|
|
48
|
+
const renderValue = (value: T): ReactNode => {
|
|
49
|
+
if (fetching) {
|
|
50
|
+
return (
|
|
51
|
+
<CenterContainer centerVertical centerHorizontal>
|
|
52
|
+
<CircularProgress color="inherit" size={ProgressSize[size]} />
|
|
53
|
+
</CenterContainer>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (loading) {
|
|
58
|
+
return (
|
|
59
|
+
<Box display="flex" flexDirection="column">
|
|
60
|
+
{value}
|
|
61
|
+
<LinearProgress
|
|
62
|
+
color="inherit"
|
|
63
|
+
sx={{ position: "absolute", left: 0, right: 0, bottom: 0 }}
|
|
64
|
+
/>
|
|
65
|
+
</Box>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return value;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const StyledFormControl = styled(FormControl)(() => {
|
|
73
|
+
if (!color) {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
label: {
|
|
79
|
+
color,
|
|
80
|
+
},
|
|
81
|
+
".MuiOutlinedInput-notchedOutline": {
|
|
82
|
+
borderColor: `${color} !important`,
|
|
83
|
+
},
|
|
84
|
+
".MuiInputBase-root": {
|
|
85
|
+
color,
|
|
86
|
+
},
|
|
87
|
+
".MuiSelect-icon": {
|
|
88
|
+
fill: color,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<StyledFormControl fullWidth={fullWidth}>
|
|
95
|
+
<InputLabel id={id}>{label}</InputLabel>
|
|
96
|
+
<Select
|
|
97
|
+
labelId={id}
|
|
98
|
+
id={id}
|
|
99
|
+
value={value}
|
|
100
|
+
label={label}
|
|
101
|
+
onChange={onChange}
|
|
102
|
+
disabled={fetching}
|
|
103
|
+
size={size}
|
|
104
|
+
renderValue={renderValue}
|
|
105
|
+
>
|
|
106
|
+
{children}
|
|
107
|
+
</Select>
|
|
108
|
+
</StyledFormControl>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./enhanced-select";
|
package/src/components/index.ts
CHANGED