playbook_ui 14.7.0.pre.rc.17 → 14.7.0.pre.rc.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +1 -1
- data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading.scss +37 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading.tsx +67 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading_mixins.scss +40 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius.jsx +51 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius.md +1 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_color.jsx +26 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_color.md +1 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_default.html.erb +1 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_default.jsx +11 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.jsx +59 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.md +3 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_layout.jsx +20 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_layout.md +3 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/example.yml +13 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/docs/index.js +5 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.html.erb +12 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.rb +8 -0
- data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.test.jsx +81 -0
- data/dist/chunks/{_weekday_stacked-B4YQ6Z-d.js → _weekday_stacked-Bu2Zfe7P.js} +2 -2
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +4 -1
- data/dist/playbook-doc.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff95e6830d7c3a6d2ad6c69bd177579486ca0ceac9e75f827311089beeee445e
|
4
|
+
data.tar.gz: 12abc183a5222f5e601530a455f77a39de018355c50d0d84b064871e0c406fb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61fd7de49207a9766dbbcf14a08d0ec23a2a337b7aa1aaf28b17202893f41c9661c380302a096c399b5855521f44c3b715a8ccf08d9b78a58cfd698cba7c570c
|
7
|
+
data.tar.gz: 6f7bd6331cbca3e289110278961cf96b6c5149465d70c5ca15ce8a0f098259da0b42dceea0745998fade1d97a44c7f12030f8de6655af5e51f9dcdf08c5816b7
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
@import 'pb_advanced_table/advanced_table';
|
3
2
|
@import 'pb_avatar/avatar';
|
4
3
|
@import 'pb_avatar_action_button/avatar_action_button';
|
@@ -85,6 +84,7 @@
|
|
85
84
|
@import 'pb_selectable_card_icon/selectable_card_icon';
|
86
85
|
@import 'pb_selectable_icon/selectable_icon';
|
87
86
|
@import 'pb_selectable_list/selectable_list';
|
87
|
+
@import 'pb_skeleton_loading/skeleton_loading';
|
88
88
|
@import 'pb_source/source';
|
89
89
|
@import 'pb_star_rating/star_rating';
|
90
90
|
@import 'pb_stat_change/stat_change';
|
@@ -0,0 +1,37 @@
|
|
1
|
+
@import 'skeleton_loading_mixins';
|
2
|
+
|
3
|
+
.pb_skeleton_loading {
|
4
|
+
display: "flex";
|
5
|
+
flex-direction: "column";
|
6
|
+
height: 100%;
|
7
|
+
.color_default {
|
8
|
+
@include skeleton-shimmer($silver);
|
9
|
+
}
|
10
|
+
.color_white {
|
11
|
+
@include skeleton-shimmer-light($white);
|
12
|
+
}
|
13
|
+
.dark {
|
14
|
+
@include skeleton-shimmer($border_dark);
|
15
|
+
}
|
16
|
+
.gap_xxs {
|
17
|
+
margin-top: 4px;
|
18
|
+
}
|
19
|
+
.gap_xs {
|
20
|
+
margin-top: 8px;
|
21
|
+
}
|
22
|
+
.gap_sm {
|
23
|
+
margin-top: 16px;
|
24
|
+
}
|
25
|
+
.gap_md {
|
26
|
+
margin-top: 24px;
|
27
|
+
}
|
28
|
+
.gap_lg {
|
29
|
+
margin-top: 32px;
|
30
|
+
}
|
31
|
+
.gap_xl {
|
32
|
+
margin-top: 40px;
|
33
|
+
}
|
34
|
+
.gap_xxl {
|
35
|
+
margin-top: 48px;
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
import React from 'react'
|
3
|
+
import classnames from 'classnames'
|
4
|
+
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
5
|
+
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
6
|
+
import { Sizes } from '../types'
|
7
|
+
|
8
|
+
|
9
|
+
type SkeletonLoadingProps = {
|
10
|
+
aria?: { [key: string]: string },
|
11
|
+
className?: string,
|
12
|
+
data?: { [key: string]: string },
|
13
|
+
id?: string,
|
14
|
+
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
15
|
+
height?: string,
|
16
|
+
width?: string,
|
17
|
+
borderRadius?: string,
|
18
|
+
gap?: Sizes | "none",
|
19
|
+
stack?: number,
|
20
|
+
color?: "default" | "white",
|
21
|
+
dark?: boolean,
|
22
|
+
} & GlobalProps
|
23
|
+
|
24
|
+
const SkeletonLoading = (props: SkeletonLoadingProps): React.ReactElement => {
|
25
|
+
const {
|
26
|
+
aria = {},
|
27
|
+
className,
|
28
|
+
data = {},
|
29
|
+
id,
|
30
|
+
htmlOptions = {},
|
31
|
+
height = "16px",
|
32
|
+
width = "100%",
|
33
|
+
borderRadius = "sm",
|
34
|
+
gap = "xxs",
|
35
|
+
stack = 1,
|
36
|
+
color = "default",
|
37
|
+
dark = false,
|
38
|
+
} = props
|
39
|
+
|
40
|
+
const ariaProps = buildAriaProps(aria)
|
41
|
+
const dataProps = buildDataProps(data)
|
42
|
+
const htmlProps = buildHtmlProps(htmlOptions)
|
43
|
+
const skeletonContainerCss = classnames(buildCss('pb_skeleton_loading'), globalProps(props), className)
|
44
|
+
const gapClass = gap !== 'none' ? `gap_${gap}` : ''
|
45
|
+
const innerSkeletonCss = classnames(`border_radius_${borderRadius}`,`color_${color}`, dark && 'dark', )
|
46
|
+
const innerSizeStyle = { height, width }
|
47
|
+
|
48
|
+
return (
|
49
|
+
<div
|
50
|
+
{...ariaProps}
|
51
|
+
{...dataProps}
|
52
|
+
{...htmlProps}
|
53
|
+
className={skeletonContainerCss}
|
54
|
+
id={id}
|
55
|
+
>
|
56
|
+
{Array.from({ length: Number(stack) }).map((_, index) => (
|
57
|
+
<div
|
58
|
+
className={classnames(buildCss('pb_skeleton_loading_item'), innerSkeletonCss, index > 0 && gapClass)}
|
59
|
+
key={index}
|
60
|
+
style={innerSizeStyle}
|
61
|
+
/>
|
62
|
+
))}
|
63
|
+
</div>
|
64
|
+
)
|
65
|
+
}
|
66
|
+
|
67
|
+
export default SkeletonLoading
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// Animation
|
2
|
+
@keyframes wave {
|
3
|
+
0% {
|
4
|
+
background-position: -468px 0;
|
5
|
+
}
|
6
|
+
100% {
|
7
|
+
background-position: 468px 0;
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
// Shimmer animation and gradient mixin based on color
|
12
|
+
@mixin skeleton-shimmer($color) {
|
13
|
+
background: $color;
|
14
|
+
background-color: $color;
|
15
|
+
background-image: linear-gradient(
|
16
|
+
to left,
|
17
|
+
$color 0%,
|
18
|
+
lighten($color, 1%) 50%,
|
19
|
+
lighten($color, 1%) 60%,
|
20
|
+
$color 80%,
|
21
|
+
$color 100%
|
22
|
+
);
|
23
|
+
background-repeat: no-repeat;
|
24
|
+
animation: wave 1.5s linear infinite forwards;
|
25
|
+
}
|
26
|
+
|
27
|
+
@mixin skeleton-shimmer-light($color) {
|
28
|
+
background: $color;
|
29
|
+
background-color: $color;
|
30
|
+
background-image: linear-gradient(
|
31
|
+
to left,
|
32
|
+
$color 0%,
|
33
|
+
darken($color, 1%) 50%,
|
34
|
+
darken($color, 1%) 60%,
|
35
|
+
$color 80%,
|
36
|
+
$color 100%
|
37
|
+
);
|
38
|
+
background-repeat: no-repeat;
|
39
|
+
animation: wave 1.5s linear infinite forwards;
|
40
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Flex, SkeletonLoading } from "playbook-ui"
|
3
|
+
|
4
|
+
|
5
|
+
const SkeletonLoadingBorderRadius = (props) => (
|
6
|
+
<Flex justify="evenly">
|
7
|
+
<SkeletonLoading
|
8
|
+
borderRadius="rounded"
|
9
|
+
height="50px"
|
10
|
+
width="100px"
|
11
|
+
{...props}
|
12
|
+
/>
|
13
|
+
<SkeletonLoading
|
14
|
+
borderRadius="xl"
|
15
|
+
height="50px"
|
16
|
+
width="100px"
|
17
|
+
{...props}
|
18
|
+
/>
|
19
|
+
<SkeletonLoading
|
20
|
+
borderRadius="lg"
|
21
|
+
height="50px"
|
22
|
+
width="100px"
|
23
|
+
{...props}
|
24
|
+
/>
|
25
|
+
<SkeletonLoading
|
26
|
+
borderRadius="md"
|
27
|
+
height="50px"
|
28
|
+
width="100px"
|
29
|
+
{...props}
|
30
|
+
/>
|
31
|
+
<SkeletonLoading
|
32
|
+
height="50px"
|
33
|
+
width="100px"
|
34
|
+
{...props}
|
35
|
+
/>
|
36
|
+
<SkeletonLoading
|
37
|
+
borderRadius="xs"
|
38
|
+
height="50px"
|
39
|
+
width="100px"
|
40
|
+
{...props}
|
41
|
+
/>
|
42
|
+
<SkeletonLoading
|
43
|
+
borderRadius="none"
|
44
|
+
height="50px"
|
45
|
+
width="100px"
|
46
|
+
{...props}
|
47
|
+
/>
|
48
|
+
</Flex>
|
49
|
+
)
|
50
|
+
|
51
|
+
export default SkeletonLoadingBorderRadius
|
@@ -0,0 +1 @@
|
|
1
|
+
The `borderRadius` prop accepts all of our [BorderRadius](https://playbook.powerapp.cloud/visual_guidelines/border_radius) tokens, with `sm` as default.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Card, SkeletonLoading } from "playbook-ui"
|
3
|
+
|
4
|
+
|
5
|
+
const SkeletonLoadingColor = (props) => (
|
6
|
+
<div>
|
7
|
+
<Card
|
8
|
+
borderNone
|
9
|
+
{...props}
|
10
|
+
>
|
11
|
+
<SkeletonLoading {...props}/>
|
12
|
+
</Card>
|
13
|
+
<Card
|
14
|
+
background="light"
|
15
|
+
borderNone
|
16
|
+
{...props}
|
17
|
+
>
|
18
|
+
<SkeletonLoading
|
19
|
+
color="white"
|
20
|
+
{...props}
|
21
|
+
/>
|
22
|
+
</Card>
|
23
|
+
</div>
|
24
|
+
)
|
25
|
+
|
26
|
+
export default SkeletonLoadingColor
|
@@ -0,0 +1 @@
|
|
1
|
+
The SkeletonLoading component has a default and a white `color` variant.
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= pb_rails("skeleton_loading") %>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Card, SkeletonLoading } from "playbook-ui"
|
3
|
+
|
4
|
+
|
5
|
+
const SkeletonLoadingHeightWidth = (props) => (
|
6
|
+
<div>
|
7
|
+
<SkeletonLoading
|
8
|
+
height="100px"
|
9
|
+
width="50%"
|
10
|
+
{...props}
|
11
|
+
/>
|
12
|
+
<SkeletonLoading
|
13
|
+
gap="md"
|
14
|
+
height="20px"
|
15
|
+
marginY="md"
|
16
|
+
stack="3"
|
17
|
+
width="50px"
|
18
|
+
{...props}
|
19
|
+
/>
|
20
|
+
<Card htmlOptions={{ style: { height: '200px', width: '100%' }}}
|
21
|
+
marginBottom="md"
|
22
|
+
padding="none"
|
23
|
+
>
|
24
|
+
<SkeletonLoading
|
25
|
+
borderRadius="md"
|
26
|
+
gap="xl"
|
27
|
+
height="50%"
|
28
|
+
width="300px"
|
29
|
+
{...props}
|
30
|
+
/>
|
31
|
+
</Card>
|
32
|
+
<Card htmlOptions={{ style: { height: '200px', width: '100%' }}}
|
33
|
+
padding="none"
|
34
|
+
>
|
35
|
+
<SkeletonLoading
|
36
|
+
borderRadius="md"
|
37
|
+
gap="xl"
|
38
|
+
height="30%"
|
39
|
+
stack="2"
|
40
|
+
width="70%"
|
41
|
+
{...props}
|
42
|
+
/>
|
43
|
+
</Card>
|
44
|
+
<SkeletonLoading
|
45
|
+
height="150px"
|
46
|
+
marginY="md"
|
47
|
+
width="150px"
|
48
|
+
{...props}
|
49
|
+
/>
|
50
|
+
<SkeletonLoading
|
51
|
+
borderRadius="rounded"
|
52
|
+
height="150px"
|
53
|
+
width="150px"
|
54
|
+
{...props}
|
55
|
+
/>
|
56
|
+
</div>
|
57
|
+
)
|
58
|
+
|
59
|
+
export default SkeletonLoadingHeightWidth
|
@@ -0,0 +1,3 @@
|
|
1
|
+
The `height` and `width` props accept pixel and percentage values. If using a percentage for `height`, the parent container must have a set height.
|
2
|
+
|
3
|
+
Set the `height` and `width` props to the same value to make a square. A `rounded` borderRadius will make a square a circle. If using percentages to make a square, your parent container must also be a square.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { SkeletonLoading } from "playbook-ui"
|
3
|
+
|
4
|
+
|
5
|
+
const SkeletonLoadingLayout = (props) => (
|
6
|
+
<div>
|
7
|
+
<SkeletonLoading
|
8
|
+
stack="5"
|
9
|
+
{...props}
|
10
|
+
/>
|
11
|
+
<SkeletonLoading
|
12
|
+
gap="md"
|
13
|
+
paddingTop="xl"
|
14
|
+
stack="3"
|
15
|
+
{...props}
|
16
|
+
/>
|
17
|
+
</div>
|
18
|
+
)
|
19
|
+
|
20
|
+
export default SkeletonLoadingLayout
|
@@ -0,0 +1,3 @@
|
|
1
|
+
Use the `stack` and `gap` props in conjunction to layer multiple Skeleton loading bars on top of each other.
|
2
|
+
|
3
|
+
`stack` accepts a number that correlates to the number of rows (1 is default), and `gap` accepts a portion of our [spacing props](https://playbook.powerapp.cloud/visual_guidelines/spacing) (`xxs` as default, `xs`, `sm`, `md`, `lg`, `xl`, `xxl`) to set the pixel distance between each row. `gap` will not do anything if there is no corresponding `stack` prop set.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
examples:
|
2
|
+
|
3
|
+
rails:
|
4
|
+
# - skeleton_loading_default: Default
|
5
|
+
|
6
|
+
|
7
|
+
react:
|
8
|
+
- skeleton_loading_default: Default
|
9
|
+
- skeleton_loading_color: Color
|
10
|
+
- skeleton_loading_layout: Layout
|
11
|
+
- skeleton_loading_border_radius: Border Radius
|
12
|
+
- skeleton_loading_height_width: Height & Width
|
13
|
+
|
@@ -0,0 +1,5 @@
|
|
1
|
+
export { default as SkeletonLoadingDefault } from './_skeleton_loading_default.jsx'
|
2
|
+
export { default as SkeletonLoadingColor } from './_skeleton_loading_color.jsx'
|
3
|
+
export { default as SkeletonLoadingLayout } from './_skeleton_loading_layout.jsx'
|
4
|
+
export { default as SkeletonLoadingBorderRadius } from './_skeleton_loading_border_radius.jsx'
|
5
|
+
export { default as SkeletonLoadingHeightWidth } from './_skeleton_loading_height_width.jsx'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<!-- Go to pb_content_tag definition in kit_base.rb for usage information. Commented out options are default (showing the default shape), and each can be deleted if not customizing that param. -->
|
2
|
+
<!-- If using nonstandard params please un-comment out and replace with your custom params. -->
|
3
|
+
<%= pb_content_tag(
|
4
|
+
# :div,
|
5
|
+
# aria: object.aria,
|
6
|
+
# class: object.classname,
|
7
|
+
# data: object.data,
|
8
|
+
# id: object.id,
|
9
|
+
# **combined_html_options
|
10
|
+
) do %>
|
11
|
+
<span>SKELETON_LOADING CONTENT</span>
|
12
|
+
<% end %>
|
@@ -0,0 +1,81 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { render, screen } from '@testing-library/react'
|
3
|
+
import { ensureAccessible } from '../utilities/test-utils'
|
4
|
+
import { SkeletonLoading } from 'playbook-ui'
|
5
|
+
|
6
|
+
/* See these resources for more testing info:
|
7
|
+
- https://github.com/testing-library/jest-dom#usage for useage and examples
|
8
|
+
- https://jestjs.io/docs/en/using-matchers
|
9
|
+
*/
|
10
|
+
|
11
|
+
describe('SkeletonLoading', () => {
|
12
|
+
const defaultProps = {
|
13
|
+
data: { testid: 'skeleton-loading' }
|
14
|
+
}
|
15
|
+
|
16
|
+
it('should be accessible', async () => {
|
17
|
+
ensureAccessible(SkeletonLoading, defaultProps)
|
18
|
+
})
|
19
|
+
|
20
|
+
it('renders with default props', () => {
|
21
|
+
const { container } = render(<SkeletonLoading {...defaultProps} />)
|
22
|
+
const skeleton = screen.getByTestId('skeleton-loading')
|
23
|
+
|
24
|
+
expect(skeleton).toBeInTheDocument()
|
25
|
+
expect(skeleton).toHaveClass('pb_skeleton_loading')
|
26
|
+
expect(container.querySelectorAll('div[class*="border_radius_"]')).toHaveLength(1)
|
27
|
+
})
|
28
|
+
|
29
|
+
it('renders multiple skeleton items based on stack prop', () => {
|
30
|
+
const props = {
|
31
|
+
...defaultProps,
|
32
|
+
stack: 3
|
33
|
+
}
|
34
|
+
const { container } = render(<SkeletonLoading {...props} />)
|
35
|
+
|
36
|
+
expect(container.querySelectorAll('div[class*="border_radius_"]')).toHaveLength(3)
|
37
|
+
})
|
38
|
+
|
39
|
+
it('applies custom styles correctly', () => {
|
40
|
+
const props = {
|
41
|
+
...defaultProps,
|
42
|
+
height: '24px',
|
43
|
+
width: '50%',
|
44
|
+
borderRadius: 'lg',
|
45
|
+
color: 'light',
|
46
|
+
dark: true
|
47
|
+
}
|
48
|
+
const { container } = render(<SkeletonLoading {...props} />)
|
49
|
+
const skeletonItem = container.querySelector('div[class*="border_radius_"]')
|
50
|
+
|
51
|
+
expect(skeletonItem).toHaveClass('border_radius_lg')
|
52
|
+
expect(skeletonItem).toHaveClass('dark')
|
53
|
+
})
|
54
|
+
|
55
|
+
it('applies gap class to items after first one', () => {
|
56
|
+
const props = {
|
57
|
+
...defaultProps,
|
58
|
+
stack: 3,
|
59
|
+
gap: 'md'
|
60
|
+
}
|
61
|
+
const { container } = render(<SkeletonLoading {...props} />)
|
62
|
+
const skeletonItems = container.querySelectorAll('div[class*="border_radius_"]')
|
63
|
+
|
64
|
+
expect(skeletonItems[0]).not.toHaveClass('gap_md')
|
65
|
+
expect(skeletonItems[1]).toHaveClass('gap_md')
|
66
|
+
expect(skeletonItems[2]).toHaveClass('gap_md')
|
67
|
+
})
|
68
|
+
|
69
|
+
it('handles no gap properly', () => {
|
70
|
+
const props = {
|
71
|
+
...defaultProps,
|
72
|
+
stack: 2,
|
73
|
+
gap: 'none'
|
74
|
+
}
|
75
|
+
const { container } = render(<SkeletonLoading {...props} />)
|
76
|
+
const skeletonItems = container.querySelectorAll('div[class*="border_radius_"]')
|
77
|
+
|
78
|
+
expect(skeletonItems[0]).not.toHaveClass('gap_none')
|
79
|
+
expect(skeletonItems[1]).not.toHaveClass('gap_none')
|
80
|
+
})
|
81
|
+
})
|