Skip to content

Commit 9aeba25

Browse files
authored
Merge pull request #16 from marklearst/pr/16-core-components
feat(components): refresh core controls
2 parents 5b93927 + b1a5732 commit 9aeba25

45 files changed

Lines changed: 1239 additions & 943 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
1-
import type { Meta, StoryObj } from "@storybook/react";
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
22

3-
import React from "react";
4-
import { Alert, AlertProps } from "./alert";
5-
import { getStoryDescription, hiddenArgControl } from "../../util/storybook-utils";
3+
import { Alert, AlertProps } from './alert'
4+
import {
5+
getStoryDescription,
6+
hiddenArgControl,
7+
} from '../../util/storybook-utils'
68

7-
const intents: AlertProps["intent"][] = ["info", "success", "warning", "danger"];
9+
const intents: AlertProps['intent'][] = ['info', 'success', 'warning', 'danger']
810

911
const meta: Meta<typeof Alert> = {
10-
title: "Alert",
11-
component: Alert,
12-
parameters: {
13-
layout: "fullscreen",
14-
...getStoryDescription("Wide and big alert bar to inform user about important things"),
15-
},
16-
args: {
17-
title: "Alert Title",
18-
children: "Alert content",
19-
intent: "info",
20-
},
21-
};
12+
title: 'Alert',
13+
component: Alert,
14+
parameters: {
15+
layout: 'fullscreen',
16+
...getStoryDescription(
17+
'Wide and big alert bar to inform user about important things',
18+
),
19+
},
20+
args: {
21+
title: 'Alert Title',
22+
children: 'Alert content',
23+
intent: 'info',
24+
},
25+
}
2226

23-
export default meta;
24-
type Story = StoryObj<typeof Alert>;
27+
export default meta
28+
type Story = StoryObj<typeof Alert>
2529

26-
export const Basic: Story = {};
30+
export const Basic: Story = {}
2731

2832
export const Intents: Story = {
29-
argTypes: { intent: hiddenArgControl },
30-
render: ({ children, ...args }) => (
31-
<div className="flex flex-col gap-4">
32-
{intents.map((intent) => (
33-
<Alert key={intent} {...args} intent={intent}>
34-
{children}
35-
</Alert>
36-
))}
37-
</div>
38-
),
39-
};
33+
argTypes: { intent: hiddenArgControl },
34+
render: ({ children, ...args }) => (
35+
<div className='flex flex-col gap-4'>
36+
{intents.map((intent) => (
37+
<Alert key={intent} {...args} intent={intent}>
38+
{children}
39+
</Alert>
40+
))}
41+
</div>
42+
),
43+
}
4044

4145
export const OnlyTitles: Story = {
42-
...Intents,
43-
args: { children: undefined },
44-
argTypes: { ...Intents.argTypes, children: hiddenArgControl },
45-
};
46+
...Intents,
47+
args: { children: undefined },
48+
argTypes: { ...Intents.argTypes, children: hiddenArgControl },
49+
}
Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
import { describe, expect, it } from "vitest";
2-
import { getByText, render, screen } from "@testing-library/react";
3-
import React from "react";
4-
import { Alert } from "./alert";
1+
import { describe, expect, it } from 'vitest'
2+
import { getByText, render, screen } from '@testing-library/react'
3+
import { Alert } from './alert'
54

6-
describe("Alert", () => {
7-
it("renders an alert with a title and children", () => {
8-
// ARRANGE
9-
render(
10-
<Alert intent="info" title="Hello">
11-
World
12-
</Alert>
13-
);
5+
describe('Alert', () => {
6+
it('renders an alert with a title and children', () => {
7+
// ARRANGE
8+
render(
9+
<Alert intent='info' title='Hello'>
10+
World
11+
</Alert>,
12+
)
1413

15-
// ASSERT
16-
const alert = screen.getByRole("alert");
17-
expect(alert).toBeInTheDocument();
18-
expect(getByText(alert, "Hello")).toBeInTheDocument();
19-
expect(getByText(alert, "World")).toBeInTheDocument();
20-
});
21-
});
14+
// ASSERT
15+
const alert = screen.getByRole('alert')
16+
expect(alert).toBeInTheDocument()
17+
expect(getByText(alert, 'Hello')).toBeInTheDocument()
18+
expect(getByText(alert, 'World')).toBeInTheDocument()
19+
})
20+
})

