Skip to content

Commit 24df01b

Browse files
authored
Merge pull request #253 from CrowdStrike/textarea-w-full-fix
fix: Add container to textarea to resolve style issues and add padding to input to match
2 parents a6ed2cc + c18922f commit 24df01b

File tree

9 files changed

+71
-46
lines changed

9 files changed

+71
-46
lines changed

.changeset/olive-buttons-kiss.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@crowdstrike/ember-toucan-core': minor
3+
'@crowdstrike/ember-toucan-form': minor
4+
---
5+
6+
Both `Textarea` and `Input` Controls are now full width by default.
7+
8+
The `Textarea` Control markup was adjusted to account for collision with the resize handle and focus/error shadows.
9+
10+
The `Input` Control now has small padding along the x-axis.

docs/components/input/demo/base-demo.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
```hbs template
2-
<Form::Controls::Input />
2+
<div class='w-96'>
3+
<Form::Controls::Input />
4+
</div>
35
```
46

57
```js component

docs/components/textarea/demo/base-demo.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
```hbs template
2-
<Form::Controls::Textarea />
2+
<div class='w-96'>
3+
<Form::Controls::Textarea />
4+
</div>
35
```
46

57
```js component

packages/ember-toucan-core/src/components/form/controls/input.gts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export default class ToucanFormControlsInputComponent extends Component<ToucanFo
6363

6464
<template>
6565
<input
66-
class="focus:outline-none block rounded-sm p-1 transition-shadow
66+
class="focus:outline-none block rounded-sm py-1 transition-shadow w-full px-2
6767
{{this.styles}}"
6868
disabled={{@isDisabled}}
6969
readonly={{@isReadOnly}}

packages/ember-toucan-core/src/components/form/controls/textarea.gts

+20-11
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ export default class ToucanFormTextareaControlComponent extends Component<Toucan
4444
}
4545

4646
if (isReadOnly) {
47-
return 'focus:shadow-focus-outline bg-surface-xl shadow-read-only-outline text-titles-and-attributes';
47+
return 'focus-within:shadow-focus-outline bg-surface-xl shadow-read-only-outline text-titles-and-attributes';
4848
}
4949

5050
if (hasError) {
51-
return 'shadow-error-outline focus:shadow-error-focus-outline bg-overlay-1 text-titles-and-attributes';
51+
return 'shadow-error-outline focus-within:shadow-error-focus-outline bg-overlay-1 text-titles-and-attributes';
5252
}
5353

54-
return 'shadow-focusable-outline focus:shadow-focus-outline bg-overlay-1 text-titles-and-attributes';
54+
return 'shadow-focusable-outline focus-within:shadow-focus-outline bg-overlay-1 text-titles-and-attributes';
5555
}
5656

5757
@action
@@ -65,13 +65,22 @@ export default class ToucanFormTextareaControlComponent extends Component<Toucan
6565
}
6666

6767
<template>
68-
<textarea
69-
class="min-h-6 focus:outline-none block h-20 rounded-sm p-1 transition-shadow
70-
{{this.styles}}"
71-
disabled={{@isDisabled}}
72-
readonly={{@isReadOnly}}
73-
...attributes
74-
{{on "input" this.handleInput}}
75-
>{{@value}}</textarea>
68+
{{!
69+
A styled container div is used here so that we can give some space for
70+
the textarea resize handle and focus/error shadows. Otherwise, the
71+
shadows / handle visually collides.
72+
}}
73+
<div
74+
class="{{this.styles}} w-full py-1 px-2 rounded-sm transition-shadow"
75+
data-container
76+
>
77+
<textarea
78+
class="min-h-6 focus:outline-none block h-20 bg-transparent w-full"
79+
disabled={{@isDisabled}}
80+
readonly={{@isReadOnly}}
81+
...attributes
82+
{{on "input" this.handleInput}}
83+
>{{@value}}</textarea>
84+
</div>
7685
</template>
7786
}

packages/ember-toucan-core/src/components/form/fields/input.gts

