Skip to content

Commit

Permalink
feat(input): add support for value change and keyboard events
Browse files Browse the repository at this point in the history
  • Loading branch information
Nexyll authored and MonsieurMan committed Oct 4, 2019
1 parent d8b307f commit 929e5a2
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 1,153 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@material/ripple": "1.1.0",
"@stencil/core": "^1.4.0",
"@stencil/sass": "^1.0.1",
"@types/dom-inputevent": "^1.0.5",
"@types/jest": "^24.0.18",
"@types/puppeteer": "^1.19.1",
"chokidar": "^3.0.2",
Expand Down
13 changes: 13 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ export namespace Components {
* The type of control to display. The default type is text.
*/
'type': TextFieldTypes;
/**
* The text value of the input.
*/
'value': string | null;
}
interface WcsInputGroup {}
Expand Down Expand Up @@ -492,8 +495,15 @@ declare namespace LocalJSX {
* The name of the control, which is submitted with the form data.
*/
'name'?: string;
/**
* Emitted when the value has changed.
*/
'onWcsChange'?: (event: CustomEvent<InputChangeEventDetail>) => void;
/**
* Emitted when a keyboard input ocurred.
*/
'onWcsInput'?: (event: CustomEvent<InputEvent>) => void;
/**
* A regular expression that the value is checked against. The pattern must match the entire value, not just some subset. Use the title attribute to describe the pattern to help the user. This attribute applies when the value of the type attribute is `"text"`, `"search"`, `"tel"`, `"url"`, `"email"`, or `"password"`, otherwise it is ignored.
*/
'pattern'?: string;
Expand All @@ -517,6 +527,9 @@ declare namespace LocalJSX {
* The type of control to display. The default type is text.
*/
'type'?: TextFieldTypes;
/**
* The text value of the input.
*/
'value'?: string | null;
}
interface WcsInputGroup extends JSXBase.HTMLAttributes<HTMLWcsInputGroupElement> {}
Expand Down
2 changes: 1 addition & 1 deletion src/components/input/input-interface.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface InputChangeEventDetail {
value: string | undefined | null;

}

export type TextFieldTypes = 'date' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'url' | 'time';
44 changes: 44 additions & 0 deletions src/components/input/input.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { newE2EPage } from '@stencil/core/testing';
describe(`Input`, () => {

it(`Propagates wcsChange event when a key stroke occurs on the native input`, async () => {
// Given
const page = await newE2EPage({
html: `
<wcs-input />
`
});
const select = await page.find('wcs-input');
const input_wrapper = await page.find('wcs-input >>> input');
const changeSpy = await select.spyOnEvent('wcsChange');

// When
await input_wrapper.press('A');
await page.waitForChanges();

// Then
expect(changeSpy).toHaveReceivedEventTimes(1);
expect(changeSpy).toHaveReceivedEventDetail({ value: 'A' });
});

it(`Propagates wcsInput event when a key stroke occurs on the native input`, async () => {
// Given
const page = await newE2EPage({
html: `
<wcs-input />
`
});
const select = await page.find('wcs-input');
const input_wrapper = await page.find('wcs-input >>> input');
const changeSpy = await select.spyOnEvent('wcsInput');

// When
await input_wrapper.press('A');
await page.waitForChanges();

// Then
expect(changeSpy).toHaveReceivedEventTimes(1);
console.dir(changeSpy.firstEvent); // TODO: fix the test (Quantum behaviour for now...)
expect(changeSpy).toHaveReceivedEventDetail({ data: 'A' });
});
});
4 changes: 2 additions & 2 deletions src/components/input/input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ input {
background-clip: padding-box;
}

input:focus{
outline:0;
input:focus {
outline: 0;
border: solid 1px var(--wcs-primary);
}

Expand Down
41 changes: 22 additions & 19 deletions src/components/input/input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Element, Event, EventEmitter, Method, Prop, Watch, h } from '@stencil/core';
import { Component, Element, Event, EventEmitter, Method, Prop, Watch, h, ComponentInterface } from '@stencil/core';
import { InputChangeEventDetail, TextFieldTypes } from './input-interface';

/**
Expand All @@ -9,20 +9,32 @@ import { InputChangeEventDetail, TextFieldTypes } from './input-interface';
styleUrl: 'input.scss',
shadow: true,
})
export class Input {
export class Input implements ComponentInterface {
@Element() el: HTMLElement;

private inputId = `ion-input-${inputIds++}`;

private nativeInput?: HTMLInputElement;

/**
* Emitted when a keyboard input ocurred.
*/
@Event() wcsInput!: EventEmitter<InputEvent>;

/**
* Emitted when the value has changed.
*/
@Event() wcsChange!: EventEmitter<InputChangeEventDetail>;

/**
* The name of the control, which is submitted with the form data.
*/
@Prop() name: string = this.inputId;

@Prop({ reflect: true }) background: 'normal' | 'white' = 'normal';

/**
* The text value of the input.
*/
@Prop({ reflect: true, mutable: true }) value: string | null = '';

/**
Expand All @@ -45,18 +57,17 @@ export class Input {
*/
@Prop() autofocus = false;

// TODO: Add styling for disabled input.
/**
* If `true`, the user cannot interact with the input.
*/
@Prop() disabled = false;


/**
* If the value of the type attribute is `"file"`, then this attribute will indicate the types of files that the server accepts, otherwise it will be ignored. The value must be a comma-separated list of unique content type specifiers.
*/
@Prop() accept?: string;


/**
* A hint to the browser for which keyboard to display.
* This attribute applies when the value of the type attribute is `"text"`, `"password"`, `"email"`, or `"url"`. Possible values are: `"verbatim"`, `"latin"`, `"latin-name"`, `"latin-prose"`, `"full-width-latin"`, `"kana"`, `"katakana"`, `"numeric"`, `"tel"`, `"email"`, `"url"`.
Expand Down Expand Up @@ -119,28 +130,20 @@ export class Input {
*/
@Prop() type: TextFieldTypes = 'text';

@Event() wcsChange!: EventEmitter<InputChangeEventDetail>;

private getValue(): string {
return this.value || '';
}

@Watch('value')
protected valueChanged() {
this.wcsChange.emit({ value: this.value });
console.log(this.value);
}

private onInput(ev: Event) {
const input = ev.target as HTMLInputElement | null;
if (input) {
this.value = input.value || '';
}
}

@Watch('disabled')
protected disabledChanged() {
// TODO: implement
private onInput(event: InputEvent) {
this.value = (event.target as HTMLInputElement).value;
console.log(this.value);
// TODO: This needs test
this.wcsInput.emit(event);
}

render() {
Expand All @@ -152,7 +155,7 @@ export class Input {
name={this.name}
class={this.background}
value={value}
onInput={this.onInput}
onInput={(evt: InputEvent) => this.onInput(evt)}
ref={input => this.nativeInput = input}
disabled={this.disabled}
accept={this.accept}
Expand Down
Loading

0 comments on commit 929e5a2

Please sign in to comment.