playbook_ui 8.0.1 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +8 -7
  3. data/app/pb_kits/playbook/data/menu.yml +1 -0
  4. data/app/pb_kits/playbook/index.js +1 -0
  5. data/app/pb_kits/playbook/pb_card/card_header.rb +7 -7
  6. data/app/pb_kits/playbook/pb_collapsible/_collapsible.jsx +84 -0
  7. data/app/pb_kits/playbook/pb_collapsible/_collapsible.scss +15 -0
  8. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleContent.jsx +40 -0
  9. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleMain.jsx +59 -0
  10. data/app/pb_kits/playbook/pb_collapsible/collapsible.html.erb +7 -0
  11. data/app/pb_kits/playbook/pb_collapsible/collapsible.rb +11 -0
  12. data/app/pb_kits/playbook/pb_collapsible/collapsible.test.js +50 -0
  13. data/app/pb_kits/playbook/pb_collapsible/collapsible_content.html.erb +7 -0
  14. data/app/pb_kits/playbook/pb_collapsible/collapsible_content.rb +17 -0
  15. data/app/pb_kits/playbook/pb_collapsible/collapsible_main.html.erb +16 -0
  16. data/app/pb_kits/playbook/pb_collapsible/collapsible_main.rb +15 -0
  17. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_default.html.erb +10 -0
  18. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_default.jsx +19 -0
  19. data/app/pb_kits/playbook/pb_collapsible/docs/example.yml +9 -0
  20. data/app/pb_kits/playbook/pb_collapsible/docs/index.js +1 -0
  21. data/app/pb_kits/playbook/pb_collapsible/index.js +79 -0
  22. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.jsx +6 -2
  23. data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.html.erb +1 -1
  24. data/app/pb_kits/playbook/pb_docs/kit_example.rb +1 -1
  25. data/app/pb_kits/playbook/pb_nav/_item.jsx +2 -0
  26. data/app/pb_kits/playbook/pb_nav/_nav.jsx +2 -2
  27. data/app/pb_kits/playbook/pb_nav/item.html.erb +2 -2
  28. data/app/pb_kits/playbook/pb_nav/nav.html.erb +1 -1
  29. data/app/pb_kits/playbook/pb_progress_simple/_progress_simple.jsx +1 -1
  30. data/app/pb_kits/playbook/pb_progress_simple/_progress_simple.scss +5 -0
  31. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_variants.html.erb +5 -0
  32. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_variants.jsx +7 -0
  33. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_variants.md +1 -1
  34. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.rb +1 -1
  35. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.jsx +43 -26
  36. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.scss +18 -0
  37. data/app/pb_kits/playbook/pb_time_stacked/docs/_time_stacked_default.html.erb +18 -5
  38. data/app/pb_kits/playbook/pb_time_stacked/docs/_time_stacked_default.jsx +10 -5
  39. data/app/pb_kits/playbook/pb_time_stacked/time_stacked.html.erb +7 -3
  40. data/app/pb_kits/playbook/pb_time_stacked/time_stacked.rb +8 -30
  41. data/app/pb_kits/playbook/pb_time_stacked/time_stacked.test.js +33 -0
  42. data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +4 -3
  43. data/app/pb_kits/playbook/vendor.js +3 -0
  44. data/lib/playbook/props/base.rb +1 -1
  45. data/lib/playbook/version.rb +1 -1
  46. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25e534d853cf741d99d4409bad4b63fae3c01e5367a94b84ba4a37c598c95417
4
- data.tar.gz: 40d42989c78e9926e7e68cbe60212563fd4922ef5308f86def18d03ddff71cdd
3
+ metadata.gz: bde6450a7a9b834c1c16de60363a43d58a9f28da53ca2aa0089d8d96ec9ea89d
4
+ data.tar.gz: 4a067f64e965d58c3d12d23a8303d3e51482063d001c89693206bbea86ae952f
5
5
  SHA512:
6
- metadata.gz: 9a551ebc7c39683e38b31a74a6452518da6433a548468d4ae83f78bb0642db278d262918f91c07b29a98983f60ba6032ed302993984e5c7deda1b1da68749b8c
7
- data.tar.gz: 9a78ee36e72c2469c5c442aefdf04dd907cd708d534fb17267ed035284d9ed79026e113906d5185fe2afdb3e0eee73e20932150c170baf5e234d7d06797cbc25
6
+ metadata.gz: 42b92e641da9e7e5b1611bed31240d3a08934d7c6b612195407d92ab3c0b3bcbe3a13c1ebbd9e21f3d00c65f7e13f0198e5a2180edbc2dfa4e2048ad6e6f10a0
7
+ data.tar.gz: 8e9d47f263458035522e390cd25b90183c556cdbca33a7a910a76ffadf711760cafe970382759191909ff6ef44427649aa52d32100c6d452dc69ed850d7eedb2
@@ -1,11 +1,11 @@
1
- @import "tokens/fonts";
2
- @import "pb_background/background";
3
- @import "pb_body/body";
4
- @import "pb_button/button";
1
+ @import 'tokens/fonts';
2
+ @import 'pb_background/background';
3
+ @import 'pb_body/body';
4
+ @import 'pb_button/button';
5
5
  @import 'pb_button_toolbar/button_toolbar';
6
- @import "pb_caption/caption";
7
- @import "pb_card/card";
8
- @import "pb_title/title";
6
+ @import 'pb_caption/caption';
7
+ @import 'pb_card/card';
8
+ @import 'pb_title/title';
9
9
  @import 'pb_avatar/avatar';
10
10
  @import 'pb_avatar_action_button/avatar_action_button';
11
11
  @import 'pb_badge/badge';