src/components/alert/alert.tsx

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,68 @@
1-
import React from "react";
2-
import { classNames } from "../../util/class-names";
3-
import { ErrorIcon, InfoSignIcon, TickCircleIcon, WarningSignIcon } from "../../icons";
1+
import type { ElementType, ComponentPropsWithoutRef } from 'react'
2+
import { ReactNode } from 'react'
3+
import { classNames } from '../../util/class-names'
4+
import {
5+
ErrorIcon,
6+
InfoSignIcon,
7+
TickCircleIcon,
8+
WarningSignIcon,
9+
} from '../../icons'
410

5-
export type AlertIntent = "success" | "info" | "warning" | "danger";
11+
export type AlertIntent = 'success' | 'info' | 'warning' | 'danger'
612

713
const alertVariants: Record<AlertIntent, string> = {
8-
info: "border-primary-400 bg-primary-50 text-primary-600",
9-
danger: "border-danger-400 bg-danger-50 text-danger-500",
10-
warning: "border-warning-500 bg-warning-50 text-warning-600",
11-
success: "border-success-400 bg-success-50 text-success-500",
12-
};
14+
info: 'border-primary-400 bg-primary-50 text-primary-600',
15+
danger: 'border-danger-400 bg-danger-50 text-danger-500',
16+
warning: 'border-warning-500 bg-warning-50 text-warning-600',
17+
success: 'border-success-400 bg-success-50 text-success-500',
18+
}
1319

1420
const iconVariants: Record<AlertIntent, string> = {
15-
info: "fill-primary-500",
16-
danger: "fill-danger-400",
17-
success: "fill-success-400",
18-
warning: "fill-warning-500",
19-
};
21+
info: 'fill-primary-500',
22+
danger: 'fill-danger-400',
23+
success: 'fill-success-400',
24+
warning: 'fill-warning-500',
25+
}
2026

21-
const iconNames: Record<AlertIntent, React.ElementType> = {
22-
info: InfoSignIcon,
23-
success: TickCircleIcon,
24-
warning: WarningSignIcon,
25-
danger: ErrorIcon,
26-
};
27+
const iconNames: Record<AlertIntent, ElementType> = {
28+
info: InfoSignIcon,
29+
success: TickCircleIcon,
30+
warning: WarningSignIcon,
31+
danger: ErrorIcon,
32+
}
2733

