playbook_ui 12.14.0 → 12.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }