@indico-data/design-system 2.13.0 → 2.15.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/lib/index.css +84 -0
- package/lib/index.d.ts +71 -53
- package/lib/index.esm.css +84 -0
- package/lib/index.esm.js +16 -1
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -1
- package/lib/src/components/card/Card.d.ts +10 -0
- package/lib/src/components/card/Card.stories.d.ts +6 -0
- package/lib/src/components/card/__tests__/Card.test.d.ts +1 -0
- package/lib/src/components/card/index.d.ts +1 -0
- package/lib/src/components/index.d.ts +2 -0
- package/lib/src/components/skeleton/Skeleton.d.ts +9 -0
- package/lib/src/components/skeleton/Skeleton.stories.d.ts +9 -0
- package/lib/src/components/skeleton/__tests__/Skeleton.test.d.ts +1 -0
- package/lib/src/components/skeleton/index.d.ts +1 -0
- package/lib/src/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/card/Card.mdx +14 -0
- package/src/components/card/Card.stories.tsx +97 -0
- package/src/components/card/Card.tsx +33 -0
- package/src/components/card/__tests__/Card.test.tsx +26 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/card/styles/Card.scss +44 -0
- package/src/components/index.ts +2 -0
- package/src/components/skeleton/Skeleton.mdx +44 -0
- package/src/components/skeleton/Skeleton.stories.tsx +132 -0
- package/src/components/skeleton/Skeleton.tsx +20 -0
- package/src/components/skeleton/__tests__/Skeleton.test.tsx +25 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skeleton/styles/Skeleton.scss +41 -0
- package/src/index.ts +2 -0
- package/src/styles/index.scss +2 -0
- package/src/styles/storybook.scss +12 -0
- package/src/styles/variables/_dropshadows.scss +5 -0
- package/src/styles/variables/index.scss +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Card } from './Card';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
className?: string;
|
|
3
|
+
height?: number;
|
|
4
|
+
width?: number;
|
|
5
|
+
isCircle?: boolean;
|
|
6
|
+
isFullHeight?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare const Skeleton: ({ className, height, width, isCircle, isFullHeight, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Skeleton } from './Skeleton';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof Skeleton>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Circle: Story;
|
|
8
|
+
export declare const Square: Story;
|
|
9
|
+
export declare const Composition: Story;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Skeleton } from './Skeleton';
|
package/lib/src/index.d.ts
CHANGED
|
@@ -15,3 +15,5 @@ export { Textarea } from './components/forms/textarea';
|
|
|
15
15
|
export { PasswordInput } from './components/forms/passwordInput';
|
|
16
16
|
export { Select as SelectInput } from './components/forms/select';
|
|
17
17
|
export { Form } from './components/forms/form';
|
|
18
|
+
export { Skeleton } from './components/skeleton';
|
|
19
|
+
export { Card } from './components/card';
|
package/package.json
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls, Story } from '@storybook/blocks';
|
|
2
|
+
import * as Card from './Card.stories';
|
|
3
|
+
|
|
4
|
+
<Meta title="Layout/Card" name="Card" of={Card} />
|
|
5
|
+
|
|
6
|
+
# Card
|
|
7
|
+
|
|
8
|
+
The Card component is a container that can be used to display content in a structured way. It can be used to display images, text, or even other components. The Card component mainly serves as a wrapper for your content.
|
|
9
|
+
|
|
10
|
+
<Canvas of={Card.Default} />
|
|
11
|
+
|
|
12
|
+
### The following props are available for the Card component:
|
|
13
|
+
|
|
14
|
+
<Controls of={Card.Default} />
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Card } from './Card';
|
|
3
|
+
import { Button } from '../button';
|
|
4
|
+
import { Col, Container, Row } from '../grid';
|
|
5
|
+
|
|
6
|
+
const meta: Meta = {
|
|
7
|
+
title: 'Layout/Card',
|
|
8
|
+
component: Card,
|
|
9
|
+
argTypes: {
|
|
10
|
+
title: {
|
|
11
|
+
control: 'text',
|
|
12
|
+
description: 'The title of the card',
|
|
13
|
+
table: {
|
|
14
|
+
category: 'Props',
|
|
15
|
+
type: {
|
|
16
|
+
summary: 'string',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultValue: { summary: '' },
|
|
20
|
+
},
|
|
21
|
+
subtitle: {
|
|
22
|
+
control: 'text',
|
|
23
|
+
description: 'The subtitle of the card',
|
|
24
|
+
table: {
|
|
25
|
+
category: 'Props',
|
|
26
|
+
type: {
|
|
27
|
+
summary: 'string',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultValue: { summary: '' },
|
|
31
|
+
},
|
|
32
|
+
hasBoxShadow: {
|
|
33
|
+
control: 'boolean',
|
|
34
|
+
description: 'Adds a box shadow to the card',
|
|
35
|
+
table: {
|
|
36
|
+
category: 'Props',
|
|
37
|
+
type: {
|
|
38
|
+
summary: 'boolean',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
defaultValue: { summary: false },
|
|
42
|
+
},
|
|
43
|
+
className: {
|
|
44
|
+
control: 'text',
|
|
45
|
+
description: 'Additional classes for the card component',
|
|
46
|
+
table: {
|
|
47
|
+
category: 'Props',
|
|
48
|
+
type: {
|
|
49
|
+
summary: 'string',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
children: {
|
|
54
|
+
control: false,
|
|
55
|
+
description: 'The content of the card',
|
|
56
|
+
table: {
|
|
57
|
+
category: 'Props',
|
|
58
|
+
type: {
|
|
59
|
+
summary: 'React.ReactNode',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default meta;
|
|
67
|
+
|
|
68
|
+
type Story = StoryObj<typeof Card>;
|
|
69
|
+
|
|
70
|
+
export const Default: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
title: 'Adventurer Class: Bard',
|
|
73
|
+
subtitle: 'Champion of the lute and song',
|
|
74
|
+
hasBoxShadow: true,
|
|
75
|
+
className: '',
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
render: (args) => {
|
|
79
|
+
return (
|
|
80
|
+
<Container>
|
|
81
|
+
<Row>
|
|
82
|
+
<Col sm={4}>
|
|
83
|
+
<Card {...args}>
|
|
84
|
+
<hr />A versatile and charismatic character class known for their magical abilities,
|
|
85
|
+
musical talents, and wide array of skills. Bards are often seen as
|
|
86
|
+
jacks-of-all-trades, able to adapt to various situations and roles within a party.
|
|
87
|
+
<hr />
|
|
88
|
+
<Button color="secondary" ariaLabel="Learn More" onClick={() => alert('Learn More')}>
|
|
89
|
+
Learn More
|
|
90
|
+
</Button>
|
|
91
|
+
</Card>
|
|
92
|
+
</Col>
|
|
93
|
+
</Row>
|
|
94
|
+
</Container>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import classNames from 'classnames'; // Assuming you have this utility
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
className?: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
title?: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
hasBoxShadow?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Card: React.FC<Props> = ({
|
|
13
|
+
className = '',
|
|
14
|
+
children,
|
|
15
|
+
title,
|
|
16
|
+
subtitle,
|
|
17
|
+
hasBoxShadow = false,
|
|
18
|
+
...rest
|
|
19
|
+
}) => {
|
|
20
|
+
const cardClasses = classNames('card', { 'card--box-shadow': hasBoxShadow }, className);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={cardClasses} {...rest}>
|
|
24
|
+
{(title || subtitle) && (
|
|
25
|
+
<div className="card__header">
|
|
26
|
+
{title && <h2>{title}</h2>}
|
|
27
|
+
{subtitle && <p>{subtitle}</p>}
|
|
28
|
+
</div>
|
|
29
|
+
)}
|
|
30
|
+
<div className="card__content">{children}</div>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { Card } from '@/components/card/Card';
|
|
3
|
+
|
|
4
|
+
describe('Card', () => {
|
|
5
|
+
it('Renders the title for the card if one exists', () => {
|
|
6
|
+
render(
|
|
7
|
+
<Card title="Title" data-testid="Card">
|
|
8
|
+
Text
|
|
9
|
+
</Card>,
|
|
10
|
+
);
|
|
11
|
+
expect(screen.getByTestId('Card')).toHaveTextContent('Title');
|
|
12
|
+
});
|
|
13
|
+
it('Renders the subtitle for the card if one exists', () => {
|
|
14
|
+
render(
|
|
15
|
+
<Card subtitle="Subtitle" data-testid="Card">
|
|
16
|
+
Text
|
|
17
|
+
</Card>,
|
|
18
|
+
);
|
|
19
|
+
expect(screen.getByTestId('Card')).toHaveTextContent('Subtitle');
|
|
20
|
+
});
|
|
21
|
+
it('does not render a title or a subtitle if neither are provided', () => {
|
|
22
|
+
render(<Card data-testid="Card">Text</Card>);
|
|
23
|
+
expect(screen.getByTestId('Card')).not.toHaveTextContent('Title');
|
|
24
|
+
expect(screen.getByTestId('Card')).not.toHaveTextContent('Subtitle');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Card } from './Card';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Common Variables
|
|
2
|
+
:root,
|
|
3
|
+
:root [data-theme='light'],
|
|
4
|
+
:root [data-theme='dark'] {
|
|
5
|
+
--pf-card-background-color: var(--pf-white-color);
|
|
6
|
+
--pf-card-text-color: var(--pf-gray-color);
|
|
7
|
+
--pf-card-border-color: var(--pf-gray-color);
|
|
8
|
+
--pf-card-rounded: var(--pf-rounded);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Dark Theme Specific Variables
|
|
12
|
+
:root [data-theme='dark'] {
|
|
13
|
+
--pf-card-background-color: var(--pf-primary-color);
|
|
14
|
+
--pf-card-border-color: var(--pf-primary-color-200);
|
|
15
|
+
--pf-card-text-color: var(--pf-gray-color-100);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.card {
|
|
19
|
+
border-radius: var(--pf-rounded);
|
|
20
|
+
padding: var(--pf-padding-3);
|
|
21
|
+
background: var(--pf-card-background-color);
|
|
22
|
+
border: var(--pf-border-sm) solid var(--pf-card-border-color);
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.card__header {
|
|
27
|
+
margin-bottom: var(--pf-margin-2);
|
|
28
|
+
p {
|
|
29
|
+
font-size: var(--pf-font-size-subtitle2);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.card__content {
|
|
34
|
+
hr {
|
|
35
|
+
border: var(--pf-border-thin) solid var(--pf-card-border-color);
|
|
36
|
+
border-bottom: none;
|
|
37
|
+
margin-bottom: var(--pf-margin-3);
|
|
38
|
+
margin-top: var(--pf-margin-3);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.card--box-shadow {
|
|
43
|
+
box-shadow: var(--pf-dropshadow);
|
|
44
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls } from '@storybook/blocks';
|
|
2
|
+
import * as Skeleton from './Skeleton.stories';
|
|
3
|
+
|
|
4
|
+
<Meta title="Layout/Skeleton" name="Skeleton" />
|
|
5
|
+
|
|
6
|
+
# Skeleton
|
|
7
|
+
|
|
8
|
+
This component is meant to be used in situations where you need a loading placeholder. It can be used as an image placeholder, text, or even a composite of multiple elements as shown below.
|
|
9
|
+
|
|
10
|
+
<Canvas of={Skeleton.Default} source={{
|
|
11
|
+
code: `<Skeleton width={100} height={20} />`}} />
|
|
12
|
+
<Controls of={Skeleton.Default} />
|
|
13
|
+
|
|
14
|
+
## Composition
|
|
15
|
+
This is an example of how you can compose the Skeleton component to create a more complex loading placeholder.
|
|
16
|
+
|
|
17
|
+
<Canvas of={Skeleton.Composition} source={{
|
|
18
|
+
code: `
|
|
19
|
+
<Container>
|
|
20
|
+
<Row>
|
|
21
|
+
<Col sm={4}>
|
|
22
|
+
<h2 className="mb-2">Composition</h2>
|
|
23
|
+
<div className="sb__mock-card border-gray-100 border-md pa-4 rounded">
|
|
24
|
+
<div className="sb__mock-card-title">
|
|
25
|
+
<Skeleton height={40} width={40} isCircle className="mb-5" />
|
|
26
|
+
<Skeleton height={40} className="mb-5" />
|
|
27
|
+
</div>
|
|
28
|
+
<Skeleton height={20} className="mb-2" />
|
|
29
|
+
<Skeleton height={20} className="mb-2" />
|
|
30
|
+
<Skeleton height={20} className="mb-2" />
|
|
31
|
+
<Skeleton height={20} width={200} className="mb-2" />
|
|
32
|
+
</div>
|
|
33
|
+
</Col>
|
|
34
|
+
<Col sm={4}>
|
|
35
|
+
<h2 className="mb-2">Circle</h2>
|
|
36
|
+
<Skeleton height={40} width={40} isCircle />
|
|
37
|
+
</Col>
|
|
38
|
+
<Col sm={4}>
|
|
39
|
+
<h2 className="mb-2">Square</h2>
|
|
40
|
+
<Skeleton height={40} width={40} />
|
|
41
|
+
</Col>
|
|
42
|
+
</Row>
|
|
43
|
+
</Container>`
|
|
44
|
+
}} />
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Skeleton } from './Skeleton';
|
|
3
|
+
import { Col, Container, Row } from '../grid';
|
|
4
|
+
|
|
5
|
+
const meta: Meta = {
|
|
6
|
+
title: 'Layout/Skeleton',
|
|
7
|
+
component: Skeleton,
|
|
8
|
+
argTypes: {
|
|
9
|
+
className: {
|
|
10
|
+
control: 'text',
|
|
11
|
+
description: 'Additional classes for the skeleton component',
|
|
12
|
+
table: {
|
|
13
|
+
category: 'Props',
|
|
14
|
+
type: {
|
|
15
|
+
summary: 'string',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
height: {
|
|
20
|
+
control: 'number',
|
|
21
|
+
description: 'The height of the skeleton component',
|
|
22
|
+
table: {
|
|
23
|
+
category: 'Props',
|
|
24
|
+
type: {
|
|
25
|
+
summary: 'number',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
width: {
|
|
30
|
+
control: 'number',
|
|
31
|
+
description: 'The width of the skeleton component',
|
|
32
|
+
table: {
|
|
33
|
+
category: 'Props',
|
|
34
|
+
type: {
|
|
35
|
+
summary: 'number',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
isCircle: {
|
|
40
|
+
control: 'boolean',
|
|
41
|
+
description: 'Sets the skeleton component to be a circle',
|
|
42
|
+
table: {
|
|
43
|
+
category: 'Props',
|
|
44
|
+
type: {
|
|
45
|
+
summary: 'boolean',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
defaultValue: { summary: false },
|
|
49
|
+
},
|
|
50
|
+
isFullHeight: {
|
|
51
|
+
control: 'boolean',
|
|
52
|
+
description: 'Sets the skeleton component to be full height',
|
|
53
|
+
table: {
|
|
54
|
+
category: 'Props',
|
|
55
|
+
type: {
|
|
56
|
+
summary: 'boolean',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaultValue: { summary: false },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default meta;
|
|
65
|
+
|
|
66
|
+
type Story = StoryObj<typeof Skeleton>;
|
|
67
|
+
|
|
68
|
+
export const Default: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
height: 20,
|
|
71
|
+
width: 100,
|
|
72
|
+
isCircle: false,
|
|
73
|
+
isFullHeight: false,
|
|
74
|
+
className: 'custom-class',
|
|
75
|
+
},
|
|
76
|
+
render: (args) => {
|
|
77
|
+
return <Skeleton {...args} />;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Circle: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
height: 50,
|
|
84
|
+
width: 50,
|
|
85
|
+
isCircle: true,
|
|
86
|
+
},
|
|
87
|
+
render: (args) => {
|
|
88
|
+
return <Skeleton {...args} />;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const Square: Story = {
|
|
93
|
+
args: {
|
|
94
|
+
height: 50,
|
|
95
|
+
width: 50,
|
|
96
|
+
},
|
|
97
|
+
render: (args) => {
|
|
98
|
+
return <Skeleton {...args} />;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const Composition: Story = {
|
|
103
|
+
render: () => {
|
|
104
|
+
return (
|
|
105
|
+
<Container>
|
|
106
|
+
<Row>
|
|
107
|
+
<Col sm={4}>
|
|
108
|
+
<h2 className="mb-2">Composition</h2>
|
|
109
|
+
<div className="sb__mock-card border-gray-100 border-md pa-4 rounded">
|
|
110
|
+
<div className="sb__mock-card-title">
|
|
111
|
+
<Skeleton height={40} width={40} isCircle className="mb-5" />
|
|
112
|
+
<Skeleton height={40} className="mb-5" />
|
|
113
|
+
</div>
|
|
114
|
+
<Skeleton height={20} className="mb-2" />
|
|
115
|
+
<Skeleton height={20} className="mb-2" />
|
|
116
|
+
<Skeleton height={20} className="mb-2" />
|
|
117
|
+
<Skeleton height={20} width={200} className="mb-2" />
|
|
118
|
+
</div>
|
|
119
|
+
</Col>
|
|
120
|
+
<Col sm={4}>
|
|
121
|
+
<h2 className="mb-2">Circle</h2>
|
|
122
|
+
<Skeleton height={40} width={40} isCircle />
|
|
123
|
+
</Col>
|
|
124
|
+
<Col sm={4}>
|
|
125
|
+
<h2 className="mb-2">Square</h2>
|
|
126
|
+
<Skeleton height={40} width={40} />
|
|
127
|
+
</Col>
|
|
128
|
+
</Row>
|
|
129
|
+
</Container>
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
className?: string;
|
|
3
|
+
height?: number;
|
|
4
|
+
width?: number;
|
|
5
|
+
isCircle?: boolean;
|
|
6
|
+
isFullHeight?: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const Skeleton = ({ className, height, width, isCircle, isFullHeight, ...rest }: Props) => {
|
|
10
|
+
const dynamicStyle = {
|
|
11
|
+
...(height && { height: `${height}px` }),
|
|
12
|
+
...(width && { width: `${width}px` }),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const circleClass = isCircle ? 'skeleton--circle' : '';
|
|
16
|
+
const fullHeightClass = isFullHeight ? 'skeleton--full-height' : '';
|
|
17
|
+
const combinedClassName = `skeleton ${circleClass} ${fullHeightClass} ${className || ''}`.trim();
|
|
18
|
+
|
|
19
|
+
return <div className={combinedClassName} style={dynamicStyle} {...rest} />;
|
|
20
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { Skeleton } from '@/components/skeleton/Skeleton';
|
|
3
|
+
|
|
4
|
+
describe('Skeleton', () => {
|
|
5
|
+
it('sets the width of the skeleton component', () => {
|
|
6
|
+
render(<Skeleton width={100} data-testid="skeleton" />);
|
|
7
|
+
expect(screen.getByTestId('skeleton')).toHaveStyle({ width: '100px' });
|
|
8
|
+
});
|
|
9
|
+
it('sets the height of the skeleton component', () => {
|
|
10
|
+
render(<Skeleton height={100} data-testid="skeleton" />);
|
|
11
|
+
expect(screen.getByTestId('skeleton')).toHaveStyle({ height: '100px' });
|
|
12
|
+
});
|
|
13
|
+
it('sets the skeleton component to be a circle', () => {
|
|
14
|
+
render(<Skeleton isCircle data-testid="skeleton" />);
|
|
15
|
+
expect(screen.getByTestId('skeleton')).toHaveClass('skeleton--circle');
|
|
16
|
+
});
|
|
17
|
+
it('sets the skeleton component to be full height', () => {
|
|
18
|
+
render(<Skeleton isFullHeight data-testid="skeleton" />);
|
|
19
|
+
expect(screen.getByTestId('skeleton')).toHaveClass('skeleton--full-height');
|
|
20
|
+
});
|
|
21
|
+
it('sets the className of the skeleton component', () => {
|
|
22
|
+
render(<Skeleton className="custom-class" data-testid="skeleton" />);
|
|
23
|
+
expect(screen.getByTestId('skeleton')).toHaveClass('custom-class');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Skeleton } from './Skeleton';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Common Variables
|
|
2
|
+
:root,
|
|
3
|
+
:root [data-theme='light'],
|
|
4
|
+
:root [data-theme='dark'] {
|
|
5
|
+
--pf-skeleton-color-one: var(--pf-gray-color-200);
|
|
6
|
+
--pf-skeleton-color-two: var(--pf-gray-color-100);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Dark Theme Specific Variables
|
|
10
|
+
:root [data-theme='dark'] {
|
|
11
|
+
--pf-skeleton-color-one: var(--pf-primary-color-200);
|
|
12
|
+
--pf-skeleton-color-two: var(--pf-primary-color-100);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.skeleton {
|
|
16
|
+
border-radius: var(--pf-rounded);
|
|
17
|
+
background-color: var(--pf-gray-color-100);
|
|
18
|
+
opacity: 0.7;
|
|
19
|
+
animation: skeleton-loading 1s linear infinite alternate;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 30px;
|
|
24
|
+
|
|
25
|
+
&.skeleton--full-height {
|
|
26
|
+
height: 100%;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.skeleton--circle {
|
|
30
|
+
border-radius: var(--pf-rounded-circle);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes skeleton-loading {
|
|
34
|
+
0% {
|
|
35
|
+
background-color: var(--pf-skeleton-color-one);
|
|
36
|
+
}
|
|
37
|
+
100% {
|
|
38
|
+
background-color: var(--pf-skeleton-color-two);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -69,3 +69,5 @@ export { Textarea } from './components/forms/textarea';
|
|
|
69
69
|
export { PasswordInput } from './components/forms/passwordInput';
|
|
70
70
|
export { Select as SelectInput } from './components/forms/select';
|
|
71
71
|
export { Form } from './components/forms/form';
|
|
72
|
+
export { Skeleton } from './components/skeleton';
|
|
73
|
+
export { Card } from './components/card';
|
package/src/styles/index.scss
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
@import '../components/forms/form/styles/Form.scss';
|
|
15
15
|
@import '../components/forms/select/styles/Select.scss';
|
|
16
16
|
@import '../components/forms/toggle/styles/Toggle.scss';
|
|
17
|
+
@import '../components/skeleton/styles/Skeleton.scss';
|
|
18
|
+
@import '../components/card/styles/Card.scss';
|
|
17
19
|
|
|
18
20
|
@import 'typography';
|
|
19
21
|
@import 'colors';
|
|
@@ -13,3 +13,15 @@
|
|
|
13
13
|
background-color: var(--storybook-bg-color);
|
|
14
14
|
color: var(--storybook-font-color);
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
.sb__mock-card {
|
|
18
|
+
border-radius: var(--pf-rounded-lg);
|
|
19
|
+
box-shadow: 0 0 0 1px var(--pf-border-color);
|
|
20
|
+
margin: 1rem;
|
|
21
|
+
padding: 1rem;
|
|
22
|
+
.sb__mock-card-title {
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-gap: 1rem;
|
|
25
|
+
grid-template-columns: 1fr 11fr;
|
|
26
|
+
}
|
|
27
|
+
}
|