@kroo-web/design-system 1.0.0 → 1.0.2
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/hooks/useWindowSize.d.ts +4 -0
- package/dist/hooks/useWindowSize.js +24 -0
- package/dist/main.d.ts +1 -0
- package/{src/index.ts → dist/main.js} +0 -1
- package/dist/product/components/TextField/index.d.ts +24 -0
- package/dist/product/components/TextField/index.js +57 -0
- package/dist/product/components/TextField/textField.stories.d.ts +10 -0
- package/dist/product/components/TextField/textField.stories.js +56 -0
- package/dist/product/components/TextField/textField.test.d.ts +1 -0
- package/dist/product/components/TextField/textField.test.js +85 -0
- package/{src/product/index.ts → dist/product/index.d.ts} +0 -1
- package/dist/product/index.js +2 -0
- package/package.json +13 -5
- package/.storybook/main.js +0 -19
- package/.storybook/preview-head.html +0 -8
- package/.storybook/preview.js +0 -21
- package/src/hooks/useWindowSize.ts +0 -29
- package/src/product/components/TextField/index.tsx +0 -126
- package/src/product/components/TextField/textField.stories.mdx +0 -113
- package/src/product/components/TextField/textField.stories.tsx +0 -263
- package/src/product/components/TextField/textField.test.tsx +0 -111
- package/tsconfig.json +0 -26
- /package/{src → dist}/marketing/styles/tokens/variables.css +0 -0
- /package/{src → dist}/product/components/TextField/textField.module.css +0 -0
- /package/{src → dist}/product/styles/tokens/variables.css +0 -0
- /package/{src → dist}/styles/global.css +0 -0
- /package/{src → dist}/styles/tokens/variables.css +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export function useWindowSize() {
|
|
3
|
+
var _a = useState({
|
|
4
|
+
width: 600,
|
|
5
|
+
height: undefined,
|
|
6
|
+
}), windowSize = _a[0], setWindowSize = _a[1];
|
|
7
|
+
useEffect(function () {
|
|
8
|
+
// Handler to call on window resize
|
|
9
|
+
function handleResize() {
|
|
10
|
+
// Set window width/height to state
|
|
11
|
+
setWindowSize({
|
|
12
|
+
width: window.innerWidth || 600,
|
|
13
|
+
height: window.innerHeight,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
// Add event listener
|
|
17
|
+
window.addEventListener('resize', handleResize, { passive: true });
|
|
18
|
+
// Call handler right away so state gets updated with initial window size
|
|
19
|
+
handleResize();
|
|
20
|
+
// Remove event listener on cleanup
|
|
21
|
+
return function () { return window.removeEventListener('resize', handleResize); };
|
|
22
|
+
}, []); // Empty array ensures that effect is only run on mount
|
|
23
|
+
return windowSize;
|
|
24
|
+
}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./product";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { DetailedHTMLProps, InputHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { FieldValues, Path, UseFormRegister } from 'react-hook-form';
|
|
3
|
+
export type TTextFieldProps<T extends FieldValues> = {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
name: Path<T>;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
helper?: {
|
|
9
|
+
message: ReactNode | string;
|
|
10
|
+
};
|
|
11
|
+
error?: {
|
|
12
|
+
message: ReactNode | string;
|
|
13
|
+
};
|
|
14
|
+
/** React Hook form requirement if you dont pass it in the component will act like a normal uncontrolled input */
|
|
15
|
+
register?: UseFormRegister<T>;
|
|
16
|
+
type?: DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['type'];
|
|
17
|
+
prefix?: string | ReactNode;
|
|
18
|
+
suffix?: string | ReactNode;
|
|
19
|
+
value?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
rightContent?: ReactNode | string;
|
|
22
|
+
leftContent?: ReactNode | string;
|
|
23
|
+
};
|
|
24
|
+
export declare const TextField: <T extends FieldValues>({ id, label, helper, error, register, name, type, prefix, suffix, disabled, value, className, rightContent, leftContent, }: TTextFieldProps<T>) => React.JSX.Element;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import React, { useState, } from 'react';
|
|
13
|
+
import { motion } from 'framer-motion';
|
|
14
|
+
import clsx from 'clsx';
|
|
15
|
+
import { useWindowSize } from '../../../hooks/useWindowSize';
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
import styles from "./textField.module.css";
|
|
18
|
+
export var TextField = function (_a) {
|
|
19
|
+
var id = _a.id, label = _a.label, helper = _a.helper, error = _a.error, register = _a.register, name = _a.name, type = _a.type, prefix = _a.prefix, suffix = _a.suffix, disabled = _a.disabled, value = _a.value, className = _a.className, rightContent = _a.rightContent, leftContent = _a.leftContent;
|
|
20
|
+
var width = useWindowSize().width;
|
|
21
|
+
var _b = useState(value || false), hasValue = _b[0], setHasValue = _b[1];
|
|
22
|
+
var isDesktop = width > 768;
|
|
23
|
+
var variants = {
|
|
24
|
+
focused: {
|
|
25
|
+
fontSize: isDesktop ? '1rem' : '0.875rem',
|
|
26
|
+
top: '1rem',
|
|
27
|
+
},
|
|
28
|
+
notFocused: {
|
|
29
|
+
transform: 'translateY(-50%)',
|
|
30
|
+
fontSize: isDesktop ? '1.25rem' : '1.125rem',
|
|
31
|
+
top: '50%',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
return (React.createElement("div", { className: styles.outer },
|
|
35
|
+
React.createElement("div", { className: clsx(styles.container, error && styles['container--error']) },
|
|
36
|
+
React.createElement(motion.label, { className: styles.label, initial: "notFocused", variants: variants, htmlFor: "input-".concat(id), animate: hasValue ? 'focused' : 'notFocused' },
|
|
37
|
+
prefix && React.createElement("span", null, prefix),
|
|
38
|
+
" ",
|
|
39
|
+
label,
|
|
40
|
+
' ',
|
|
41
|
+
suffix && React.createElement("span", null, suffix)),
|
|
42
|
+
React.createElement("input", __assign({ className: clsx(styles["input--".concat(className)], styles.input), id: "input-".concat(id), type: type, "aria-describedby": "error-".concat(id), disabled: disabled }, (register && register(name),
|
|
43
|
+
{
|
|
44
|
+
onFocus: function () {
|
|
45
|
+
setHasValue(true);
|
|
46
|
+
},
|
|
47
|
+
onBlur: function (e) {
|
|
48
|
+
setHasValue(!!e.target.value);
|
|
49
|
+
},
|
|
50
|
+
}), { value: value })),
|
|
51
|
+
React.createElement("div", null,
|
|
52
|
+
rightContent && (React.createElement("div", { className: styles.rightContent }, rightContent)),
|
|
53
|
+
leftContent && (React.createElement("div", { className: styles.leftContent }, leftContent)))),
|
|
54
|
+
React.createElement("div", { className: styles.inputDescription },
|
|
55
|
+
helper && (React.createElement("span", { id: "feedback-".concat(id), className: styles.helper }, helper.message)),
|
|
56
|
+
error && (React.createElement("span", { id: "error-".concat(id), className: styles.error }, error.message)))));
|
|
57
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
import { TextField } from '.';
|
|
3
|
+
declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react").ReactRenderer, import(".").TTextFieldProps<import("react-hook-form").FieldValues>>;
|
|
4
|
+
export default _default;
|
|
5
|
+
type Story = StoryObj<typeof TextField>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Error: Story;
|
|
8
|
+
export declare const HelperText: Story;
|
|
9
|
+
export declare const RightContent: Story;
|
|
10
|
+
export declare const LeftContent: Story;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { TextField } from '.';
|
|
2
|
+
export default {
|
|
3
|
+
title: 'Design System Product/C1 - TextField',
|
|
4
|
+
component: TextField,
|
|
5
|
+
parameters: {},
|
|
6
|
+
};
|
|
7
|
+
export var Default = {
|
|
8
|
+
render: function () { return (React.createElement(React.Fragment, null,
|
|
9
|
+
React.createElement(TextField, { id: "default-no-value", label: "Default", name: "example" }),
|
|
10
|
+
React.createElement(TextField, { className: "hover", id: "default2-no-value", label: "Hovered", name: "example2" }),
|
|
11
|
+
React.createElement(TextField, { className: "focus", id: "default3-no-value", label: "Focused", name: "example3" }),
|
|
12
|
+
React.createElement(TextField, { id: "default-value", label: "Default", name: "example", value: "Example text" }),
|
|
13
|
+
React.createElement(TextField, { className: "hover", id: "default2-value", label: "Hovered", name: "example2", value: "Example text" }),
|
|
14
|
+
React.createElement(TextField, { className: "focus", id: "default3-value", label: "Focused", name: "example3", value: "Example text" }),
|
|
15
|
+
React.createElement(TextField, { id: "default4-value", label: "Disabled ", name: "example4", disabled: true }))); },
|
|
16
|
+
};
|
|
17
|
+
export var Error = {
|
|
18
|
+
render: function () { return (React.createElement(React.Fragment, null,
|
|
19
|
+
React.createElement(TextField, { id: "error", label: "Default", name: "error1", error: { message: 'This is an error' } }),
|
|
20
|
+
React.createElement(TextField, { className: "hover", id: "error2", label: "Hovered", name: "error2", error: { message: 'This is an error' } }),
|
|
21
|
+
React.createElement(TextField, { className: "focus", id: "error3", label: "Focused", name: "error3", error: { message: 'This is an error' } }),
|
|
22
|
+
React.createElement(TextField, { id: "error4-value", label: "Default", name: "error4-value", value: "Example text", error: { message: 'This is an error' } }),
|
|
23
|
+
React.createElement(TextField, { className: "hover", id: "error5-value", label: "Hovered", name: "error5-value", value: "Example text", error: { message: 'This is an error' } }),
|
|
24
|
+
React.createElement(TextField, { className: "focus", id: "error5-value", label: "Focused", name: "error5-value", value: "Example text", error: { message: 'This is an error' } }),
|
|
25
|
+
React.createElement(TextField, { id: "error4", label: "Disabled", name: "error4", error: { message: 'This is an error' }, disabled: true }))); },
|
|
26
|
+
};
|
|
27
|
+
export var HelperText = {
|
|
28
|
+
render: function () { return (React.createElement(React.Fragment, null,
|
|
29
|
+
React.createElement(TextField, { id: "helper", label: "Default", name: "helper1", helper: { message: 'This is helper text' } }),
|
|
30
|
+
React.createElement(TextField, { className: "hover", id: "helper2", label: "Hovered", name: "helper2", helper: { message: 'This is helper text' } }),
|
|
31
|
+
React.createElement(TextField, { className: "focus", id: "helper3", label: "Focused", name: "helper3", helper: { message: 'This is helper text' } }),
|
|
32
|
+
React.createElement(TextField, { id: "helper4-text", label: "Default", name: "helper4-text", helper: { message: 'This is helper text' }, value: "Example text" }),
|
|
33
|
+
React.createElement(TextField, { className: "hover", id: "helper5-text", label: "Hovered", name: "helper5-text", helper: { message: 'This is helper text' }, value: "Example text" }),
|
|
34
|
+
React.createElement(TextField, { className: "focus", id: "helper6-text", label: "Focused", name: "helper6-text", helper: { message: 'This is helper text' }, value: "Example text" }),
|
|
35
|
+
React.createElement(TextField, { id: "helper4", label: "Disabled", name: "helper4", helper: { message: 'This is helper text' }, disabled: true }))); },
|
|
36
|
+
};
|
|
37
|
+
export var RightContent = {
|
|
38
|
+
render: function () { return (React.createElement(React.Fragment, null,
|
|
39
|
+
React.createElement(TextField, { id: "right", label: "Default", name: "right1", rightContent: React.createElement("button", null, "Example") }),
|
|
40
|
+
React.createElement(TextField, { className: "hover", id: "right2", label: "Hovered", name: "right2", rightContent: React.createElement("button", null, "Example") }),
|
|
41
|
+
React.createElement(TextField, { className: "focus", id: "right3", label: "Focused", name: "right3", rightContent: React.createElement("button", null, "Example") }),
|
|
42
|
+
React.createElement(TextField, { id: "right4-text", label: "Default", name: "right4-text", value: "Example text", rightContent: React.createElement("button", null, "Example") }),
|
|
43
|
+
React.createElement(TextField, { className: "hover", id: "right5-text", label: "Hovered", name: "right5-text", value: "Example text", rightContent: React.createElement("button", null, "Example") }),
|
|
44
|
+
React.createElement(TextField, { className: "focus", id: "right6-text", label: "Focused", name: "right6-text", value: "Example text", rightContent: React.createElement("button", null, "Example") }),
|
|
45
|
+
React.createElement(TextField, { id: "right4", label: "Disabled", name: "right4", rightContent: React.createElement("button", null, "Example"), disabled: true }))); },
|
|
46
|
+
};
|
|
47
|
+
export var LeftContent = {
|
|
48
|
+
render: function () { return (React.createElement(React.Fragment, null,
|
|
49
|
+
React.createElement("h1", null, "No Designs"),
|
|
50
|
+
React.createElement("br", null),
|
|
51
|
+
React.createElement("br", null),
|
|
52
|
+
React.createElement(TextField, { id: "left", label: "Default", name: "left1", leftContent: "Example" }),
|
|
53
|
+
React.createElement(TextField, { className: "hover", id: "left2", label: "Hovered", name: "left2", leftContent: "Example" }),
|
|
54
|
+
React.createElement(TextField, { className: "focus", id: "left3", label: "Focused", name: "left3", leftContent: "Example" }),
|
|
55
|
+
React.createElement(TextField, { id: "left4", label: "Disabled", name: "left4", leftContent: "Example", disabled: true }))); },
|
|
56
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { render } from '@testing-library/react';
|
|
38
|
+
import { describe, it, expect } from 'vitest';
|
|
39
|
+
import userEvent from '@testing-library/user-event';
|
|
40
|
+
import { TextField } from '.';
|
|
41
|
+
describe('<TextField />', function () {
|
|
42
|
+
it('should render', function () {
|
|
43
|
+
var component = render(React.createElement(TextField, { id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
44
|
+
expect(component).toBeTruthy();
|
|
45
|
+
});
|
|
46
|
+
it('should show the helper text when supplied to the component', function () {
|
|
47
|
+
var component = render(React.createElement(TextField, { helper: { message: 'Helper text' }, id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
48
|
+
expect(component.getByText('Helper text')).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
it('should show the error text when supplied to the component', function () {
|
|
51
|
+
var component = render(React.createElement(TextField, { error: { message: 'Error text' }, id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
52
|
+
expect(component.getByText('Error text')).toBeTruthy();
|
|
53
|
+
});
|
|
54
|
+
it('should show the prefix when supplied to the component', function () {
|
|
55
|
+
var component = render(React.createElement(TextField, { id: "example-TextField", label: "example-TextField", name: "example", prefix: "Prefix" }));
|
|
56
|
+
expect(component.getByText('Prefix')).toBeTruthy();
|
|
57
|
+
});
|
|
58
|
+
it('should show the suffix when supplied to the component', function () {
|
|
59
|
+
var component = render(React.createElement(TextField, { id: "example-TextField", label: "example-TextField", name: "example", suffix: "Suffix" }));
|
|
60
|
+
expect(component.getByText('Suffix')).toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
it('should show the label when supplied to the component', function () {
|
|
63
|
+
var component = render(React.createElement(TextField, { id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
64
|
+
expect(component.getByText('example-TextField')).toBeTruthy();
|
|
65
|
+
});
|
|
66
|
+
it('Should show an error message if one is present', function () {
|
|
67
|
+
var component = render(React.createElement(TextField, { error: { message: 'Error text' }, id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
68
|
+
expect(component.getByText('Error text')).toBeTruthy();
|
|
69
|
+
});
|
|
70
|
+
it('should be able to input text into the input field', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
71
|
+
var component, input;
|
|
72
|
+
return __generator(this, function (_a) {
|
|
73
|
+
switch (_a.label) {
|
|
74
|
+
case 0:
|
|
75
|
+
component = render(React.createElement(TextField, { id: "example-TextField", label: "example-TextField", name: "example" }));
|
|
76
|
+
input = component.getByLabelText('example-TextField');
|
|
77
|
+
return [4 /*yield*/, userEvent.type(input, 'Hello, World!')];
|
|
78
|
+
case 1:
|
|
79
|
+
_a.sent();
|
|
80
|
+
expect(input).toHaveValue('Hello, World!');
|
|
81
|
+
return [2 /*return*/];
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}); });
|
|
85
|
+
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kroo-web/design-system",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Web design system for Kroo including the components for the marketing site and the product side.",
|
|
5
|
+
"main": "./dist/main.js",
|
|
6
|
+
"types": "./dist/main.d.ts",
|
|
7
|
+
"module": "./dist/main.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
6
11
|
"scripts": {
|
|
7
12
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
13
|
"storybook": "storybook dev -p 6006",
|
|
9
14
|
"build-storybook": "storybook build",
|
|
10
|
-
"
|
|
15
|
+
"copy-files": "copyfiles -u 1 \"src/**/*.css\" \"src/**/*.svg\" \"src/**/*.json\" dist/",
|
|
16
|
+
"deploy": "npm run copy-files && npm publish --access public"
|
|
11
17
|
},
|
|
12
18
|
"keywords": [],
|
|
13
19
|
"author": "",
|
|
@@ -21,6 +27,7 @@
|
|
|
21
27
|
"@storybook/react": "^7.6.17",
|
|
22
28
|
"@storybook/react-vite": "^7.6.17",
|
|
23
29
|
"@storybook/test": "^7.6.17",
|
|
30
|
+
"copyfiles": "^2.4.1",
|
|
24
31
|
"prop-types": "^15.8.1",
|
|
25
32
|
"react": "^18.2.0",
|
|
26
33
|
"react-dom": "^18.2.0",
|
|
@@ -30,6 +37,7 @@
|
|
|
30
37
|
"@storybook/addon-docs": "^7.6.17",
|
|
31
38
|
"clsx": "^2.1.0",
|
|
32
39
|
"framer-motion": "^11.0.8",
|
|
33
|
-
"react-hook-form": "^7.51.0"
|
|
40
|
+
"react-hook-form": "^7.51.0",
|
|
41
|
+
"typescript": "^5.4.2"
|
|
34
42
|
}
|
|
35
43
|
}
|
package/.storybook/main.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
|
2
|
-
const config = {
|
|
3
|
-
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
|
4
|
-
addons: [
|
|
5
|
-
"@storybook/addon-links",
|
|
6
|
-
"@storybook/addon-essentials",
|
|
7
|
-
"@storybook/addon-onboarding",
|
|
8
|
-
"@storybook/addon-interactions",
|
|
9
|
-
"@storybook/addon-docs"
|
|
10
|
-
],
|
|
11
|
-
framework: {
|
|
12
|
-
name: "@storybook/react-vite",
|
|
13
|
-
options: {},
|
|
14
|
-
},
|
|
15
|
-
docs: {
|
|
16
|
-
autodocs: "tag",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
export default config;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
2
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
3
|
-
<link
|
|
4
|
-
href="https://fonts.googleapis.com/css2?family=Brygada+1918:ital,wght@0,400;0,500;0,700;1,500&family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
|
|
5
|
-
rel="stylesheet"
|
|
6
|
-
crossorigin="anonymous"
|
|
7
|
-
/>
|
|
8
|
-
|
package/.storybook/preview.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** @type { import('@storybook/react').Preview } */
|
|
2
|
-
import "../src/styles/global.css";
|
|
3
|
-
const preview = {
|
|
4
|
-
parameters: {
|
|
5
|
-
docs: {
|
|
6
|
-
toc: {
|
|
7
|
-
headingSelector: "h2, h3, h4, h5, h6",
|
|
8
|
-
title: "Contents"
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
actions: { argTypesRegex: "^on[A-Z].*" },
|
|
12
|
-
controls: {
|
|
13
|
-
matchers: {
|
|
14
|
-
color: /(background|color)$/i,
|
|
15
|
-
date: /Date$/i,
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default preview;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
export function useWindowSize() {
|
|
4
|
-
const [windowSize, setWindowSize] = useState<{
|
|
5
|
-
width: number;
|
|
6
|
-
height?: number;
|
|
7
|
-
}>({
|
|
8
|
-
width: 600,
|
|
9
|
-
height: undefined,
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
// Handler to call on window resize
|
|
14
|
-
function handleResize() {
|
|
15
|
-
// Set window width/height to state
|
|
16
|
-
setWindowSize({
|
|
17
|
-
width: window.innerWidth || 600,
|
|
18
|
-
height: window.innerHeight,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
// Add event listener
|
|
22
|
-
window.addEventListener('resize', handleResize, { passive: true });
|
|
23
|
-
// Call handler right away so state gets updated with initial window size
|
|
24
|
-
handleResize();
|
|
25
|
-
// Remove event listener on cleanup
|
|
26
|
-
return () => window.removeEventListener('resize', handleResize);
|
|
27
|
-
}, []); // Empty array ensures that effect is only run on mount
|
|
28
|
-
return windowSize;
|
|
29
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
DetailedHTMLProps,
|
|
3
|
-
InputHTMLAttributes,
|
|
4
|
-
ReactNode,
|
|
5
|
-
useState,
|
|
6
|
-
} from 'react';
|
|
7
|
-
import { motion } from 'framer-motion';
|
|
8
|
-
import clsx from 'clsx';
|
|
9
|
-
import { FieldValues, Path, UseFormRegister } from 'react-hook-form';
|
|
10
|
-
import { useWindowSize } from '../../../hooks/useWindowSize';
|
|
11
|
-
import styles from "./textField.module.css"
|
|
12
|
-
|
|
13
|
-
export type TTextFieldProps<T extends FieldValues> = {
|
|
14
|
-
id: string;
|
|
15
|
-
label: string;
|
|
16
|
-
name: Path<T>;
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
helper?: {
|
|
19
|
-
message: ReactNode | string;
|
|
20
|
-
};
|
|
21
|
-
error?: {
|
|
22
|
-
message: ReactNode | string;
|
|
23
|
-
};
|
|
24
|
-
/** React Hook form requirement if you dont pass it in the component will act like a normal uncontrolled input */
|
|
25
|
-
register?: UseFormRegister<T>;
|
|
26
|
-
type?: DetailedHTMLProps<
|
|
27
|
-
InputHTMLAttributes<HTMLInputElement>,
|
|
28
|
-
HTMLInputElement
|
|
29
|
-
>['type'];
|
|
30
|
-
prefix?: string | ReactNode;
|
|
31
|
-
suffix?: string | ReactNode;
|
|
32
|
-
value?: string;
|
|
33
|
-
className?: string;
|
|
34
|
-
rightContent?: ReactNode | string;
|
|
35
|
-
leftContent?: ReactNode | string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const TextField = <T extends FieldValues>({
|
|
39
|
-
id,
|
|
40
|
-
label,
|
|
41
|
-
helper,
|
|
42
|
-
error,
|
|
43
|
-
register,
|
|
44
|
-
name,
|
|
45
|
-
type,
|
|
46
|
-
prefix,
|
|
47
|
-
suffix,
|
|
48
|
-
disabled,
|
|
49
|
-
value,
|
|
50
|
-
className,
|
|
51
|
-
rightContent,
|
|
52
|
-
leftContent,
|
|
53
|
-
}: TTextFieldProps<T>) => {
|
|
54
|
-
const { width } = useWindowSize();
|
|
55
|
-
const [hasValue, setHasValue] = useState(value || false);
|
|
56
|
-
const isDesktop = width > 768;
|
|
57
|
-
|
|
58
|
-
const variants = {
|
|
59
|
-
focused: {
|
|
60
|
-
fontSize: isDesktop ? '1rem' : '0.875rem',
|
|
61
|
-
top: '1rem',
|
|
62
|
-
},
|
|
63
|
-
notFocused: {
|
|
64
|
-
transform: 'translateY(-50%)',
|
|
65
|
-
fontSize: isDesktop ? '1.25rem' : '1.125rem',
|
|
66
|
-
top: '50%',
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div className={styles.outer}>
|
|
72
|
-
<div
|
|
73
|
-
className={clsx(styles.container, error && styles['container--error'])}
|
|
74
|
-
>
|
|
75
|
-
<motion.label
|
|
76
|
-
className={styles.label}
|
|
77
|
-
initial="notFocused"
|
|
78
|
-
variants={variants}
|
|
79
|
-
htmlFor={`input-${id}`}
|
|
80
|
-
animate={hasValue ? 'focused' : 'notFocused'}
|
|
81
|
-
>
|
|
82
|
-
{prefix && <span>{prefix}</span>} {label}{' '}
|
|
83
|
-
{suffix && <span>{suffix}</span>}
|
|
84
|
-
</motion.label>
|
|
85
|
-
<input
|
|
86
|
-
className={clsx(styles[`input--${className}`], styles.input)}
|
|
87
|
-
id={`input-${id}`}
|
|
88
|
-
type={type}
|
|
89
|
-
aria-describedby={`error-${id}`}
|
|
90
|
-
disabled={disabled}
|
|
91
|
-
{...(register && register(name),
|
|
92
|
-
{
|
|
93
|
-
onFocus: () => {
|
|
94
|
-
setHasValue(true);
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
onBlur: (e) => {
|
|
98
|
-
setHasValue(!!e.target.value);
|
|
99
|
-
},
|
|
100
|
-
})}
|
|
101
|
-
value={value}
|
|
102
|
-
/>
|
|
103
|
-
<div>
|
|
104
|
-
{rightContent && (
|
|
105
|
-
<div className={styles.rightContent}>{rightContent}</div>
|
|
106
|
-
)}
|
|
107
|
-
{leftContent && (
|
|
108
|
-
<div className={styles.leftContent}>{leftContent}</div>
|
|
109
|
-
)}
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
<div className={styles.inputDescription}>
|
|
113
|
-
{helper && (
|
|
114
|
-
<span id={`feedback-${id}`} className={styles.helper}>
|
|
115
|
-
{helper.message}
|
|
116
|
-
</span>
|
|
117
|
-
)}
|
|
118
|
-
{error && (
|
|
119
|
-
<span id={`error-${id}`} className={styles.error}>
|
|
120
|
-
{error.message}
|
|
121
|
-
</span>
|
|
122
|
-
)}
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
);
|
|
126
|
-
};
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas } from "@storybook/addon-docs";
|
|
2
|
-
import { TextField } from '.'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<Meta title="Design System Product/C1 - TextField / Documentation" />
|
|
6
|
-
|
|
7
|
-
# TextField
|
|
8
|
-
|
|
9
|
-
TextFields are text inputs that allow users to input custom text entries with a keyboard. Various decorations can be displayed around the field to communicate the entry requirements.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Example
|
|
13
|
-
|
|
14
|
-
<Canvas>
|
|
15
|
-
<TextField
|
|
16
|
-
label="Label"
|
|
17
|
-
/>
|
|
18
|
-
</Canvas>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
### Usage
|
|
22
|
-
|
|
23
|
-
In the Nextjs repo and this component is expected to be used with react-hook-form and accepts the
|
|
24
|
-
register prop from useForm to hook it upto the form.
|
|
25
|
-
|
|
26
|
-
However, it can be used as a standalone component as well without registering in a HTML form if needed.
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import { useForm } from 'react-hook-form'
|
|
30
|
-
import { TextField } from 'design-system-product'
|
|
31
|
-
|
|
32
|
-
const { register, handleSubmit } = useForm()
|
|
33
|
-
|
|
34
|
-
const onSubmit = (data) => {
|
|
35
|
-
console.log(data)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<form onSubmit={handleSubmit(onSubmit)}>
|
|
40
|
-
<TextField
|
|
41
|
-
label="Label"
|
|
42
|
-
{...register('example')}
|
|
43
|
-
/>
|
|
44
|
-
</form>
|
|
45
|
-
)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Labelling
|
|
49
|
-
|
|
50
|
-
The label prop is required and is used to display the label for the input field. A label is required for accessiblity and should
|
|
51
|
-
always be provided.
|
|
52
|
-
|
|
53
|
-
<Canvas>
|
|
54
|
-
<TextField
|
|
55
|
-
label="Label" />
|
|
56
|
-
</Canvas>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
### Required Fields
|
|
62
|
-
|
|
63
|
-
Currently we do not support the required prop with the TextField component due to currently our forms assumes that everything
|
|
64
|
-
is required and we have no reason to ask for everything to be required. Instead please use the suffix prop to add an (optional) tag
|
|
65
|
-
to the label.
|
|
66
|
-
|
|
67
|
-
<Canvas>
|
|
68
|
-
<TextField
|
|
69
|
-
label="Label"
|
|
70
|
-
suffix="(optional)" />
|
|
71
|
-
</Canvas>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
## Visual Options
|
|
75
|
-
|
|
76
|
-
### Validation
|
|
77
|
-
Validation will be handled by react-hook-form or by passing an error with a message to the error prop.
|
|
78
|
-
The error prop will display an error message below the input field and change the border of the input field to red.
|
|
79
|
-
|
|
80
|
-
<Canvas>
|
|
81
|
-
<TextField
|
|
82
|
-
label="Label"
|
|
83
|
-
error="Error Message" />
|
|
84
|
-
</Canvas>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
### Read Only
|
|
90
|
-
The ReadOnly prop is used to make the input field read only. This is useful when you want to display and copy the value of the input field but not allow the user to edit it. Use this instead of the disabled state.
|
|
91
|
-
|
|
92
|
-
<Canvas>
|
|
93
|
-
<TextField
|
|
94
|
-
value="Read Only Value"
|
|
95
|
-
label="Label"
|
|
96
|
-
readOnly />
|
|
97
|
-
</Canvas>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
### Disabled
|
|
102
|
-
The disabled prop is used to disable the input field. This is useful when you want to prevent the user from editing the input field. Use this instead of the readOnly state.
|
|
103
|
-
|
|
104
|
-
<Canvas>
|
|
105
|
-
<TextField
|
|
106
|
-
value="Example Value"
|
|
107
|
-
label="Label"
|
|
108
|
-
disabled />
|
|
109
|
-
</Canvas>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
|
|
3
|
-
import { TextField } from '.';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
title: 'Design System Product/C1 - TextField',
|
|
7
|
-
component: TextField,
|
|
8
|
-
parameters: {},
|
|
9
|
-
} as Meta<typeof TextField>;
|
|
10
|
-
|
|
11
|
-
type Story = StoryObj<typeof TextField>;
|
|
12
|
-
|
|
13
|
-
export const Default: Story = {
|
|
14
|
-
render: () => (
|
|
15
|
-
<>
|
|
16
|
-
<TextField id="default-no-value" label="Default" name="example" />
|
|
17
|
-
<TextField
|
|
18
|
-
className="hover"
|
|
19
|
-
id="default2-no-value"
|
|
20
|
-
label="Hovered"
|
|
21
|
-
name="example2"
|
|
22
|
-
/>
|
|
23
|
-
<TextField
|
|
24
|
-
className="focus"
|
|
25
|
-
id="default3-no-value"
|
|
26
|
-
label="Focused"
|
|
27
|
-
name="example3"
|
|
28
|
-
/>
|
|
29
|
-
|
|
30
|
-
<TextField
|
|
31
|
-
id="default-value"
|
|
32
|
-
label="Default"
|
|
33
|
-
name="example"
|
|
34
|
-
value="Example text"
|
|
35
|
-
/>
|
|
36
|
-
<TextField
|
|
37
|
-
className="hover"
|
|
38
|
-
id="default2-value"
|
|
39
|
-
label="Hovered"
|
|
40
|
-
name="example2"
|
|
41
|
-
value="Example text"
|
|
42
|
-
/>
|
|
43
|
-
<TextField
|
|
44
|
-
className="focus"
|
|
45
|
-
id="default3-value"
|
|
46
|
-
label="Focused"
|
|
47
|
-
name="example3"
|
|
48
|
-
value="Example text"
|
|
49
|
-
/>
|
|
50
|
-
<TextField
|
|
51
|
-
id="default4-value"
|
|
52
|
-
label="Disabled "
|
|
53
|
-
name="example4"
|
|
54
|
-
disabled
|
|
55
|
-
/>
|
|
56
|
-
</>
|
|
57
|
-
),
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const Error: Story = {
|
|
61
|
-
render: () => (
|
|
62
|
-
<>
|
|
63
|
-
<TextField
|
|
64
|
-
id="error"
|
|
65
|
-
label="Default"
|
|
66
|
-
name="error1"
|
|
67
|
-
error={{ message: 'This is an error' }}
|
|
68
|
-
/>
|
|
69
|
-
<TextField
|
|
70
|
-
className="hover"
|
|
71
|
-
id="error2"
|
|
72
|
-
label="Hovered"
|
|
73
|
-
name="error2"
|
|
74
|
-
error={{ message: 'This is an error' }}
|
|
75
|
-
/>
|
|
76
|
-
<TextField
|
|
77
|
-
className="focus"
|
|
78
|
-
id="error3"
|
|
79
|
-
label="Focused"
|
|
80
|
-
name="error3"
|
|
81
|
-
error={{ message: 'This is an error' }}
|
|
82
|
-
/>
|
|
83
|
-
<TextField
|
|
84
|
-
id="error4-value"
|
|
85
|
-
label="Default"
|
|
86
|
-
name="error4-value"
|
|
87
|
-
value="Example text"
|
|
88
|
-
error={{ message: 'This is an error' }}
|
|
89
|
-
/>
|
|
90
|
-
<TextField
|
|
91
|
-
className="hover"
|
|
92
|
-
id="error5-value"
|
|
93
|
-
label="Hovered"
|
|
94
|
-
name="error5-value"
|
|
95
|
-
value="Example text"
|
|
96
|
-
error={{ message: 'This is an error' }}
|
|
97
|
-
/>
|
|
98
|
-
<TextField
|
|
99
|
-
className="focus"
|
|
100
|
-
id="error5-value"
|
|
101
|
-
label="Focused"
|
|
102
|
-
name="error5-value"
|
|
103
|
-
value="Example text"
|
|
104
|
-
error={{ message: 'This is an error' }}
|
|
105
|
-
/>
|
|
106
|
-
<TextField
|
|
107
|
-
id="error4"
|
|
108
|
-
label="Disabled"
|
|
109
|
-
name="error4"
|
|
110
|
-
error={{ message: 'This is an error' }}
|
|
111
|
-
disabled
|
|
112
|
-
/>
|
|
113
|
-
</>
|
|
114
|
-
),
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
export const HelperText: Story = {
|
|
118
|
-
render: () => (
|
|
119
|
-
<>
|
|
120
|
-
<TextField
|
|
121
|
-
id="helper"
|
|
122
|
-
label="Default"
|
|
123
|
-
name="helper1"
|
|
124
|
-
helper={{ message: 'This is helper text' }}
|
|
125
|
-
/>
|
|
126
|
-
<TextField
|
|
127
|
-
className="hover"
|
|
128
|
-
id="helper2"
|
|
129
|
-
label="Hovered"
|
|
130
|
-
name="helper2"
|
|
131
|
-
helper={{ message: 'This is helper text' }}
|
|
132
|
-
/>
|
|
133
|
-
<TextField
|
|
134
|
-
className="focus"
|
|
135
|
-
id="helper3"
|
|
136
|
-
label="Focused"
|
|
137
|
-
name="helper3"
|
|
138
|
-
helper={{ message: 'This is helper text' }}
|
|
139
|
-
/>
|
|
140
|
-
<TextField
|
|
141
|
-
id="helper4-text"
|
|
142
|
-
label="Default"
|
|
143
|
-
name="helper4-text"
|
|
144
|
-
helper={{ message: 'This is helper text' }}
|
|
145
|
-
value="Example text"
|
|
146
|
-
/>
|
|
147
|
-
<TextField
|
|
148
|
-
className="hover"
|
|
149
|
-
id="helper5-text"
|
|
150
|
-
label="Hovered"
|
|
151
|
-
name="helper5-text"
|
|
152
|
-
helper={{ message: 'This is helper text' }}
|
|
153
|
-
value="Example text"
|
|
154
|
-
/>
|
|
155
|
-
<TextField
|
|
156
|
-
className="focus"
|
|
157
|
-
id="helper6-text"
|
|
158
|
-
label="Focused"
|
|
159
|
-
name="helper6-text"
|
|
160
|
-
helper={{ message: 'This is helper text' }}
|
|
161
|
-
value="Example text"
|
|
162
|
-
/>
|
|
163
|
-
<TextField
|
|
164
|
-
id="helper4"
|
|
165
|
-
label="Disabled"
|
|
166
|
-
name="helper4"
|
|
167
|
-
helper={{ message: 'This is helper text' }}
|
|
168
|
-
disabled
|
|
169
|
-
/>
|
|
170
|
-
</>
|
|
171
|
-
),
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export const RightContent: Story = {
|
|
175
|
-
render: () => (
|
|
176
|
-
<>
|
|
177
|
-
<TextField
|
|
178
|
-
id="right"
|
|
179
|
-
label="Default"
|
|
180
|
-
name="right1"
|
|
181
|
-
rightContent={<button>Example</button>}
|
|
182
|
-
/>
|
|
183
|
-
<TextField
|
|
184
|
-
className="hover"
|
|
185
|
-
id="right2"
|
|
186
|
-
label="Hovered"
|
|
187
|
-
name="right2"
|
|
188
|
-
rightContent={<button>Example</button>}
|
|
189
|
-
/>
|
|
190
|
-
<TextField
|
|
191
|
-
className="focus"
|
|
192
|
-
id="right3"
|
|
193
|
-
label="Focused"
|
|
194
|
-
name="right3"
|
|
195
|
-
rightContent={<button>Example</button>}
|
|
196
|
-
/>
|
|
197
|
-
<TextField
|
|
198
|
-
id="right4-text"
|
|
199
|
-
label="Default"
|
|
200
|
-
name="right4-text"
|
|
201
|
-
value="Example text"
|
|
202
|
-
rightContent={<button>Example</button>}
|
|
203
|
-
/>
|
|
204
|
-
<TextField
|
|
205
|
-
className="hover"
|
|
206
|
-
id="right5-text"
|
|
207
|
-
label="Hovered"
|
|
208
|
-
name="right5-text"
|
|
209
|
-
value="Example text"
|
|
210
|
-
rightContent={<button>Example</button>}
|
|
211
|
-
/>
|
|
212
|
-
<TextField
|
|
213
|
-
className="focus"
|
|
214
|
-
id="right6-text"
|
|
215
|
-
label="Focused"
|
|
216
|
-
name="right6-text"
|
|
217
|
-
value="Example text"
|
|
218
|
-
rightContent={<button>Example</button>}
|
|
219
|
-
/>
|
|
220
|
-
|
|
221
|
-
<TextField
|
|
222
|
-
id="right4"
|
|
223
|
-
label="Disabled"
|
|
224
|
-
name="right4"
|
|
225
|
-
rightContent={<button>Example</button>}
|
|
226
|
-
disabled
|
|
227
|
-
/>
|
|
228
|
-
</>
|
|
229
|
-
),
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
export const LeftContent: Story = {
|
|
233
|
-
render: () => (
|
|
234
|
-
<>
|
|
235
|
-
<h1>No Designs</h1>
|
|
236
|
-
<br />
|
|
237
|
-
<br />
|
|
238
|
-
|
|
239
|
-
<TextField id="left" label="Default" name="left1" leftContent="Example" />
|
|
240
|
-
<TextField
|
|
241
|
-
className="hover"
|
|
242
|
-
id="left2"
|
|
243
|
-
label="Hovered"
|
|
244
|
-
name="left2"
|
|
245
|
-
leftContent="Example"
|
|
246
|
-
/>
|
|
247
|
-
<TextField
|
|
248
|
-
className="focus"
|
|
249
|
-
id="left3"
|
|
250
|
-
label="Focused"
|
|
251
|
-
name="left3"
|
|
252
|
-
leftContent="Example"
|
|
253
|
-
/>
|
|
254
|
-
<TextField
|
|
255
|
-
id="left4"
|
|
256
|
-
label="Disabled"
|
|
257
|
-
name="left4"
|
|
258
|
-
leftContent="Example"
|
|
259
|
-
disabled
|
|
260
|
-
/>
|
|
261
|
-
</>
|
|
262
|
-
),
|
|
263
|
-
};
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/react';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import userEvent from '@testing-library/user-event';
|
|
4
|
-
import { TextField } from '.';
|
|
5
|
-
|
|
6
|
-
describe('<TextField />', () => {
|
|
7
|
-
it('should render', () => {
|
|
8
|
-
const component = render(
|
|
9
|
-
<TextField
|
|
10
|
-
id="example-TextField"
|
|
11
|
-
label="example-TextField"
|
|
12
|
-
name="example"
|
|
13
|
-
/>,
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
expect(component).toBeTruthy();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should show the helper text when supplied to the component', () => {
|
|
20
|
-
const component = render(
|
|
21
|
-
<TextField
|
|
22
|
-
helper={{ message: 'Helper text' }}
|
|
23
|
-
id="example-TextField"
|
|
24
|
-
label="example-TextField"
|
|
25
|
-
name="example"
|
|
26
|
-
/>,
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
expect(component.getByText('Helper text')).toBeTruthy();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should show the error text when supplied to the component', () => {
|
|
33
|
-
const component = render(
|
|
34
|
-
<TextField
|
|
35
|
-
error={{ message: 'Error text' }}
|
|
36
|
-
id="example-TextField"
|
|
37
|
-
label="example-TextField"
|
|
38
|
-
name="example"
|
|
39
|
-
/>,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
expect(component.getByText('Error text')).toBeTruthy();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should show the prefix when supplied to the component', () => {
|
|
46
|
-
const component = render(
|
|
47
|
-
<TextField
|
|
48
|
-
id="example-TextField"
|
|
49
|
-
label="example-TextField"
|
|
50
|
-
name="example"
|
|
51
|
-
prefix="Prefix"
|
|
52
|
-
/>,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
expect(component.getByText('Prefix')).toBeTruthy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should show the suffix when supplied to the component', () => {
|
|
59
|
-
const component = render(
|
|
60
|
-
<TextField
|
|
61
|
-
id="example-TextField"
|
|
62
|
-
label="example-TextField"
|
|
63
|
-
name="example"
|
|
64
|
-
suffix="Suffix"
|
|
65
|
-
/>,
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
expect(component.getByText('Suffix')).toBeTruthy();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should show the label when supplied to the component', () => {
|
|
72
|
-
const component = render(
|
|
73
|
-
<TextField
|
|
74
|
-
id="example-TextField"
|
|
75
|
-
label="example-TextField"
|
|
76
|
-
name="example"
|
|
77
|
-
/>,
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
expect(component.getByText('example-TextField')).toBeTruthy();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('Should show an error message if one is present', () => {
|
|
84
|
-
const component = render(
|
|
85
|
-
<TextField
|
|
86
|
-
error={{ message: 'Error text' }}
|
|
87
|
-
id="example-TextField"
|
|
88
|
-
label="example-TextField"
|
|
89
|
-
name="example"
|
|
90
|
-
/>,
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
expect(component.getByText('Error text')).toBeTruthy();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should be able to input text into the input field', async () => {
|
|
97
|
-
const component = render(
|
|
98
|
-
<TextField
|
|
99
|
-
id="example-TextField"
|
|
100
|
-
label="example-TextField"
|
|
101
|
-
name="example"
|
|
102
|
-
/>,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
const input = component.getByLabelText('example-TextField');
|
|
106
|
-
|
|
107
|
-
await userEvent.type(input, 'Hello, World!');
|
|
108
|
-
|
|
109
|
-
expect(input).toHaveValue('Hello, World!');
|
|
110
|
-
});
|
|
111
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"lib": [
|
|
4
|
-
"dom",
|
|
5
|
-
"dom.iterable",
|
|
6
|
-
"esnext"
|
|
7
|
-
],
|
|
8
|
-
"allowJs": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"strict": true,
|
|
11
|
-
"noEmit": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"module": "esnext",
|
|
14
|
-
"moduleResolution": "node",
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"isolatedModules": true,
|
|
17
|
-
"jsx": "preserve",
|
|
18
|
-
"incremental": true,
|
|
19
|
-
"paths": {
|
|
20
|
-
"@/*": ["./src/*"],
|
|
21
|
-
"@hooks/*": ["./src/hooks/*"]
|
|
22
|
-
},
|
|
23
|
-
"forceConsistentCasingInFileNames": true,
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|