Skip to content

Commit

Permalink
fix(textfield): update validation path, add "allowed-keys"
Browse files Browse the repository at this point in the history
  • Loading branch information
Westbrook Johnson authored and Westbrook committed Mar 25, 2020
1 parent 00f6cb0 commit ae9f85d
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 26 deletions.
24 changes: 22 additions & 2 deletions packages/textfield/src/textfield.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export class Textfield extends Focusable {
];
}

@property({ attribute: 'allowed-keys' })
allowedKeys = '';

@query('#input')
private inputElement!: HTMLInputElement | HTMLTextAreaElement;

Expand Down Expand Up @@ -86,6 +89,20 @@ export class Textfield extends Focusable {
}

protected onInput(): void {
if (this.allowedKeys && this.inputElement.value) {
const regExp = new RegExp(`^[${this.allowedKeys}]*$`);
if (!regExp.test(this.inputElement.value)) {
const selectionStart = this.inputElement
.selectionStart as number;
const nextSelectStart = selectionStart - 1;
this.inputElement.value = this.value;
this.inputElement.setSelectionRange(
nextSelectStart,
nextSelectStart
);
return;
}
}
this.value = this.inputElement.value;
}

Expand Down Expand Up @@ -164,13 +181,16 @@ export class Textfield extends Focusable {
}

protected updated(changedProperties: PropertyValues): void {
if (changedProperties.has('value')) {
if (
changedProperties.has('value') ||
(changedProperties.has('required') && this.required)
) {
this.checkValidity();
}
}

public checkValidity(): boolean {
if (this.value && (this.pattern || this.required)) {
if (this.required || (this.value && this.pattern)) {
let validity = this.inputElement.checkValidity();
if ((this.disabled || this.multiline) && this.pattern) {
const regex = new RegExp(this.pattern);
Expand Down
47 changes: 24 additions & 23 deletions packages/textfield/stories/textfield.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ governing permissions and limitations under the License.
*/
import {
html,
boolean,
withKnobs,
withWebComponentsKnobs,
} from '@open-wc/demoing-storybook';
Expand All @@ -26,49 +25,51 @@ export default {
};

export const Default = (): TemplateResult => {
const quiet = boolean('Quiet', false, 'Element');
return html`
<sp-textfield placeholder="Enter your name"></sp-textfield>
<sp-textfield placeholder="Enter your name" disabled></sp-textfield>
<sp-textfield
placeholder="Enter your name"
?quiet=${quiet}
></sp-textfield>
<sp-textfield
placeholder="Enter your name"
disabled
?quiet=${quiet}
></sp-textfield>
<sp-textfield
placeholder="Enter your name"
pattern="[\\w\\s]+"
pattern="[\\w\\s]*"
required
valid
value="A valid input"
?quiet=${quiet}
></sp-textfield>
<sp-textfield
placeholder="Enter your name"
pattern="[\\w\\s]+"
pattern="[\\w\\s]*"
required
valid
value="A valid input"
disabled
?quiet=${quiet}
></sp-textfield>
<sp-textfield
placeholder="Enter your name"
pattern="[\\d]+"
required
pattern="[\\d]*"
value="Not a valid input"
?quiet=${quiet}
></sp-textfield>
<sp-textfield
placeholder="Enter your name"
pattern="[\\d]+"
invalid
pattern="^[\\d]$"
required
value="Not a valid input"
disabled
?quiet=${quiet}
></sp-textfield>
`;
};

export const notRequiredWithPattern = (): TemplateResult => {
return html`
<sp-textfield
placeholder="Enter z, x, c, or v"
pattern="[zxcv]+"
></sp-textfield>
`;
};

export const allowedKeys = (): TemplateResult => {
return html`
<sp-textfield
placeholder="Enter your name"
allowed-keys="a-z"
></sp-textfield>
`;
};
49 changes: 48 additions & 1 deletion packages/textfield/test/textfield.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ describe('Textfield', () => {
const testSource = eventSource as Textfield;
expect(testSource.isSameNode(el)).to.be.true;
});

it('passes through `autocomplete` attribute', async () => {
let el = await litFixture<Textfield>(
html`
Expand All @@ -226,4 +225,52 @@ describe('Textfield', () => {
expect(input.getAttribute('autocomplete')).to.not.exist;
}
});
it('tests on `required` changes', async () => {
const el = await litFixture<Textfield>(
html`
<sp-textfield value=""></sp-textfield>
`
);
await elementUpdated(el);
expect(el.invalid).to.be.false;

el.required = true;
await elementUpdated(el);
expect(el.invalid).to.be.true;
});
it('manages `allowed-keys`', async () => {
const el = await litFixture<Textfield>(
html`
<sp-textfield allowed-keys="asdf"></sp-textfield>
`
);
await elementUpdated(el);
expect(el.value).to.equal('');

const inputElement = (el.shadowRoot
? el.shadowRoot.querySelector('#input')
: el.querySelector('#input')) as HTMLInputElement;

inputElement.value = 'asdf';
inputElement.dispatchEvent(new InputEvent('input'));

await elementUpdated(el);
expect(el.value).to.equal('asdf');

inputElement.value = `asdff`;
inputElement.setSelectionRange(1, 1);
inputElement.dispatchEvent(new InputEvent('input'));

await elementUpdated(el);
expect(el.value).to.equal('asdff');
expect(inputElement.selectionStart).to.equal(1);

inputElement.value = `asdoff`;
inputElement.setSelectionRange(4, 4);
inputElement.dispatchEvent(new InputEvent('input'));

await elementUpdated(el);
expect(el.value).to.equal('asdff');
expect(inputElement.selectionStart).to.equal(3);
});
});

0 comments on commit ae9f85d

Please sign in to comment.