Skip to content

Commit

Permalink
Feat(web): Introduce TextArea component #DS-319
Browse files Browse the repository at this point in the history
  • Loading branch information
dlouhak committed Nov 28, 2022
1 parent b7aa908 commit 8e14ddd
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 0 deletions.
135 changes: 135 additions & 0 deletions packages/web/src/scss/components/TextArea/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# TextArea

Basic usage:

```html
<div class="TextArea">
<label for="TextArea1" class="TextArea__label">Label</label>
<textarea id="TextArea1" class="TextArea__input" placeholder="Placeholder"></textarea>
</div>
```

Required textarea:

```html
<div class="TextArea">
<label for="TextArea2" class="TextArea__label TextArea__label--required">Label of required textarea</label>
<textarea id="TextArea2" class="TextArea__input" placeholder="Placeholder" required></textarea>
</div>
```

Additional message:

```html
<div class="TextArea">
<label for="TextArea3" class="TextArea__label">Label of textarea with message</label>
<textarea id="TextArea3" class="TextArea__input" placeholder="Placeholder"></textarea>
<div class="TextArea__message">Message</div>
</div>
```

Hidden label:

```html
<div class="TextArea">
<label for="TextArea4" class="TextArea__label TextArea__label--hidden">Label hidden</label>
<textarea id="TextArea4" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
</div>
```

Fluid width:

```html
<div class="TextArea TextArea--fluid">
<label for="TextArea7" class="TextArea__label">Label of a fluid textarea</label>
<textarea id="TextArea7" class="TextArea__input" placeholder="Placeholder"></textarea>
<div class="TextArea__message">Message</div>
</div>
```

## Input Width

There are several ways to adjust the textarea width:

### `rows` Attribute

The number of visible text lines for the control. Supported values are positive integers from `3` up.

```html
<div class="TextArea">
<label for="TextArea-rows" class="TextArea__label">Label</label>
<textarea rows="3" id="TextArea-rows" class="TextArea__input"></textarea>
</div>
```

### Grid

For other use cases (wider textarea or textarea with unknown value length), we
recommend placing them inside the Grid component and using `TextArea--fluid`
modifier to fill the available space.

## Validation States

Validation states can be presented either by adding a CSS modifier class
(`TextArea--success`, `TextArea--warning`, `TextArea--error`), or by adding
a JS interaction class when controlled by JavaScript (`has-success`,
`has-warning`, `has-error`).

```html
<div class="TextArea TextArea--error">
<label for="TextAreaValidation1" class="TextArea__label TextArea__label--required">
Label of textarea with error
</label>
<textarea id="TextAreaValidation1" class="TextArea__input" placeholder="Placeholder" required>Filled</textarea>
<div class="TextArea__message">Error message</div>
</div>
<div class="TextArea has-error">
<label for="TextAreaValidation2" class="TextArea__label TextArea__label--required">
Label of textarea with error
</label>
<textarea id="TextAreaValidation2" class="TextArea__input" placeholder="Placeholder" required>Filled</textarea>
<div class="TextArea__message">Error message</div>
</div>
```

### JavaScript-Controlled Validation Message

When implementing client-side form validation, use JS interaction state classes
(`has-success`, `has-warning`, `has-error`) on the wrapping `<div>` element and
render validation messages in a `<div>` with `data-element="validator_message"`
attribute. This way your JS remains disconnected from CSS that may or may not be
[prefixed].

**Remember this approach is only valid for vanilla JS implementation. React
components mix CSS with JS by design and handle prefixes their own way.**

```html
<div class="TextArea has-error">
<label for="TextAreaJSValidation1" class="TextArea__label TextArea__label--required">
Label of textarea with error
</label>
<textarea id="TextAreaJSValidation1" class="TextArea__input" placeholder="Placeholder" required>Filled</textarea>
<div data-element="validator_message">Error message inserted by JS</div>
</div>
```

## Disabled State

On top of adding the `disabled` attribute to the textarea, disabled TextArea can
be marked by adding `TextArea--disabled` modifier class, or with `is-disabled`
JS interaction class when controlled by JavaScript:

```html
<div class="TextArea TextArea--disabled">
<label for="TextAreaDisabled1" class="TextArea__label TextArea__label--required">Label of disabled textarea</label>
<textarea id="TextAreaDisabled1" class="TextArea__input" placeholder="Placeholder" disabled required></textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea is-disabled">
<label for="TextAreaDisabled2" class="TextArea__label TextArea__label--required">Label of disabled textarea</label>
<textarea id="TextAreaDisabled2" class="TextArea__input" placeholder="Placeholder" disabled required></textarea>
<div class="TextArea__message">Message</div>
</div>
```

