diff --git a/apps/docs/_data/components.json b/apps/docs/_data/components.json index 3fef465a24..1be632767c 100644 --- a/apps/docs/_data/components.json +++ b/apps/docs/_data/components.json @@ -269,6 +269,11 @@ "title": "Audio Player", "markdown": "./libs/components/src/lib/audio-player/README.md" }, + { + "title": "Dial Pad", + "status": "alpha", + "markdown": "./libs/components/src/lib/dial-pad/README.md" + }, { "title": "Video Player", "status": "alpha", diff --git a/apps/vue-docs/docs/examples/components/dial-pad/BasicExample.vue b/apps/vue-docs/docs/examples/components/dial-pad/BasicExample.vue new file mode 100644 index 0000000000..16e5e5cf64 --- /dev/null +++ b/apps/vue-docs/docs/examples/components/dial-pad/BasicExample.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/vue-docs/docs/examples/dial-pad.md b/apps/vue-docs/docs/examples/dial-pad.md new file mode 100644 index 0000000000..da0424464f --- /dev/null +++ b/apps/vue-docs/docs/examples/dial-pad.md @@ -0,0 +1,22 @@ +# Dial Pad Examples + +## Basic + + + + + + + diff --git a/libs/components/src/lib/components.ts b/libs/components/src/lib/components.ts index 25dd05b18f..a2489a17e0 100644 --- a/libs/components/src/lib/components.ts +++ b/libs/components/src/lib/components.ts @@ -17,6 +17,7 @@ export * from './combobox/definition'; export * from './data-grid/definition'; export * from './date-picker/definition'; export * from './date-range-picker/definition'; +export * from './dial-pad/definition'; export * from './dialog/definition'; export * from './divider/definition'; export * from './empty-state/definition'; diff --git a/libs/components/src/lib/dial-pad/README.md b/libs/components/src/lib/dial-pad/README.md new file mode 100644 index 0000000000..3cbe319527 --- /dev/null +++ b/libs/components/src/lib/dial-pad/README.md @@ -0,0 +1,112 @@ +# Dial Pad + +This is a composed component that allows users to enter / dial telephone numbers. + +```js + +``` + +```html preview + +``` + +## Members + +### Value + +To set the value of the input, use the `value` attribute to set the text displayed in the input. + +- Type: `string` +- Default: `undefined` + +```html preview + +``` + +### Helper Text + +To give extra context to the number that is being displayed, use the `helper-text` attribute to set the text displayed under the input. + +- Type: `string` +- Default: `undefined` + +```html preview + +``` + +### Placeholder + +To give a hint to the user of what to enter in the input, use the `placeholder` attribute to set the text displayed in the input. + +- Type: `string` +- Default: `undefined` + +```html preview + +``` + +### Disabled + +Use the `disabled` attribute to disable the keypad, input and Call/End call buttons. + +- Type: `boolean` +- Default: `false` + +```html preview + +``` + +### Call Active + +Use the `call-active` attribute (or `callActive` property) to enable the `end call button` and disable the `dial button`. + +- Type: `boolean` +- Default: `false` + +```html preview + +``` + +### No Call + +Use the `no-call` attribute (or `noCall` property) to disable call/end call functionality and hide the call/end call button. + +- Type: `boolean` +- Default: `false` + +```html preview + +``` + +### Pattern + +Use the `pattern` attribute to set the regex string of allowed characters in the input. +Read more about [vwc-text-field validation](/components/text-field/#validation). +You can change the error text with the `error-text` attribute. + +- Type: `string` +- Default: `^[0-9#*]*$` (key pad buttons) + +```html preview + +``` + +## Events + +
+ +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------- | +| `dial` | Emitted (with the value of the input) when the dial pad is submitted and there is a value in the input. | +| `end-call` | Emitted when the end call button is clicked. | +| `keypad-click` | Emitted when a keypad button is clicked. The `detail` object holds the clicked button. | +| `input` | Emitted from the input element. | +| `change` | Emitted from the input element. | +| `blur` | Emitted from the input element. | +| `focus` | Emitted from the input element. | + +
diff --git a/libs/components/src/lib/dial-pad/definition.ts b/libs/components/src/lib/dial-pad/definition.ts new file mode 100644 index 0000000000..5ce16da5e1 --- /dev/null +++ b/libs/components/src/lib/dial-pad/definition.ts @@ -0,0 +1,30 @@ +import type { FoundationElementDefinition } from '@microsoft/fast-foundation'; +import { registerFactory } from '../../shared/design-system'; +import { buttonRegistries } from '../button/definition'; +import { textFieldRegistries } from '../text-field/definition'; +import styles from './dial-pad.scss?inline'; + +import { DialPad } from './dial-pad'; +import { DialPadTemplate as template } from './dial-pad.template'; + +export const dialPadDefinition = DialPad.compose({ + baseName: 'dial-pad', + template: template as any, + styles, +}); + +/** + * @internal + */ +export const dialPadRegistries = [ + dialPadDefinition(), + ...buttonRegistries, + ...textFieldRegistries, +]; + +/** + * Registers the dial-pad element with the design system. + * + * @param prefix - the prefix to use for the component name + */ +export const registerDialPad = registerFactory(dialPadRegistries); diff --git a/libs/components/src/lib/dial-pad/dial-pad.scss b/libs/components/src/lib/dial-pad/dial-pad.scss new file mode 100644 index 0000000000..ebbec3ebf5 --- /dev/null +++ b/libs/components/src/lib/dial-pad/dial-pad.scss @@ -0,0 +1,68 @@ +@use '../../../../../dist/libs/tokens/scss/tokens.constants' as constants; +@use '../../../../shared/src/lib/sass/mixins/border-radius' as + border-radius-variables; +@use '../../../../shared/src/lib/sass/mixins/connotation/config' with ( + $connotations: accent, + $shades: contrast soft pale fierce firm-all faint dim, + $default: accent +); +@use '../../../../shared/src/lib/sass/mixins/connotation' as connotation; +@use '../../../../shared/src/lib/sass/mixins/appearance/config' as + appearance-config with ( + $appearances: duotone, + $states: idle hover disabled, + $default: duotone +); +@use '../../../../shared/src/lib/sass/mixins/appearance' as appearance; + +$gap: 16px; + +:host { + display: inline-block; + margin: 16px; + inline-size: 230px; +} + +.base { + display: grid; + box-sizing: border-box; + grid-template-rows: 80px 1fr auto; +} + +.digits { + display: grid; + gap: $gap; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(4, 1fr); + inline-size: 100%; +} + +.phone-field { + align-self: flex-start; + grid-column: 1 / -1; +} + +.digit-btn { + @include appearance.appearance; + @include connotation.connotation(dial-pad); + + --vvd-button-accent-primary: var(#{appearance.get-appearance-token(text)}); + + display: flex; + overflow: hidden; + flex-direction: column; + border-radius: #{border-radius-variables.$border-radius-expanded}; + box-shadow: 0 0 0 1px var(#{appearance.get-appearance-token(outline)}); + inline-size: 100%; + + &-num { + .digit-btn:not(.disabled) & { + color: var(#{constants.$vvd-color-canvas-text}); + } + } +} + +.call-btn { + margin-top: 32px; + grid-column: 1/-1; +} diff --git a/libs/components/src/lib/dial-pad/dial-pad.spec.ts b/libs/components/src/lib/dial-pad/dial-pad.spec.ts new file mode 100644 index 0000000000..a59b91dc6a --- /dev/null +++ b/libs/components/src/lib/dial-pad/dial-pad.spec.ts @@ -0,0 +1,275 @@ +import { axe, elementUpdated, fixture, getBaseElement } from '@vivid-nx/shared'; +import { FoundationElementRegistry } from '@microsoft/fast-foundation'; +import { TextField } from '../text-field/text-field'; +import { Button } from '../button/button'; +import { DialPad } from './dial-pad'; +import { dialPadDefinition } from './definition'; +import '.'; + +const COMPONENT_TAG = 'vwc-dial-pad'; + +describe('vwc-dial-pad', () => { + let element: DialPad; + + function getTextField() { + return getBaseElement(element).querySelector('.phone-field') as TextField; + } + + function getCallButton() { + return getBaseElement(element).querySelector('.call-btn') as Button; + } + + function getDigitButtons() { + const digits: HTMLDivElement | null = + getBaseElement(element).querySelector('.digits'); + return digits?.querySelectorAll('vwc-button') as NodeListOf