Skip to content

Commit

Permalink
feat(helper-text): allow setting helper-text via slot (VIV-1616) (#1636)
Browse files Browse the repository at this point in the history
* Refactor feedback template to include logic

* Add helper-text slot

* Document helper-text slot

* Forward helper-text slot

* Fix select styling

* Update snapshots

* Update READMEs

* Fix select

* Add test for feedbackTemplate

* Refactor tests

* Add test for ignored events
  • Loading branch information
RichardHelm authored Apr 3, 2024
1 parent f437ce3 commit 53f3a34
Show file tree
Hide file tree
Showing 52 changed files with 553 additions and 774 deletions.
20 changes: 19 additions & 1 deletion libs/components/src/lib/checkbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Use the `connotation` attribute to set the checkbox color.

### Helper text

Add the `helper-text` to add some helper text below the checkbox.
Add the `helper-text` to add some helper text below the checkbox. If you need to add HTML to the helper text, use the `helper-text` slot.

- Type: `string` | `undefined`
- Default: `undefined`
Expand Down Expand Up @@ -165,6 +165,24 @@ The default slot allows you to use rich content as the checkbox's label.
</vwc-checkbox>
```

### Helper-Text

The `helper-text` slot allows you to use rich content as the checkbox's helper text.

```html preview
<style>
.checkbox {
width: 300px;
}
</style>
<vwc-checkbox class="checkbox" label="Use Signed Webhooks">
<span slot="helper-text"
><a href="#">Signed Webhooks</a> are a way to verify that the request is
coming from Vonage.</span
>
</vwc-checkbox>
```

## Events

<div class="table-wrapper">
Expand Down
54 changes: 2 additions & 52 deletions libs/components/src/lib/checkbox/checkbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,72 +132,22 @@ describe('vwc-checkbox', () => {
});
});

describe('helper text', function () {
it('should render the helper text when attribute is set on checkbox', async function () {
const helperTextElementWithoutText =
element.shadowRoot?.querySelector('.helper-text');
const helperText = 'Helper Text';
element.helperText = helperText;
await elementUpdated(element);
expect(helperTextElementWithoutText).toBeNull();
expect(
element.shadowRoot
?.querySelector('.helper-message')
?.textContent?.trim()
).toEqual(helperText);
});
});

describe('success Text', () => {
it('should add success class to base when successText is set', async function () {
(element as any).successText = 'success';
element.successText = 'success';
await elementUpdated(element);
expect(
getBaseElement(element).classList.contains('success')
).toBeTruthy();
});

it('should show success text when successText is set', async function () {
(element as any).successText = 'success';
await elementUpdated(element);
expect(
element.shadowRoot
?.querySelector('.success-message')
?.textContent?.trim()
).toEqual('success');
});

it('should remove success text when undefined', async function () {
(element as any).successText = 'success';
await elementUpdated(element);
(element as any).successText = undefined;
await elementUpdated(element);
expect(element.shadowRoot?.querySelector('.success-message')).toBeNull();
});
});

describe('error Text', () => {
it('should add error class to base when errorText is set', async function () {
(element as any).errorText = 'error';
element.errorText = 'error';
await elementUpdated(element);
expect(getBaseElement(element).classList.contains('error')).toBeTruthy();
});

it('should show error text when errorText is set', async function () {
(element as any).errorText = 'error';
await elementUpdated(element);
expect(
element.shadowRoot?.querySelector('.error-message')?.textContent?.trim()
).toEqual('error');
});

it('should remove error text when undefined', async function () {
(element as any).errorText = 'error';
await elementUpdated(element);
(element as any).errorText = undefined;
await elementUpdated(element);
expect(element.shadowRoot?.querySelector('.error-message')).toBeNull();
});
});

describe.each(['input', 'change'])('%s event', (eventName) => {
Expand Down
7 changes: 1 addition & 6 deletions libs/components/src/lib/checkbox/checkbox.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ export const CheckboxTemplate: FoundationElementTemplate<
>${(x) => x.label}<slot ${slotted('slottedContent')}></slot
></label>`}
</div>
${when((x) => x.helperText?.length, getFeedbackTemplate('helper', context))}
${when(
(x) => !x.successText && x.errorValidationMessage,
getFeedbackTemplate('error', context)
)}
${when((x) => x.successText, getFeedbackTemplate('success', context))}
${getFeedbackTemplate(context)}
</template>`;
};
13 changes: 8 additions & 5 deletions libs/components/src/lib/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
applyMixins,
Checkbox as FoundationCheckbox,
} from '@microsoft/fast-foundation';
import { Checkbox as FoundationCheckbox } from '@microsoft/fast-foundation';
import { attr, observable } from '@microsoft/fast-element';
import type { Connotation } from '../enums.js';
import {
Expand All @@ -12,6 +9,7 @@ import {
formElements,
FormElementSuccessText,
} from '../../shared/patterns';
import { applyMixinsWithObservables } from '../../shared/utils/applyMixinsWithObservables';

export const keySpace: ' ' = ' ' as const;

Expand All @@ -28,6 +26,7 @@ export type CheckboxConnotation = Extract<
/**
* @public
* @component checkbox
* @slot helper-text - Describes how to use the checkbox. Alternative to the `helper-text` attribute.
* @event input - Event that emits when the component checked state changes
* @vueModel modelValue current-checked change `(event.target as HTMLInputElement).checked`
*/
Expand Down Expand Up @@ -114,4 +113,8 @@ export interface Checkbox
FormElementHelperText,
ErrorText,
FormElementSuccessText {}
applyMixins(Checkbox, FormElementHelperText, FormElementSuccessText);
applyMixinsWithObservables(
Checkbox,
FormElementHelperText,
FormElementSuccessText
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion libs/components/src/lib/date-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ In case you choose not to add a label, it is strongly recommended to add an `ari

