@purpurds/text-field 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LICENSE.txt +66 -0
- package/dist/styles.css +1 -0
- package/dist/text-field.cjs.js +30 -0
- package/dist/text-field.cjs.js.map +1 -0
- package/dist/text-field.d.ts +98 -0
- package/dist/text-field.d.ts.map +1 -0
- package/dist/text-field.es.js +708 -0
- package/dist/text-field.es.js.map +1 -0
- package/dist/text-field.system.js +30 -0
- package/dist/text-field.system.js.map +1 -0
- package/package.json +65 -0
- package/readme.mdx +61 -0
- package/src/global.d.ts +4 -0
- package/src/text-field.module.scss +143 -0
- package/src/text-field.stories.tsx +71 -0
- package/src/text-field.test.tsx +218 -0
- package/src/text-field.tsx +184 -0
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@purpurds/text-field",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"main": "./dist/text-field.cjs.js",
|
|
6
|
+
"types": "./dist/text-field.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/text-field.cjs.js",
|
|
10
|
+
"systemjs": "./dist/text-field.system.js",
|
|
11
|
+
"types": "./dist/text-field.d.ts",
|
|
12
|
+
"default": "./dist/text-field.es.js"
|
|
13
|
+
},
|
|
14
|
+
"./styles": "./dist/styles.css"
|
|
15
|
+
},
|
|
16
|
+
"source": "src/text-field.tsx",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"classnames": "~2.5.0",
|
|
19
|
+
"@purpurds/field-helper-text": "3.0.0",
|
|
20
|
+
"@purpurds/field-error-text": "3.0.0",
|
|
21
|
+
"@purpurds/icon": "3.0.0",
|
|
22
|
+
"@purpurds/label": "3.0.0",
|
|
23
|
+
"@purpurds/spinner": "3.0.0",
|
|
24
|
+
"@purpurds/tokens": "3.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@rushstack/eslint-patch": "~1.7.0",
|
|
28
|
+
"@storybook/blocks": "~7.6.0",
|
|
29
|
+
"@storybook/client-api": "~7.6.0",
|
|
30
|
+
"@storybook/react": "~7.6.0",
|
|
31
|
+
"@telia/base-rig": "~8.2.0",
|
|
32
|
+
"@telia/react-rig": "~3.2.0",
|
|
33
|
+
"@testing-library/dom": "~9.3.3",
|
|
34
|
+
"@testing-library/jest-dom": "~6.3.0",
|
|
35
|
+
"@testing-library/react": "~14.1.2",
|
|
36
|
+
"@types/node": "18",
|
|
37
|
+
"@types/react-dom": "~18.2.17",
|
|
38
|
+
"@types/react": "~18.2.42",
|
|
39
|
+
"eslint-plugin-testing-library": "~6.2.0",
|
|
40
|
+
"eslint": "~8.56.0",
|
|
41
|
+
"jsdom": "~22.1.0",
|
|
42
|
+
"lint-staged": "~10.5.3",
|
|
43
|
+
"prettier": "~2.8.8",
|
|
44
|
+
"react-dom": "~18.2.0",
|
|
45
|
+
"react": "~18.2.0",
|
|
46
|
+
"typescript": "~5.2.2",
|
|
47
|
+
"vite": "~5.0.6",
|
|
48
|
+
"vitest": "~1.2.0",
|
|
49
|
+
"@purpurds/component-rig": "1.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build:dev": "vite",
|
|
53
|
+
"build:watch": "vite build --watch",
|
|
54
|
+
"build": "rm -rf dist && vite build && vite build --mode systemjs",
|
|
55
|
+
"ci:build": "rushx build",
|
|
56
|
+
"coverage": "vitest run --coverage",
|
|
57
|
+
"lint:fix": "eslint . --fix",
|
|
58
|
+
"lint": "lint-staged --no-stash 2>&1",
|
|
59
|
+
"sbdev": "rush sbdev",
|
|
60
|
+
"test:unit": "vitest run --passWithNoTests",
|
|
61
|
+
"test:watch": "vitest --watch",
|
|
62
|
+
"test": "rushx test:unit",
|
|
63
|
+
"typecheck": "tsc -p ./tsconfig.check.json"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/readme.mdx
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Meta, Stories, ArgTypes, Primary, Subtitle } from "@storybook/blocks";
|
|
2
|
+
|
|
3
|
+
import * as TextFieldStories from "./src/text-field.stories";
|
|
4
|
+
import packageInfo from "./package.json";
|
|
5
|
+
|
|
6
|
+
<Meta name="Docs" title="Components/TextField" of={TextFieldStories} />
|
|
7
|
+
|
|
8
|
+
# TextField
|
|
9
|
+
|
|
10
|
+
<Subtitle>Version {packageInfo.version}</Subtitle>
|
|
11
|
+
|
|
12
|
+
### Showcase
|
|
13
|
+
|
|
14
|
+
<Primary />
|
|
15
|
+
|
|
16
|
+
### Properties
|
|
17
|
+
|
|
18
|
+
Except for the props below, [all "native" input attributs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) are also valid props. The only exceptions are:
|
|
19
|
+
|
|
20
|
+
- `type` - Restricted to `"email" | "number" | "password" | "search" | "tel" | "text"`
|
|
21
|
+
- `id` - Required
|
|
22
|
+
|
|
23
|
+
<ArgTypes />
|
|
24
|
+
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
#### Via NPM
|
|
28
|
+
|
|
29
|
+
Add the dependency to your consumer app like `"@purpurds/text-field": "x.y.z"`
|
|
30
|
+
|
|
31
|
+
#### From outside the monorepo (build-time)
|
|
32
|
+
|
|
33
|
+
To install this package, you need to setup access to the artifactory. [Click here to go to the guide on how to do that](https://github.com/telia-company/jfrog-documentation/blob/main/doc/JFrog/JFrog_Onboarding.md#getting-access-to-artifactory-and-other-jfrog-applications).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
In MyApp.tsx
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import "@purpurds/tokens/index.css";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
and
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import "@purpurds/text-field/styles";
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
In MyComponent.tsx
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { TextField } from "@purpurds/text-field";
|
|
53
|
+
|
|
54
|
+
export const MyComponent = () => {
|
|
55
|
+
return (
|
|
56
|
+
<div>
|
|
57
|
+
<TextField {...someProps}>Some content</TextField>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
```
|
package/src/global.d.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
.purpur-text-field {
|
|
2
|
+
$root: &;
|
|
3
|
+
|
|
4
|
+
position: relative;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
gap: var(--purpur-spacing-50);
|
|
8
|
+
|
|
9
|
+
&__label {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
gap: var(--purpur-spacing-50);
|
|
13
|
+
width: fit-content;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&__label-text {
|
|
17
|
+
width: fit-content;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&__field-row {
|
|
21
|
+
display: flex;
|
|
22
|
+
width: 100%;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&__frame {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
border-radius: var(--purpur-border-radius-sm);
|
|
29
|
+
border: var(--purpur-border-width-xs) solid var(--purpur-color-border-interactive-subtle);
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&__input-container {
|
|
34
|
+
position: relative;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
width: 100%;
|
|
38
|
+
border-radius: var(--purpur-border-radius-sm);
|
|
39
|
+
background: var(--purpur-color-background-primary);
|
|
40
|
+
|
|
41
|
+
&--disabled {
|
|
42
|
+
background: var(--purpur-color-background-interactive-disabled);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&--readonly {
|
|
46
|
+
background: var(--purpur-color-background-interactive-read-only);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&--end-adornment {
|
|
50
|
+
padding-right: var(--purpur-spacing-150);
|
|
51
|
+
|
|
52
|
+
#{$root}__input {
|
|
53
|
+
padding-right: var(--purpur-spacing-100);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&--start-adornment {
|
|
58
|
+
padding-left: var(--purpur-spacing-150);
|
|
59
|
+
|
|
60
|
+
#{$root}__input {
|
|
61
|
+
padding-left: var(--purpur-spacing-100);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&__input {
|
|
67
|
+
$inputRoot: &;
|
|
68
|
+
|
|
69
|
+
border-radius: var(--purpur-border-radius-sm);
|
|
70
|
+
padding: calc(var(--purpur-spacing-100) + var(--purpur-spacing-25)) var(--purpur-spacing-150);
|
|
71
|
+
border: none;
|
|
72
|
+
width: 100%;
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
font-family: var(--purpur-typography-family-default), Helvetica, Arial, "Lucida Grande",
|
|
75
|
+
sans-serif;
|
|
76
|
+
font-size: var(--purpur-typography-scale-100);
|
|
77
|
+
line-height: 150%;
|
|
78
|
+
outline: none;
|
|
79
|
+
background: transparent;
|
|
80
|
+
|
|
81
|
+
&:hover {
|
|
82
|
+
~ #{$root}__frame {
|
|
83
|
+
border-width: var(--purpur-border-width-sm);
|
|
84
|
+
border-color: var(--purpur-color-border-interactive-subtle-hover);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:active:not(:disabled):not(:read-only),
|
|
89
|
+
&:focus:not(:disabled):not(:read-only) {
|
|
90
|
+
~ #{$root}__frame {
|
|
91
|
+
outline: var(--purpur-border-width-sm) solid var(--purpur-color-border-interactive-focus);
|
|
92
|
+
outline-offset: calc(var(--purpur-spacing-10) * 2);
|
|
93
|
+
border-width: var(--purpur-border-width-xs);
|
|
94
|
+
border-color: var(--purpur-color-border-interactive-subtle-hover);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&:disabled {
|
|
99
|
+
color: var(--purpur-color-text-weak);
|
|
100
|
+
|
|
101
|
+
~ #{$root}__frame {
|
|
102
|
+
border-width: var(--purpur-border-width-xs);
|
|
103
|
+
border-color: var(--purpur-color-border-medium);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&:read-only:not(:disabled) {
|
|
108
|
+
color: var(--purpur-color-text-default);
|
|
109
|
+
|
|
110
|
+
~ #{$root}__frame {
|
|
111
|
+
border-width: var(--purpur-border-width-xs);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&:not(#{$inputRoot}--valid):not(#{$inputRoot}--error) {
|
|
115
|
+
~ #{$root}__frame {
|
|
116
|
+
border-color: var(--purpur-color-border-medium);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
&#{$inputRoot}--valid {
|
|
122
|
+
~ #{$root}__frame {
|
|
123
|
+
border-color: var(--purpur-color-border-status-success);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&#{$inputRoot}--error:not(:hover) {
|
|
128
|
+
~ #{$root}__frame {
|
|
129
|
+
border-color: var(--purpur-color-border-status-error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&__adornment-container {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: var(--purpur-spacing-50);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&__valid-icon {
|
|
141
|
+
color: var(--purpur-color-text-status-success-medium);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useArgs } from "@storybook/client-api";
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
+
|
|
5
|
+
import "@purpurds/label/styles";
|
|
6
|
+
import "@purpurds/field-helper-text/styles";
|
|
7
|
+
import "@purpurds/field-error-text/styles";
|
|
8
|
+
import "@purpurds/icon/styles";
|
|
9
|
+
import "@purpurds/spinner/styles";
|
|
10
|
+
import { TextField } from "./text-field";
|
|
11
|
+
|
|
12
|
+
const meta: Meta<typeof TextField> = {
|
|
13
|
+
title: "Inputs/TextField",
|
|
14
|
+
component: TextField,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof TextField>;
|
|
19
|
+
|
|
20
|
+
export const Showcase: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
value: "Text field",
|
|
23
|
+
label: "Text field label",
|
|
24
|
+
helperText: "Helper text",
|
|
25
|
+
placeholder: "Enter text",
|
|
26
|
+
valid: false,
|
|
27
|
+
errorText: undefined,
|
|
28
|
+
loading: false,
|
|
29
|
+
disabled: false,
|
|
30
|
+
readOnly: false,
|
|
31
|
+
required: false,
|
|
32
|
+
type: "text",
|
|
33
|
+
},
|
|
34
|
+
argTypes: {
|
|
35
|
+
onChange: { action: "inputChange", table: { disable: true } },
|
|
36
|
+
type: { options: ["email", "number", "password", "search", "tel", "text"], control: "select" },
|
|
37
|
+
startAdornment: { table: { disable: true } },
|
|
38
|
+
endAdornment: { table: { disable: true } },
|
|
39
|
+
afterField: { table: { disable: true } },
|
|
40
|
+
},
|
|
41
|
+
parameters: {
|
|
42
|
+
design: [
|
|
43
|
+
{
|
|
44
|
+
name: "TextField",
|
|
45
|
+
type: "figma",
|
|
46
|
+
url: "https://www.figma.com/file/XEaIIFskrrxIBHMZDkIuIg/Purpur-DS---Component-library-%26-guidelines?node-id=1528%3A1886",
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
decorators: [
|
|
51
|
+
(Story) => (
|
|
52
|
+
<div style={{ maxWidth: "18.5rem" }}>
|
|
53
|
+
<Story />
|
|
54
|
+
</div>
|
|
55
|
+
),
|
|
56
|
+
],
|
|
57
|
+
render: ({ onChange, ...args }) => {
|
|
58
|
+
const [{ value }, updateArgs] = useArgs(); // eslint-disable-line react-hooks/rules-of-hooks
|
|
59
|
+
return (
|
|
60
|
+
<TextField
|
|
61
|
+
{...args}
|
|
62
|
+
id="playground-input"
|
|
63
|
+
value={value}
|
|
64
|
+
onChange={(e) => {
|
|
65
|
+
onChange?.(e);
|
|
66
|
+
updateArgs({ value: e.target.value });
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import * as matchers from "@testing-library/jest-dom/matchers";
|
|
3
|
+
import { cleanup, fireEvent, render, screen, within } from "@testing-library/react";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { TextField } from "./text-field";
|
|
7
|
+
const rootClassName = "purpur-text-field";
|
|
8
|
+
|
|
9
|
+
expect.extend(matchers);
|
|
10
|
+
|
|
11
|
+
describe("TextField", () => {
|
|
12
|
+
afterEach(cleanup);
|
|
13
|
+
|
|
14
|
+
it("should render plain", () => {
|
|
15
|
+
render(<TextField id="test" data-testid="test" />);
|
|
16
|
+
|
|
17
|
+
const input = screen.getByTestId("test-input");
|
|
18
|
+
expect(input).toBeInTheDocument();
|
|
19
|
+
expect(input.className).toBe(`${rootClassName}__input`);
|
|
20
|
+
expect(screen.queryByTestId("test-label")).not.toBeInTheDocument();
|
|
21
|
+
expect(screen.queryByTestId("test-helper-text")).not.toBeInTheDocument();
|
|
22
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
23
|
+
expect(screen.queryByTestId("test-endrootClassName-adornments")).not.toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should render with label", () => {
|
|
27
|
+
render(<TextField id="test" data-testid="test" label="Test label" />);
|
|
28
|
+
|
|
29
|
+
const input = screen.getByTestId("test-input");
|
|
30
|
+
expect(input).toBeInTheDocument();
|
|
31
|
+
expect(input.className).toBe(`${rootClassName}__input`);
|
|
32
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
33
|
+
expect(screen.queryByTestId("test-helper-text")).not.toBeInTheDocument();
|
|
34
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
35
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should render with helper-text", () => {
|
|
39
|
+
render(<TextField id="test" data-testid="test" label="Test label" helperText="Helper text" />);
|
|
40
|
+
|
|
41
|
+
const input = screen.getByTestId("test-input");
|
|
42
|
+
expect(input).toBeInTheDocument();
|
|
43
|
+
expect(input.className).toBe(`${rootClassName}__input`);
|
|
44
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
45
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
46
|
+
expect(screen.getByTestId("test-helper-text").querySelector("svg")).not.toBeInTheDocument();
|
|
47
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
48
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should render with helper-text and error-text", () => {
|
|
52
|
+
render(
|
|
53
|
+
<TextField
|
|
54
|
+
errorText="Test error"
|
|
55
|
+
id="test"
|
|
56
|
+
data-testid="test"
|
|
57
|
+
label="Test label"
|
|
58
|
+
helperText="Helper text"
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const input = screen.getByTestId("test-input");
|
|
63
|
+
expect(input).toBeInTheDocument();
|
|
64
|
+
expect(input).toHaveClass(`${rootClassName}__input--error`);
|
|
65
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
66
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
67
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
68
|
+
expect(screen.getByTestId("test-error-text")).toHaveTextContent("Test error");
|
|
69
|
+
expect(screen.getByTestId("test-error-text").querySelector("svg")).toBeInTheDocument();
|
|
70
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
71
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should render valid", () => {
|
|
75
|
+
render(
|
|
76
|
+
<TextField valid id="test" data-testid="test" label="Test label" helperText="Helper text" />
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const input = screen.getByTestId("test-input");
|
|
80
|
+
expect(input).toBeInTheDocument();
|
|
81
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
82
|
+
expect(input).toHaveClass(`${rootClassName}__input--valid`);
|
|
83
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
84
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
85
|
+
expect(screen.getByTestId("test-helper-text").querySelector("svg")).not.toBeInTheDocument();
|
|
86
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
87
|
+
expect(screen.getByTestId("test-end-adornments")).toBeInTheDocument();
|
|
88
|
+
expect(screen.getByTestId("test-valid-icon")).toBeInTheDocument();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should render loading", () => {
|
|
92
|
+
render(
|
|
93
|
+
<TextField loading id="test" data-testid="test" label="Test label" helperText="Helper text" />
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const input = screen.getByTestId("test-input");
|
|
97
|
+
expect(input).toBeInTheDocument();
|
|
98
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
99
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
100
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
101
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
102
|
+
expect(screen.getByTestId("test-helper-text").querySelector("svg")).not.toBeInTheDocument();
|
|
103
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
104
|
+
expect(screen.getByTestId("test-end-adornments")).toBeInTheDocument();
|
|
105
|
+
expect(screen.getByTestId("test-spinner")).toBeInTheDocument();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should render with adornment", () => {
|
|
109
|
+
render(
|
|
110
|
+
<TextField
|
|
111
|
+
startAdornment={<span data-testid="start-adornment" />}
|
|
112
|
+
endAdornment={<span data-testid="end-adornment" />}
|
|
113
|
+
id="test"
|
|
114
|
+
data-testid="test"
|
|
115
|
+
label="Test label"
|
|
116
|
+
helperText="Helper text"
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const input = screen.getByTestId("test-input");
|
|
121
|
+
expect(input).toBeInTheDocument();
|
|
122
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
123
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
124
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
125
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
126
|
+
expect(screen.getByTestId("test-helper-text").querySelector("svg")).not.toBeInTheDocument();
|
|
127
|
+
|
|
128
|
+
const startAdornment = screen.getByTestId("test-start-adornments");
|
|
129
|
+
expect(startAdornment).toBeInTheDocument();
|
|
130
|
+
expect(within(startAdornment).getByTestId("start-adornment")).toBeInTheDocument();
|
|
131
|
+
|
|
132
|
+
const endAdornment = screen.getByTestId("test-end-adornments");
|
|
133
|
+
expect(endAdornment).toBeInTheDocument();
|
|
134
|
+
expect(within(endAdornment).getByTestId("end-adornment")).toBeInTheDocument();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should render required", () => {
|
|
138
|
+
render(
|
|
139
|
+
<TextField
|
|
140
|
+
required
|
|
141
|
+
id="test"
|
|
142
|
+
data-testid="test"
|
|
143
|
+
label="Test label"
|
|
144
|
+
helperText="Helper text"
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const input = screen.getByTestId("test-input");
|
|
149
|
+
expect(input).toBeRequired();
|
|
150
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
151
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
152
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("* Test label");
|
|
153
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
154
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
155
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should render disabled", () => {
|
|
159
|
+
render(
|
|
160
|
+
<TextField
|
|
161
|
+
disabled
|
|
162
|
+
id="test"
|
|
163
|
+
data-testid="test"
|
|
164
|
+
label="Test label"
|
|
165
|
+
helperText="Helper text"
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const input = screen.getByTestId("test-input");
|
|
170
|
+
expect(input).toBeDisabled();
|
|
171
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
172
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
173
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
174
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
175
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
176
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should render readOnly", () => {
|
|
180
|
+
render(
|
|
181
|
+
<TextField
|
|
182
|
+
readOnly
|
|
183
|
+
id="test"
|
|
184
|
+
data-testid="test"
|
|
185
|
+
label="Test label"
|
|
186
|
+
helperText="Helper text"
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const input = screen.getByTestId("test-input");
|
|
191
|
+
expect(input).toHaveAttribute("readOnly");
|
|
192
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--error`);
|
|
193
|
+
expect(input).not.toHaveClass(`${rootClassName}__input--valid`);
|
|
194
|
+
expect(screen.getByTestId("test-label")).toHaveTextContent("Test label");
|
|
195
|
+
expect(screen.getByTestId("test-helper-text")).toHaveTextContent("Helper text");
|
|
196
|
+
expect(screen.queryByTestId("test-start-adornments")).not.toBeInTheDocument();
|
|
197
|
+
expect(screen.queryByTestId("test-end-adornments")).not.toBeInTheDocument();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should render with default value and onChange", () => {
|
|
201
|
+
const onChangeMock = vi.fn();
|
|
202
|
+
render(
|
|
203
|
+
<TextField
|
|
204
|
+
id="test"
|
|
205
|
+
data-testid="test"
|
|
206
|
+
onChange={onChangeMock}
|
|
207
|
+
defaultValue="Default value"
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
const input = screen.getByTestId("test-input");
|
|
211
|
+
expect(input).toHaveValue("Default value");
|
|
212
|
+
|
|
213
|
+
fireEvent.change(input, { target: { value: "Changed" } });
|
|
214
|
+
|
|
215
|
+
expect(input).toHaveValue("Changed");
|
|
216
|
+
expect(onChangeMock).toHaveBeenCalled();
|
|
217
|
+
});
|
|
218
|
+
});
|