playbook_ui 9.10.0.pre.alpha1 → 9.12.0.pre.text.addon

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_button/_button.jsx +8 -19
  3. data/app/pb_kits/playbook/pb_button/button.rb +5 -3
  4. data/app/pb_kits/playbook/pb_button/docs/_button_accessibility.html.erb +1 -1
  5. data/app/pb_kits/playbook/pb_button/docs/_button_accessibility.jsx +1 -1
  6. data/app/pb_kits/playbook/pb_button/docs/_button_link.html.erb +3 -3
  7. data/app/pb_kits/playbook/pb_button/docs/_button_link.jsx +3 -0
  8. data/app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb +3 -3
  9. data/app/pb_kits/playbook/pb_button/docs/_button_loading.jsx +3 -0
  10. data/app/pb_kits/playbook/pb_passphrase/useZxcvbn.js +3 -3
  11. data/app/pb_kits/playbook/pb_table/docs/_table_side_highlight.md +1 -1
  12. data/app/pb_kits/playbook/pb_text_input/_text_input.jsx +80 -31
  13. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +98 -0
  14. data/app/pb_kits/playbook/pb_text_input/add_on.html.erb +13 -0
  15. data/app/pb_kits/playbook/pb_text_input/add_on.rb +30 -0
  16. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_add_on.html.erb +24 -0
  17. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_add_on.jsx +82 -0
  18. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_custom.html.erb +1 -1
  19. data/app/pb_kits/playbook/pb_text_input/docs/example.yml +2 -0
  20. data/app/pb_kits/playbook/pb_text_input/docs/index.js +1 -0
  21. data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +7 -16
  22. data/app/pb_kits/playbook/pb_text_input/text_input.rb +36 -2
  23. data/lib/playbook/props.rb +1 -0
  24. data/lib/playbook/props/nested_props.rb +23 -0
  25. data/lib/playbook/version.rb +1 -1
  26. metadata +24 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b36c79f834fafef501c48ece8fc72990708ab4323f3c172527d9a9a31bb9fa4
4
- data.tar.gz: ddc237d11376abb37c4e0d8630fbf06f4f2510dd0bdadefebc364bdf4b4e735a
3
+ metadata.gz: f94c4155e43cfcdf17c58b5afce6b032c570576aff59506dc1751cb4f0763010
4
+ data.tar.gz: 24b67df04fa47777d4c4f8ec6d43c648e61e7b1f2325c15acd4b125045d45012
5
5
  SHA512:
6
- metadata.gz: 71667f6a96f25e9fee0bd7d741b38c09eeced8c397c1126fafc1b3525b984d6a717e6332d2690818df67c0eb7da370429bbc50481f17c820256121d9972f48ae
7
- data.tar.gz: 953083fe2726a16fbbd33b7b550c1136230b6dec1043e0fd4f3c6ed47c52249c47b98a9da5e889cec15c05b11a42257f32cc1824d62e6109a8ad0009c1824f5e
6
+ metadata.gz: f5bd3d916766662441b2e5ca737747554866e2ee519669bdb557da95faccab27a5dcaf1f28b8fa1764cdf5b5687f9972739323e2b97e8aa1bc3516893eb1e4a1
7
+ data.tar.gz: c4ae6e848dbea60dcc6e6b990579223d65c10fb6fc1b30ceb22769e3d4c95d24338b4086cde2464743db270be9330fc4950cc3b801d0671894e8dac87f1a25e5
@@ -2,16 +2,14 @@
2
2
 
3
3
  import React from 'react'
4
4
  import classnames from 'classnames'
5
- import { buildDataProps } from '../utilities/props'
5
+ import { buildAriaProps, buildDataProps } from '../utilities/props'
6
6
  import { globalProps } from '../utilities/globalProps.js'
7
7
 
8
8
  import Icon from '../pb_icon/_icon.jsx'
9
9
 
10
10
  type EventHandler = (SyntheticInputEvent<HTMLInputElement>) => void