-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ export default class ToucanFormInputFieldComponent extends Component<ToucanFormI
158158
field.errorId
159159
}}"
160160
aria-invalid={{if @error "true"}}
161-
class="w-full"
162161
@isDisabled={{@isDisabled}}
163162
@isReadOnly={{@isReadOnly}}
164163
@value={{@value}}

packages/ember-toucan-core/src/components/form/fields/textarea.gts

-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ export default class ToucanFormTextareaFieldComponent extends Component<ToucanFo
163163
@hint
164164
field.hintId
165165
}}"
166-
class="w-full"
167166
id={{field.id}}
168167
@isDisabled={{@isDisabled}}
169168
@isReadOnly={{@isReadOnly}}

test-app/tests/integration/components/textarea-field-test.gts

+15-13
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
1919
assert
2020
.dom('[data-hint]')
2121
.doesNotExist(
22-
'Expected hint block not to be displayed as a hint was not provided'
22+
'Expected hint block not to be displayed as a hint was not provided',
2323
);
2424

2525
assert.dom('[data-textarea]').hasTagName('textarea');
2626
assert.dom('[data-textarea]').hasAttribute('id');
27-
assert.dom('[data-textarea]').hasClass('text-titles-and-attributes');
27+
assert.dom('[data-container]').hasClass('text-titles-and-attributes');
2828

2929
assert
3030
.dom('[data-error]')
3131
.doesNotExist(
32-
'Expected hint block not to be displayed as an error was not provided'
32+
'Expected hint block not to be displayed as an error was not provided',
3333
);
3434

3535
assert.dom('[data-lock-icon]').doesNotExist();
@@ -54,7 +54,7 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
5454

5555
assert.ok(
5656
describedby.includes(hintId),
57-
'Expected hintId to be included in the aria-describedby'
57+
'Expected hintId to be included in the aria-describedby',
5858
);
5959
});
6060

@@ -89,14 +89,16 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
8989

9090
assert.ok(
9191
describedby.includes(errorId),
92-
'Expected errorId to be included in the aria-describedby'
92+
'Expected errorId to be included in the aria-describedby',
9393
);
9494

9595
assert.dom('[data-textarea]').hasAttribute('aria-invalid', 'true');
9696

97-
assert.dom('[data-textarea]').hasClass('shadow-error-outline');
98-
assert.dom('[data-textarea]').hasClass('focus:shadow-error-focus-outline');
99-
assert.dom('[data-textarea]').doesNotHaveClass('shadow-focusable-outline');
97+
assert.dom('[data-container]').hasClass('shadow-error-outline');
98+
assert
99+
.dom('[data-container]')
100+
.hasClass('focus-within:shadow-error-focus-outline');
101+
assert.dom('[data-container]').doesNotHaveClass('shadow-focusable-outline');
100102
});
101103

