Skip to content

Commit

Permalink
Merge branch 'develop' into Add-css-variable-for-suggestions-hover-state
Browse files Browse the repository at this point in the history
  • Loading branch information
chromaticWaster committed Oct 2, 2024
2 parents d3f8fea + 49eba67 commit dcbba8c
Show file tree
Hide file tree
Showing 119 changed files with 440 additions and 39 deletions.
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.
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.
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.
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.
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.
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@capitec/omni-components",
"version": "0.9.9",
"version": "0.9.10",
"type": "module",
"description": "Modern UI component library for mobile and web",
"scripts": {
Expand Down
31 changes: 31 additions & 0 deletions src/email-field/EmailField.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,37 @@ test(`Email Field - Visual and Behaviour`, async ({ page }) => {
});
});

test(`Email Field - Max Length Behaviour`, async ({ page }) => {
await withCoverage(page, async () => {
await page.goto('/components/email-field/');
await page.evaluate(() => document.fonts.ready);

const container = page.locator('.Max_Length');
const emailField = container.locator('[data-testid]').first();
emailField.evaluate(async (t: EmailField) => {
t.value = '';
t.maxLength = 4;
await t.updateComplete;
});

// Confirm that the component matches the provided screenshot.
await expect(emailField).toHaveScreenshot('email-field.png');

const inputFn = await mockEventListener(emailField, 'input');

const inputField = emailField.locator('#inputField');

const typedValue = '[email protected]';
const value = 'mail';
await inputField.type(typedValue);

await expect(emailField).toHaveScreenshot('email-field-value.png');
await expect(inputField).toHaveValue(value);

await expect(inputFn).toBeCalledTimes(typedValue.length);
});
});

