playbook_ui 14.6.2.pre.alpha.PLAY1551tiptapextbump4350 → 14.6.2.pre.alpha.PLAY1613darkdatetimecolors4432
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_advanced_table/Components/CustomCell.tsx +8 -1
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +21 -28
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +37 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.jsx +13 -2
- data/app/pb_kits/playbook/pb_card/_card.tsx +11 -4
- data/app/pb_kits/playbook/pb_date/_date.scss +3 -0
- data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +5 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +8 -7
- data/app/pb_kits/playbook/pb_flex/_flex.tsx +3 -1
- data/app/pb_kits/playbook/pb_flex/_flex_item.tsx +8 -2
- data/app/pb_kits/playbook/pb_flex/flex_item.html.erb +3 -6
- data/app/pb_kits/playbook/pb_flex/flex_item.rb +7 -2
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +6 -2
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +30 -26
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +24 -1
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +25 -2
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_rails.md +3 -0
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text_react.md +1 -0
- data/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +46 -8
- data/app/pb_kits/playbook/pb_popover/_popover.tsx +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/app/pb_kits/playbook/pb_timeline/_item.tsx +59 -23
- data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +8 -0
- data/app/pb_kits/playbook/pb_timeline/detail.html.erb +3 -0
- data/app/pb_kits/playbook/pb_timeline/detail.rb +11 -0
- data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb +43 -0
- data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx +68 -0
- data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.md +2 -0
- data/app/pb_kits/playbook/pb_timeline/docs/example.yml +2 -1
- data/app/pb_kits/playbook/pb_timeline/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_timeline/item.html.erb +17 -21
- data/app/pb_kits/playbook/pb_timeline/item.rb +4 -0
- data/app/pb_kits/playbook/pb_timeline/label.html.erb +12 -0
- data/app/pb_kits/playbook/pb_timeline/label.rb +13 -0
- data/app/pb_kits/playbook/pb_timeline/step.html.erb +14 -0
- data/app/pb_kits/playbook/pb_timeline/step.rb +16 -0
- data/app/pb_kits/playbook/pb_timeline/subcomponents/Detail.tsx +29 -0
- data/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx +38 -0
- data/app/pb_kits/playbook/pb_timeline/subcomponents/Step.tsx +42 -0
- data/app/pb_kits/playbook/pb_timeline/subcomponents/index.tsx +3 -0
- data/app/pb_kits/playbook/pb_timeline/timeline.test.js +84 -0
- data/app/pb_kits/playbook/utilities/_hover.scss +46 -43
- data/app/pb_kits/playbook/utilities/globalPropNames.mjs +4 -0
- data/app/pb_kits/playbook/utilities/globalProps.ts +44 -2
- data/dist/chunks/_typeahead-DhLic2Fe.js +22 -0
- data/dist/chunks/_weekday_stacked-Mx8TYP5I.js +45 -0
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +4 -1
- data/dist/playbook-doc.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/hover.rb +4 -1
- data/lib/playbook/kit_base.rb +43 -5
- data/lib/playbook/version.rb +1 -1
- metadata +37 -5
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +0 -1
- data/dist/chunks/_typeahead-BV_n6U5W.js +0 -22
- data/dist/chunks/_weekday_stacked-BLVPFG6h.js +0 -45
@@ -1,19 +1,57 @@
|
|
1
1
|
<%= content_tag(:div, id: object.id, data: object.data, class: object.classname + object.size_class, tabindex: object.tabindex, **combined_html_options) do %>
|
2
2
|
<% if object.name.present? %>
|
3
3
|
<%= pb_rails("avatar", props: { name: object.name, image_url: object.avatar_url, size: "xxs" }) %>
|
4
|
-
|
4
|
+
<% if object.truncate %>
|
5
|
+
<div>
|
6
|
+
<%= pb_rails("title", props: {
|
7
|
+
classname: "pb_form_pill_text truncate_#{object.truncate}",
|
8
|
+
id: object.id,
|
9
|
+
size: 4,
|
10
|
+
text: object.name,
|
11
|
+
}) %>
|
12
|
+
<% if object.id.present? %>
|
13
|
+
<%= pb_rails("tooltip", props: {
|
14
|
+
position: "top",
|
15
|
+
tooltip_id: "tooltip-#{object.id}",
|
16
|
+
trigger_element_selector: "##{object.id}"
|
17
|
+
}) do %>
|
18
|
+
<%= object.name %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
</div>
|
22
|
+
<% else %>
|
23
|
+
<%= pb_rails("title", props: { classname: "pb_form_pill_text", id: object.id, size: 4, text: object.name }) %>
|
24
|
+
<% end %>
|
5
25
|
<% if object.icon.present? %>
|
6
26
|
<%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %>
|
7
27
|
<% end %>
|
8
28
|
<% elsif object.text.present? %>
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
29
|
+
<% if object.icon.present? %>
|
30
|
+
<%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %>
|
31
|
+
<% end %>
|
32
|
+
<% if object.truncate %>
|
33
|
+
<div>
|
34
|
+
<%= pb_rails("title", props: {
|
35
|
+
classname: "pb_form_pill_tag truncate_#{object.truncate}",
|
36
|
+
id: object.id,
|
37
|
+
size: 4,
|
38
|
+
text: object.text,
|
39
|
+
}) %>
|
40
|
+
<% if object.id.present? %>
|
41
|
+
<%= pb_rails("tooltip", props: {
|
42
|
+
position: "top",
|
43
|
+
tooltip_id: "tooltip-#{object.id}",
|
44
|
+
trigger_element_selector: "##{object.id}"
|
45
|
+
}) do %>
|
46
|
+
<%= object.text %>
|
47
|
+
<% end %>
|
48
|
+
<% end %>
|
49
|
+
</div>
|
50
|
+
<% else %>
|
51
|
+
<%= pb_rails("title", props: { classname: "pb_form_pill_tag", id: object.id, size: 4, text: object.text, }) %>
|
52
|
+
<% end %>
|
15
53
|
<% end %>
|
16
54
|
<%= pb_rails("body", props: { classname: "pb_form_pill_close" }) do %>
|
17
55
|
<%= pb_rails("icon", props: { icon: 'times', fixed_width: true, size: object.close_icon_size }) %>
|
18
56
|
<% end %>
|
19
|
-
<% end %>
|
57
|
+
<% end %>
|
@@ -21,7 +21,7 @@ import classnames from "classnames";
|
|
21
21
|
import { globalProps, GlobalProps } from "../utilities/globalProps";
|
22
22
|
import { uniqueId } from 'lodash';
|
23
23
|
|
24
|
-
type ModifiedGlobalProps = Omit<GlobalProps, 'minWidth'>
|
24
|
+
type ModifiedGlobalProps = Omit<GlobalProps, 'minWidth' | 'maxHeight' | 'minHeight'>
|
25
25
|
|
26
26
|
type PbPopoverProps = {
|
27
27
|
aria?: { [key: string]: string };
|
@@ -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
|
+
})
|
@@ -1,12 +1,15 @@
|
|
1
1
|
import React from 'react'
|
2
2
|
import classnames from 'classnames'
|
3
|
-
|
4
3
|
import { buildCss, buildHtmlProps } from '../utilities/props'
|
5
|
-
import { globalProps, GlobalProps } from "../utilities/globalProps"
|
4
|
+
import { globalProps, GlobalProps } from "../utilities/globalProps"
|
6
5
|
|
7
6
|
import DateStacked from '../pb_date_stacked/_date_stacked'
|
8
7
|
import IconCircle from '../pb_icon_circle/_icon_circle'
|
9
8
|
|
9
|
+
import TimelineLabel from './subcomponents/Label'
|
10
|
+
import TimelineStep from './subcomponents/Step'
|
11
|
+
import TimelineDetail from './subcomponents/Detail'
|
12
|
+
|
10
13
|
type ItemProps = {
|
11
14
|
className?: string,
|
12
15
|
children?: React.ReactNode[] | React.ReactNode,
|
@@ -17,6 +20,13 @@ type ItemProps = {
|
|
17
20
|
lineStyle?: 'solid' | 'dotted',
|
18
21
|
} & GlobalProps
|
19
22
|
|
23
|
+
function isElementOfType<P>(
|
24
|
+
element: React.ReactNode,
|
25
|
+
component: React.ComponentType<P>
|
26
|
+
): element is React.ReactElement<P> {
|
27
|
+
return React.isValidElement<P>(element) && element.type === component
|
28
|
+
}
|
29
|
+
|
20
30
|
const TimelineItem = ({
|
21
31
|
className,
|
22
32
|
children,
|
@@ -31,31 +41,57 @@ const TimelineItem = ({
|
|
31
41
|
|
32
42
|
const htmlProps = buildHtmlProps(htmlOptions)
|
33
43
|
|
44
|
+
const childrenArray = React.Children.toArray(children)
|
45
|
+
|
46
|
+
const labelChild = childrenArray.find(
|
47
|
+
(child): child is React.ReactElement => isElementOfType(child, TimelineLabel)
|
48
|
+
)
|
49
|
+
|
50
|
+
const stepChild = childrenArray.find(
|
51
|
+
(child): child is React.ReactElement => isElementOfType(child, TimelineStep)
|
52
|
+
)
|
53
|
+
|
54
|
+
const detailChild = childrenArray.find(
|
55
|
+
(child): child is React.ReactElement => isElementOfType(child, TimelineDetail)
|
56
|
+
)
|
57
|
+
|
58
|
+
const otherChildren = childrenArray.filter(
|
59
|
+
(child) =>
|
60
|
+
!isElementOfType(child, TimelineLabel) &&
|
61
|
+
!isElementOfType(child, TimelineStep) &&
|
62
|
+
!isElementOfType(child, TimelineDetail)
|
63
|
+
)
|
64
|
+
|
34
65
|
return (
|
35
|
-
<div
|
66
|
+
<div
|
36
67
|
{...htmlProps}
|
37
68
|
className={classnames(timelineItemCss, globalProps(props), className)}
|
38
69
|
>
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
70
|
+
{labelChild || (
|
71
|
+
<div className="pb_timeline_item_left_block">
|
72
|
+
{date && (
|
73
|
+
<DateStacked
|
74
|
+
align="center"
|
75
|
+
date={date}
|
76
|
+
size="sm"
|
77
|
+
/>
|
78
|
+
)}
|
79
|
+
</div>
|
80
|
+
)}
|
81
|
+
{stepChild || (
|
82
|
+
<div className="pb_timeline_item_step">
|
83
|
+
<IconCircle icon={icon}
|
84
|
+
size="xs"
|
85
|
+
variant={iconColor}
|
86
|
+
/>
|
87
|
+
<div className="pb_timeline_item_connector" />
|
88
|
+
</div>
|
89
|
+
)}
|
90
|
+
{detailChild || (
|
91
|
+
<div className="pb_timeline_item_right_block">
|
92
|
+
{ otherChildren }
|
93
|
+
</div>
|
94
|
+
)}
|
59
95
|
</div>
|
60
96
|
)
|
61
97
|
}
|
@@ -5,6 +5,11 @@ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../uti
|
|
5
5
|
import { GlobalProps, globalProps } from '../utilities/globalProps'
|
6
6
|
|
7
7
|
import TimelineItem from './_item'
|
8
|
+
import {
|
9
|
+
TimelineStep,
|
10
|
+
TimelineLabel,
|
11
|
+
TimelineDetail,
|
12
|
+
} from './subcomponents'
|
8
13
|
|
9
14
|
type TimelineProps = {
|
10
15
|
aria?: { [key: string]: string },
|
@@ -47,5 +52,8 @@ const Timeline = ({
|
|
47
52
|
}
|
48
53
|
|
49
54
|
Timeline.Item = TimelineItem
|
55
|
+
Timeline.Step = TimelineStep
|
56
|
+
Timeline.Label = TimelineLabel
|
57
|
+
Timeline.Detail = TimelineDetail
|
50
58
|
|
51
59
|
export default Timeline
|