11
11
  type ButtonPropTypes = {
12
- aria?: {
13
- label: string,
14
- },
12
+ aria?: object,
15
13
  children?: array<React.ReactChild>,
16
14
  className?: string | array<string>,
17
15
  data?: object,
@@ -55,20 +53,9 @@ const buttonClassName = (props: ButtonPropTypes) => {
55
53
  return className
56
54
  }
57
55
 
58
- const buttonAriaProps = (props: ButtonPropTypes) => {
59
- const { aria } = props
60
- if (typeof aria !== 'object') return {}
61
- const { label } = aria
62
-
63
- const ariaProps = {}
64
-
65
- if (label !== null) ariaProps['aria-label'] = label
66
-
67
- return ariaProps
68
- }
69
-
70
56
  const Button = (props: ButtonPropTypes) => {
71
57
  const {
58
+ aria = {},
72
59
  children,
73
60
  className,
74
61
  data = {},
@@ -84,7 +71,7 @@ const Button = (props: ButtonPropTypes) => {
84
71
  value,
85
72
  } = props
86
73
 
87
- const buttonAria = buttonAriaProps(props)
74
+ const ariaProps = buildAriaProps(aria)
88
75
  const dataProps = buildDataProps(data)
89
76
  const css = classnames(
90
77
  buttonClassName(props),
@@ -114,11 +101,12 @@ const Button = (props: ButtonPropTypes) => {
114
101
  return (
115
102
  <If condition={link !== null}>
116
103
  <a
117
- {...buttonAria}
104
+ {...ariaProps}
118
105
  {...dataProps}
119
106
  className={css}
120
107
  href={link}
121
108
  id={id}
109
+ role="link"
122
110
  target={newWindow ? '_blank' : null}
123
111
  >
124
112
  <If condition={loading}>{loadingIcon}</If>
@@ -126,12 +114,13 @@ const Button = (props: ButtonPropTypes) => {
126
114
  </a>
127
115
  <Else />
128
116
  <button
129
- {...buttonAria}
117
+ {...ariaProps}
130
118
  {...dataProps}
131
119
  className={css}
132
120
  disabled={disabled}
133
121
  id={id}
134
122
  onClick={onClick}
123
+ role="button"
135
124
  type={htmlType}
136
125
  value={value}
137
126
  >
@@ -21,11 +21,12 @@ module Playbook
21
21
 
22
22
  def options
23
23
  {
24
- id: id,
25
- data: data,
24
+ aria: aria,
26
25
  class: classname,
26
+ data: data,
27
27
  disabled: disabled,
28
- aria: aria,
28
+ id: id,
29
+ role: "button",
29
30
  type: type,
30
31
  value: value,
31
32
  }.compact
@@ -34,6 +35,7 @@ module Playbook
34
35
  def link_options
35
36
  options.merge(
36
37
  href: link,
38
+ role: "link",
37
39
  target: new_window ? "_blank" : "_self"
38
40
  )
39
41
  end
@@ -1 +1 @@
1
- <%= pb_rails("button", props: { text: "Button with ARIA", aria: {label: "button"}, tag: "a", link: "http://google.com" }) %>
1
+ <%= pb_rails("button", props: { text: "Button with ARIA", aria: {label: "Go to Google"}, tag: "a", link: "http://google.com" }) %>
@@ -4,7 +4,7 @@ import { Button } from '../../'
4
4
  const ButtonAccessibility = (props) => (
5
5
  <div>
6
6
  <Button
7
- aria={{ label: 'button' }}
7
+ aria={{ label: 'Go to Google' }}
8
8
  link="https://google.com"
9
9
  tag="a"
10
10
  text="Button with ARIA"
@@ -1,3 +1,3 @@
1
- <%= pb_rails("button", props: { text: "A Tag Button", tag: "a", link: "http://google.com" }) %>
2
- <%= pb_rails("button", props: { text: "Open in new Window", new_window: true, link: "http://google.com" }) %>
3
- <%= pb_rails("button", props: { text: "A Tag Button Disabled", disabled: true, link: "http://google.com" }) %>
1
+ <%= pb_rails("button", props: { text: "A Tag Button", aria: { label: "Link to Google" }, tag: "a", link: "http://google.com" }) %>
2
+ <%= pb_rails("button", props: { text: "Open in new Window", aria: { label: "Link to Google in new window" }, new_window: true, link: "http://google.com" }) %>
3
+ <%= pb_rails("button", props: { text: "A Tag Button Disabled", aria: { label: "Disabled link to Google" }, disabled: true, link: "http://google.com" }) %>
@@ -4,12 +4,14 @@ import { Button } from '../../'
4
4
  const ButtonLink = (props) => (
5
5
  <div>
6
6
  <Button
7
+ aria={{ label: 'Link to Google' }}
7
8
  link="https://google.com"
8
9
  text="A Tag Button"
9
10
  {...props}
10
11
  />
11
12
  {' '}
12
13
  <Button
14
+ aria={{ label: 'Link to Google in new window' }}
13
15
  link="https://google.com"
14
16
  newWindow
15
17
  text="Open in New Window"
@@ -17,6 +19,7 @@ const ButtonLink = (props) => (
17
19
  />
18
20
  {' '}
19
21
  <Button
22
+ aria={{ label: 'Disabled link to Google' }}
20
23
  disabled
21
24
  link="https://google.com"
22
25
  text="A Tag Button Disabled"
@@ -1,3 +1,3 @@
1
- <%= pb_rails("button", props: { text: "Button Primary", loading: true }) %>
2
- <%= pb_rails("button", props: { text: "Button Primary", variant: "secondary", loading: true }) %>
3
- <%= pb_rails("button", props: { text: "Button Primary", variant: "link", loading: true }) %>
1
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", loading: true }) %>
2
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "secondary", loading: true }) %>
3
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "link", loading: true }) %>
@@ -4,12 +4,14 @@ import { Button } from '../../'
4
4
  const ButtonLoading = (props) => (
5
5
  <div>
6
6
  <Button
7
+ aria={{ label: 'Loading' }}
7
8
  loading
8
9
  text="Button Primary"
9
10
  {...props}
10
11
  />
11
12
  {' '}
12
13
  <Button
14
+ aria={{ label: 'Loading' }}
13
15
  loading
14
16
  text="Button Secondary"
15
17
  variant="secondary"
@@ -17,6 +19,7 @@ const ButtonLoading = (props) => (
17
19
  />
18
20
  {' '}
19
21
  <Button
22
+ aria={{ label: 'Loading' }}
20
23
  loading
21
24
  text="A Tag Button Disabled"
22
25
  variant="link"
@@ -15,9 +15,9 @@ export default function useZxcvbn(options) {
15
15
 
16
16
  useEffect(() => {
17
17
  if (confirmation) return
18
-
19
- setResult(calculator(passphrase))
20
- const str = result.score
18
+ const newResult = calculator(passphrase)
19
+ setResult(newResult)
20
+ const str = newResult.score
21
21
 
22
22
  const noPassphrase = passphrase.length <= 0
23
23
  const commonPassphrase = common || isPwned
@@ -1,3 +1,3 @@
1
- Side highlight can take product, status, and category colors. To view full list of colors, visit <a href="https://playbook.powerapp.cloud/utilities" target="_blank">token colors</a>.
1
+ Side highlight can take product, status, and category colors. To view full list of colors, visit <a href="https://playbook.powerapp.cloud/visual_guidelines" target="_blank">token colors</a>.
2
2
 
3
3
  Note: Only use category colors for categories. Do not mix it with product or status colors.
@@ -1,13 +1,10 @@
1
1
  /* @flow */
2
2
  import React, { forwardRef } from 'react'
3
3
  import classnames from 'classnames'
4
- import { Body, Caption } from '../'
4
+ import { Body, Caption, Card, Flex, Icon } from '../'
5
5
  import { globalProps } from '../utilities/globalProps.js'
6
6
 
7
- import {
8
- buildAriaProps,
9
- buildDataProps,
10
- } from '../utilities/props'
7
+ import { buildAriaProps, buildDataProps } from '../utilities/props'
11
8
 
12
9
  type TextInputProps = {
13
10
  aria?: object,
@@ -25,12 +22,14 @@ type TextInputProps = {
25
22
  type: string,
26
23
  value: string | number,
27
24
  children: Node,
25
+ addOn?: {
26
+ icon?: string,
27
+ alignment?: "right" | "left",
28
+ border?: boolean,
29
+ },
28
30
  }
29
31
 
30
- const TextInput = (
31
- props: TextInputProps,
32
- ref: React.ElementRef<"input">
33
- ) => {
32
+ const TextInput = (props: TextInputProps, ref: React.ElementRef<"input">) => {
34
33
  const {
35
34
  aria = {},
36
35
  className,
@@ -47,16 +46,78 @@ const TextInput = (
47
46
  type = 'text',
48
47
  value = '',
49
48
  children = null,
49
+ addOn = { icon: null, alignment: 'right', border: true },
50
50
  } = props
51
51
 
52
52
  const ariaProps = buildAriaProps(aria)
53
53
  const dataProps = buildDataProps(data)
54
+
55
+ const { alignment, border, icon } = addOn
56
+ const addOnAlignment = alignment === 'left' ? 'left' : 'right'
57
+ const borderToChange = addOnAlignment === 'left' ? 'right' : 'left'
58
+ const borderToggle = border === false ? 'off' : 'on'
59
+ const borderCss = `border_${borderToChange}_${borderToggle}`
60
+
61
+ const shouldShowAddOn = icon !== null
62
+ const addOnCss = shouldShowAddOn ? 'text_input_wrapper_add_on' : null
63
+ const addOnDarkModeCardCss = (shouldShowAddOn && dark) ? 'add-on-card-dark' : null
54
64
  const css = classnames([
55
65
  'pb_text_input_kit',
56
66
  error ? 'error' : null,
57
67
  globalProps(props),
58
68
  className,
59
69
  ])
70
+ const addOnIcon = (
71
+ <Icon
72
+ className="add-on-icon"
73
+ dark={dark}
74
+ fixedWidth={false}
75
+ icon={icon}
76
+ />
77
+ )
78
+ const textInput = (
79
+ <input
80
+ {...props}
81
+ className="text_input"
82
+ disabled={disabled}
83
+ id={id}
84
+ name={name}
85
+ onChange={onChange}
86
+ placeholder={placeholder}
87
+ ref={ref}
88
+ required={required}
89
+ type={type}
90
+ value={value}
91
+ />
92
+ )
93
+
94
+ const addOnInput = (
95
+ <React.Fragment>
96
+ <Flex
97
+ className={`add-on-${addOnAlignment} ${borderCss}`}
98
+ inline="flex-container"
99
+ vertical="center"
100
+ >
101
+ <If condition={addOnAlignment == 'left'}>
102
+ <Card
103
+ className={`${addOnDarkModeCardCss} add-on-card card-left-aligned`}
104
+ dark={dark}
105
+ >
106
+ {addOnIcon}
107
+ </Card>
108
+ {textInput}
109
+ <Else />
110
+ {textInput}
111
+ <Card
112
+ className={`${addOnDarkModeCardCss} add-on-card card-right-aligned`}
113
+ dark={dark}
114
+ >
115
+ {addOnIcon}
116
+ </Card>
117
+ </If>
118
+ </Flex>
119
+ </React.Fragment>
120
+ )
60
121
 
61
122
  return (
62
123
  <div
@@ -69,29 +130,17 @@ const TextInput = (
69
130
  dark={dark}
70
131
  text={label}
71
132
  />
72
- <div className="text_input_wrapper">
73
- <If condition={children}>
74
- {children}
75
- <Else />
76
- <input
77
- {...props}
78
- className="text_input"
79
- disabled={disabled}
80
- id={id}
81
- name={name}
82
- onChange={onChange}
83
- placeholder={placeholder}
84
- ref={ref}
85
- required={required}
86
- type={type}
87
- value={value}
133
+ <div className={`${addOnCss} text_input_wrapper`}>
134
+ <Choose>
135
+ <When condition={children}>{children}</When>
136
+ <When condition={shouldShowAddOn}>{addOnInput}</When>
137
+ <Otherwise>{textInput}</Otherwise>
138
+ </Choose>
139
+ <If condition={error}>
140
+ <Body
141
+ status="negative"
142
+ text={error}
88
143
  />
89
- <If condition={error}>
90
- <Body
91
- status="negative"
92
- text={error}
93
- />
94
- </If>
95
144
  </If>
96
145
  </div>
97
146
  </div>
@@ -36,6 +36,16 @@
36
36
  }
37
37
  }
38
38
  &.dark {
39
+ .add_on_left {
40
+ .text_input {
41
+ border-left: 0;
42
+ }
43
+ }
44
+ .add_on_right {
45
+ .text_input {
46
+ border-right: 0;
47
+ }
48
+ }
39
49
  .text_input_wrapper {
40
50
  margin-bottom: 1rem;
41
51
  input::placeholder,
@@ -80,3 +90,91 @@
80
90
  }
81
91
  }
82
92
  }
93
+
94
+ .text_input_wrapper_add_on {
95
+ & > [class^=pb_text_input_kit]:not(:last-child) {
96
+ .text_input_wrapper_add_on input, [class^=pb_text_input_kit] .text_input_wrapper_add_on .text_input {
97
+ border-bottom-right-radius: 0;
98
+ border-top-right-radius: 0;
99
+ border-right-width: 0;
100
+ }
101
+ }
102
+ .section-separator span {
103
+ padding: 0;
104
+ }
105
+
106
+ .add-on {
107
+ &-card {
108
+ height: 45px;
109
+ margin: 0;
110
+ padding: 0 !important;
111
+ align-items: center;
112
+ justify-content: center;
113
+ width: 45px;
114
+ }
115
+ &-icon {
116
+ color: $text_lt_lighter;
117
+ }
118
+ &-card-dark {
119
+ background-color: $bg-dark;
120
+ }
121
+ &-left {
122
+ .text_input {
123
+ border-top-left-radius: 0 !important;
124
+ border-bottom-left-radius: 0 !important;
125
+ }
126
+ }
127
+
128
+ &-right {
129
+ .text_input{
130
+ border-top-right-radius: 0 !important;
131
+ border-bottom-right-radius: 0 !important;
132
+ }
133
+ }
134
+ }
135
+ .text_input:focus ~ .add-on-card-dark {
136
+ background-color: $focus_input_dark;
137
+ border-width: 0px;
138
+ }
139
+
140
+ .card-left-aligned {
141
+ border-top-right-radius: 0 !important;
142
+ border-bottom-right-radius: 0 !important;
143
+ }
144
+
145
+ .card-right-aligned {
146
+ border-top-left-radius: 0 !important;
147
+ border-bottom-left-radius: 0 !important;
148
+ }
149
+
150
+ .border {
151
+ &_right_off {
152
+ .card-left-aligned {
153
+ border-right: 0;
154
+ }
155
+ .text_input {
156
+ border-left: 0 !important;
157
+ padding-left: 0 !important;
158
+ }
159
+ }
160
+ &_left_on {
161
+ .card-right-aligned {
162
+ border-left: 0;
163
+ }
164
+ }
165
+ &_right_on {
166
+ .card-left-aligned {
167
+ border-right: 0;
168
+ }
169
+ }
170
+ &_left_off {
171
+ .card-right-aligned {
172
+ border-left: 0;
173
+ }
174
+ .text_input {
175
+ border-right: 0 !important;
176
+ padding-right: 0 !important;
177
+ }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,13 @@
1
+ <%= pb_rails("flex", props: { classname: "add-on-#{alignment} #{border_css}", vertical: "center"}) do %>
2
+ <% if left_aligned? %>
3
+ <%= pb_rails("card", props: {classname: "#{dark_mode_css} add-on-card card-left-aligned", dark: dark}) do %>
4
+ <%= pb_rails("icon", props: { icon: icon, classname: "add-on-icon", fixed_width: false, dark: dark }) %>
5
+ <% end %>
6
+ <%= content %>
7
+ <% else %>
8
+ <%= content %>
9
+ <%= pb_rails("card", props: {classname: "#{dark_mode_css} add-on-card card-right-aligned", dark: dark}) do %>
10
+ <%= pb_rails("icon", props: { icon: icon, classname: "add-on-icon", fixed_width: false, dark: dark }) %>
11
+ <% end %>
12
+ <% end %>
13
+ <% end %>
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbTextInput
5
+ class AddOn < Playbook::KitBase
6
+ prop :icon, type: Playbook::Props::String, required: true
7
+ prop :alignment, type: Playbook::Props::Enum, values: %w[right left], default: "right"
8
+ prop :border, type: Playbook::Props::Boolean, default: true
9
+
10
+ def border_css
11
+ border_toggle = border ? "on" : "off"
12
+ border_to_change = if alignment == "left"
13
+ "right"
14
+ else
15
+ "left"
16
+ end
17
+
18
+ "border_#{border_to_change}_#{border_toggle}"
19
+ end
20
+
21
+ def left_aligned?
22
+ alignment == "left"
23
+ end
24
+
25
+ def dark_mode_css
26
+ dark ? "add-on-card-dark" : nil
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ <%= pb_rails("text_input", props: {
2
+ label: "Add On With Defaults",
3
+ add_on: { icon: "bat" }
4
+ }) %>
5
+
6
+ <%= pb_rails("text_input", props: {
7
+ label: "Right-Aligned Add On With Border",
8
+ add_on: { icon: "user", alignment: 'right', border: true }
9
+ }) %>
10
+
11
+ <%= pb_rails("text_input", props: {
12
+ label: "Left-Aligned Add On With No Border",
13
+ add_on: { icon: "percent", alignment: 'left', border: false }
14
+ }) %>
15
+
16
+ <%= pb_rails("text_input", props: {
17
+ label: "Left-Aligned Add On With Border",
18
+ add_on: { icon: "user", alignment: 'left', border: true }
19
+ }) %>
20
+
21
+ <%= pb_rails("text_input", props: {
22
+ label: "Right-Aligned Add On With No Border",
23
+ add_on: { icon: "percent", alignment: 'right', border: false }
24
+ }) %>
@@ -0,0 +1,82 @@
1
+ import React, { useState } from 'react'
2
+ import { TextInput } from '../../'
3
+
4
+ const TextInputAddOn = (props) => {
5
+ const [defaultInput, setDefaultInput] = useState('')
6
+ const [firstInput, setFirstInput] = useState('')
7
+ const [secondInput, setSecondInput] = useState('')
8
+ const [thirdInput, setThirdInput] = useState('')
9
+ const [fourthInput, setFourthInput] = useState('')
10
+
11
+ const handleUpdateDefaultInput = ({ target }) => {
12
+ setDefaultInput(target.value)
13
+ }
14
+
15
+ const handleUpdateFirstInput = ({ target }) => {
16
+ setFirstInput(target.value)
17
+ }
18
+
19
+ const handleUpdateSecondInput = ({ target }) => {
20
+ setSecondInput(target.value)
21
+ }
22
+
23
+ const handleUpdateThirdInput = ({ target }) => {
24
+ setThirdInput(target.value)
25
+ }
26
+
27
+ const handleUpdateFourthInput = ({ target }) => {
28
+ setFourthInput(target.value)
29
+ }
30
+
31
+ return (
32
+ <>
33
+ <div>
34
+ <TextInput
35
+ addOn={{ icon: 'bat' }}
36
+ label="Add On With Defaults"
37
+ onChange={handleUpdateDefaultInput}
38
+ value={defaultInput}
39
+ {...props}
40
+ />
41
+ </div>
42
+ <div>
43
+ <TextInput
44
+ addOn={{ icon: 'user', alignment: 'right', border: true }}
45
+ label="Right-Aligned Add On With Border"
46
+ onChange={handleUpdateFirstInput}
47
+ value={firstInput}
48
+ {...props}
49
+ />
50
+ </div>
51
+ <div>
52
+ <TextInput
53
+ addOn={{ icon: 'percent', alignment: 'left', border: false }}
54
+ label="Left-Aligned Add On With No Border"
55
+ onChange={handleUpdateSecondInput}
56
+ value={secondInput}
57
+ {...props}
58
+ />
59
+ </div>
60
+ <div>
61
+ <TextInput
62
+ addOn={{ icon: 'percent', alignment: 'right', border: false }}
63
+ label="Right-Aligned Add On With No Border"
64
+ onChange={handleUpdateThirdInput}
65
+ value={thirdInput}
66
+ {...props}
67
+ />
68
+ </div>
69
+ <div>
70
+ <TextInput
71
+ addOn={{ icon: 'percent', alignment: 'left', border: true }}
72
+ label="Left-Aligned Add On With Border"
73
+ onChange={handleUpdateFourthInput}
74
+ value={fourthInput}
75
+ {...props}
76
+ />
77
+ </div>
78
+ </>
79
+ )
80
+ }
81
+
82
+ export default TextInputAddOn
@@ -1,3 +1,3 @@
1
1
  <%= pb_rails("text_input", props: {label: "Custom Input"}) do %>
2
2
  <input placeholder="Custom placeholder" name="custom-name"></input>
3
- <% end %>
3
+ <% end %>
@@ -4,8 +4,10 @@ examples:
4
4
  - text_input_error: With Error
5
5
  - text_input_custom: Custom
6
6
  - text_input_disabled: Disabled
7
+ - text_input_add_on: Add On
7
8
  react:
8
9
  - text_input_default: Default
9
10
  - text_input_error: With Error
10
11
  - text_input_custom: Custom
11
12
  - text_input_disabled: Disabled
13
+ - text_input_add_on: Add On
@@ -2,3 +2,4 @@ export { default as TextInputDefault } from './_text_input_default.jsx'
2
2
  export { default as TextInputCustom } from './_text_input_custom.jsx'
3
3
  export { default as TextInputError } from './_text_input_error.jsx'
4
4
  export { default as TextInputDisabled } from './_text_input_disabled.jsx'
5
+ export { default as TextInputAddOn } from './_text_input_add_on.jsx'
@@ -5,25 +5,16 @@
5
5
  <% if object.label.present? %>
6
6
  <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_text_input_kit_label" }) %>
7
7
  <% end %>
8
- <%= content_tag(:div, class: "text_input_wrapper") do %>
8
+ <%= content_tag(:div, class: "#{add_on_class} text_input_wrapper") do %>
9
9
  <% if content.present? %>
10
10
  <%= content %>
11
+ <% elsif has_add_on? %>
12
+ <%= pb_rails("text_input/add_on", props: object.add_on_props) do %>
13
+ <%= input_tag %>
14
+ <% end %>
11
15
  <% else %>
12
- <%= tag(:input,
13
- autocomplete: object.autocomplete ? nil : "off",
14
- class: "text_input",
15
- data: object.validation_data,
16
- disabled: object.disabled,
17
- id: object.id,
18
- name: object.name,
19
- pattern: object.validation_pattern,
20
- placeholder: object.placeholder,
21
- required: object.required,
22
- type: object.type,
23
- value: object.value) %>
24
- <% end %>
25
- <% if object.error %>
26
- <%= pb_rails("body", props: {dark: object.dark, status: "negative", text: object.error}) %>
16
+ <%= input_tag %>
27
17
  <% end %>
18
+ <%= pb_rails("body", props: {dark: object.dark, status: "negative", text: object.error}) if object.error %>
28
19
  <% end %>
29
20
  <% end %>
@@ -17,11 +17,47 @@ module Playbook
17
17
  prop :validation, type: Playbook::Props::Hash,
18
18
  default: {}
19
19
  prop :value
20
+ prop :add_on, type: Playbook::Props::NestedProps,
21
+ nested_kit: Playbook::PbTextInput::AddOn
20
22
 
21
23
  def classname
22
24
  generate_classname("pb_text_input_kit") + error_class
23
25
  end
24
26
 
27
+ def input_tag
28
+ tag(:input, input_options)
29
+ end
30
+
31
+ def has_add_on?
32
+ add_on.present?
33
+ end
34
+
35
+ def add_on_class
36
+ has_add_on? ? 'text_input_wrapper_add_on' : nil
37
+ end
38
+
39
+ def add_on_props
40
+ { dark: dark }.merge(add_on || {})
41
+ end
42
+
43
+ private
44
+
45
+ def input_options
46
+ {
47
+ autocomplete: autocomplete ? nil : "off",
48
+ class: "text_input",
49
+ data: validation_data,
50
+ disabled: disabled,
51
+ id: id,
52
+ name: name,
53
+ pattern: validation_pattern,
54
+ placeholder: placeholder,
55
+ required: required,
56
+ type: type,
57
+ value: value
58
+ }
59
+ end
60
+
25
61
  def validation_message
26
62
  validation[:message] || ""
27
63
  end
@@ -36,8 +72,6 @@ module Playbook
36
72
  fields
37
73
  end
38
74
 
39
- private
40
-
41
75
  def error_class
42
76
  error ? " error" : ""
43
77
  end
@@ -17,6 +17,7 @@ require_relative "./props/numeric"
17
17
  require_relative "./props/percentage"
18
18
  require_relative "./props/proc"
19
19
  require_relative "./props/string"
20
+ require_relative "./props/nested_props"
20
21
 
21
22
  module Playbook
22
23
  module Props
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module Props
5
+ class NestedProps < Playbook::Props::Base
6
+ def initialize(nested_kit:, **kwargs)
7
+ super **kwargs
8
+ @nested_kit = nested_kit
9
+ end
10
+
11
+ def validate(values)
12
+ return true if values.nil?
13
+
14
+ @nested_kit.props.each do |prop_key, definition|
15
+ definition.validate! definition.value(values[prop_key])
16
+ end
17
+ true
18
+ rescue Playbook::Props::Error
19
+ false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- VERSION = "9.10.0.pre.alpha1"
4
+ VERSION = "9.12.0.pre.text.addon"
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.10.0.pre.alpha1
4
+ version: 9.12.0.pre.text.addon
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
8
8
  - Power Devs
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-04-26 00:00:00.000000000 Z
12
+ date: 2021-05-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -17,7 +17,7 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 5.2.4.4
20
+ version: 5.2.4.5
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
23
  version: '7.0'
@@ -27,7 +27,7 @@ dependencies:
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: 5.2.4.4
30
+ version: 5.2.4.5
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '7.0'
@@ -37,7 +37,7 @@ dependencies:
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 5.2.4.4
40
+ version: 5.2.4.5
41
41
  - - "<"
42
42
  - !ruby/object:Gem::Version
43
43
  version: '7.0'
@@ -47,7 +47,7 @@ dependencies:
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: 5.2.4.4
50
+ version: 5.2.4.5
51
51
  - - "<"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '7.0'
@@ -57,7 +57,7 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 5.2.4.4
60
+ version: 5.2.4.5
61
61
  - - "<"
62
62
  - !ruby/object:Gem::Version
63
63
  version: '7.0'
@@ -67,7 +67,7 @@ dependencies:
67
67
  requirements:
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
- version: 5.2.4.4
70
+ version: 5.2.4.5
71
71
  - - "<"
72
72
  - !ruby/object:Gem::Version
73
73
  version: '7.0'
@@ -299,22 +299,22 @@ dependencies:
299
299
  name: rspec-rails
300
300
  requirement: !ruby/object:Gem::Requirement
301
301
  requirements:
302
- - - ">="
303
- - !ruby/object:Gem::Version
304
- version: 3.8.0
305
302
  - - "~>"
306
303
  - !ruby/object:Gem::Version
307
304
  version: '3.8'
305
+ - - ">="
306
+ - !ruby/object:Gem::Version
307
+ version: 3.8.0
308
308
  type: :development
309
309
  prerelease: false
310
310
  version_requirements: !ruby/object:Gem::Requirement
311
311
  requirements:
312
- - - ">="
313
- - !ruby/object:Gem::Version
314
- version: 3.8.0
315
312
  - - "~>"
316
313
  - !ruby/object:Gem::Version
317
314
  version: '3.8'
315
+ - - ">="
316
+ - !ruby/object:Gem::Version
317
+ version: 3.8.0
318
318
  - !ruby/object:Gem::Dependency
319
319
  name: rubocop
320
320
  requirement: !ruby/object:Gem::Requirement
@@ -1792,8 +1792,12 @@ files:
1792
1792
  - app/pb_kits/playbook/pb_table/table_row.rb
1793
1793
  - app/pb_kits/playbook/pb_text_input/_text_input.jsx
1794
1794
  - app/pb_kits/playbook/pb_text_input/_text_input.scss
1795
+ - app/pb_kits/playbook/pb_text_input/add_on.html.erb
1796
+ - app/pb_kits/playbook/pb_text_input/add_on.rb
1795
1797
  - app/pb_kits/playbook/pb_text_input/docs/_description.md
1796
1798
  - app/pb_kits/playbook/pb_text_input/docs/_footer.md
1799
+ - app/pb_kits/playbook/pb_text_input/docs/_text_input_add_on.html.erb
1800
+ - app/pb_kits/playbook/pb_text_input/docs/_text_input_add_on.jsx
1797
1801
  - app/pb_kits/playbook/pb_text_input/docs/_text_input_custom.html.erb
1798
1802
  - app/pb_kits/playbook/pb_text_input/docs/_text_input_custom.jsx
1799
1803
  - app/pb_kits/playbook/pb_text_input/docs/_text_input_default.html.erb
@@ -2109,6 +2113,7 @@ files:
2109
2113
  - lib/playbook/props/enum.rb
2110
2114
  - lib/playbook/props/hash.rb
2111
2115
  - lib/playbook/props/hash_array.rb
2116
+ - lib/playbook/props/nested_props.rb
2112
2117
  - lib/playbook/props/number.rb
2113
2118
  - lib/playbook/props/number_array.rb
2114
2119
  - lib/playbook/props/numeric.rb
@@ -2123,7 +2128,7 @@ homepage: http://playbook.powerapp.cloud
2123
2128
  licenses:
2124
2129
  - MIT
2125
2130
  metadata: {}
2126
- post_install_message:
2131
+ post_install_message:
2127
2132
  rdoc_options: []
2128
2133
  require_paths:
2129
2134
  - lib
@@ -2138,8 +2143,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
2138
2143
  - !ruby/object:Gem::Version
2139
2144
  version: 1.3.1
2140
2145
  requirements: []
2141
- rubygems_version: 3.0.3
2142
- signing_key:
2146
+ rubyforge_project:
2147
+ rubygems_version: 2.7.3
2148
+ signing_key:
2143
2149
  specification_version: 4
2144
2150
  summary: Playbook Design System
2145
2151
  test_files: []