playbook_ui 16.0.0.pre.alpha.play250713764 → 16.0.0.pre.alpha.play263413732
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +1 -1
- data/app/pb_kits/playbook/pb_filter/docs/_filter_default.html.erb +2 -2
- data/app/pb_kits/playbook/pb_filter/docs/_filter_default.jsx +9 -16
- data/app/pb_kits/playbook/pb_filter/filter.rb +2 -2
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +1 -2
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.tsx +20 -5
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.jsx +1 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_required_indicator.html.erb +7 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_required_indicator.jsx +24 -0
- data/app/pb_kits/playbook/{pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.md → pb_passphrase/docs/_passphrase_required_indicator.md} +1 -1
- data/app/pb_kits/playbook/pb_passphrase/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +2 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.test.jsx +30 -1
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.html.erb +5 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.jsx +14 -0
- data/app/pb_kits/playbook/{pb_rich_text_editor/docs/_rich_text_editor_required_indicator.md → pb_phone_number_input/docs/_phone_number_input_required_indicator.md} +1 -1
- data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +34 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +6 -33
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +0 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +0 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +0 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js +18 -33
- data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +11 -29
- data/app/pb_kits/playbook/pb_textarea/docs/example.yml +1 -3
- data/app/pb_kits/playbook/pb_textarea/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_textarea/index.ts +5 -12
- data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +0 -6
- data/app/pb_kits/playbook/pb_textarea/textarea.rb +0 -2
- data/app/pb_kits/playbook/pb_textarea/textarea.test.js +1 -18
- data/dist/chunks/{_pb_line_graph-BgKF_zz1.js → _pb_line_graph-hxi01lk7.js} +1 -1
- data/dist/chunks/_typeahead-CoJpI3RG.js +1 -0
- data/dist/chunks/{globalProps-BhVYCqRf.js → globalProps-DgYwLYNx.js} +1 -1
- data/dist/chunks/{lib-DD34ZrWL.js → lib-NLxTo8OB.js} +1 -1
- data/dist/chunks/vendor.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/lib/playbook/forms/builder/phone_number_field.rb +9 -0
- data/lib/playbook/version.rb +1 -1
- metadata +12 -14
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.jsx +0 -35
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.html.erb +0 -10
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.jsx +0 -21
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.html.erb +0 -5
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.jsx +0 -25
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.md +0 -3
- data/dist/chunks/_typeahead-B9a6ZsEP.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28617f4ae9161e1509366284f53708aacf06482d3c3acf6ad556281eacc6eb0f
|
|
4
|
+
data.tar.gz: 1d4a3acb8922f30259bed23161b5adfe9ce1aaea99880a26181deec26b5420d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0afdd7ba0dfd9a04dcd3fe768150d05be2a4bd61066654664d4593f19e030046616cc4fa0d08305fbbbdda970a4eceff4b20a3cb7dbbef1deb1d1896ba320ca4
|
|
7
|
+
data.tar.gz: 2b36e35618c97ba6be60522fb2166d3a737e8a24db9f8ff46583b7c22b33f32a220e28ae8ba5e8b54f00847659258fee7aa5cf5a4b6cdfec6cfdf6e6b7462b17
|
|
@@ -21,7 +21,7 @@ const nextValue = (value: SortValue[], name: string): SortValue => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const directionIcon = (dir: Direction) => (
|
|
24
|
-
dir == 'asc' ? '
|
|
24
|
+
dir == 'asc' ? 'sort-amount-up' : 'sort-amount-down'
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
const renderOptions = (options: SortOptions, value: SortValue[], handleChange: (arg0: SortValue) => void) => (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<%=
|
|
2
2
|
pb_rails("filter", props: {
|
|
3
3
|
min_width: "360px",
|
|
4
|
-
id: "
|
|
4
|
+
id: "1",
|
|
5
5
|
margin_bottom: "xl",
|
|
6
6
|
filters: [
|
|
7
7
|
{ name: "name", value: "John Wick" },
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<%=
|
|
45
45
|
pb_rails("filter", props: {
|
|
46
46
|
min_width: "360px",
|
|
47
|
-
id: "
|
|
47
|
+
id: "def2",
|
|
48
48
|
sort_menu: [
|
|
49
49
|
{ item: "Popularity", link: "?q[sorts]=managers_popularity+asc", active: true, direction: "desc" },
|
|
50
50
|
{ item: "Mananger's Title", link: "?q[sorts]=managers_title+asc", active: false },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
2
|
|
|
3
3
|
import Button from '../../pb_button/_button'
|
|
4
4
|
import Filter from '../../pb_filter/_filter'
|
|
@@ -6,18 +6,11 @@ import Flex from '../../pb_flex/_flex'
|
|
|
6
6
|
import Select from '../../pb_select/_select'
|
|
7
7
|
import TextInput from '../../pb_text_input/_text_input'
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const handleSortChange = (sortOptions) => {
|
|
14
|
-
setSortValue(sortOptions)
|
|
15
|
-
alert(JSON.stringify(sortOptions[0]))
|
|
16
|
-
}
|
|
9
|
+
const SortingChangeCallback = (sortOptions) => {
|
|
10
|
+
alert(JSON.stringify(sortOptions[0]))
|
|
11
|
+
}
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
setSortValue2(sortOptions)
|
|
20
|
-
}
|
|
13
|
+
const FilterDefault = (props) => {
|
|
21
14
|
const options = [
|
|
22
15
|
{ value: 'USA' },
|
|
23
16
|
{ value: 'Canada' },
|
|
@@ -36,7 +29,7 @@ const FilterDefault = (props) => {
|
|
|
36
29
|
}}
|
|
37
30
|
marginBottom="xl"
|
|
38
31
|
minWidth="375px"
|
|
39
|
-
onSortChange={
|
|
32
|
+
onSortChange={SortingChangeCallback}
|
|
40
33
|
results={1}
|
|
41
34
|
sortOptions={{
|
|
42
35
|
popularity: 'Popularity',
|
|
@@ -45,7 +38,7 @@ const FilterDefault = (props) => {
|
|
|
45
38
|
// eslint-disable-next-line
|
|
46
39
|
manager_name: 'Manager\'s Name',
|
|
47
40
|
}}
|
|
48
|
-
sortValue={
|
|
41
|
+
sortValue={[{ name: 'popularity', dir: 'desc' }]}
|
|
49
42
|
{...props}
|
|
50
43
|
>
|
|
51
44
|
{({ closePopover }) => (
|
|
@@ -89,7 +82,7 @@ const FilterDefault = (props) => {
|
|
|
89
82
|
<Filter
|
|
90
83
|
double
|
|
91
84
|
minWidth="375px"
|
|
92
|
-
onSortChange={
|
|
85
|
+
onSortChange={SortingChangeCallback}
|
|
93
86
|
results={0}
|
|
94
87
|
sortOptions={{
|
|
95
88
|
popularity: 'Popularity',
|
|
@@ -98,7 +91,7 @@ const FilterDefault = (props) => {
|
|
|
98
91
|
// eslint-disable-next-line
|
|
99
92
|
manager_name: 'Manager\'s Name',
|
|
100
93
|
}}
|
|
101
|
-
sortValue={
|
|
94
|
+
sortValue={[{ name: 'popularity', dir: 'desc' }]}
|
|
102
95
|
{...props}
|
|
103
96
|
>
|
|
104
97
|
{({ closePopover }) => (
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
<%= pb_form_with(scope: :example, url: "", method: :get, validate: true) do |form| %>
|
|
2
2
|
<%= form.text_field :example_text_field, props: { label: true, required: true, required_indicator: true } %>
|
|
3
3
|
<%= form.text_field :example_text_field_2, props: { label: "Text Field Custom Label", required: true, required_indicator: true } %>
|
|
4
|
-
<%= form.text_area :example_text_area, props: { label: true, required: true, required_indicator: true } %>
|
|
5
|
-
<%= form.text_area :example_text_area_2, props: { label: "Textarea Custom Label", required: true, required_indicator: true } %>
|
|
6
4
|
<%= form.email_field :example_email_field, props: { label: true, required: true, required_indicator: true } %>
|
|
7
5
|
<%= form.number_field :example_number_field, props: { label: true, required: true, required_indicator: true } %>
|
|
8
6
|
<%= form.search_field :example_search_field, props: { label: true, required: true, required_indicator: true } %>
|
|
9
7
|
<%= form.password_field :example_password_field, props: { label: true, required: true, required_indicator: true } %>
|
|
10
8
|
<%= form.url_field :example_url_field, props: { label: true, required: true, required_indicator: true } %>
|
|
9
|
+
<%= form.phone_number_field :example_phone_number_field, props: { label: true, required: true, required_indicator: true } %>
|
|
11
10
|
|
|
12
11
|
<%= form.actions do |action| %>
|
|
13
12
|
<%= action.submit %>
|
|
@@ -7,6 +7,7 @@ import { globalProps } from "../utilities/globalProps"
|
|
|
7
7
|
import Body from '../pb_body/_body'
|
|
8
8
|
import Caption from '../pb_caption/_caption'
|
|
9
9
|
import CircleIconButton from '../pb_circle_icon_button/_circle_icon_button'
|
|
10
|
+
import colors from '../tokens/exports/_colors.module.scss'
|
|
10
11
|
import Flex from '../pb_flex/_flex'
|
|
11
12
|
import Icon from '../pb_icon/_icon'
|
|
12
13
|
import PbReactPopover from '../pb_popover/_popover'
|
|
@@ -25,6 +26,7 @@ type PassphraseProps = {
|
|
|
25
26
|
inputProps?: GenericObject,
|
|
26
27
|
label?: string,
|
|
27
28
|
onChange: (inputValue: string) => void,
|
|
29
|
+
requiredIndicator?: boolean,
|
|
28
30
|
showTipsBelow?: "always" | "xs" | "sm" | "md" | "lg" | "xl",
|
|
29
31
|
tips?: Array<string>,
|
|
30
32
|
uncontrolled?: boolean,
|
|
@@ -43,6 +45,7 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
43
45
|
inputProps = {},
|
|
44
46
|
label = confirmation ? "Confirm Passphrase" : "Passphrase",
|
|
45
47
|
onChange = () => undefined,
|
|
48
|
+
requiredIndicator = false,
|
|
46
49
|
showTipsBelow = "always",
|
|
47
50
|
tips = [],
|
|
48
51
|
uncontrolled = false,
|
|
@@ -99,6 +102,7 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
99
102
|
|
|
100
103
|
const shieldIcon = getAllIcons()["shieldCheck"]
|
|
101
104
|
const eyeIcon = getAllIcons()["eye"]
|
|
105
|
+
const hasLabel = label && label !== ""
|
|
102
106
|
|
|
103
107
|
return (
|
|
104
108
|
<div
|
|
@@ -109,11 +113,22 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
109
113
|
id={id}
|
|
110
114
|
>
|
|
111
115
|
<label>
|
|
112
|
-
<Flex
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
<Flex
|
|
117
|
+
align="baseline"
|
|
118
|
+
{...(hasLabel ? { marginBottom: "xs" } : {})}
|
|
119
|
+
>
|
|
120
|
+
{hasLabel && (requiredIndicator ? (
|
|
121
|
+
<Caption
|
|
122
|
+
className="passphrase-label"
|
|
123
|
+
>
|
|
124
|
+
{label} <span style={{ color: `${colors.error}` }}>*</span>
|
|
125
|
+
</Caption>
|
|
126
|
+
) : (
|
|
127
|
+
<Caption
|
|
128
|
+
className="passphrase-label"
|
|
129
|
+
text={label}
|
|
130
|
+
/>
|
|
131
|
+
))}
|
|
117
132
|
{tips.length > 0 && !confirmation &&
|
|
118
133
|
<PbReactPopover
|
|
119
134
|
className="passphrase-tips"
|
|
@@ -120,6 +120,7 @@ const PassphraseMeterSettings = (props) => {
|
|
|
120
120
|
"These examples will all share the same input value. Type in any of the inputs to see how the strength meter changes in response to different settings."
|
|
121
121
|
}
|
|
122
122
|
</Body>
|
|
123
|
+
<br/>
|
|
123
124
|
<Passphrase
|
|
124
125
|
label={"Type your passphrase"}
|
|
125
126
|
onChange={handleChange}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import Passphrase from '../_passphrase'
|
|
4
|
+
|
|
5
|
+
const PassphraseRequiredIndicator = (props) => {
|
|
6
|
+
const [passphrase, setPassphrase] = useState('')
|
|
7
|
+
const handleOnChangePassphrase = (e) => {
|
|
8
|
+
setPassphrase(e.target ? e.target.value : e)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Passphrase
|
|
13
|
+
id="passphrase_required_indicator"
|
|
14
|
+
label="Passphrase"
|
|
15
|
+
name="passphrase"
|
|
16
|
+
onChange={handleOnChangePassphrase}
|
|
17
|
+
requiredIndicator
|
|
18
|
+
value={passphrase}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default PassphraseRequiredIndicator
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
The `requiredIndicator`/`required_indicator` prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
|
|
1
|
+
The `requiredIndicator`/`required_indicator` prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
|
|
2
2
|
|
|
3
3
|
You can use `requiredIndicator`/`required_indicator` with any validation approach: HTML5 validation via the `required` prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the `required` prop.
|
|
@@ -9,6 +9,7 @@ examples:
|
|
|
9
9
|
- passphrase_strength_change: Strength Change
|
|
10
10
|
- passphrase_common: Common Passphrases
|
|
11
11
|
- passphrase_breached: Breached Passphrases
|
|
12
|
+
- passphrase_required_indicator: Required Indicator
|
|
12
13
|
|
|
13
14
|
react:
|
|
14
15
|
- passphrase_default: Default
|
|
@@ -19,3 +20,4 @@ examples:
|
|
|
19
20
|
- passphrase_strength_change: Strength Change
|
|
20
21
|
- passphrase_common: Common Passphrases
|
|
21
22
|
- passphrase_breached: Breached Passphrases
|
|
23
|
+
- passphrase_required_indicator: Required Indicator
|
|
@@ -6,3 +6,4 @@ export { default as PassphraseTips } from './_passphrase_tips'
|
|
|
6
6
|
export { default as PassphraseStrengthChange } from './_passphrase_strength_change'
|
|
7
7
|
export { default as PassphraseCommon } from './_passphrase_common'
|
|
8
8
|
export { default as PassphraseBreached } from './_passphrase_breached'
|
|
9
|
+
export { default as PassphraseRequiredIndicator } from './_passphrase_required_indicator.jsx'
|
|
@@ -10,6 +10,7 @@ module Playbook
|
|
|
10
10
|
values: %w[always xs sm md lg xl],
|
|
11
11
|
default: "always"
|
|
12
12
|
prop :tips, type: Playbook::Props::Array, default: []
|
|
13
|
+
prop :required_indicator, type: Playbook::Props::Boolean, default: false
|
|
13
14
|
prop :value, type: Playbook::Props::String
|
|
14
15
|
|
|
15
16
|
def classname
|
|
@@ -23,6 +24,7 @@ module Playbook
|
|
|
23
24
|
confirmation: confirmation,
|
|
24
25
|
inputProps: input_props,
|
|
25
26
|
label: label,
|
|
27
|
+
requiredIndicator: required_indicator,
|
|
26
28
|
showTipsBelow: show_tips_below,
|
|
27
29
|
tips: tips,
|
|
28
30
|
uncontrolled: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { render, screen } from '../utilities/test-utils'
|
|
2
|
+
import { render, screen, within } from '../utilities/test-utils'
|
|
3
3
|
import { Passphrase } from 'playbook-ui'
|
|
4
4
|
|
|
5
5
|
const testId = 'text-input1',
|
|
@@ -86,3 +86,32 @@ test('popover target does not show when tips are not given', () => {
|
|
|
86
86
|
const kit = screen.getByTestId(testId)
|
|
87
87
|
expect(kit.querySelector('[class^=pb_popover_reference_wrapper]')).toBeNull()
|
|
88
88
|
})
|
|
89
|
+
|
|
90
|
+
test('renders required indicator asterisk when requiredIndicator is true', () => {
|
|
91
|
+
render(
|
|
92
|
+
<Passphrase
|
|
93
|
+
data={{ testid: testId }}
|
|
94
|
+
label="Passphrase"
|
|
95
|
+
requiredIndicator
|
|
96
|
+
/>
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const kit = screen.getByTestId(testId)
|
|
100
|
+
const label = within(kit).getByText(/Passphrase/)
|
|
101
|
+
expect(label).toBeInTheDocument()
|
|
102
|
+
expect(kit).toHaveTextContent('*')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('does not render required indicator asterisk when requiredIndicator is false', () => {
|
|
106
|
+
render(
|
|
107
|
+
<Passphrase
|
|
108
|
+
data={{ testid: testId }}
|
|
109
|
+
label="Passphrase"
|
|
110
|
+
/>
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const kit = screen.getByTestId(testId)
|
|
114
|
+
const label = within(kit).getByText(/Passphrase/)
|
|
115
|
+
expect(label).toBeInTheDocument()
|
|
116
|
+
expect(kit).not.toHaveTextContent('*')
|
|
117
|
+
})
|
|
@@ -36,6 +36,7 @@ type PhoneNumberInputProps = {
|
|
|
36
36
|
excludeCountries: string[],
|
|
37
37
|
preferredCountries?: string[],
|
|
38
38
|
required?: boolean,
|
|
39
|
+
requiredIndicator?: boolean,
|
|
39
40
|
value?: string,
|
|
40
41
|
formatAsYouType?: boolean,
|
|
41
42
|
strictMode?: boolean,
|
|
@@ -91,6 +92,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
91
92
|
onlyCountries = [],
|
|
92
93
|
excludeCountries = [],
|
|
93
94
|
required = false,
|
|
95
|
+
requiredIndicator = false,
|
|
94
96
|
preferredCountries = [],
|
|
95
97
|
value = "",
|
|
96
98
|
formatAsYouType = false,
|
|
@@ -533,6 +535,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
533
535
|
validateErrors()
|
|
534
536
|
},
|
|
535
537
|
onChange: formatAsYouType ? undefined : handleOnChange,
|
|
538
|
+
requiredIndicator,
|
|
536
539
|
value: inputValue
|
|
537
540
|
}
|
|
538
541
|
|
data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.jsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PhoneNumberInput from '../../pb_phone_number_input/_phone_number_input'
|
|
3
|
+
|
|
4
|
+
const PhoneNumberInputRequiredIndicator = (props) => (
|
|
5
|
+
<>
|
|
6
|
+
<PhoneNumberInput
|
|
7
|
+
id='phone_number_input_required_indicator'
|
|
8
|
+
label='Phone Number'
|
|
9
|
+
requiredIndicator
|
|
10
|
+
{...props} />
|
|
11
|
+
</>
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
export default PhoneNumberInputRequiredIndicator
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
The `requiredIndicator`/`required_indicator` prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
|
|
1
|
+
The `requiredIndicator`/`required_indicator` prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
|
|
2
2
|
|
|
3
3
|
You can use `requiredIndicator`/`required_indicator` with any validation approach: HTML5 validation via the `required` prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the `required` prop.
|
|
@@ -12,6 +12,7 @@ examples:
|
|
|
12
12
|
- phone_number_input_format: Format as You Type
|
|
13
13
|
- phone_number_input_strict_mode: Strict Mode
|
|
14
14
|
- phone_number_input_country_search: Country Search
|
|
15
|
+
- phone_number_input_required_indicator: Required Indicator
|
|
15
16
|
|
|
16
17
|
rails:
|
|
17
18
|
- phone_number_input_default: Default
|
|
@@ -24,3 +25,4 @@ examples:
|
|
|
24
25
|
- phone_number_input_strict_mode: Strict Mode
|
|
25
26
|
- phone_number_input_hidden_inputs: Hidden Inputs
|
|
26
27
|
- phone_number_input_country_search: Country Search
|
|
28
|
+
- phone_number_input_required_indicator: Required Indicator
|
|
@@ -9,3 +9,4 @@ export { default as PhoneNumberInputAccessInputElement } from './_phone_number_i
|
|
|
9
9
|
export { default as PhoneNumberInputFormat } from './_phone_number_input_format'
|
|
10
10
|
export { default as PhoneNumberInputStrictMode } from './_phone_number_input_strict_mode'
|
|
11
11
|
export { default as PhoneNumberInputCountrySearch } from './_phone_number_input_country_search'
|
|
12
|
+
export { default as PhoneNumberInputRequiredIndicator } from './_phone_number_input_required_indicator.jsx'
|
|
@@ -7,6 +7,8 @@ module Playbook
|
|
|
7
7
|
default: false
|
|
8
8
|
prop :required, type: Playbook::Props::Boolean,
|
|
9
9
|
default: false
|
|
10
|
+
prop :required_indicator, type: Playbook::Props::Boolean,
|
|
11
|
+
default: false
|
|
10
12
|
prop :initial_country, type: Playbook::Props::String,
|
|
11
13
|
default: ""
|
|
12
14
|
prop :label, type: Playbook::Props::String,
|
|
@@ -52,6 +54,7 @@ module Playbook
|
|
|
52
54
|
excludeCountries: exclude_countries,
|
|
53
55
|
preferredCountries: preferred_countries,
|
|
54
56
|
required: required,
|
|
57
|
+
requiredIndicator: required_indicator,
|
|
55
58
|
value: value,
|
|
56
59
|
countrySearch: country_search,
|
|
57
60
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { render, screen, act } from "../utilities/test-utils";
|
|
2
|
+
import { render, screen, act, within } from "../utilities/test-utils";
|
|
3
3
|
import PhoneNumberInput from "./_phone_number_input";
|
|
4
4
|
|
|
5
5
|
const testId = "phoneNumberInput";
|
|
@@ -129,7 +129,7 @@ test("should format phone number as '555-555-5555' with formatAsYouType and 'us'
|
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
render(<PhoneNumberInput {...props} />);
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
const input = screen.getByRole("textbox");
|
|
134
134
|
|
|
135
135
|
act(() => {
|
|
@@ -154,7 +154,38 @@ test("should pass countrySearch prop to component", () => {
|
|
|
154
154
|
};
|
|
155
155
|
|
|
156
156
|
render(<PhoneNumberInput {...props} />);
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
const wrapper = screen.getByTestId('phone-input-with-search');
|
|
159
159
|
expect(wrapper).toBeInTheDocument();
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
test("renders required indicator asterisk when requiredIndicator is true", () => {
|
|
163
|
+
const props = {
|
|
164
|
+
data: { testid: testId },
|
|
165
|
+
id: testId,
|
|
166
|
+
label: "Required Phone Number",
|
|
167
|
+
requiredIndicator: true,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
render(<PhoneNumberInput {...props} />);
|
|
171
|
+
|
|
172
|
+
const kit = screen.getByTestId(testId);
|
|
173
|
+
const label = within(kit).getByText(/Required Phone Number/);
|
|
174
|
+
expect(label).toBeInTheDocument();
|
|
175
|
+
expect(kit).toHaveTextContent("*");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("does not render required indicator asterisk when requiredIndicator is false", () => {
|
|
179
|
+
const props = {
|
|
180
|
+
data: { testid: testId },
|
|
181
|
+
id: testId,
|
|
182
|
+
label: "Phone Number",
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
render(<PhoneNumberInput {...props} />);
|
|
186
|
+
|
|
187
|
+
const kit = screen.getByTestId(testId);
|
|
188
|
+
const label = within(kit).getByText(/Phone Number/);
|
|
189
|
+
expect(label).toBeInTheDocument();
|
|
190
|
+
expect(kit).not.toHaveTextContent("*");
|
|
191
|
+
});
|
|
@@ -4,8 +4,6 @@ import { TrixEditor } from 'react-trix'
|
|
|
4
4
|
|
|
5
5
|
import inlineFocus from './inlineFocus'
|
|
6
6
|
import useFocus from './useFocus'
|
|
7
|
-
import Caption from '../pb_caption/_caption'
|
|
8
|
-
import colors from '../tokens/exports/_colors.module.scss'
|
|
9
7
|
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
|
10
8
|
import { buildAriaProps, buildDataProps, noop, buildHtmlProps } from '../utilities/props'
|
|
11
9
|
|
|
@@ -42,14 +40,12 @@ type RichTextEditorProps = {
|
|
|
42
40
|
inputOptions?: { [key: string]: string | number | boolean | (() => void) },
|
|
43
41
|
id?: string,
|
|
44
42
|
inline?: boolean,
|
|
45
|
-
label?: string,
|
|
46
43
|
extensions?: { [key: string]: string }[],
|
|
47
44
|
name?: string,
|
|
48
45
|
onChange: (html: string, text: string) => void,
|
|
49
46
|
placeholder?: string,
|
|
50
47
|
inputHeight?: "sm" | "md" | "lg",
|
|
51
48
|
inputMinHeight?: "sm" | "md" | "lg",
|
|
52
|
-
requiredIndicator?: boolean,
|
|
53
49
|
simple?: boolean,
|
|
54
50
|
sticky?: boolean,
|
|
55
51
|
template: string,
|
|
@@ -68,7 +64,6 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
68
64
|
data = {},
|
|
69
65
|
focus = false,
|
|
70
66
|
htmlOptions = {},
|
|
71
|
-
id,
|
|
72
67
|
inputOptions = {},
|
|
73
68
|
inline = false,
|
|
74
69
|
extensions,
|
|
@@ -81,9 +76,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
81
76
|
sticky = false,
|
|
82
77
|
template = '',
|
|
83
78
|
value = '',
|
|
84
|
-
maxWidth = "md"
|
|
85
|
-
requiredIndicator = false,
|
|
86
|
-
label,
|
|
79
|
+
maxWidth = "md"
|
|
87
80
|
} = props
|
|
88
81
|
|
|
89
82
|
const ariaProps = buildAriaProps(aria),
|
|
@@ -93,7 +86,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
93
86
|
containerRef = useRef<HTMLDivElement>(null)
|
|
94
87
|
|
|
95
88
|
const htmlProps = buildHtmlProps(htmlOptions)
|
|
96
|
-
|
|
89
|
+
|
|
97
90
|
const handleOnEditorReady = (editorInstance: Editor) => {
|
|
98
91
|
setEditor(editorInstance)
|
|
99
92
|
setTimeout(() => {
|
|
@@ -101,7 +94,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
101
94
|
if (oldId) {
|
|
102
95
|
const hiddenInput = document.getElementById(oldId)
|
|
103
96
|
if (hiddenInput) {
|
|
104
|
-
const newId = (inputOptions.id as string) || oldId
|
|
97
|
+
const newId = (inputOptions.id as string) || oldId
|
|
105
98
|
hiddenInput.id = newId
|
|
106
99
|
editorInstance.element.setAttribute('input', newId)
|
|
107
100
|
|
|
@@ -126,7 +119,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
126
119
|
// set button attributes
|
|
127
120
|
inlineCodeButton.dataset.trixAttribute = 'inlineCode'
|
|
128
121
|
blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
|
|
129
|
-
}
|
|
122
|
+
}
|
|
130
123
|
|
|
131
124
|
if (toolbarBottom) editor.element.after(toolbarElement)
|
|
132
125
|
|
|
@@ -154,7 +147,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
154
147
|
if (!advancedEditor || !focus) return
|
|
155
148
|
|
|
156
149
|
const handleFocus = () => setShowToolbarOnFocus(true)
|
|
157
|
-
|
|
150
|
+
|
|
158
151
|
const handleClickOutside = (event: Event) => {
|
|
159
152
|
if (isClickInContainer(event) || isClickInPopover(event)) return
|
|
160
153
|
setShowToolbarOnFocus(false)
|
|
@@ -222,29 +215,9 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
222
215
|
className={css}
|
|
223
216
|
ref={focus ? containerRef : undefined}
|
|
224
217
|
>
|
|
225
|
-
{label && (
|
|
226
|
-
<label htmlFor={id}>
|
|
227
|
-
{
|
|
228
|
-
requiredIndicator ? (
|
|
229
|
-
<Caption className="pb_text_input_kit_label"
|
|
230
|
-
marginBottom="xs"
|
|
231
|
-
>
|
|
232
|
-
{label} <span style={{ color: `${colors.error}` }}>*</span>
|
|
233
|
-
</Caption>
|
|
234
|
-
) : (
|
|
235
|
-
<Caption
|
|
236
|
-
className="pb_text_input_kit_label"
|
|
237
|
-
marginBottom="xs"
|
|
238
|
-
text={label}
|
|
239
|
-
/>
|
|
240
|
-
)
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
</label>
|
|
244
|
-
)}
|
|
245
218
|
{
|
|
246
219
|
advancedEditor ? (
|
|
247
|
-
<div
|
|
220
|
+
<div
|
|
248
221
|
className={classnames(
|
|
249
222
|
"pb_rich_text_editor_advanced_container",
|
|
250
223
|
{ [`input_height_${inputHeight}`]: !!inputHeight,[`input_min_height_${inputMinHeight}`]: !!inputMinHeight ,["toolbar-active"]: shouldShowToolbar }
|
|
@@ -9,7 +9,6 @@ examples:
|
|
|
9
9
|
- rich_text_editor_templates: Templates
|
|
10
10
|
# - rich_text_editor_toolbar_bottom: Toolbar Bottom
|
|
11
11
|
- rich_text_editor_inline: Inline
|
|
12
|
-
- rich_text_editor_required_indicator: Required Indicator
|
|
13
12
|
- rich_text_editor_preview: Preview
|
|
14
13
|
|
|
15
14
|
react:
|
|
@@ -32,7 +31,5 @@ examples:
|
|
|
32
31
|
- rich_text_editor_advanced_inline: Advanced (Inline)
|
|
33
32
|
- rich_text_editor_advanced_height: Advanced Height
|
|
34
33
|
- rich_text_editor_advanced_min_height: Advanced Min Height
|
|
35
|
-
- rich_text_editor_required_indicator: Required Indicator
|
|
36
|
-
- rich_text_editor_advanced_required_indicator: Advanced Required Indicator
|
|
37
34
|
- rich_text_editor_preview: Preview
|
|
38
35
|
- rich_text_editor_advanced_preview: Advanced Preview
|
|
@@ -19,5 +19,3 @@ export { default as RichTextEditorAdvancedSticky } from './_rich_text_editor_adv
|
|
|
19
19
|
export { default as RichTextEditorAdvancedInline } from './_rich_text_editor_advanced_inline.jsx'
|
|
20
20
|
export { default as RichTextEditorAdvancedHeight } from './_rich_text_editor_advanced_height.jsx'
|
|
21
21
|
export { default as RichTextEditorAdvancedMinHeight } from './_rich_text_editor_advanced_min_height.jsx'
|
|
22
|
-
export { default as RichTextEditorRequiredIndicator } from './_rich_text_editor_required_indicator.jsx'
|
|
23
|
-
export { default as RichTextEditorAdvancedRequiredIndicator } from './_rich_text_editor_advanced_required_indicator.jsx'
|
|
@@ -21,9 +21,6 @@ module Playbook
|
|
|
21
21
|
prop :template
|
|
22
22
|
prop :placeholder
|
|
23
23
|
prop :input_options
|
|
24
|
-
prop :label
|
|
25
|
-
prop :required_indicator, type: Playbook::Props::Boolean,
|
|
26
|
-
default: false
|
|
27
24
|
|
|
28
25
|
def classname
|
|
29
26
|
generate_classname("pb_rich_text_editor_kit", simple_class, focus_class, sticky_class, separator: " ")
|
|
@@ -54,8 +51,6 @@ module Playbook
|
|
|
54
51
|
template: template,
|
|
55
52
|
placeholder: placeholder,
|
|
56
53
|
inputOptions: input_options,
|
|
57
|
-
label: label,
|
|
58
|
-
requiredIndicator: required_indicator,
|
|
59
54
|
}
|
|
60
55
|
end
|
|
61
56
|
end
|