@@ -13,6 +13,7 @@
13
13
  @import 'pb_checkbox/checkbox';
14
14
  @import 'pb_circle_chart/circle_chart';
15
15
  @import 'pb_circle_icon_button/circle_icon_button';
16
+ @import 'pb_collapsible/collapsible';
16
17
  @import 'pb_contact/contact';
17
18
  @import 'pb_currency/currency';
18
19
  @import 'pb_dashboard_value/dashboard_value';
@@ -8,6 +8,7 @@ kits:
8
8
  - circle_icon_button
9
9
  - card
10
10
  - checkbox
11
+ - collapsible
11
12
  - charts_and_graphs:
12
13
  - bar_graph
13
14
  - circle_chart
@@ -17,6 +17,7 @@ export Card from './pb_card/_card.jsx'
17
17
  export Checkbox from './pb_checkbox/_checkbox.jsx'
18
18
  export CircleChart from './pb_circle_chart/_circle_chart.jsx'
19
19
  export CircleIconButton from './pb_circle_icon_button/_circle_icon_button.jsx'
20
+ export Collapsible from './pb_collapsible/_collapsible.jsx'
20
21
  export Contact from './pb_contact/_contact.jsx'
21
22
  export Currency from './pb_currency/_currency.jsx'
22
23
  export DashboardValue from './pb_dashboard_value/_dashboard_value.jsx'
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- module PbCard
5
- class CardHeader < Playbook::KitBase
6
- prop :header_color, type: Playbook::Props::String,
7
- default: "category_1"
4
+ module PbCard
5
+ class CardHeader < Playbook::KitBase
6
+ prop :header_color, type: Playbook::Props::String,
7
+ default: "category_1"
8
8
 
9
- def classname
10
- generate_classname("pb_card_header_kit", header_color)
11
- end
9
+ def classname
10
+ generate_classname("pb_card_header_kit", header_color)
12
11
  end
13
12
  end
14
13
  end