28-
export interface AlertProps extends React.ComponentPropsWithoutRef<"div"> {
29-
title: string;
30-
intent: AlertIntent;
31-
children?: React.ReactNode;
34+
export interface AlertProps extends ComponentPropsWithoutRef<'div'> {
35+
title: string
36+
intent: AlertIntent
37+
children?: ReactNode
3238
}
3339

34-
export const Alert = ({ title, children, intent, className, ...props }: AlertProps) => {
35-
const Icon = iconNames[intent];
40+
export const Alert = ({
41+
title,
42+
children,
43+
intent,
44+
className,
45+
...props
46+
}: AlertProps) => {
47+
const Icon = iconNames[intent]
3648

37-
return (
38-
<div
39-
role="alert"
40-
className={classNames(
41-
"flex flex-row gap-4 rounded-lg border px-4 py-3 text-neutral-800",
42-
alertVariants[intent],
43-
className
44-
)}
45-
{...props}
46-
>
47-
<Icon className={classNames("h-4 w-4 shrink-0", iconVariants[intent])} />
48-
<div className="grow">
49-
<div className="text-sm font-medium">{title}</div>
50-
{children && <div className="pt-1 text-sm text-neutral-800">{children}</div>}
51-
</div>
52-
</div>
53-
);
54-
};
49+
return (
50+
<div
51+
role='alert'
52+
className={classNames(
53+
'flex flex-row gap-4 rounded-lg border px-4 py-3 text-neutral-800',
54+
alertVariants[intent],
55+
className,
56+
)}
57+
{...props}
58+
>
59+
<Icon className={classNames('h-4 w-4 shrink-0', iconVariants[intent])} />
60+
<div className='grow'>
61+
<div className='text-sm font-medium'>{title}</div>
62+
{children && (
63+
<div className='pt-1 text-sm text-neutral-800'>{children}</div>
64+
)}
65+
</div>
66+
</div>
67+
)
68+
}

src/components/alert/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { Alert, AlertIntent } from "./alert";
1+
export { Alert, AlertIntent } from './alert'
Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,51 @@
1-
import type { Meta, StoryObj } from "@storybook/react";
2-
import React from "react";
3-
import type { AvatarProps } from "./avatar";
4-
import { Avatar } from "./avatar";
5-
import { getStoryDescription, hiddenArgControl } from "../../util/storybook-utils";
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
2+
import type { AvatarProps } from './avatar'
3+
import { Avatar } from './avatar'
4+
import {
5+
getStoryDescription,
6+
hiddenArgControl,
7+
} from '../../util/storybook-utils'
68

7-
const colors: AvatarProps["color"][] = ["primary", "success", "neutral", "warning", "danger"];
9+
const colors: AvatarProps['color'][] = [
10+
'primary',
11+
'success',
12+
'neutral',
13+
'warning',
14+
'danger',
15+
]
816

917
const meta: Meta<typeof Avatar> = {
10-
title: "Avatar",
11-
component: Avatar,
12-
parameters: getStoryDescription(
13-
"Circular user icon. It displays first 2 characters from the passed children text "
14-
),
15-
args: {
16-
children: "Name Lastname",
17-
color: colors[0],
18-
},
19-
argTypes: {
20-
color: { options: colors },
21-
onClick: hiddenArgControl,
22-
},
23-
};
18+
title: 'Avatar',
19+
component: Avatar,
20+
parameters: getStoryDescription(
21+
'Circular user icon. It displays first 2 characters from the passed children text ',
22+
),
23+
args: {
24+
children: 'Name Lastname',
25+
color: colors[0],
26+
},
27+
argTypes: {
28+
color: { options: colors },
29+
onClick: hiddenArgControl,
30+
},
31+
}
2432

25-
export default meta;
26-
type Story = StoryObj<typeof Avatar>;
33+
export default meta
34+
type Story = StoryObj<typeof Avatar>
2735

28-
export const Default: Story = {};
36+
export const Default: Story = {}
2937

3038
export const Colors: Story = {
31-
argTypes: {
32-
color: hiddenArgControl,
33-
},
34-
render: ({ children, ...args }) => (
35-
<div className="flex flex-col gap-4">
36-
{colors.map((color) => (
37-
<Avatar key={color} {...args} color={color}>
38-
{children}
39-
</Avatar>
40-
))}
41-
</div>
42-
),
43-
};
39+
argTypes: {
40+
color: hiddenArgControl,
41+
},
42+
render: ({ children, ...args }) => (
43+
<div className='flex flex-col gap-4'>
44+
{colors.map((color) => (
45+
<Avatar key={color} {...args} color={color}>
46+
{children}
47+
</Avatar>
48+
))}
49+
</div>
50+
),
51+
}
Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { describe, expect, it } from "vitest";
2-
import { getByText, render, screen } from "@testing-library/react";
3-
import React from "react";
4-
import { Avatar } from "./avatar";
1+
import { describe, expect, it } from 'vitest'
2+
import { getByText, render, screen } from '@testing-library/react'
3+
import { Avatar } from './avatar'
54

6-
describe("Avatar", () => {
7-
it("renders an avatar with substring of child", () => {
8-
const text = "Test User";
9-
// ARRANGE
10-
render(<Avatar color="primary">{text}</Avatar>);
5+
describe('Avatar', () => {
6+
it('renders an avatar with substring of child', () => {
7+
const text = 'Test User'
8+
// ARRANGE
9+
render(<Avatar color='primary'>{text}</Avatar>)
1110

12-
// ASSERT
13-
const alert = screen.getByRole("button");
14-
expect(alert).toBeInTheDocument();
15-
expect(getByText(alert, "Te")).toBeInTheDocument();
16-
});
17-
});
11+
// ASSERT
12+
const alert = screen.getByRole('button')
13+
expect(alert).toBeInTheDocument()
14+
expect(getByText(alert, 'Te')).toBeInTheDocument()
15+
})
16+
})

0 commit comments

Comments
 (0)