playbook_ui 12.14.0 → 12.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +1 -1
  3. data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +1 -1
  4. data/app/pb_kits/playbook/pb_avatar/avatar.rb +4 -0
  5. data/app/pb_kits/playbook/pb_avatar/avatar.test.js +14 -0
  6. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_default.html.erb +0 -1
  7. data/app/pb_kits/playbook/pb_background/_background.tsx +1 -1
  8. data/app/pb_kits/playbook/pb_background/background.rb +1 -1
  9. data/app/pb_kits/playbook/pb_badge/_badge.scss +1 -0
  10. data/app/pb_kits/playbook/pb_badge/_badge.tsx +1 -1
  11. data/app/pb_kits/playbook/pb_badge/badge.rb +5 -1
  12. data/app/pb_kits/playbook/pb_badge/badge.test.js +16 -1
  13. data/app/pb_kits/playbook/pb_body/_body_mixins.scss +3 -3
  14. data/app/pb_kits/playbook/pb_caption/_caption_mixin.scss +2 -2
  15. data/app/pb_kits/playbook/pb_card/_card.scss +13 -0
  16. data/app/pb_kits/playbook/pb_card/_card.tsx +3 -2
  17. data/app/pb_kits/playbook/pb_card/card_header.rb +9 -1
  18. data/app/pb_kits/playbook/pb_card/docs/_card_header.html.erb +11 -0
  19. data/app/pb_kits/playbook/pb_card/docs/_card_header.jsx +169 -139
  20. data/app/pb_kits/playbook/pb_enhanced_element/index.ts +1 -1
  21. data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.tsx +5 -5
  22. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.html.erb +1 -1
  23. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +0 -5
  24. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +0 -4
  25. data/app/pb_kits/playbook/pb_star_rating/{_star_rating.jsx → _star_rating.tsx} +18 -22
  26. data/app/pb_kits/playbook/pb_star_rating/star_rating.test.js +71 -0
  27. data/app/pb_kits/playbook/pb_table/{_table.jsx → _table.tsx} +9 -11
  28. data/app/pb_kits/playbook/pb_table/{_table_row.jsx → _table_row.tsx} +7 -8
  29. data/app/pb_kits/playbook/pb_table/docs/_table_with_background_kit.html.erb +41 -0
  30. data/app/pb_kits/playbook/pb_table/docs/_table_with_background_kit.jsx +62 -0
  31. data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
  32. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  33. data/app/pb_kits/playbook/pb_table/{index.js → index.ts} +4 -4
  34. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +129 -0
  35. data/app/pb_kits/playbook/pb_textarea/{index.js → index.tsx} +2 -0
  36. data/app/pb_kits/playbook/pb_textarea/textarea.test.js +213 -0
  37. data/app/pb_kits/playbook/tokens/_colors.scss +16 -1
  38. data/app/pb_kits/playbook/utilities/_cursor.scss +141 -1
  39. data/app/pb_kits/playbook/utilities/globalProps.ts +5 -2
  40. data/lib/playbook/cursor.rb +2 -2
  41. data/lib/playbook/version.rb +2 -2
  42. metadata +12 -9
  43. data/app/pb_kits/playbook/pb_flex/_flex_item.jsx +0 -41
  44. data/app/pb_kits/playbook/pb_textarea/_textarea.jsx +0 -135
@@ -7,12 +7,10 @@ module Playbook
7
7
  default: false
8
8
  prop :initial_country, type: Playbook::Props::String,
9
9
  default: ""
10
- prop :is_valid
11
10
  prop :label, type: Playbook::Props::String,
12
11
  default: ""
13
12
  prop :name, type: Playbook::Props::String,
14
13
  default: ""
15
- prop :onchange
16
14
  prop :only_countries, type: Playbook::Props::Array,
17
15
  default: []
18
16
  prop :preferred_countries, type: Playbook::Props::Array,
@@ -30,10 +28,8 @@ module Playbook
30
28
  dark: dark,
31
29
  disabled: disabled,
32
30
  initialCountry: initial_country,
33
- isValid: is_valid,
34
31
  label: label,
35
32
  name: name,
36
- onChange: onchange,
37
33
  onlyCountries: only_countries,
38
34
  preferredCountries: preferred_countries,
39
35
  value: value,
@@ -1,14 +1,12 @@
1
- /* @flow */
1
+ import React from "react"
2
+ import classnames from "classnames"
2
3
 
3
- import React from 'react'
4
- import classnames from 'classnames'
4
+ import { buildAriaProps, buildDataProps } from "../utilities/props"
5
5
 