[prefixed]: https://github.com/lmc-eu/spirit-design-system/tree/main/packages/web#prefixing-css-class-names
58 changes: 58 additions & 0 deletions packages/web/src/scss/components/TextArea/_TextArea.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@use '../../theme/form-fields' as form-fields-theme;
@use '../../tools/form-fields' as form-fields-tools;
@use 'theme';

$_field-name: 'TextArea';

.TextArea {
@include form-fields-tools.box-field-root();
}

.TextArea__label {
@include form-fields-tools.box-field-label();
}

.TextArea__label--hidden {
@include form-fields-tools.label-hidden();
}

.TextArea__label--required::after {
@include form-fields-tools.label-required();
}

.TextArea__input {
@include form-fields-tools.box-field-input();

min-height: calc(
#{theme.$input-min-height} + 2 * #{form-fields-theme.$box-field-input-padding-x} + 2 * #{form-fields-theme.$box-field-input-border-width}
);
resize: vertical;
}

.TextArea--fluid {
@include form-fields-tools.box-field-fluid();
}

.TextArea > .TextArea__input:focus-visible {
@include form-fields-tools.box-field-focus-visible();
}

.TextArea__message,
.TextArea > [data-element='validator_message'] {
@include form-fields-tools.message();
}

@include form-fields-tools.box-field-variants($_field-name);

.TextArea--disabled > .TextArea__label {
@include form-fields-tools.label-disabled();
}

.TextArea .TextArea__input:disabled,
:is(.TextArea--disabled, .TextArea.is-disabled) .TextArea__input {
@include form-fields-tools.box-field-disabled-input();
}

:is(.TextArea--disabled, .TextArea.is-disabled) > :is(.TextArea__message, [data-element='validator_message']) {
@include form-fields-tools.message-disabled();
}
1 change: 1 addition & 0 deletions packages/web/src/scss/components/TextArea/_theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$input-min-height: 3.375rem;
75 changes: 75 additions & 0 deletions packages/web/src/scss/components/TextArea/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{{#> layout/plain }}

<div class="docs-FormFieldGrid">
<div class="TextArea">
<label for="textareaSimple" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaSimple" class="TextArea__input" placeholder="Placeholder"></textarea>
</div>
<div class="TextArea">
<label for="textareaMessage" class="TextArea__label">Label</label>
<textarea id="textareaMessage" class="TextArea__input" placeholder="Placeholder"></textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea">
<label for="textareaFilled" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaFilled" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
</div>
<div class="TextArea">
<label for="textareaFilledMessage" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaFilledMessage" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--error">
<label for="textareaError" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaError" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
</div>
<div class="TextArea TextArea--error">
<label for="textareaErrorMessage" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaErrorMessage" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--success">
<label for="textareaSuccess" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaSuccess" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--warning">
<label for="textareaWarning" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaWarning" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--disabled">
<label for="textareaDisabled" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaDisabled" class="TextArea__input" placeholder="Placeholder" disabled></textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--disabled">
<label for="textareaDisabledFilled" class="TextArea__label TextArea__label--required">Label</label>
<textarea
id="textareaDisabledFilled"
class="TextArea__input"
placeholder="Placeholder"
disabled
>Filled</textarea>
<div class="TextArea__message">Message</div>
</div>
<div class="TextArea TextArea--fluid">
<label for="textareaFluid" class="TextArea__label TextArea__label--required">Label</label>
<textarea id="textareaFluid" class="TextArea__input" placeholder="Placeholder">Filled</textarea>
<div class="TextArea__message">Message</div>
</div>

<div style="display: flex; gap: 1rem; align-items: flex-end;">
<div class="TextArea">
<label for="textareaInlineHiddenLabel" class="TextArea__label TextArea__label--hidden">Hidden Label</label>
<textarea
id="textareaInlineHiddenLabel"
class="TextArea__input"
placeholder="Placeholder"
>Filled</textarea>
</div>
<button type="button" class="Button Button--primary Button--medium">Button</button>
</div>
</div>

{{/layout/plain }}
1 change: 1 addition & 0 deletions packages/web/src/scss/components/TextArea/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@forward 'TextArea';
1 change: 1 addition & 0 deletions packages/web/src/scss/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
@forward 'Stack';
@forward 'Tabs';
@forward 'Tag';
@forward 'TextArea';
@forward 'TextField';
@forward 'Tooltip';

0 comments on commit 8e14ddd

Please sign in to comment.