playbook_ui 16.1.0.pre.rc.2 → 16.1.0.pre.rc.3
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_background/docs/_background_responsive.jsx +30 -0
- data/app/pb_kits/playbook/pb_background/docs/_background_responsive.md +1 -0
- data/app/pb_kits/playbook/pb_background/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_background/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +3 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_input_display.html.erb +74 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_input_display.jsx +87 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_input_display.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +35 -33
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +33 -6
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.jsx +35 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.html.erb +10 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.jsx +21 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +3 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +2 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +5 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js +33 -18
- data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +29 -11
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.html.erb +5 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.jsx +25 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_textarea/docs/example.yml +3 -1
- data/app/pb_kits/playbook/pb_textarea/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_textarea/index.ts +12 -5
- data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +6 -0
- data/app/pb_kits/playbook/pb_textarea/textarea.rb +2 -0
- data/app/pb_kits/playbook/pb_textarea/textarea.test.js +18 -1
- data/app/pb_kits/playbook/utilities/test/globalProps/globalProps.integration.test.js +936 -0
- data/dist/chunks/{_pb_line_graph-hxi01lk7.js → _pb_line_graph-BgKF_zz1.js} +1 -1
- data/dist/chunks/{_typeahead-BgLnlhzP.js → _typeahead-B9a6ZsEP.js} +1 -1
- data/dist/chunks/{globalProps-DgYwLYNx.js → globalProps-BhVYCqRf.js} +1 -1
- data/dist/chunks/{lib-NLxTo8OB.js → lib-DD34ZrWL.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/version.rb +1 -1
- metadata +20 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { render, screen, fireEvent, waitFor } from '../utilities/test-utils'
|
|
2
|
+
import { render, screen, fireEvent, waitFor, within } from '../utilities/test-utils'
|
|
3
3
|
import { useEditor, EditorContent } from "@tiptap/react"
|
|
4
4
|
import StarterKit from "@tiptap/starter-kit"
|
|
5
5
|
|
|
@@ -89,14 +89,14 @@ const TestAdvancedEditor = ({ toolbarOnFocus = false, ...props }) => {
|
|
|
89
89
|
describe('Advanced TipTap Editor works as expected', () => {
|
|
90
90
|
test('renders advanced editor with toolbar', () => {
|
|
91
91
|
render(<TestAdvancedEditor />)
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
const kit = screen.getByTestId(testId)
|
|
94
94
|
expect(kit).toHaveClass(kitClass)
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
// Check for advanced container
|
|
97
97
|
const advancedContainer = kit.querySelector('.pb_rich_text_editor_advanced_container')
|
|
98
98
|
expect(advancedContainer).toBeInTheDocument()
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
// Check for toolbar
|
|
101
101
|
const toolbar = kit.querySelector('.toolbar')
|
|
102
102
|
expect(toolbar).toBeInTheDocument()
|
|
@@ -104,7 +104,7 @@ describe('Advanced TipTap Editor works as expected', () => {
|
|
|
104
104
|
|
|
105
105
|
test('renders advanced editor without toolbar when advancedEditorToolbar is false', () => {
|
|
106
106
|
render(<TestAdvancedEditor advancedEditorToolbar={false} />)
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
const kit = screen.getByTestId(testId)
|
|
109
109
|
const toolbar = kit.querySelector('.toolbar')
|
|
110
110
|
expect(toolbar).not.toBeInTheDocument()
|
|
@@ -112,17 +112,17 @@ describe('Advanced TipTap Editor works as expected', () => {
|
|
|
112
112
|
|
|
113
113
|
test('shows/hides toolbar on focus when focus is enabled', async () => {
|
|
114
114
|
render(<TestAdvancedEditor focus />)
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
const kit = screen.getByTestId(testId)
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
// Initially toolbar should be hidden
|
|
119
119
|
let toolbar = kit.querySelector('.toolbar')
|
|
120
120
|
expect(toolbar).not.toBeInTheDocument()
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
const editorElement = kit.querySelector('.ProseMirror')
|
|
123
123
|
// Focus the editor
|
|
124
124
|
fireEvent.focus(editorElement)
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
// Toolbar should now be visible
|
|
127
127
|
await waitFor(() => {
|
|
128
128
|
toolbar = kit.querySelector('.toolbar')
|
|
@@ -133,7 +133,7 @@ describe('Advanced TipTap Editor works as expected', () => {
|
|
|
133
133
|
|
|
134
134
|
test('supports simple prop with advanced editor', () => {
|
|
135
135
|
render(<TestAdvancedEditor simple />)
|
|
136
|
-
|
|
136
|
+
|
|
137
137
|
const kit = screen.getByTestId(testId)
|
|
138
138
|
const toolbar = kit.querySelector('.toolbar')
|
|
139
139
|
expect(toolbar).toBeInTheDocument()
|
|
@@ -144,7 +144,7 @@ describe('Advanced TipTap Editor works as expected', () => {
|
|
|
144
144
|
|
|
145
145
|
test('supports sticky prop with advanced editor', () => {
|
|
146
146
|
render(<TestAdvancedEditor sticky />)
|
|
147
|
-
|
|
147
|
+
|
|
148
148
|
const kit = screen.getByTestId(testId)
|
|
149
149
|
const stickyToolbar = kit.querySelector('.pb_rich_text_editor_tiptap_toolbar_sticky')
|
|
150
150
|
expect(stickyToolbar).toBeInTheDocument()
|
|
@@ -154,37 +154,52 @@ describe('Advanced TipTap Editor works as expected', () => {
|
|
|
154
154
|
test('applies aria-label when provided', () => {
|
|
155
155
|
const ariaLabel = 'Rich Text Editor'
|
|
156
156
|
render(<TestAdvancedEditor aria={{ label: ariaLabel }} />)
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
const kit = screen.getByTestId(testId)
|
|
159
159
|
expect(kit).toHaveAttribute('aria-label', ariaLabel)
|
|
160
160
|
})
|
|
161
161
|
|
|
162
162
|
test('supports inline prop with advanced editor', () => {
|
|
163
163
|
render(<TestAdvancedEditor inline />)
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
const kit = screen.getByTestId(testId)
|
|
166
166
|
const toolbar = kit.querySelector('.toolbar')
|
|
167
167
|
expect(toolbar).toBeInTheDocument()
|
|
168
168
|
expect(kit).toHaveClass(`${kitClass} inline`)
|
|
169
169
|
})
|
|
170
170
|
|
|
171
|
+
test('renders required indicator asterisk when requiredIndicator is true', () => {
|
|
172
|
+
render(
|
|
173
|
+
<RichTextEditor
|
|
174
|
+
data={{ testid: testId }}
|
|
175
|
+
label="Label"
|
|
176
|
+
requiredIndicator
|
|
177
|
+
/>
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
const kit = screen.getByTestId(testId)
|
|
181
|
+
const label = within(kit).getByText(/Label/)
|
|
182
|
+
|
|
183
|
+
expect(label).toBeInTheDocument()
|
|
184
|
+
expect(kit).toHaveTextContent('*')
|
|
185
|
+
})
|
|
186
|
+
|
|
171
187
|
describe('TipTap Editor Functionality', () => {
|
|
172
188
|
test('can type and update content', async () => {
|
|
173
189
|
render(<TestAdvancedEditor />)
|
|
174
|
-
|
|
190
|
+
|
|
175
191
|
const kit = screen.getByTestId(testId)
|
|
176
192
|
const editorContent = kit.querySelector('.ProseMirror')
|
|
177
|
-
|
|
193
|
+
|
|
178
194
|
// Focus and type in the editor
|
|
179
195
|
fireEvent.focus(editorContent)
|
|
180
|
-
fireEvent.input(editorContent, {
|
|
196
|
+
fireEvent.input(editorContent, {
|
|
181
197
|
target: { textContent: 'New content' }
|
|
182
198
|
})
|
|
183
|
-
|
|
199
|
+
|
|
184
200
|
await waitFor(() => {
|
|
185
201
|
expect(editorContent).toHaveTextContent('New content')
|
|
186
202
|
})
|
|
187
203
|
})
|
|
188
204
|
})
|
|
189
205
|
})
|
|
190
|
-
|
|
@@ -13,6 +13,7 @@ import Body from '../pb_body/_body'
|
|
|
13
13
|
import Caption from '../pb_caption/_caption'
|
|
14
14
|
import Flex from '../pb_flex/_flex'
|
|
15
15
|
import FlexItem from '../pb_flex/_flex_item'
|
|
16
|
+
import colors from '../tokens/exports/_colors.module.scss'
|
|
16
17
|
|
|
17
18
|
import { stripEmojisForPaste, applyEmojiMask } from '../utilities/emojiMask'
|
|
18
19
|
|
|
@@ -36,6 +37,7 @@ type TextareaProps = {
|
|
|
36
37
|
value?: string,
|
|
37
38
|
name?: string,
|
|
38
39
|
required?: boolean,
|
|
40
|
+
requiredIndicator?: boolean,
|
|
39
41
|
rows?: number,
|
|
40
42
|
resize: "none" | "both" | "horizontal" | "vertical" | "auto",
|
|
41
43
|
onChange?: InputCallback<HTMLTextAreaElement>,
|
|
@@ -50,6 +52,7 @@ const Textarea = ({
|
|
|
50
52
|
disabled,
|
|
51
53
|
emojiMask = false,
|
|
52
54
|
htmlOptions = {},
|
|
55
|
+
id,
|
|
53
56
|
inline = false,
|
|
54
57
|
resize = 'none',
|
|
55
58
|
error,
|
|
@@ -60,6 +63,7 @@ const Textarea = ({
|
|
|
60
63
|
onChange = () => {},
|
|
61
64
|
placeholder,
|
|
62
65
|
required,
|
|
66
|
+
requiredIndicator = false,
|
|
63
67
|
rows = 4,
|
|
64
68
|
value,
|
|
65
69
|
...props
|
|
@@ -84,7 +88,7 @@ const Textarea = ({
|
|
|
84
88
|
if (emojiMask) {
|
|
85
89
|
const pastedText = e.clipboardData.getData('text')
|
|
86
90
|
const filteredText = stripEmojisForPaste(pastedText)
|
|
87
|
-
|
|
91
|
+
|
|
88
92
|
if (pastedText !== filteredText) {
|
|
89
93
|
e.preventDefault()
|
|
90
94
|
const textarea = e.currentTarget
|
|
@@ -93,10 +97,10 @@ const Textarea = ({
|
|
|
93
97
|
const currentValue = textarea.value
|
|
94
98
|
const newValue = currentValue.slice(0, start) + filteredText + currentValue.slice(end)
|
|
95
99
|
const newCursorPosition = start + filteredText.length
|
|
96
|
-
|
|
100
|
+
|
|
97
101
|
textarea.value = newValue
|
|
98
102
|
textarea.selectionStart = textarea.selectionEnd = newCursorPosition
|
|
99
|
-
|
|
103
|
+
|
|
100
104
|
onChange({ ...e, target: textarea, currentTarget: textarea } as unknown as ChangeEvent<HTMLTextAreaElement>)
|
|
101
105
|
}
|
|
102
106
|
}
|
|
@@ -124,7 +128,21 @@ const Textarea = ({
|
|
|
124
128
|
{...htmlProps}
|
|
125
129
|
className={classes}
|
|
126
130
|
>
|
|
127
|
-
|
|
131
|
+
{label && (
|
|
132
|
+
<label htmlFor={id}>
|
|
133
|
+
{
|
|
134
|
+
requiredIndicator ? (
|
|
135
|
+
<Caption className="pb_text_input_kit_label">
|
|
136
|
+
{label} <span style={{ color: `${colors.error}` }}>*</span>
|
|
137
|
+
</Caption>
|
|
138
|
+
) : (
|
|
139
|
+
<Caption className="pb_text_input_kit_label"
|
|
140
|
+
text={label}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
</label>
|
|
145
|
+
)}
|
|
128
146
|
{children || (
|
|
129
147
|
<textarea
|
|
130
148
|
disabled={disabled}
|
|
@@ -143,19 +161,19 @@ const Textarea = ({
|
|
|
143
161
|
{error ? (
|
|
144
162
|
<>
|
|
145
163
|
{characterCount ? (
|
|
146
|
-
<Flex
|
|
147
|
-
spacing="between"
|
|
164
|
+
<Flex
|
|
165
|
+
spacing="between"
|
|
148
166
|
vertical="center"
|
|
149
167
|
>
|
|
150
168
|
<FlexItem>
|
|
151
|
-
<Body
|
|
169
|
+
<Body
|
|
152
170
|
margin="none"
|
|
153
171
|
status="negative"
|
|
154
|
-
text={error}
|
|
172
|
+
text={error}
|
|
155
173
|
/>
|
|
156
174
|
</FlexItem>
|
|
157
175
|
<FlexItem>
|
|
158
|
-
<Caption
|
|
176
|
+
<Caption
|
|
159
177
|
margin="none"
|
|
160
178
|
size="xs"
|
|
161
179
|
text={characterCounter()}
|
|
@@ -163,7 +181,7 @@ const Textarea = ({
|
|
|
163
181
|
</FlexItem>
|
|
164
182
|
</Flex>
|
|
165
183
|
) : (
|
|
166
|
-
<Body
|
|
184
|
+
<Body
|
|
167
185
|
status="negative"
|
|
168
186
|
text={error}
|
|
169
187
|
/>
|
|
@@ -171,7 +189,7 @@ const Textarea = ({
|
|
|
171
189
|
</>
|
|
172
190
|
) : (
|
|
173
191
|
noCount && (
|
|
174
|
-
<Caption
|
|
192
|
+
<Caption
|
|
175
193
|
margin="none"
|
|
176
194
|
size="xs"
|
|
177
195
|
text={characterCounter()}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, {useState} from 'react'
|
|
2
|
+
|
|
3
|
+
import Textarea from '../_textarea'
|
|
4
|
+
|
|
5
|
+
const TextareaRequiredIndicator = (props) => {
|
|
6
|
+
const [value, setValue] = useState('Default value text')
|
|
7
|
+
const handleChange = (event) => {
|
|
8
|
+
setValue(event.target.value)
|
|
9
|
+
}
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<Textarea
|
|
13
|
+
label="Label"
|
|
14
|
+
name="comment"
|
|
15
|
+
onChange={(e) => handleChange(e)}
|
|
16
|
+
placeholder="Placeholder text"
|
|
17
|
+
requiredIndicator
|
|
18
|
+
value={value}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default TextareaRequiredIndicator
|
|
@@ -0,0 +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.
|
|
2
|
+
|
|
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.
|
|
@@ -8,6 +8,7 @@ examples:
|
|
|
8
8
|
- textarea_character_counter: Character Counter
|
|
9
9
|
- textarea_inline: Inline
|
|
10
10
|
- textarea_emoji_mask: Emoji Mask
|
|
11
|
+
- textarea_required_indicator: Required Indicator
|
|
11
12
|
- textarea_input_options: Input Options
|
|
12
13
|
|
|
13
14
|
react:
|
|
@@ -18,8 +19,9 @@ examples:
|
|
|
18
19
|
- textarea_character_counter: Character Counter
|
|
19
20
|
- textarea_inline: Inline
|
|
20
21
|
- textarea_emoji_mask: Emoji Mask
|
|
22
|
+
- textarea_required_indicator: Required Indicator
|
|
21
23
|
|
|
22
24
|
swift:
|
|
23
25
|
- textarea_default_swift: Default
|
|
24
26
|
- textarea_error_swift: Textarea w/ Error
|
|
25
|
-
- textarea_props_swift: ""
|
|
27
|
+
- textarea_props_swift: ""
|
|
@@ -5,3 +5,4 @@ export { default as TextareaError } from './_textarea_error.jsx'
|
|
|
5
5
|
export { default as TextareaCharacterCounter } from './_textarea_character_counter.jsx'
|
|
6
6
|
export { default as TextareaInline } from './_textarea_inline.jsx'
|
|
7
7
|
export { default as TextareaEmojiMask } from './_textarea_emoji_mask.jsx'
|
|
8
|
+
export { default as TextareaRequiredIndicator } from './_textarea_required_indicator.jsx'
|
|
@@ -11,18 +11,21 @@ export default class PbTextarea extends PbEnhancedElement {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
hasEmojiMask(): boolean {
|
|
14
|
+
if (!this.element) return false
|
|
14
15
|
return (this.element as HTMLElement).dataset.pbEmojiMask === "true"
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
onInput(): void {
|
|
18
|
+
onInput = (): void => {
|
|
19
|
+
if (!this.element) return
|
|
20
|
+
|
|
18
21
|
if ((this.element as HTMLElement).closest('.resize_auto')) {
|
|
19
|
-
this.style.height = 'auto'
|
|
20
|
-
this.style.height = (this.scrollHeight
|
|
22
|
+
(this.element as HTMLTextAreaElement).style.height = 'auto';
|
|
23
|
+
(this.element as HTMLTextAreaElement).style.height = (this.element as HTMLTextAreaElement).scrollHeight + 'px'
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
handleEmojiInput = (): void => {
|
|
25
|
-
if (!this.hasEmojiMask()) return
|
|
28
|
+
if (!this.element || !this.hasEmojiMask()) return
|
|
26
29
|
|
|
27
30
|
if (this.skipNextEmojiFilter) {
|
|
28
31
|
this.skipNextEmojiFilter = false
|
|
@@ -33,7 +36,7 @@ export default class PbTextarea extends PbEnhancedElement {
|
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
handleEmojiPaste = (event: ClipboardEvent): void => {
|
|
36
|
-
if (!this.hasEmojiMask()) return
|
|
39
|
+
if (!this.element || !this.hasEmojiMask()) return
|
|
37
40
|
|
|
38
41
|
const pastedText = event.clipboardData?.getData('text') || ''
|
|
39
42
|
const filteredText = stripEmojisForPaste(pastedText)
|
|
@@ -57,6 +60,8 @@ export default class PbTextarea extends PbEnhancedElement {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
connect(): void {
|
|
63
|
+
if (!this.element) return
|
|
64
|
+
|
|
60
65
|
if ((this.element as HTMLElement).closest('.resize_auto')) {
|
|
61
66
|
this.element.setAttribute('style', 'height:' + (this.element as HTMLTextAreaElement).scrollHeight + 'px;overflow-y:hidden;')
|
|
62
67
|
this.element.addEventListener('input', this.onInput, false)
|
|
@@ -69,6 +74,8 @@ export default class PbTextarea extends PbEnhancedElement {
|
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
disconnect(): void {
|
|
77
|
+
if (!this.element) return
|
|
78
|
+
|
|
72
79
|
this.element.removeEventListener('input', this.onInput, false)
|
|
73
80
|
this.element.removeEventListener('input', this.handleEmojiInput, false)
|
|
74
81
|
this.element.removeEventListener('paste', this.handleEmojiPaste as EventListener, false)
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<%= pb_content_tag do %>
|
|
2
2
|
<% if object.label.present? %>
|
|
3
|
+
<% if object.required_indicator %>
|
|
4
|
+
<%= pb_rails("caption", props: { text: object.label, dark: object.dark }) do %>
|
|
5
|
+
<%= object.label %><span style="color: #DA0014;"> *</span>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% else %>
|
|
3
8
|
<%= pb_rails("caption", props: {text: object.label, dark: object.dark}) %>
|
|
9
|
+
<% end %>
|
|
4
10
|
<% end %>
|
|
5
11
|
<% if content.present? %>
|
|
6
12
|
<%= content %>
|
|
@@ -23,6 +23,8 @@ module Playbook
|
|
|
23
23
|
prop :character_count
|
|
24
24
|
prop :onkeyup
|
|
25
25
|
prop :max_characters
|
|
26
|
+
prop :required_indicator, type: Playbook::Props::Boolean,
|
|
27
|
+
default: false
|
|
26
28
|
|
|
27
29
|
def classname
|
|
28
30
|
generate_classname("pb_textarea_kit") + error_class + resize_class + inline_class
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState } from "react"
|
|
2
|
-
import { render, screen, fireEvent } from "../utilities/test-utils"
|
|
2
|
+
import { render, screen, fireEvent, within } from "../utilities/test-utils"
|
|
3
3
|
|
|
4
4
|
import Textarea from "./_textarea"
|
|
5
5
|
|
|
@@ -265,4 +265,21 @@ describe("Textarea Emoji Mask", () => {
|
|
|
265
265
|
fireEvent.change(textarea, { target: { value: 'àëǒüñ' } })
|
|
266
266
|
expect(textarea.value).toBe('àëǒüñ')
|
|
267
267
|
})
|
|
268
|
+
|
|
269
|
+
test('renders required indicator asterisk when requiredIndicator is true', () => {
|
|
270
|
+
render(
|
|
271
|
+
<Textarea
|
|
272
|
+
data={{ testid: testId }}
|
|
273
|
+
label="Name"
|
|
274
|
+
required
|
|
275
|
+
requiredIndicator
|
|
276
|
+
/>
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
const kit = screen.getByTestId(testId)
|
|
280
|
+
const label = within(kit).getByText(/Name/)
|
|
281
|
+
|
|
282
|
+
expect(label).toBeInTheDocument()
|
|
283
|
+
expect(kit).toHaveTextContent('*')
|
|
284
|
+
})
|
|
268
285
|
})
|