6
- import { buildAriaProps, buildDataProps } from '../utilities/props'
7
-
8
- import Icon from '../pb_icon/_icon'
6
+ import Icon from "../pb_icon/_icon"
9
7
 
10
8
  type StarRatingProps = {
11
- aria?: object,
9
+ aria?: {[key: string]: string},
12
10
  className?: string,
13
11
  data?: object,
14
12
  fixedWidth?: boolean,
@@ -16,7 +14,7 @@ type StarRatingProps = {
16
14
  icon?: string,
17
15
  id?: string,
18
16
  rating: number,
19
- }
17
+ };
20
18
 
21
19
  const StarRating = ({
22
20
  aria = {},
@@ -29,15 +27,15 @@ const StarRating = ({
29
27
  const ariaProps = buildAriaProps(aria)
30
28
  const dataProps = buildDataProps(data)
31
29
  const css = classnames([
32
- 'pb_star_rating_kit', className,
30
+ "pb_star_rating_kit", className,
33
31
  ])
34
32
 
35
33
  const starCount = () => (
36
- [...Array(parseInt(rating))]
34
+ [...Array(Math.floor(rating))]
37
35
  )
38
36
 
39
37
  const hasHalfStar = () => (
40
- parseFloat(rating) % 1 !== 0
38
+ rating % 1 !== 0
41
39
  )
42
40
 
43
41
  return (
@@ -47,12 +45,11 @@ const StarRating = ({
47
45
  className={css}
48
46
  id={id}
49
47
  >
50
- <If condition={!hideRating}>
51
- <div className="pb_star_rating_number">
52
- {rating}
53
- </div>
54
- </If>
55
-
48
+ {!hideRating && (
49
+ <div className="pb_star_rating_number">
50
+ {rating}
51
+ </div>
52
+ )}
56
53
  <div className="pb_star_rating_wrapper">
57
54
  <div className="pb_star_rating_highlight">
58
55
  {starCount().map((_, index) => (
@@ -62,13 +59,12 @@ const StarRating = ({
62
59
  key={index}
63
60
  />
64
61
  ))}
65
-
66
- <If condition={hasHalfStar()}>
62
+ {hasHalfStar() && (
67
63
  <Icon
68
- fixedWidth={false}
69
- icon="star-half"
64
+ fixedWidth={false}
65
+ icon="star-half"
70
66
  />
71
- </If>
67
+ )}
72
68
  </div>
73
69
 
74
70
  <div className="pb_star_rating_base">
@@ -0,0 +1,71 @@
1
+ import React from "react";
2
+ import { render, screen } from "../utilities/test-utils";
3
+
4
+ import StarRating from "./_star_rating";
5
+
6
+ const testId = "star-rating-kit";
7
+
8
+ describe("Star Rating Kit", () => {
9
+ test("Expects to have correct classname", () => {
10
+ render(
11
+ <StarRating
12
+ data={{ testid: testId }}
13
+ rating={2}
14
+ />
15
+ );
16
+
17
+
18
+ const kit = screen.getByTestId(testId);
19
+ expect(kit).toHaveClass("pb_star_rating_kit");
20
+
21
+ });
22
+
23
+ test('should render aria-label', () => {
24
+ render(
25
+ <StarRating
26
+ aria={{ label: testId }}
27
+ data={{ testid: testId }}
28
+ rating={2}
29
+ />
30
+ );
31
+
32
+ const kit = screen.getByTestId(testId)
33
+ expect(kit).toHaveAttribute('aria-label', testId)
34
+ });
35
+
36
+ test("Displays two highlighted stars", () => {
37
+ render(
38
+ <StarRating
39
+ data={{ testid: testId }}
40
+ rating={2}
41
+ />
42
+ );
43
+
44
+
45
+ const kit = screen.getByTestId(testId);
46
+ const highlight = kit.querySelector(".pb_star_rating_highlight");
47
+ const stars = highlight.querySelectorAll(".far.fa-star");
48
+ const count = stars.length;
49
+
50
+ expect(count).toBe(2);
51
+ });
52
+
53
+ test("Displays three highlighted stars and a half star", () => {
54
+ render(
55
+ <StarRating
56
+ data={{ testid: testId }}
57
+ rating={3.5}
58
+ />
59
+ );
60
+
61
+ const kit = screen.getByTestId(testId);
62
+ const highlight = kit.querySelector(".pb_star_rating_highlight");
63
+ const stars = highlight.querySelectorAll(".far.fa-star");
64
+ const halfStars = highlight.querySelectorAll(".far.fa-star-half");
65
+ const starCount = stars.length;
66
+ const halfStarCount = halfStars.length;
67
+
68
+ expect(starCount).toBe(3);
69
+ expect(halfStarCount).toBe(1);
70
+ });
71
+ });
@@ -1,19 +1,17 @@
1
- /* @flow */
2
-
3
- import React, { useEffect, type Node } from 'react'
1
+ import React, { useEffect } from 'react'
4
2
  import classnames from 'classnames'
5
3
  import { buildAriaProps, buildDataProps } from '../utilities/props'
6
4
  import { globalProps } from '../utilities/globalProps'
7
- import PbTable from './'
5
+ import PbTable from '.'
8
6
 
9
7
  type TableProps = {
10
- aria?: object,
11
- children: array<Node> | Node,
8
+ aria?: { [key: string]: string },
9
+ children: React.ReactNode[] | React.ReactNode,
12
10
  className: string,
13
11
  collapse?: "sm" | "md" | "lg",
14
12
  container: boolean,
15
13
  dark?: boolean,
16
- data?: object,
14
+ data?: { [key: string]: string },
17
15
  dataTable: boolean,
18
16
  disableHover: boolean,
19
17
  id?: string,
@@ -52,9 +50,9 @@ const Table = (props: TableProps) => {
52
50
 
53
51
  return (
54
52
  <table
55
- {...ariaProps}
56
- {...dataProps}
57
- className={classnames(
53
+ {...ariaProps}
54
+ {...dataProps}
55
+ className={classnames(
58
56
  'pb_table',
59
57
  `table-${size}`,
60
58
  `table-responsive-${responsive}`,
@@ -70,7 +68,7 @@ const Table = (props: TableProps) => {
70
68
  tableCollapseCss,
71
69
  className
72
70
  )}
73
- id={id}
71
+ id={id}
74
72
  >
75
73
  {children}
76
74
  </table>
@@ -1,14 +1,13 @@
1
- /* @flow */
2
1
  import React from 'react'
3
2
  import classnames from 'classnames'
4
3
  import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
4
  import { globalProps } from '../utilities/globalProps'
6
5
 
7
6
  type TableRowPropTypes = {
8
- aria?: object,
9
- children: array<React.ReactNode> | React.ReactNode,
7
+ aria?: { [key: string]: string },
8
+ children: React.ReactNode[] | React.ReactNode,
10
9
  className: string,
11
- data?: object,
10
+ data?: { [key: string]: string },
12
11
  id?: string,
13
12
  sideHighlightColor: string,
14
13
  }
@@ -31,10 +30,10 @@ const TableRow = (props: TableRowPropTypes) => {
31
30
 
32
31
  return (
33
32
  <tr
34
- {...ariaProps}
35
- {...dataProps}
36
- className={classes}
37
- id={id}
33
+ {...ariaProps}
34
+ {...dataProps}
35
+ className={classes}
36
+ id={id}
38
37
  >
39
38
  {children}
40
39
  </tr>
@@ -0,0 +1,41 @@
1
+ <%= pb_rails("table", props: { size: "sm", margin_bottom: "lg" }) do %>
2
+ <thead>
3
+ <tr>
4
+ <th>Column 1</th>
5
+ <th>Column 2</th>
6
+ <th>Column 3</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <tr>
11
+ <td>Value 1</td>
12
+ <td>Value 2</td>
13
+ <td>Value 3</td>
14
+ </tr>
15
+ <%= pb_rails("background", props: { background_color: "error_subtle", tag: "tr" }) do %>
16
+ <td>Value 1</td>
17
+ <td>Value 2</td>
18
+ <td>Value 3</td>
19
+ <% end %>
20
+ <tr>
21
+ <td>Value 1</td>
22
+ <td>Value 2</td>
23
+ <td>Value 3</td>
24
+ </tr>
25
+ <tr>
26
+ <td>Value 1</td>
27
+ <td>Value 2</td>
28
+ <td>Value 3</td>
29
+ </tr>
30
+ <%= pb_rails("background", props: { background_color: "warning_subtle", tag: "tr" }) do %>
31
+ <td>Value 1</td>
32
+ <td>Value 2</td>
33
+ <td>Value 3</td>
34
+ <% end %>
35
+ <tr>
36
+ <td>Value 1</td>
37
+ <td>Value 2</td>
38
+ <td>Value 3</td>
39
+ </tr>
40
+ </tbody>
41
+ <% end %>
@@ -0,0 +1,62 @@
1
+ import React from 'react'
2
+
3
+ import Table from '../_table'
4
+ import Background from "../../pb_background/_background"
5
+
6
+ const TableWithBackgroundKit = (props) => {
7
+ return (
8
+ <div>
9
+ <Table
10
+ {...props}
11
+ >
12
+ <thead>
13
+ <tr>
14
+ <th>{'Column 1'}</th>
15
+ <th>{'Column 2'}</th>
16
+ <th>{'Column 3'}</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <tr>
21
+ <td>{'Value 1'}</td>
22
+ <td>{'Value 2'}</td>
23
+ <td>{'Value 3'}</td>
24
+ </tr>
25
+ <Background
26
+ backgroundColor="error_subtle"
27
+ tag='tr'
28
+ >
29
+ <td>{'Value 1'}</td>
30
+ <td>{'Value 2'}</td>
31
+ <td>{'Value 3'}</td>
32
+ </Background>
33
+ <tr>
34
+ <td>{'Value 1'}</td>
35
+ <td>{'Value 2'}</td>
36
+ <td>{'Value 3'}</td>
37
+ </tr>
38
+ <tr>
39
+ <td>{'Value 1'}</td>
40
+ <td>{'Value 2'}</td>
41
+ <td>{'Value 3'}</td>
42
+ </tr>
43
+ <Background
44
+ backgroundColor="warning_subtle"
45
+ tag='tr'
46
+ >
47
+ <td>{'Value 1'}</td>
48
+ <td>{'Value 2'}</td>
49
+ <td>{'Value 3'}</td>
50
+ </Background>
51
+ <tr>
52
+ <td>{'Value 1'}</td>
53
+ <td>{'Value 2'}</td>
54
+ <td>{'Value 3'}</td>
55
+ </tr>
56
+ </tbody>
57
+ </Table>
58
+ </div>
59
+ )
60
+ }
61
+
62
+ export default TableWithBackgroundKit
@@ -20,6 +20,7 @@ examples:
20
20
  - table_two_plus_actions: Table with 2+ Actions
21
21
  - table_action_middle: Table with Actions in the Middle
22
22
  - table_icon_buttons: Table with Icon Buttons
23
+ - table_with_background_kit: Table With Background Kit
23
24
 
24
25
 
25
26
  react:
@@ -43,4 +44,5 @@ examples:
43
44
  - table_two_plus_actions: Table with 2+ Actions
44
45
  - table_action_middle: Table with Actions in the Middle
45
46
  - table_icon_buttons: Table with Icon Buttons
47
+ - table_with_background_kit: Table With Background Kit
46
48
 
@@ -18,3 +18,4 @@ export { default as TableAlignmentColumn } from './_table_alignment_column.jsx'
18
18
  export { default as TableAlignmentRow } from './_table_alignment_row.jsx'
19
19
  export { default as TableAlignmentShiftRow } from './_table_alignment_shift_row.jsx'
20
20
  export { default as TableAlignmentShiftData } from './_table_alignment_shift_data.jsx'
21
+ export { default as TableWithBackgroundKit } from './_table_with_background_kit.jsx'
@@ -9,16 +9,16 @@ export default class PbTable extends PbEnhancedElement {
9
9
  const tables = document.querySelectorAll('.table-responsive-collapse');
10
10
 
11
11
  // Each Table
12
- [].forEach.call(tables, (table) => {
12
+ [].forEach.call(tables, (table: HTMLTableElement) => {
13
13
  // Header Titles
14
- var headers = [].map.call(table.querySelectorAll('th'), (header) => {
14
+ var headers = [].map.call(table.querySelectorAll('th'), (header: Element) => {
15
15
  return header.textContent.replace(/\r?\n|\r/, '')
16
16
  });
17
17
 
18
18
  // for each row in tbody
19
- [].forEach.call(table.querySelectorAll('tbody tr'), (row) => {
19
+ [].forEach.call(table.querySelectorAll('tbody tr'), (row: HTMLTableRowElement) => {
20
20
  // for each cell
21
- [].forEach.call(row.cells, (cell, headerIndex) => {
21
+ [].forEach.call(row.cells, (cell: HTMLTableCellElement, headerIndex: number) => {
22
22
  // apply the attribute
23
23
  cell.setAttribute('data-title', headers[headerIndex])
24
24
  })
@@ -0,0 +1,129 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+
3
+ import React, { forwardRef, useEffect, useRef } from 'react'
4
+ import classnames from 'classnames'
5
+
6
+ import PbTextarea from '.'
7
+ import type { InputCallback } from '../types'
8
+
9
+ import { buildAriaProps, buildDataProps } from '../utilities/props'
10
+ import { globalProps, GlobalProps } from '../utilities/globalProps'
11
+
12
+ import Body from '../pb_body/_body'
13
+ import Caption from '../pb_caption/_caption'
14
+ import Flex from '../pb_flex/_flex'
15
+ import FlexItem from '../pb_flex/_flex_item'
16
+
17
+ type TextareaProps = {
18
+ aria?: {[key: string]: string},
19
+ characterCount?: string,
20
+ className?: string,
21
+ children?: React.ReactChild[],
22
+ data?: {[key: string]: string},
23
+ disabled?: boolean,
24
+ error?: string,
25
+ id?: string,
26
+ inline?: boolean,
27
+ object?: string,
28
+ method?: string,
29
+ label?: string,
30
+ maxCharacters?: string,
31
+ placeholder?: string,
32
+ value?: string,
33
+ name?: string,
34
+ required?: boolean,
35
+ rows?: number,
36
+ resize: "none" | "both" | "horizontal" | "vertical" | "auto",
37
+ onChange?: InputCallback<HTMLTextAreaElement>,
38
+ } & GlobalProps
39
+
40
+ const Textarea = ({
41
+ aria = {},
42
+ characterCount,
43
+ className,
44
+ children,
45
+ data = {},
46
+ disabled,
47
+ inline = false,
48
+ resize = 'none',
49
+ error,
50
+ label,
51
+ maxCharacters,
52
+ name,
53
+ onChange = () => {},
54
+ placeholder,
55
+ required,
56
+ rows = 4,
57
+ value,
58
+ ...props
59
+ }: TextareaProps, ref: any) => {
60
+ ref = useRef<HTMLTextAreaElement>(null)
61
+ useEffect(() => {
62
+ if (ref.current && resize === 'auto') {
63
+ PbTextarea.addMatch(ref.current)
64
+ }
65
+ })
66
+
67
+ const errorClass = error ? 'error' : null
68
+ const inlineClass = inline ? 'inline' : ''
69
+ const resizeClass = `resize_${resize}`
70
+ const classes = classnames('pb_textarea_kit', errorClass, inlineClass, resizeClass, globalProps(props), className)
71
+ const noCount = typeof characterCount !== 'undefined'
72
+ const ariaProps: {[key: string]: any} = buildAriaProps(aria)
73
+ const dataProps: {[key: string]: any} = buildDataProps(data)
74
+
75
+ const characterCounter = () => {
76
+ return maxCharacters && characterCount ? `${checkIfZero(characterCount)} / ${maxCharacters}` : `${checkIfZero(characterCount)}`
77
+ }
78
+
79
+ const checkIfZero = (characterCount: string | number) => {
80
+ return characterCount == 0 ? characterCount.toString() : characterCount
81
+ }
82
+
83
+ return (
84
+ <div
85
+ {...ariaProps}
86
+ {...dataProps}
87
+ className={classes}
88
+ >
89
+ <Caption text={label} />
90
+ {children || (
91
+ <textarea
92
+ className="pb_textarea_kit"
93
+ disabled={disabled}
94
+ name={name}
95
+ onChange={onChange}
96
+ placeholder={placeholder}
97
+ ref={ref}
98
+ required={required}
99
+ rows={rows}
100
+ value={value}
101
+ {...props}
102
+ />
103
+ )}
104
+
105
+ {error ? (
106
+ <>
107
+ {characterCount ? (
108
+ <Flex spacing="between" vertical="center">
109
+ <FlexItem>
110
+ <Body margin="none" status="negative" text={error} />
111
+ </FlexItem>
112
+ <FlexItem>
113
+ <Caption margin="none" size="xs" text={characterCounter()} />
114
+ </FlexItem>
115
+ </Flex>
116
+ ) : (
117
+ <Body status="negative" text={error} />
118
+ )}
119
+ </>
120
+ ) : (
121
+ noCount && (
122
+ <Caption margin="none" size="xs" text={characterCounter()} />
123
+ )
124
+ )}
125
+ </div>
126
+ );
127
+ }
128
+
129
+ export default forwardRef(Textarea)
@@ -1,6 +1,8 @@
1
1
  import PbEnhancedElement from '../pb_enhanced_element'
2
2
 
3
3
  export default class PbTextarea extends PbEnhancedElement {
4
+ style: {[key: string]: string}
5
+ scrollHeight: string
4
6
  static get selector() {
5
7
  return '.resize_auto textarea'
6
8
  }