@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.
@@ -0,0 +1,4 @@
1
+ export declare function useWindowSize(): {
2
+ width: number;
3
+ height?: number | undefined;
4
+ };
@@ -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";
@@ -1,3 +1,2 @@
1
-
2
1
  // ? All of the Product components
3
2
  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,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
+ });
@@ -1,3 +1,2 @@
1
1
  import { TextField } from "./components/TextField";
2
-
3
2
  export { TextField };
@@ -0,0 +1,2 @@
1
+ import { TextField } from "./components/TextField";
2
+ export { TextField };
package/package.json CHANGED
@@ -1,13 +1,19 @@
1
1
  {
2
2
  "name": "@kroo-web/design-system",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "src/index.ts",
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
- "deploy": "npm publish --access public"
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
  }
@@ -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
-
@@ -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