### Helper text

Add the `helper-text` to add some helper text below the date picker.
Add the `helper-text` to add some helper text below the date picker. If you need to add HTML to the helper text, use the `helper-text` slot.

- Type: `string` | `undefined`
- Default: `undefined`
Expand Down Expand Up @@ -120,6 +120,18 @@ Set the `max` attribute to configure the latest date to accept. The user will be
></vwc-date-picker>
```

## Slots

### Helper-Text

The `helper-text` slot allows you to use rich content as the date picker's helper text.

```html preview locale-switcher 460px
<vwc-date-picker label="Start date">
<span slot="helper-text">Please see our <a href="#">opening times</a>.</span>
</vwc-date-picker>
```

## Events

<div class="table-wrapper">
Expand Down
1 change: 1 addition & 0 deletions libs/components/src/lib/date-picker/date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
*
* @public
* @component date-picker
* @slot helper-text - Describes how to use the date-picker. Alternative to the `helper-text` attribute.
* @vueModel modelValue value input `(event.target as HTMLInputElement).value`
*/
@errorText
Expand Down
14 changes: 13 additions & 1 deletion libs/components/src/lib/date-range-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ In case you choose not to add a label, it is strongly recommended to add an `ari

### Helper text

Add the `helper-text` to add some helper text below the date range picker.
Add the `helper-text` to add some helper text below the date range picker. If you need to add HTML to the helper text, use the `helper-text` slot.

- Type: `string` | `undefined`
- Default: `undefined`
Expand Down Expand Up @@ -153,6 +153,18 @@ Set the `max` attribute to configure the latest date to accept. The user will be
></vwc-date-range-picker>
```

## Slots

### Helper-Text

The `helper-text` slot allows you to use rich content as the date range picker's helper text.

```html preview locale-switcher 460px
<vwc-date-range-picker label="Date range">
<span slot="helper-text">Please see our <a href="#">opening times</a>.</span>
</vwc-date-range-picker>
```

## Events

<div class="table-wrapper">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function isDefined<T>(value: T | null | undefined): value is T {
/**
* @public
* @component date-range-picker
* @slot helper-text - Describes how to use the date-range-picker. Alternative to the `helper-text` attribute.
* @event input:start - Event emitted when the start value changes
* @event input:end - Event emitted when the end value changes
* @vueModel start current-start input:start `(event.target as any).start`
Expand Down
16 changes: 15 additions & 1 deletion libs/components/src/lib/file-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Use the `label` member to set the file picker's label.

### Helper text

Add the `helper-text` to add some helper text below the file picker.
Add the `helper-text` to add some helper text below the file picker. If you need to add HTML to the helper text, use the `helper-text` slot.

- Type: `string` | `undefined`
- Default: `undefined`
Expand Down Expand Up @@ -127,6 +127,20 @@ Use the default slot to set the content of the file picker.
</vwc-file-picker>
```

### Helper-Text

The `helper-text` slot allows you to use rich content as the file picker's helper text.