14
+ end
@@ -0,0 +1,84 @@
1
+ /* @flow */
2
+
3
+ import classnames from 'classnames'
4
+ import React, { useState } from 'react'
5
+ import { globalProps } from '../utilities/globalProps.js'
6
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
7
+ import CollapsibleContent from './child_kits/CollapsibleContent'
8
+ import CollapsibleMain from './child_kits/CollapsibleMain'
9
+
10
+ export const CollapsibleContext = React.createContext({})
11
+
12
+ type CollapsibleProps = {
13
+ children: CollapsibleMain | CollapsibleContent | ReactNode,
14
+ aria?: object,
15
+ className?: string,
16
+ collapsed?: boolean,
17
+ data?: object,
18
+ id?: string,
19
+ padding?: string,
20
+ }
21
+
22
+ const useCollapsible = (initial = false) => {
23
+ const [collapsed, setCollapsed] = useState(initial)
24
+
25
+ return [
26
+ collapsed,
27
+ () => setCollapsed((t) => !t),
28
+ ]
29
+ }
30
+
31
+ const Collapsible = ({
32
+ aria = {},
33
+ className,
34
+ children = [],
35
+ collapsed = true,
36
+ data = {},
37
+ id,
38
+ padding = 'md',
39
+ ...props
40
+ }: CollapsibleProps) => {
41
+ const [isCollapsed, collapse] = useCollapsible(collapsed)
42
+ const CollapsibleParent = React.Children.toArray(children)
43
+
44
+ if (CollapsibleParent.length !== 2) {
45
+ throw new Error('Collapsible requires <CollapsibleMain> and <CollapsibleContent> to function properly.')
46
+ }
47
+
48
+ const Main = CollapsibleParent[0]
49
+ const Content = CollapsibleParent[1]
50
+
51
+ const { children: mainChildren, ...mainProps } = Main.props
52
+ const { children: contentChildren, ...contentProps } = Content.props
53
+ const ariaProps = buildAriaProps(aria)
54
+ const dataProps = buildDataProps(data)
55
+ const classes = classnames(
56
+ buildCss('pb_collapsible'),
57
+ className,
58
+ globalProps(props, { padding })
59
+ )
60
+
61
+ return (
62
+ <CollapsibleContext.Provider value={{ collapsed: isCollapsed, collapse }}>
63
+ <div
64
+ {...ariaProps}
65
+ {...dataProps}
66
+ className={classes}
67
+ id={id}
68
+ >
69
+ <CollapsibleMain {...mainProps}>
70
+ {mainChildren}
71
+ </CollapsibleMain>
72
+
73
+ <CollapsibleContent {...contentProps}>
74
+ {contentChildren}
75
+ </CollapsibleContent>
76
+ </div>
77
+ </CollapsibleContext.Provider>
78
+ )
79
+ }
80
+
81
+ Collapsible.Main = CollapsibleMain
82
+ Collapsible.Content = CollapsibleContent
83
+
84
+ export default Collapsible
@@ -0,0 +1,15 @@
1
+ [class^=pb_collapsible_kit] {
2
+ .toggle-content {
3
+ display: none;
4
+ height: 0;
5
+ padding-bottom: 0 !important;
6
+ padding-top: 0 !important;
7
+ overflow: hidden;
8
+ transition: height 300ms, padding 300ms ease-in-out;
9
+ }
10
+
11
+ .toggle-content.is-visible {
12
+ display: block;
13
+ height: auto;
14
+ }
15
+ }
@@ -0,0 +1,40 @@
1
+ /* @flow */
2
+
3
+ import classnames from 'classnames'
4
+ import React, { useContext } from 'react'
5
+ import AnimateHeight from 'react-animate-height'
6
+ import { buildCss } from '../../utilities/props'
7
+ import { globalProps } from '../../utilities/globalProps.js'
8
+
9
+ import { CollapsibleContext } from '../_collapsible.jsx'
10
+
11
+ type CollapsibleContentProps = {
12
+ children: array<React.ReactNode> | React.ReactNode | string,
13
+ className?: string,
14
+ padding?: string,
15
+ }
16
+
17
+ const CollapsibleContent = ({
18
+ children,
19
+ className,
20
+ padding = 'md',
21
+ ...props
22
+ }: CollapsibleContentProps) => {
23
+ const context = useContext(CollapsibleContext)
24
+ const contentCSS = buildCss('pb_collapsible_content_kit')
25
+ const contentSpacing = globalProps(props, { padding })
26
+
27
+ return (
28
+ <div className={classnames(contentCSS, className, contentSpacing)}>
29
+ <AnimateHeight
30
+ duration={300}
31
+ height={context.collapsed ? 0 : 'auto'}
32
+ id="bottom-section"
33
+ >
34
+ {children}
35
+ </AnimateHeight>
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export default CollapsibleContent
@@ -0,0 +1,59 @@
1
+ /* @flow */
2
+
3
+ import classnames from 'classnames'
4
+ import { Flex, FlexItem } from '../../'
5
+ import React, { useContext } from 'react'
6
+ import { buildCss } from '../../utilities/props'
7
+ import { globalProps } from '../../utilities/globalProps.js'
8
+
9
+ import { CollapsibleContext } from '../_collapsible.jsx'
10
+
11
+ type CollapsibleMainProps = {
12
+ children: array<React.ReactNode> | React.ReactNode,
13
+ className?: string,
14
+ padding?: string,
15
+ }
16
+
17
+ type IconProps = {
18
+ collapsed: boolean
19
+ }
20
+
21
+ const Icon = ({ collapsed }: IconProps) => {
22
+ const direction = collapsed ? 'down' : 'up'
23
+
24
+ return (
25
+ <div
26
+ key={direction}
27
+ style={{ verticalAlign: 'middle' }}
28
+ >
29
+ <i className={`far fa-chevron-${direction} fa-fw`} />
30
+ </div>
31
+ )
32
+ }
33
+
34
+ const CollapsibleMain = ({
35
+ children,
36
+ className,
37
+ padding = 'md',
38
+ ...props
39
+ }: CollapsibleMainProps) => {
40
+ const context = useContext(CollapsibleContext)
41
+ const mainCSS = buildCss('pb_collapsible_main_kit')
42
+ const mainSpacing = globalProps(props, { padding })
43
+
44
+ return (
45
+ <div className={classnames(mainCSS, className, mainSpacing)}>
46
+ <div onClick={() => context.collapse()}>
47
+ <Flex
48
+ spacing="between"
49
+ vertical="center"
50
+ >
51
+ <FlexItem>{children}</FlexItem>
52
+ <FlexItem><Icon collapsed={context.collapsed} /></FlexItem>
53
+ </Flex>
54
+ </div>
55
+ </div>
56
+ )
57
+ }
58
+
59
+ export default CollapsibleMain
@@ -0,0 +1,7 @@
1
+ <%= content_tag(:div,
2
+ aria: object.aria,
3
+ class: object.classname,
4
+ data: object.data,
5
+ id: object.id) do %>
6
+ <%= content.presence %>
7
+ <% end %>
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbCollapsible
5
+ class Collapsible < Playbook::KitBase
6
+ def classname
7
+ generate_classname("pb_collapsible_kit")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import Collapsible from './_collapsible'
5
+
6
+ beforeEach(() => {
7
+ // Silences error logs within the test suite.
8
+ jest.spyOn(console, 'error')
9
+ // eslint-disable-next-line
10
+ console.error.mockImplementation(() => {})
11
+ })
12
+
13
+ afterEach(() => {
14
+ // eslint-disable-next-line
15
+ console.error.mockRestore()
16
+ })
17
+
18
+ const testId = 'collapsible1',
19
+ kitClass = 'pb_collapsible'
20
+
21
+ test('throws error if incorrect # of children', () => {
22
+ expect(() => {
23
+ render(
24
+ <Collapsible />
25
+ )
26
+ }).toThrow()
27
+ })
28
+
29
+ test('returns namespaced additional_class class name', () => {
30
+ render(
31
+ <Collapsible
32
+ className="additional_class"
33
+ data={{ testid: testId }}
34
+ >
35
+ <Collapsible.Main>
36
+ <div>{'Main Section'}</div>
37
+ </Collapsible.Main>
38
+ <Collapsible.Content>
39
+ <div>
40
+ {
41
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel erat sed purus hendrerit viverra. Duis et vestibulum metus. Sed consequat ut ante non vehicula. Etiam nunc massa, pharetra vel quam id, posuere rhoncus quam. Quisque imperdiet arcu enim, nec aliquet justo auctor eget. Curabitur in metus nec nunc rhoncus faucibus vitae ac elit. Nulla facilisi. Vestibulum quis pretium nulla. Nulla ut accumsan velit. Duis varius urna sed sem tempor, sit amet fermentum nibh auctor. Praesent lorem arcu, egestas non ante quis, placerat pellentesque lectus.Vestibulum lacinia ipsum quis venenatis tristique. Vivamus suscipit, libero eu fringilla egestas, orci urna commodo arcu, vel gravida turpis ipsum molestie nibh. Donec cursus eu ante sagittis ultrices. Phasellus id sagittis risus. Mauris dapibus neque faucibus, tempor ligula vel, cursus ante. Donec faucibus gravida porta. Nullam egestas est quis aliquam feugiat. Sed eget metus diam. Cras eget placerat libero.'
42
+ }
43
+ </div>
44
+ </Collapsible.Content>
45
+ </Collapsible>
46
+ )
47
+
48
+ const kit = screen.getByTestId(testId)
49
+ expect(kit).toHaveClass(`${kitClass} additional_class`)
50
+ })
@@ -0,0 +1,7 @@
1
+ <%= content_tag(:div,
2
+ id: object.id,
3
+ data: object.data,
4
+ class: object.classname,
5
+ aria: object.aria) do %>
6
+ <%= content.presence %>
7
+ <% end %>
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbCollapsible
5
+ class CollapsibleContent < Playbook::KitBase
6
+ def data
7
+ Hash(values[:data]).merge(
8
+ collapsible_content: true
9
+ )
10
+ end
11
+
12
+ def classname
13
+ generate_classname("pb_collapsible_content_kit", "toggle-content", padding, separator: " ")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ <%= content_tag(:div,
2
+ id: object.id,
3
+ data: object.data,
4
+ class: object.classname,
5
+ aria: object.aria) do %>
6
+
7
+ <%= pb_rails("flex", props: {vertical: "center", spacing: "between"}) do %>
8
+ <%= pb_rails("flex/flex_item") do %>
9
+ <%= content.presence %>
10
+ <% end %>
11
+ <%= pb_rails("flex/flex_item") do %>
12
+ <i class="far fa-chevron-down"></i>
13
+ <i class="far fa-chevron-up" style="display: none"></i>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbCollapsible
5
+ class CollapsibleMain < Playbook::KitBase
6
+ def data
7
+ Hash(prop(:data)).merge(collapsible_main: true)
8
+ end
9
+
10
+ def classname
11
+ generate_classname("pb_collapsible_main_kit", padding, separator: " ")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ <%= pb_rails("collapsible", props: { name: "default-example" }) do %>
2
+ <%= pb_rails("collapsible/collapsible_main", props: { padding: "md", name: "default-main" }) do %>
3
+ <%= pb_rails("body", props: { text: "Main Section"}) %>
4
+ <% end %>
5
+ <%= pb_rails("collapsible/collapsible_content", props: { padding: "md" }) do %>
6
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec iaculis, risus a fringilla luctus, sapien eros sodales ex, quis molestie est nulla non turpis. Vestibulum aliquet at ipsum eget posuere. Morbi sed laoreet erat. Sed commodo posuere lectus, at porta nulla ornare a. Suspendisse quam est, sollicitudin ut enim sit amet, commodo placerat enim. Donec laoreet metus ac mauris pellentesque mattis. Pellentesque luctus vel mauris non aliquam. Mauris hendrerit mattis porttitor. Curabitur vehicula justo non ex consectetur commodo. Quisque posuere aliquet quam. Maecenas malesuada magna mauris, ac tempor metus euismod at.
7
+ <br><br>
8
+ Cras ornare fermentum magna mollis efficitur. Sed vitae nulla vel purus ultrices mollis. Maecenas id nulla id libero faucibus feugiat quis sit amet turpis. In commodo pellentesque risus at fringilla. Integer non interdum leo, non commodo ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut mi augue, dignissim at orci vel, egestas aliquam mi. Proin finibus aliquet tempor. Integer cursus, ex quis gravida rhoncus, nisi elit viverra ipsum, non efficitur est ex ac tortor. Praesent vitae odio massa.
9
+ <% end %>
10
+ <% end %>
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import { Collapsible } from '../..'
3
+
4
+ const CollapsibleDefault = () => (
5
+ <Collapsible>
6
+ <Collapsible.Main>
7
+ <div>{'Main Section'}</div>
8
+ </Collapsible.Main>
9
+ <Collapsible.Content>
10
+ <div>
11
+ {
12
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel erat sed purus hendrerit viverra. Duis et vestibulum metus. Sed consequat ut ante non vehicula. Etiam nunc massa, pharetra vel quam id, posuere rhoncus quam. Quisque imperdiet arcu enim, nec aliquet justo auctor eget. Curabitur in metus nec nunc rhoncus faucibus vitae ac elit. Nulla facilisi. Vestibulum quis pretium nulla. Nulla ut accumsan velit. Duis varius urna sed sem tempor, sit amet fermentum nibh auctor. Praesent lorem arcu, egestas non ante quis, placerat pellentesque lectus.Vestibulum lacinia ipsum quis venenatis tristique. Vivamus suscipit, libero eu fringilla egestas, orci urna commodo arcu, vel gravida turpis ipsum molestie nibh. Donec cursus eu ante sagittis ultrices. Phasellus id sagittis risus. Mauris dapibus neque faucibus, tempor ligula vel, cursus ante. Donec faucibus gravida porta. Nullam egestas est quis aliquam feugiat. Sed eget metus diam. Cras eget placerat libero.'
13
+ }
14
+ </div>
15
+ </Collapsible.Content>
16
+ </Collapsible>
17
+ )
18
+
19
+ export default CollapsibleDefault
@@ -0,0 +1,9 @@
1
+ examples:
2
+
3
+ rails:
4
+ - collapsible_default: Light
5
+
6
+ react:
7
+ - collapsible_default: Light
8
+
9
+
@@ -0,0 +1 @@
1
+ export { default as CollapsibleDefault } from './_collapsible_default.jsx'
@@ -0,0 +1,79 @@
1
+ import PbEnhancedElement from '../pb_enhanced_element'
2
+
3
+ const MAIN_SELECTOR = '[data-collapsible-main]'
4
+ const CONTENT_SELECTOR = '[data-collapsible-content]'
5
+ const DOWN_ARROW_SELECTOR = '.fa-chevron-down'
6
+ const UP_ARROW_SELECTOR = '.fa-chevron-up'
7
+
8
+ export default class PbCollapsible extends PbEnhancedElement {
9
+ static get selector() {
10
+ return MAIN_SELECTOR
11
+ }
12
+
13
+ connect() {
14
+ this.element.addEventListener('click', () => {
15
+ this.toggleElement(this.target)
16
+ })
17
+ this.displayDownArrow()
18
+ }
19
+
20
+ get target() {
21
+ return this.element.parentNode.querySelector(CONTENT_SELECTOR)
22
+ }
23
+
24
+ showElement(elem) {
25
+ // Get the natural height of the element
26
+ const getHeight = () => {
27
+ elem.style.display = 'block'
28
+ const height = elem.scrollHeight + 'px' // Get it's height
29
+ elem.style.display = '' // Hide it again
30
+ return height
31
+ }
32
+
33
+ const height = getHeight()
34
+ elem.classList.add('is-visible')
35
+ elem.style.height = height // Update the max-height
36
+
37
+ // Once the transition is complete, remove the inline max-height so the content can scale responsively
38
+ window.setTimeout(() => {
39
+ elem.style.height = ''
40
+ }, 300)
41
+ }
42
+
43
+ hideElement(elem) {
44
+ // Give the element a height to change from
45
+ elem.style.height = elem.scrollHeight + 'px'
46
+
47
+ window.setTimeout(() => {
48
+ elem.style.height = '0'
49
+ elem.style.paddingTop = '0'
50
+ elem.style.paddingBottom = '0'
51
+ }, 1)
52
+
53
+ // When the transition is complete, hide it
54
+ window.setTimeout(() => {
55
+ elem.classList.remove('is-visible')
56
+ }, 300)
57
+ }
58
+
59
+ toggleElement(elem) {
60
+ if (elem.classList.contains('is-visible')) {
61
+ this.hideElement(elem)
62
+ this.displayDownArrow()
63
+ return
64
+ }
65
+ // Otherwise, show it
66
+ this.showElement(elem)
67
+ this.displayUpArrow()
68
+ }
69
+
70
+ displayDownArrow() {
71
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'inline-block'
72
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'none'
73
+ }
74
+
75
+ displayUpArrow() {
76
+ this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'inline-block'
77
+ this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'none'
78
+ }
79
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import React from 'react'
4
4
  import { DateStacked, Flex, FlexItem, TimeStacked } from '../'
5
+ import { buildDataProps } from '../utilities/props'
5
6
  import { globalProps } from '../utilities/globalProps.js'
6
7
 
7
8
  type DateTimeStackedProps = {
@@ -12,12 +13,15 @@ type DateTimeStackedProps = {
12
13
  }
13
14
 
14
15
  const DateTimeStacked = (props: DateTimeStackedProps) => {
15
- const { date, dark } = props
16
+ const { date, data = {}, dark } = props,
17
+ dataProps = buildDataProps(data)
18
+
16
19
  return (
17
20
  <Flex
18
21
  className={globalProps(props)}
19
22
  orientation="row"
20
23
  vertical="center"
24
+ {...dataProps}
21
25
  >
22
26
  <FlexItem>
23
27
  <DateStacked
@@ -32,8 +36,8 @@ const DateTimeStacked = (props: DateTimeStackedProps) => {
32
36
  <TimeStacked
33
37
  className="pb_date_time_stacked_kit"
34
38
  dark={dark}
35
- date={date}
36
39
  tag="caption"
40
+ time={date}
37
41
  />
38
42
  </FlexItem>
39
43
  </Flex>
@@ -7,7 +7,7 @@
7
7
  <%= pb_rails("date_stacked", props: { align: "right", date: object.date, reverse: true, size: "sm", dark: object.dark }) %>
8
8
  <% end %>
9
9
  <%= pb_rails("flex/flex_item") do %>
10
- <%= pb_rails("time_stacked", props: { classname: "pb_date_time_stacked_kit", date: object.date, tag: "caption" }) %>
10
+ <%= pb_rails("time_stacked", props: { classname: "pb_date_time_stacked_kit", time: object.date, tag: "caption" }) %>
11
11
  <% end %>
12
12
  <% end %>
13
13
  <% end %>
@@ -21,7 +21,7 @@ module Playbook
21
21
  end
22
22
 
23
23
  def description
24
- @description ||= read_kit_file(kit, "_#{example_key}.md")
24
+ @description ||= read_kit_file("_#{example_key}.md")
25
25
  end
26
26
 
27
27
  def highlighter
@@ -75,6 +75,7 @@ const NavItem = (props: NavItemProps) => {
75
75
  key={iconLeft}
76
76
  >
77
77
  <Icon
78
+ aria={{ label: iconLeft }}
78
79
  className="pb_nav_list_item_icon_left"
79
80
  fixedWidth
80
81
  icon={iconLeft}
@@ -90,6 +91,7 @@ const NavItem = (props: NavItemProps) => {
90
91
  key={iconRight}
91
92
  >
92
93
  <Icon
94
+ aria={{ label: iconRight }}
93
95
  className="pb_nav_list_item_icon_right"
94
96
  fixedWidth
95
97
  icon={iconRight}
@@ -48,7 +48,7 @@ const Nav = (props: NavProps) => {
48
48
  )
49
49
 
50
50
  return (
51
- <div
51
+ <nav
52
52
  {...ariaProps}
53
53
  {...dataProps}
54
54
  className={cardCss}
@@ -69,7 +69,7 @@ const Nav = (props: NavProps) => {
69
69
  </div>
70
70
  </If>
71
71
  <ul>{children}</ul>
72
- </div>
72
+ </nav>
73
73
  )
74
74
  }
75
75
 
@@ -9,13 +9,13 @@
9
9
  <%= pb_rails("image", props: { url: object.image_url, classname: "pb_nav_img_wrapper" }) %>
10
10
  <% end %>
11
11
  <% if object.icon_left %>
12
- <%= pb_rails("icon", props: { icon: object.icon_left, classname: "pb_nav_list_item_icon_left", fixed_width: true}) %>
12
+ <%= pb_rails("icon", props: { aria: { label: object.icon_left }, icon: object.icon_left, classname: "pb_nav_list_item_icon_left", fixed_width: true}) %>
13
13
  <% end %>
14
14
  <span class="pb_nav_list_item_text">
15
15
  <%= object.text %><%= content.presence %>
16
16
  </span>
17
17
  <% if object.icon_right %>
18
- <%= pb_rails("icon", props: { icon: object.icon_right, classname: "pb_nav_list_item_icon_right", fixed_width: true}) %>
18
+ <%= pb_rails("icon", props: { aria: { label: object.icon_right }, icon: object.icon_right, classname: "pb_nav_list_item_icon_right", fixed_width: true}) %>
19
19
  <% end %>
20
20
  <% end %>
21
21
  <% end %>
@@ -1,4 +1,4 @@
1
- <%= content_tag(:div,
1
+ <%= content_tag(:nav,
2
2
  aria: object.aria,
3
3
  class: object.classname,
4
4
  data: object.data,
@@ -14,7 +14,7 @@ type ProgressSimpleProps = {
14
14
  muted: boolean,
15
15
  percent: string,
16
16
  value: number,
17
- variant?: "default" | "positive" | "negative",
17
+ variant?: "default" | "positive" | "negative" | "warning",
18
18
  width: string,
19
19
  }
20
20
 
@@ -33,6 +33,11 @@ $pb_progress_simple_height: 4px;
33
33
  background: $error;
34
34
  }
35
35
  }
36
+ &[class*=_warning] {
37
+ .progress_simple_value {
38
+ background: $warning;
39
+ }
40
+ }
36
41
 
37
42
  [class^=progress_simple_value] {
38
43
  width: 0%;
@@ -7,3 +7,8 @@
7
7
  <br>
8
8
 
9
9
  <%= pb_rails("progress_simple", props: { percent: 10, variant: "negative" }) %>
10
+
11
+ <br>
12
+
13
+ <%= pb_rails("progress_simple", props: { percent: 40, variant: "warning" }) %>
14
+
@@ -19,6 +19,13 @@ const ProgressSimpleVariants = () => {
19
19
  percent={10}
20
20
  variant="negative"
21
21
  />
22
+
23
+ <br />
24
+
25
+ <ProgressSimple
26
+ percent={40}
27
+ variant="warning"
28
+ />
22
29
  </div>
23
30
  )
24
31
  }
@@ -1 +1 @@
1
- Progress Simple can pass colors - primary, green and red. Variants names are `default`, `positive`, and `negative` respectively.
1
+ Progress Simple can pass colors - primary, green, red, and yellow. Variants names are `default`, `positive`, `negative`, and `warning`, respectively.
@@ -18,7 +18,7 @@ module Playbook
18
18
  # could this possibly be [sm, md, lg]?
19
19
  prop :width, default: "100%"
20
20
  prop :variant, type: Playbook::Props::Enum,
21
- values: %w[default positive negative],
21
+ values: %w[default positive negative warning],
22
22
  default: "default"
23
23
 
24
24
  def number_value
@@ -4,50 +4,67 @@ import React from 'react'
4
4
  import classnames from 'classnames'
5
5
 
6
6
  import DateTime from '../pb_kit/dateTime.js'
7
- import { buildCss } from '../utilities/props'
8
- import { Body, Caption } from '../'
7
+ import { buildCss, buildDataProps } from '../utilities/props'
9
8
  import { deprecatedProps, globalProps } from '../utilities/globalProps.js'
10
9
 
10
+ import { Body, Caption } from '../'
11
+
11
12
  type TimeStackedProps = {
12
13
  align?: 'left' | 'center' | 'right',
13
14
  className?: string | array<string>,
14
15
  dark?: boolean,
15
- data?: string,
16
- date: string,
16
+ data?: object,
17
+ date?: string,
17
18
  id?: string,
18
- tag?: 'body' | 'caption',
19
+ time: number | Date,
20
+ timeZone?: string,
19
21
  }
20
22
 
21
- const TimeStacked = (props: TimeStackedProps) => {
22
- const { align, className, dark, date } = props
23
- deprecatedProps('TimeStacked', ['tag'])
23
+ const TimeStackedDefault = (props: TimeStackedProps) => {
24
+ if (props.date) deprecatedProps('Time Stacked', ['date']) //date prop is deprecated, use time instead
25
+
26
+ const {
27
+ align = 'left',
28
+ className,
29
+ dark,
30
+ data = {},
31
+ date,
32
+ time,
33
+ timeZone,
34
+ } = props
35
+
24
36
  const classes = classnames(
25
37
  buildCss('pb_time_stacked_kit', align),
26
38
  globalProps(props),
27
- className,
39
+ className
28
40
  )
41
+ const dataProps = buildDataProps(data)
29
42
 
30
- const dateTimestamp = new DateTime({ value: date })
43
+ const dateTimestamp = new DateTime({ value: date ? date : new Date(time), zone: timeZone })
31
44
 
32
45
  return (
33
- <div className={classes}>
34
- <div
35
- align={align}
36
- className="pb_time_stacked_day_month"
46
+ <div
47
+ className={classes}
48
+ {...dataProps}
49
+ >
50
+ <Body
51
+ className={classnames('pb_time_stacked', 'time-spacing')}
52
+ color="light"
53
+ dark={dark}
37
54
  >
38
- <Body
39
- color="light"
40
- dark={dark}
41
- text={dateTimestamp.toTimeWithMeridian()}
42
- />
43
- <Caption
44
- color="light"
45
- dark={dark}
46
- text={dateTimestamp.toTimezone()}
47
- />
48
- </div>
55
+ <time>
56
+ {dateTimestamp.toTimeWithMeridian()}
57
+ <Caption
58
+ className="pb_time_stacked"
59
+ color="light"
60
+ dark={dark}
61
+ tag="span"
62
+ text={dateTimestamp.toTimezone()}
63
+ />
64
+ </time>
65
+ </Body>
49
66
  </div>
50
67
  )
51
68
  }
52
69
 
53
- export default TimeStacked
70
+ export default TimeStackedDefault
@@ -1,3 +1,21 @@
1
1
  @import "../pb_title/title";
2
2
  @import "../pb_caption/caption";
3
3
  @import "../tokens/colors";
4
+
5
+ [class^=pb_time_stacked_kit] {
6
+ &[class*=_center] {
7
+ text-align: center;
8
+ }
9
+
10
+ &[class*=_right] {
11
+ text-align: right;
12
+ }
13
+
14
+ }
15
+
16
+ .time-spacing {
17
+ time {
18
+ display: inline-grid;
19
+ margin-bottom: $space_xs - 6px;
20
+ }
21
+ }
@@ -1,5 +1,18 @@
1
- <%= pb_rails("time_stacked", props: { date: DateTime.now }) %>
2
- <br/>
3
- <%= pb_rails("time_stacked", props: { align: "center", date: DateTime.now }) %>
4
- <br/>
5
- <%= pb_rails("time_stacked", props: { align: "right", date: DateTime.now }) %>
1
+ <%= pb_rails("time_stacked", props: {
2
+ time: DateTime.now,
3
+ align: "left",
4
+ }) %>
5
+
6
+ <br>
7
+
8
+ <%= pb_rails("time_stacked", props: {
9
+ time: Time.now,
10
+ align: "center"
11
+ }) %>
12
+
13
+ <br>
14
+
15
+ <%= pb_rails("time_stacked", props: {
16
+ time: Time.now,
17
+ align: "right"
18
+ }) %>
@@ -5,18 +5,23 @@ const TimeStackedDefault = (props) => {
5
5
  return (
6
6
  <div>
7
7
  <TimeStacked
8
+ time={new Date()}
9
+ timeZone="America/New_York"
8
10
  {...props}
9
- date={new Date()}
10
11
  />
12
+ <br />
11
13
  <TimeStacked
12
- {...props}
13
14
  align="center"
14
- date={new Date()}
15
+ time={new Date()}
16
+ timeZone="America/New_York"
17
+ {...props}
15
18
  />
19
+ <br />
16
20
  <TimeStacked
17
- {...props}
18
21
  align="right"
19
- date={new Date()}
22
+ time={new Date()}
23
+ timeZone="America/New_York"
24
+ {...props}
20
25
  />
21
26
  </div>
22
27
  )
@@ -1,8 +1,12 @@
1
1
  <%= content_tag(:div,
2
- align: object.align,
3
2
  id: object.id,
4
3
  data: object.data,
5
4
  class: object.classname) do %>
6
- <%= pb_rails("body", props: { text: object.format_time_string, color: "light" }) %>
7
- <%= pb_rails("caption", props: { text: object.format_timezone, color: "light" }) %>
5
+
6
+ <%= pb_rails("body", props: { color: "light", classname: "pb_time_stacked time-spacing" }) do %>
7
+ <time>
8
+ <%= object.format_time_string %>
9
+ <%= pb_rails("caption", props: { color: "light", tag: "span", text: object.pb_date_time.to_timezone.upcase, classname: "pb_time_stacked" }) %>
10
+ </time>
11
+ <% end %>
8
12
  <% end %>
@@ -3,49 +3,27 @@
3
3
  module Playbook
4
4
  module PbTimeStacked
5
5
  class TimeStacked < Playbook::KitBase
6
+ prop :time, required: true
6
7
  prop :align, type: Playbook::Props::Enum,
7
8
  values: %w[left center right],
8
9
  default: "left"
9
- prop :classnames, type: Playbook::Props::String,
10
- default: nil
11
- prop :dark, type: Playbook::Props::Boolean,
12
- default: false
13
- prop :date, type: Playbook::Props::Date, required: true
10
+ prop :timezone, default: "America/New_York"
14
11
 
15
12
  def classname
16
- generate_classname("pb_time_stacked_kit", dark_class)
17
- end
18
-
19
- def day
20
- day = Playbook::PbKit::PbDateTime.new(date)
21
- content_tag(:time, datetime: day.to_iso) do
22
- day.to_day.to_s
23
- end
24
- end
25
-
26
- def month
27
- month = Playbook::PbKit::PbDateTime.new(date)
28
- content_tag(:time, datetime: month.to_iso) do
29
- month.to_month.to_s
30
- end
13
+ # convert deprecated prop values
14
+ generate_classname("pb_time_stacked_kit", align)
31
15
  end
32
16
 
33
17
  def format_time_string
34
- "#{pb_date_time.to_full_hour}:#{pb_date_time.to_minutes}#{pb_date_time.to_meridian}"
18
+ "#{pb_date_time.to_hour}:#{pb_date_time.to_minutes}#{pb_date_time.to_meridian}"
35
19
  end
36
20
 
37
- def format_timezone
38
- pb_date_time.to_timezone
39
- end
40
-
41
- private
42
-
43
- def dark_class
44
- dark ? "dark" : nil
21
+ def format_timezone_string
22
+ pb_date_time.to_timezone.to_s
45
23
  end
46
24
 
47
25
  def pb_date_time
48
- Playbook::PbKit::PbDateTime.new(date)
26
+ Playbook::PbKit::PbDateTime.new(time, timezone)
49
27
  end
50
28
  end
51
29
  end
@@ -0,0 +1,33 @@
1
+ import { renderKit, screen } from '../utilities/test-utils'
2
+
3
+ import TimeStacked from './_time_stacked'
4
+
5
+ /*eslint no-multiple-empty-lines: 0*/
6
+
7
+ test('returns the namespaced class', () => {
8
+ const props = {
9
+ data: { testid: 'default' },
10
+ time: new Date,
11
+ }
12
+
13
+ renderKit(TimeStacked, props)
14
+ expect(screen.getByTestId('default')).toHaveClass('pb_time_stacked_kit_left')
15
+
16
+ renderKit(TimeStacked, props, {
17
+ align: 'center',
18
+ data: { testid: 'center' },
19
+ })
20
+ expect(screen.getByTestId('center')).toHaveClass('pb_time_stacked_kit_center')
21
+
22
+ renderKit(TimeStacked, props, {
23
+ align: 'right',
24
+ data: { testid: 'right' },
25
+ })
26
+ expect(screen.getByTestId('right')).toHaveClass('pb_time_stacked_kit_right')
27
+
28
+ renderKit(TimeStacked, props, {
29
+ dark: true,
30
+ data: { testid: 'dark' },
31
+ })
32
+ expect(screen.getByTestId('dark')).toHaveClass('pb_time_stacked_kit_left dark')
33
+ })
@@ -46,7 +46,7 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
46
46
  content: " ";
47
47
  position: absolute;
48
48
  top: 100%;
49
- left: 50%;
49
+ left: calc(50% - 10px);
50
50
  border-color: $white transparent transparent transparent;
51
51
  border-style: solid;
52
52
  border-width: 10px;
@@ -95,9 +95,10 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
95
95
  box-shadow: -8px 0 28px 0 $tooltip_shadow;
96
96
  margin: 0 0 0 $space_sm;
97
97
  .arrow {
98
- left: -#{$space_xs};
99
- top: $arrow_vertical_offset;
98
+ left: -18px;
99
+ right: auto;
100
100
  margin-bottom: 0;
101
+ top: $arrow_vertical_offset;
101
102
  transform: rotate(90deg);
102
103
  }
103
104
  &.flipped .arrow {
@@ -12,6 +12,9 @@ window.datePickerHelper = datePickerHelper
12
12
  // Lazy image loading
13
13
  import 'lazysizes'
14
14
 
15
+ import PbCollapsible from './pb_collapsible'
16
+ PbCollapsible.start()
17
+
15
18
  import PbPopover from './pb_popover'
16
19
  PbPopover.start()
17
20
 
@@ -46,4 +46,4 @@ module Playbook
46
46
  end
47
47
  end
48
48
  end
49
- end
49
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- VERSION = "8.0.1"
4
+ VERSION = "8.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.1
4
+ version: 8.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-02-25 00:00:00.000000000 Z
12
+ date: 2021-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -663,6 +663,22 @@ files:
663
663
  - app/pb_kits/playbook/pb_circle_icon_button/docs/_footer.md
664
664
  - app/pb_kits/playbook/pb_circle_icon_button/docs/example.yml
665
665
  - app/pb_kits/playbook/pb_circle_icon_button/docs/index.js
666
+ - app/pb_kits/playbook/pb_collapsible/_collapsible.jsx
667
+ - app/pb_kits/playbook/pb_collapsible/_collapsible.scss
668
+ - app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleContent.jsx
669
+ - app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleMain.jsx
670
+ - app/pb_kits/playbook/pb_collapsible/collapsible.html.erb
671
+ - app/pb_kits/playbook/pb_collapsible/collapsible.rb
672
+ - app/pb_kits/playbook/pb_collapsible/collapsible.test.js
673
+ - app/pb_kits/playbook/pb_collapsible/collapsible_content.html.erb
674
+ - app/pb_kits/playbook/pb_collapsible/collapsible_content.rb
675
+ - app/pb_kits/playbook/pb_collapsible/collapsible_main.html.erb
676
+ - app/pb_kits/playbook/pb_collapsible/collapsible_main.rb
677
+ - app/pb_kits/playbook/pb_collapsible/docs/_collapsible_default.html.erb
678
+ - app/pb_kits/playbook/pb_collapsible/docs/_collapsible_default.jsx
679
+ - app/pb_kits/playbook/pb_collapsible/docs/example.yml
680
+ - app/pb_kits/playbook/pb_collapsible/docs/index.js
681
+ - app/pb_kits/playbook/pb_collapsible/index.js
666
682
  - app/pb_kits/playbook/pb_contact/_contact.jsx
667
683
  - app/pb_kits/playbook/pb_contact/_contact.scss
668
684
  - app/pb_kits/playbook/pb_contact/contact.html.erb
@@ -1808,6 +1824,7 @@ files:
1808
1824
  - app/pb_kits/playbook/pb_time_stacked/docs/index.js
1809
1825
  - app/pb_kits/playbook/pb_time_stacked/time_stacked.html.erb
1810
1826
  - app/pb_kits/playbook/pb_time_stacked/time_stacked.rb
1827
+ - app/pb_kits/playbook/pb_time_stacked/time_stacked.test.js
1811
1828
  - app/pb_kits/playbook/pb_timeline/_item.jsx
1812
1829
  - app/pb_kits/playbook/pb_timeline/_timeline.jsx
1813
1830
  - app/pb_kits/playbook/pb_timeline/_timeline.scss