test('Email Field - Label Behaviour', testLabelBehaviour('omni-email-field'));
test('Email Field - Hint Behaviour', testHintBehaviour('omni-email-field'));
test('Email Field - Error Behaviour', testErrorBehaviour('omni-email-field'));
Expand Down
39 changes: 36 additions & 3 deletions src/email-field/EmailField.stories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { html, nothing } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import {
LabelStory,
Expand All @@ -16,13 +17,17 @@ import { ifNotEmpty } from '../utils/Directives.js';
import { assignToSlot, ComponentStoryFormat, getSourceFromLit } from '../utils/StoryUtils.js';

import './EmailField.js';
interface Args extends BaseArgs {
maxLength: number;
}

export const Interactive: ComponentStoryFormat<BaseArgs> = {
render: (args: BaseArgs) => html`
export const Interactive: ComponentStoryFormat<Args> = {
render: (args: Args) => html`
<omni-email-field
data-testid="test-email-field"
label="${ifNotEmpty(args.label)}"
value="${args.value}"
max-length=${ifDefined(args.maxLength)}
hint="${ifNotEmpty(args.hint)}"
error="${ifNotEmpty(args.error)}"
?disabled="${args.disabled}"
Expand Down Expand Up @@ -51,7 +56,35 @@ export const Interactive: ComponentStoryFormat<BaseArgs> = {
clearable: false,
prefix: '',
suffix: '',
clear: ''
clear: '',
maxLength: undefined
}
};

export const Max_Length: ComponentStoryFormat<Args> = {
render: (args: Args) => html`
<omni-email-field
data-testid="test-email-field"
label="${ifNotEmpty(args.label)}"
value="${args.value}"
max-length=${ifDefined(args.maxLength)}>
</omni-email-field>
`,
frameworkSources: [
{
framework: 'React',
load: (args) => `import { OmniEmailField } from "@capitec/omni-components-react/email-field";
const App = () => <OmniEmailField${args.label ? ` label='${args.label}'` : ''}${args.value ? ` value='${args.value}'` : ''}${
args.maxLength ? ` max-length='${args.maxLength}'` : ''
}/>;`
}
],
name: 'Max Length',
description: 'Limit the character input length based on the value provided to the email field.',
args: {
label: 'Max Length',
maxLength: 5
}
};

Expand Down
22 changes: 22 additions & 0 deletions src/email-field/EmailField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { OmniFormElement } from '../core/OmniFormElement.js';
* <omni-email-field
* label="Enter a value"
* value="[email protected]"
* max-length: 5
* hint="Required"
* error="Field level error message"
* disabled>
Expand Down Expand Up @@ -50,6 +51,12 @@ export class EmailField extends OmniFormElement {
*/
@property({ type: Boolean, reflect: true, attribute: 'no-native-keyboard' }) noNativeKeyboard?: boolean;

/**
* Maximum character input length.
* @attr [max-length]
*/
@property({ type: Number, reflect: true, attribute: 'max-length' }) maxLength?: number;

override connectedCallback() {
super.connectedCallback();
this.addEventListener('input', this._keyInput.bind(this), {
Expand All @@ -60,6 +67,15 @@ export class EmailField extends OmniFormElement {
});
}

// If a value is bound when the component is first updated slice the value based on the max length.
protected override async firstUpdated(): Promise<void> {
if (this.value !== null && this.value !== undefined) {
if (this.maxLength) {
this._inputElement!.value = String(this.value).slice(0, this.maxLength);
}
}
}

override focus(options?: FocusOptions | undefined): void {
if (this._inputElement) {
this._inputElement.focus(options);
Expand All @@ -76,6 +92,12 @@ export class EmailField extends OmniFormElement {

_keyInput() {
const input = this._inputElement as HTMLInputElement;
// If the input has a value and the max length property is set then slice the value according to the max length.
if (input?.value && this.maxLength) {
if (input.value.length > this.maxLength) {
input.value = input.value.slice(0, this.maxLength);
}
}
this.value = input.value;
}

Expand Down
1 change: 1 addition & 0 deletions src/email-field/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Email input control, used in forms for input validation and to display correct v
| `hint` | `hint` | | `string \| undefined` | | Hint message to assist the user. |
| `label` | `label` | | `string \| undefined` | | Text label. |
| `lang` | | | `string` | | |
| `maxLength` | `max-length` | | `number \| undefined` | | Maximum character input length. |
| `noNativeKeyboard` | `no-native-keyboard` | | `boolean \| undefined` | | Disables native on screen keyboards for the component. |
| `override` | `override` | | | | Used to set the base direction of text for display |
| `styles` | | readonly | `CSSResultGroup[]` | | |
Expand Down
32 changes: 32 additions & 0 deletions src/number-field/NumberField.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,38 @@ test(`Number Field - Visual and Behaviour`, async ({ page }) => {
});
});

test(`Number Field - Max Length Behaviour`, async ({ page }) => {
await withCoverage(page, async () => {
await page.goto('/components/number-field/');
await page.evaluate(() => document.fonts.ready);

const container = page.locator('.Max_Length');
const numberField = container.locator('[data-testid]').first();
numberField.evaluate(async (t: NumberField) => {
t.value = '';
t.maxLength = 4;
await t.updateComplete;
});

// Confirm that the component matches the provided screenshot.
await expect(numberField).toHaveScreenshot('number-field.png');

const inputFn = await mockEventListener(numberField, 'input');

const inputField = numberField.locator('#inputField');

// Update the value of the number field.
const typedValue = '12345';
const value = '1234';
await inputField.type(typedValue);

await expect(numberField).toHaveScreenshot('number-field-value.png');
await expect(inputField).toHaveValue(value);

await expect(inputFn).toBeCalledTimes(typedValue.length);
});
});

test('Number Field - Label Behaviour', testLabelBehaviour('omni-number-field'));
test('Number Field - Hint Behaviour', testHintBehaviour('omni-number-field'));
test('Number Field - Error Behaviour', testErrorBehaviour('omni-number-field'));
Expand Down
39 changes: 36 additions & 3 deletions src/number-field/NumberField.stories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { html, nothing } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import {
LabelStory,
Expand All @@ -16,13 +17,17 @@ import { ifNotEmpty } from '../utils/Directives.js';
import { assignToSlot, ComponentStoryFormat, getSourceFromLit } from '../utils/StoryUtils.js';

import './NumberField.js';
interface Args extends BaseArgs {
maxLength: number;
}

export const Interactive: ComponentStoryFormat<BaseArgs> = {
render: (args: BaseArgs) => html`
export const Interactive: ComponentStoryFormat<Args> = {
render: (args: Args) => html`
<omni-number-field
data-testid="test-number-field"
label="${ifNotEmpty(args.label)}"
value="${args.value}"
max-length=${ifDefined(args.maxLength)}
hint="${ifNotEmpty(args.hint)}"
error="${ifNotEmpty(args.error)}"
?disabled="${args.disabled}"
Expand Down Expand Up @@ -50,7 +55,35 @@ export const Interactive: ComponentStoryFormat<BaseArgs> = {
disabled: false,
prefix: '',
suffix: '',
clear: ''
clear: '',
maxLength: undefined
}
};

export const Max_Length: ComponentStoryFormat<Args> = {
render: (args: Args) => html`
<omni-number-field
data-testid="test-number-field"
label="${ifNotEmpty(args.label)}"
value="${args.value}"
max-length=${ifDefined(args.maxLength)}>
</omni-number-field>
`,
frameworkSources: [
{
framework: 'React',
load: (args) => `import { OmniNumberField } from "@capitec/omni-components-react/number-field";
const App = () => <OmniNumberField${args.label ? ` label='${args.label}'` : ''}${args.value ? ` value='${args.value}'` : ''}${
args.maxLength ? ` max-length='${args.maxLength}'` : ''
}/>;`
}
],
name: 'Max Length',
description: 'Limit the numeric input length based on the value provided.',
args: {
label: 'Max Length',
maxLength: 5
}
};

Expand Down
24 changes: 24 additions & 0 deletions src/number-field/NumberField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ifDefined, OmniFormElement } from '../core/OmniFormElement.js';
* <omni-number-field
* label="Enter a value"
* value=12345
* max-length: 5
* hint="Required"
* error="Field level error message"
* disabled>
Expand Down Expand Up @@ -49,6 +50,12 @@ export class NumberField extends OmniFormElement {
*/
@property({ type: Boolean, reflect: true, attribute: 'no-native-keyboard' }) noNativeKeyboard?: boolean;

/**
* Maximum character input length.
* @attr [max-length]
*/
@property({ type: Number, reflect: true, attribute: 'max-length' }) maxLength?: number;

override connectedCallback() {
super.connectedCallback();
this.addEventListener('input', this._keyInput.bind(this), {
Expand All @@ -59,6 +66,15 @@ export class NumberField extends OmniFormElement {
});
}

// If a value is bound when the component is first updated slice the value based on the max length if set.
protected override async firstUpdated(): Promise<void> {
if (this.value !== null && this.value !== undefined) {
if (this.maxLength) {
this._inputElement!.value = String(this.value).slice(0, this.maxLength);
}
}
}

// Added for browsers that allow text values entered into a input when type is set to number.
override async attributeChangedCallback(name: string, _old: string | null, value: string | null): Promise<void> {
super.attributeChangedCallback(name, _old, value);
Expand Down Expand Up @@ -87,6 +103,14 @@ export class NumberField extends OmniFormElement {

_keyInput() {
const input = this._inputElement as HTMLInputElement;

// If the input has a value and the max length property is set then slice the value according to the max length.
if (input?.value && this.maxLength) {
if (input.value.length > this.maxLength) {
input.value = input.value.slice(0, this.maxLength);
}
}

this.value = input?.value;
}

Expand Down
2 changes: 2 additions & 0 deletions src/number-field/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Input control to enter a single line of numbers.
<omni-number-field
label="Enter a value"
value=12345
max-length: 5
hint="Required"
error="Field level error message"
disabled>
Expand All @@ -26,6 +27,7 @@ Input control to enter a single line of numbers.
| `hint` | `hint` | | `string \| undefined` | | Hint message to assist the user. |
| `label` | `label` | | `string \| undefined` | | Text label. |
| `lang` | | | `string` | | |
| `maxLength` | `max-length` | | `number \| undefined` | | Maximum character input length. |
| `noNativeKeyboard` | `no-native-keyboard` | | `boolean \| undefined` | | Disables native on screen keyboards for the component. |
| `override` | `override` | | | | Used to set the base direction of text for display |
| `styles` | | readonly | `CSSResultGroup[]` | | |
Expand Down
29 changes: 18 additions & 11 deletions src/password-field/PasswordField.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,34 @@ test(`Password Field - Visual and Behaviour`, async ({ page }) => {
});
});

test(`Password Field - Behaviour`, async ({ page }) => {
test(`Password Field - Max Length Behaviour`, async ({ page }) => {
await withCoverage(page, async () => {
await page.goto('/components/password-field/');
await page.evaluate(() => document.fonts.ready);

const passwordField = page.locator('[data-testid]').first();
await expect(passwordField).toHaveScreenshot('password-field-initial.png');
const container = page.locator('.Max_Length');
const passwordField = container.locator('[data-testid]').first();
passwordField.evaluate(async (t: PasswordField) => {
t.value = '';
t.maxLength = 4;
await t.updateComplete;
});

const showSlotElement = passwordField.locator('slot[name=show]');
await showSlotElement.click();
// Confirm that the component matches the provided screenshot.
await expect(passwordField).toHaveScreenshot('password-field.png');

const hideSlotElement = passwordField.locator('slot[name=hide]');
await hideSlotElement.click();
const inputFn = await mockEventListener(passwordField, 'input');

const inputField = passwordField.locator('#inputField');

const valueUpdate = 'Value Update';
await passwordField.evaluate((p: PasswordField, valueUpdate) => (p.value = valueUpdate), valueUpdate);
const typedValue = 'Tests';
const value = 'Test';
await inputField.type(typedValue);

await expect(passwordField).toHaveScreenshot('password-field-value.png');
await expect(inputField).toHaveValue(value);

await expect(inputField).toHaveValue(valueUpdate);
await expect(passwordField).toHaveScreenshot('password-field-value-update.png');
await expect(inputFn).toBeCalledTimes(typedValue.length);
});
});

Expand Down
Loading

0 comments on commit dcbba8c

Please sign in to comment.