```html preview
<vwc-file-picker>
Drag & Drop the .csv file here or click to upload
<span slot="helper-text"
>Max file size is 0.1MB.
<a href="#">Learn how export your data to .csv</a></span
>
</vwc-file-picker>
```

## Properties

<div class="table-wrapper">
Expand Down
39 changes: 0 additions & 39 deletions libs/components/src/lib/file-picker/file-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,45 +103,6 @@ describe('vwc-file-picker', () => {
});
});

describe('helper text', function () {
it('should render the helper text when attribute is set on file picker', async function () {
const helperTextElementWithoutText =
element.shadowRoot?.querySelector('.helper-message');
const helperText = 'Helper Text';
element.helperText = helperText;
await elementUpdated(element);
expect(helperTextElementWithoutText).toBeNull();
expect(
element.shadowRoot
?.querySelector('.helper-message')
?.textContent?.trim()
).toEqual(helperText);
});
});

describe('error text', function () {
it('should render the error text when attribute is set', async function () {
const errorTextElementWithoutAttribute =
element.shadowRoot?.querySelector('.error-message');
element.errorText = 'Error Text';
await elementUpdated(element);
expect(errorTextElementWithoutAttribute).toBeNull();
expect(
element.shadowRoot?.querySelector('.error-message')?.textContent?.trim()
).toEqual('Error Text');
});

it('should hide helper text if error text is set', async function () {
element.helperText = 'Helper Text';
element.errorText = 'Error Text';
await elementUpdated(element);
expect(element.shadowRoot?.querySelector('.helper-message')).toBe(null);
expect(element.shadowRoot?.querySelector('.error-message')).not.toBe(
null
);
});
});

describe('value', function () {
it('should be set to a fake path when a file is added', async function () {
addFiles([await generateFile('london.png', 1)]);
Expand Down
9 changes: 1 addition & 8 deletions libs/components/src/lib/file-picker/file-picker.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,7 @@ export const FilePickerTemplate: (
>
<slot class="main"></slot>
</div>
${when(
(x) => !x.errorValidationMessage && x.helperText?.length,
getFeedbackTemplate('helper', context)
)}
${when(
(x) => x.errorValidationMessage,
getFeedbackTemplate('error', context)
)}
${getFeedbackTemplate(context)}
<div class="preview-list"></div>
</div>
`;
Expand Down
5 changes: 3 additions & 2 deletions libs/components/src/lib/file-picker/file-picker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable max-len */
import { applyMixins } from '@microsoft/fast-foundation';
import { attr } from '@microsoft/fast-element';
import type { DropzoneFile } from 'dropzone';
import Dropzone from 'dropzone';
Expand All @@ -14,6 +13,7 @@ import {
Localized,
} from '../../shared/patterns';
import type { Button } from '../button/button';
import { applyMixinsWithObservables } from '../../shared/utils/applyMixinsWithObservables';
import { FormAssociatedFilePicker } from './file-picker.form-associated';

/**
Expand All @@ -30,6 +30,7 @@ const isFormAssociatedTryingToSetFormValueToFakePath = (
/**
* @public
* @component file-picker
* @slot helper-text - Describes how to use the file-picker. Alternative to the `helper-text` attribute.
* @event change - Emitted when a file is added or removed.
*/
@errorText
Expand Down Expand Up @@ -278,4 +279,4 @@ export interface FilePicker
ErrorText,
FormElement,
FormElementHelperText {}
applyMixins(FilePicker, FormElementHelperText, Localized);
applyMixinsWithObservables(FilePicker, FormElementHelperText, Localized);
18 changes: 17 additions & 1 deletion libs/components/src/lib/number-field/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Set the `max` attribute to set the maximum value for the number field.

### Helper text

Add the `helper-text` to add some helper text below the number field.
Add the `helper-text` to add some helper text below the number field. If you need to add HTML to the helper text, use the `helper-text` slot.

- Type: `string` | `undefined`
- Default: `undefined`
Expand Down Expand Up @@ -166,6 +166,22 @@ Add the `readonly` attribute to restrict user from changing the number field's v
></vwc-number-field>
```

## Slots

### Helper-Text

The `helper-text` slot allows you to use rich content as the number field's helper text.

Example showing a link in the helper text:

```html preview
<vwc-number-field label="Timeout">
<span slot="helper-text"
>The timeout in seconds. <a href="#">Guide to setting timeouts</a></span
>
</vwc-number-field>
```

## Methods

<div class="table-wrapper">
Expand Down
Loading

0 comments on commit 53f3a34

Please sign in to comment.