102104
test('it sets aria-describedby when both a hint and error are provided using the hint and errorIds', async function (assert) {
@@ -128,7 +130,7 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
128130
</template>);
129131

130132
assert.dom('[data-textarea]').isDisabled();
131-
assert.dom('[data-textarea]').hasClass('text-disabled');
133+
assert.dom('[data-container]').hasClass('text-disabled');
132134

133135
assert.dom('[data-lock-icon]').exists();
134136

@@ -208,9 +210,9 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
208210
setupOnerror((e: Error) => {
209211
assert.ok(
210212
e.message.includes(
211-
'Assertion Failed: You need either :label or @label'
213+
'Assertion Failed: You need either :label or @label',
212214
),
213-
'Expected assertion error message'
215+
'Expected assertion error message',
214216
);
215217
});
216218

@@ -223,9 +225,9 @@ module('Integration | Component | Fields | Textarea', function (hooks) {
223225
setupOnerror((e: Error) => {
224226
assert.ok(
225227
e.message.includes(
226-
'Assertion Failed: You can have :label or @label, but not both'
228+
'Assertion Failed: You can have :label or @label, but not both',
227229
),
228-
'Expected assertion error message'
230+
'Expected assertion error message',
229231
);
230232
});
231233

test-app/tests/integration/components/textarea-test.gts

+19-17
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ module('Integration | Component | Textarea', function (hooks) {
1616
</template>);
1717

1818
assert.dom('[data-textarea]').hasTagName('textarea');
19-
assert.dom('[data-textarea]').hasClass('text-titles-and-attributes');
20-
assert.dom('[data-textarea]').hasClass('shadow-focusable-outline');
21-
assert.dom('[data-textarea]').doesNotHaveClass('text-disabled');
22-
assert.dom('[data-textarea]').doesNotHaveClass('shadow-error-outline');
19+
assert.dom('[data-container]').hasClass('text-titles-and-attributes');
20+
assert.dom('[data-container]').hasClass('shadow-focusable-outline');
21+
assert.dom('[data-container]').doesNotHaveClass('text-disabled');
22+
assert.dom('[data-container]').doesNotHaveClass('shadow-error-outline');
2323
assert
24-
.dom('[data-textarea]')
25-
.doesNotHaveClass('focus:shadow-error-focus-outline');
24+
.dom('[data-container]')
25+
.doesNotHaveClass('focus-within:shadow-error-focus-outline');
2626
});
2727

2828
test('it disables the textarea using `@isDisabled`', async function (assert) {
@@ -33,9 +33,9 @@ module('Integration | Component | Textarea', function (hooks) {
3333
</template>);
3434

3535
assert.dom('[data-textarea]').isDisabled();
36-
assert.dom('[data-textarea]').hasClass('text-disabled');
36+
assert.dom('[data-container]').hasClass('text-disabled');
3737
assert
38-
.dom('[data-textarea]')
38+
.dom('[data-container]')
3939
.doesNotHaveClass('text-titles-and-attributes');
4040
});
4141

@@ -48,12 +48,12 @@ module('Integration | Component | Textarea', function (hooks) {
4848

4949
assert.dom('[data-textarea]').hasAttribute('readonly');
5050

51-
assert.dom('[data-textarea]').hasClass('shadow-read-only-outline');
52-
assert.dom('[data-textarea]').hasClass('bg-surface-xl');
53-
assert.dom('[data-textarea]').hasNoClass('bg-overlay-1');
54-
assert.dom('[data-textarea]').hasNoClass('text-disabled');
55-
assert.dom('[data-textarea]').hasNoClass('shadow-error-outline');
56-
assert.dom('[data-textarea]').hasNoClass('shadow-focusable-outline');
51+
assert.dom('[data-container]').hasClass('shadow-read-only-outline');
52+
assert.dom('[data-container]').hasClass('bg-surface-xl');
53+
assert.dom('[data-container]').hasNoClass('bg-overlay-1');
54+
assert.dom('[data-container]').hasNoClass('text-disabled');
55+
assert.dom('[data-container]').hasNoClass('shadow-error-outline');
56+
assert.dom('[data-container]').hasNoClass('shadow-focusable-outline');
5757
});
5858

5959
test('it spreads attributes to the underlying textarea', async function (assert) {
@@ -108,8 +108,10 @@ module('Integration | Component | Textarea', function (hooks) {
108108
<TextareaControl @hasError={{true}} data-textarea />
109109
</template>);
110110

111-
assert.dom('[data-textarea]').hasClass('shadow-error-outline');
112-
assert.dom('[data-textarea]').hasClass('focus:shadow-error-focus-outline');
113-
assert.dom('[data-textarea]').doesNotHaveClass('shadow-focusable-outline');
111+
assert.dom('[data-container]').hasClass('shadow-error-outline');
112+
assert
113+
.dom('[data-container]')
114+
.hasClass('focus-within:shadow-error-focus-outline');
115+
assert.dom('[data-container]').doesNotHaveClass('shadow-focusable-outline');
114116
});
115117
});

0 commit comments

Comments
 (0)