@agility/plenum-ui 2.1.11 → 2.1.13

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/jest.config.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { Config } from "jest";
2
+ import nextJest from "next/jest.js";
3
+
4
+ const createJestConfig = nextJest({
5
+ // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
6
+ dir: "./"
7
+ });
8
+
9
+ // Add any custom config to be passed to Jest
10
+ const config: Config = {
11
+ coverageProvider: "v8",
12
+ testEnvironment: "jsdom",
13
+ // Add more setup options before each test is run
14
+ setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"]
15
+ };
16
+
17
+ // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
18
+ export default createJestConfig(config);
package/jest.setup.ts ADDED
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agility/plenum-ui",
3
- "version": "2.1.11",
3
+ "version": "2.1.13",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -24,7 +24,8 @@
24
24
  "clean": "rimraf dist",
25
25
  "create-component": "node scripts/create-component.js",
26
26
  "start:local": "bash ./local.sh",
27
- "start:watch": "yarn node watch.js"
27
+ "start:watch": "yarn node watch.js",
28
+ "test": "vitest"
28
29
  },
29
30
  "dependencies": {
30
31
  "@floating-ui/react": "^0.25.0",
@@ -36,6 +37,7 @@
36
37
  "@tabler/icons-react": "^2.27.0",
37
38
  "@tailwindcss/forms": "^0.5.3",
38
39
  "@tailwindcss/typography": "^0.5.9",
40
+ "@vitejs/plugin-react": "^4.3.3",
39
41
  "classnames": "^2.3.2",
40
42
  "concurrently": "^7.6.0",
41
43
  "next": "13.1.6",
@@ -56,17 +58,25 @@
56
58
  "@storybook/react": "^7.1.1",
57
59
  "@storybook/testing-library": "^0.2.0",
58
60
  "@storybook/theming": "^7.1.1",
61
+ "@testing-library/dom": "^10.4.0",
62
+ "@testing-library/jest-dom": "^6.6.2",
63
+ "@testing-library/react": "^16.0.1",
64
+ "@types/jest": "^29.5.14",
59
65
  "@types/node": "18.11.18",
60
66
  "autoprefixer": "^10.4.13",
61
67
  "esbuild": "^0.18.19",
62
68
  "eslint": "8.32.0",
63
69
  "eslint-config-next": "13.1.6",
64
70
  "eslint-plugin-storybook": "^0.6.13",
71
+ "jest": "^29.7.0",
72
+ "jest-environment-jsdom": "^29.7.0",
65
73
  "react": "18.2.0",
66
74
  "react-dom": "18.2.0",
67
75
  "react-icons": "^4.10.1",
68
76
  "rimraf": "^5.0.1",
69
- "storybook": "^7.1.1"
77
+ "storybook": "^7.1.1",
78
+ "ts-node": "^10.9.2",
79
+ "vitest": "^2.1.4"
70
80
  },
71
81
  "peerDependencies": {
72
82
  "@floating-ui/react": "^0.25.0",
package/setupTests.js ADDED
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1,115 @@
1
+ import Button from "../Button";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+
4
+ const defaultProps = {
5
+ label: "Button Test"
6
+ };
7
+
8
+ describe("<Button>", () => {
9
+ it("renders with the correct label", () => {
10
+ render(<Button {...defaultProps} />);
11
+
12
+ const buttonElement = screen.getByRole("button");
13
+ expect(buttonElement).toHaveTextContent("Button Test");
14
+ });
15
+
16
+ describe("actionType", () => {
17
+ it("renders with primary as default", () => {
18
+ render(<Button {...defaultProps} />);
19
+
20
+ const buttonElement = screen.getByRole("button");
21
+ expect(buttonElement).toHaveClass("bg-violet-800");
22
+ });
23
+
24
+ it("renders with actionType as secondary", () => {
25
+ render(<Button {...defaultProps} actionType="secondary" />);
26
+
27
+ const buttonElement = screen.getByRole("button");
28
+ expect(buttonElement).toHaveClass("bg-purple-50");
29
+ });
30
+
31
+ it("renders with actionType as alternative", () => {
32
+ render(<Button {...defaultProps} actionType="alternative" />);
33
+
34
+ const buttonElement = screen.getByRole("button");
35
+ expect(buttonElement).toHaveClass("border-gray-300");
36
+ });
37
+
38
+ it("renders with actionType as danger", () => {
39
+ render(<Button {...defaultProps} actionType="danger" />);
40
+
41
+ const buttonElement = screen.getByRole("button");
42
+ expect(buttonElement).toHaveClass("bg-red-600");
43
+ });
44
+
45
+ it("renders with actionType as warning", () => {
46
+ render(<Button {...defaultProps} actionType="warning" />);
47
+
48
+ const buttonElement = screen.getByRole("button");
49
+ expect(buttonElement).toHaveClass("bg-yellow-500");
50
+ });
51
+ });
52
+
53
+ describe("size", () => {
54
+ it("defaults to size sm", () => {
55
+ render(<Button {...defaultProps} />);
56
+
57
+ const buttonElement = screen.getByRole("button");
58
+ expect(buttonElement).toHaveClass("px-[13px]");
59
+ });
60
+
61
+ it("redners with size xs", () => {
62
+ render(<Button {...defaultProps} size="xs" />);
63
+
64
+ const buttonElement = screen.getByRole("button");
65
+ expect(buttonElement).toHaveClass("px-[11px]");
66
+ });
67
+
68
+ it("redners with size md", () => {
69
+ render(<Button {...defaultProps} size="md" />);
70
+
71
+ const buttonElement = screen.getByRole("button");
72
+ expect(buttonElement).toHaveClass("px-[17px] text-sm");
73
+ });
74
+
75
+ it("redners with size lg", () => {
76
+ render(<Button {...defaultProps} size="lg" />);
77
+
78
+ const buttonElement = screen.getByRole("button");
79
+ expect(buttonElement).toHaveClass("px-[17px] text-base");
80
+ });
81
+
82
+ it("redners with size xl", () => {
83
+ render(<Button {...defaultProps} size="xl" />);
84
+
85
+ const buttonElement = screen.getByRole("button");
86
+ expect(buttonElement).toHaveClass("px-[25px]");
87
+ });
88
+ });
89
+
90
+ describe("asLink", () => {
91
+ it("renders as <a /> when asLink is true", () => {
92
+ render(<Button {...defaultProps} asLink={{ href: "#", target: "_blank" }} />);
93
+
94
+ const linkElement = screen.getByRole("link");
95
+ expect(linkElement).toBeInTheDocument();
96
+ });
97
+
98
+ it("renders as <button /> when asLink is false", () => {
99
+ render(<Button {...defaultProps} />);
100
+
101
+ const linkElement = screen.getByRole("button");
102
+ expect(linkElement).toBeInTheDocument();
103
+ });
104
+ });
105
+
106
+ it("calls onClick when clicked", () => {
107
+ const handleClick = vitest.fn();
108
+ render(<Button {...defaultProps} onClick={handleClick} />);
109
+
110
+ const buttonElement = screen.getByRole("button");
111
+ fireEvent.click(buttonElement);
112
+
113
+ expect(handleClick).toHaveBeenCalledTimes(1);
114
+ });
115
+ });
@@ -1,10 +1,10 @@
1
- import React, { FC } from "react"
1
+ import { FC } from "react";
2
2
 
3
3
  export interface IInputCounterProps {
4
4
  /** Counter limit */
5
- limit: number | undefined
5
+ limit: number | undefined;
6
6
  /** Counter current number */
7
- current: number
7
+ current: number;
8
8
  }
9
9
 
10
10
  /** Primary UI component for user interaction */
@@ -19,6 +19,6 @@ const InputCounter: FC<IInputCounterProps> = ({ current = 0, limit }) => {
19
19
  </>
20
20
  )}
21
21
  </div>
22
- )
23
- }
24
- export default InputCounter
22
+ );
23
+ };
24
+ export default InputCounter;
@@ -1,16 +1,16 @@
1
- import React, { FC } from "react"
2
- import { default as cn } from "classnames"
1
+ import { FC } from "react";
2
+ import { default as cn } from "classnames";
3
3
 
4
4
  export interface IInputLabelProps {
5
5
  /** Prop comment */
6
- isPlaceholder?: boolean
7
- id: string
8
- isRequired?: boolean
9
- isDisabled?: boolean
10
- isError?: boolean
11
- isActive?: boolean
12
- isFocused?: boolean
13
- label?: string
6
+ isPlaceholder?: boolean;
7
+ id: string;
8
+ isRequired?: boolean;
9
+ isDisabled?: boolean;
10
+ isError?: boolean;
11
+ isActive?: boolean;
12
+ isFocused?: boolean;
13
+ label?: string;
14
14
  }
15
15
 
16
16
  /** Comment */
@@ -32,14 +32,14 @@ const InputLabel: FC<IInputLabelProps> = ({
32
32
  { "text-red-500 bg-white": !isPlaceholder && isError },
33
33
  { "text-gray-500/[.5]": isDisabled },
34
34
  { "inline-block transition-all text-sm text-gray-700 mb-1": !isPlaceholder }
35
- )
36
- if (!label) return null
35
+ );
36
+ if (!label) return null;
37
37
  return (
38
38
  <label htmlFor={id} className={labelStyles}>
39
39
  {label}
40
40
  {isRequired && <span className="text-red-500"> *</span>}
41
41
  </label>
42
- )
43
- }
42
+ );
43
+ };
44
44
 
45
- export default InputLabel
45
+ export default InputLabel;
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react"
2
- import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton"
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton";
3
3
 
4
4
  const meta: Meta<typeof NestedInputButton> = {
5
5
  title: "Design System/molecules/inputs/Nested Input Button",
@@ -12,10 +12,10 @@ const meta: Meta<typeof NestedInputButton> = {
12
12
  url: "https://www.figma.com/file/Rb5fJ8hD3pwvLnidgCaGgB/Agility-UI?type=design&node-id=114-2290&mode=dev&device-scaling=100%25&page-id=0%3A1"
13
13
  }
14
14
  }
15
- }
15
+ };
16
16
 
17
- export default meta
18
- type Story = StoryObj<typeof NestedInputButton>
17
+ export default meta;
18
+ type Story = StoryObj<typeof NestedInputButton>;
19
19
 
20
20
  export const RightAligned: Story = {
21
21
  args: {
@@ -25,28 +25,24 @@ export const RightAligned: Story = {
25
25
  },
26
26
  ctaLabel: "Search",
27
27
  align: "right",
28
- isClear: false,
29
- onClickHandler: () => window.alert("Clicked"),
30
- buttonProps: {
31
- type: "button"
32
- }
28
+ isClear: false
33
29
  }
34
- }
30
+ };
35
31
  export const LeftAligned: Story = {
36
32
  args: {
37
33
  ...RightAligned.args,
38
34
  align: "left"
39
35
  }
40
- }
36
+ };
41
37
  export const IsClear: Story = {
42
38
  args: {
43
39
  ...RightAligned.args,
44
40
  isClear: true
45
41
  }
46
- }
42
+ };
47
43
  export const NoIcon: Story = {
48
44
  args: {
49
45
  ...RightAligned.args,
50
46
  icon: undefined
51
47
  }
52
- }
48
+ };
@@ -95,7 +95,7 @@ const Select: React.FC<ISelectProps> = ({
95
95
  >
96
96
  {options.map(({ value, label }) => {
97
97
  return (
98
- <option key={value} value={value}>
98
+ <option key={value} value={label}>
99
99
  {label}
100
100
  </option>
101
101
  )
@@ -1,46 +1,46 @@
1
- import React, { forwardRef, useEffect, useId, useState } from "react"
2
- import { default as cn } from "classnames"
3
- import InputLabel from "../InputLabel"
4
- import InputCounter from "../InputCounter"
1
+ import React, { useId } from "react";
2
+ import { default as cn } from "classnames";
3
+ import InputLabel from "../InputLabel";
4
+ import InputCounter from "../InputCounter";
5
5
 
6
6
  interface ILabelProps extends React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement> {
7
- display: string
8
- htmlFor?: string
7
+ display: string;
8
+ htmlFor?: string;
9
9
  }
10
10
 
11
11
  export interface ITextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
12
12
  /** Input ID */
13
- id?: string
13
+ id?: string;
14
14
  /** Input Name */
15
- name?: string
15
+ name?: string;
16
16
  /** Label for the input */
17
- label?: ILabelProps
17
+ label?: ILabelProps;
18
18
  /** Error state */
19
- isError?: boolean
19
+ isError?: boolean;
20
20
  /** If field is required */
21
- isRequired?: boolean
21
+ isRequired?: boolean;
22
22
  /** Disabled state */
23
- isDisabled?: boolean
23
+ isDisabled?: boolean;
24
24
  /** Set default value */
25
- defaultValue?: string
25
+ defaultValue?: string;
26
26
 
27
- value?: string
27
+ value?: string;
28
28
 
29
29
  /** Message shown under the text field */
30
- message?: string
30
+ message?: string;
31
31
  /** Input character counter */
32
- isShowCounter?: boolean
32
+ isShowCounter?: boolean;
33
33
  /** Max length of input character */
34
- maxLength?: number
34
+ maxLength?: number;
35
35
  /** Callback on change */
36
- onChange?(value: string): void
36
+ onChange?(value: string): void;
37
37
  /** Number of rows */
38
- rows?: number
38
+ rows?: number;
39
39
  /** Number of cols */
40
- cols?: number
41
- placeholder?: string
42
- className?: string
43
- ref?: React.LegacyRef<HTMLTextAreaElement>
40
+ cols?: number;
41
+ placeholder?: string;
42
+ className?: string;
43
+ ref?: React.LegacyRef<HTMLTextAreaElement>;
44
44
  }
45
45
 
46
46
  const Textarea: React.FC<ITextareaProps> = ({
@@ -63,11 +63,11 @@ const Textarea: React.FC<ITextareaProps> = ({
63
63
  ref,
64
64
  ...rest
65
65
  }) => {
66
- const uniqueID = useId()
66
+ const uniqueID = useId();
67
67
 
68
- const discriptionStyles = cn("text-sm mt-1 block", { "text-gray-500": !isError }, { "text-red-500": isError })
68
+ const discriptionStyles = cn("text-sm mt-1 block", { "text-gray-500": !isError }, { "text-red-500": isError });
69
69
 
70
- if (!id) id = `ta-${uniqueID}`
70
+ if (!id) id = `ta-${uniqueID}`;
71
71
 
72
72
  if (!label) {
73
73
  return (
@@ -75,9 +75,9 @@ const Textarea: React.FC<ITextareaProps> = ({
75
75
  ref={ref}
76
76
  maxLength={maxLength}
77
77
  onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
78
- const targetValue = e.target.value
78
+ const targetValue = e.target.value;
79
79
  if (onChange) {
80
- onChange(targetValue)
80
+ onChange(targetValue);
81
81
  }
82
82
  }}
83
83
  rows={rows}
@@ -98,7 +98,7 @@ const Textarea: React.FC<ITextareaProps> = ({
98
98
  placeholder={placeholder}
99
99
  {...rest}
100
100
  />
101
- )
101
+ );
102
102
  }
103
103
 
104
104
  //with label
@@ -119,9 +119,9 @@ const Textarea: React.FC<ITextareaProps> = ({
119
119
  ref={ref}
120
120
  maxLength={maxLength}
121
121
  onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
122
- const targetValue = e.target.value
122
+ const targetValue = e.target.value;
123
123
  if (onChange) {
124
- onChange(targetValue)
124
+ onChange(targetValue);
125
125
  }
126
126
  }}
127
127
  rows={rows}
@@ -152,7 +152,7 @@ const Textarea: React.FC<ITextareaProps> = ({
152
152
  )}
153
153
  </div>
154
154
  </div>
155
- )
156
- }
155
+ );
156
+ };
157
157
 
158
- export default Textarea
158
+ export default Textarea;
@@ -1,26 +1,26 @@
1
- import type { Meta, StoryObj } from "@storybook/react"
2
- import AnimatedLabelTextArea, { IAnimatedLabelTextAreaProps } from "./AnimatedLabelTextArea"
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import AnimatedLabelTextArea, { IAnimatedLabelTextAreaProps } from "./AnimatedLabelTextArea";
3
3
 
4
4
  const meta: Meta<typeof AnimatedLabelTextArea> = {
5
5
  title: "Design System/organisms/Animated Label Text Area",
6
6
  component: AnimatedLabelTextArea,
7
7
  tags: ["autodocs"],
8
8
  argTypes: {}
9
- }
9
+ };
10
10
 
11
- export default meta
12
- type Story = StoryObj<typeof AnimatedLabelTextArea>
11
+ export default meta;
12
+ type Story = StoryObj<typeof AnimatedLabelTextArea>;
13
13
  export const DefaultAnimatedLabelTextAreasStory: Story = {
14
14
  args: {
15
15
  id: "test",
16
- label: "Label"
16
+ message: "Label"
17
17
  } as IAnimatedLabelTextAreaProps
18
- }
18
+ };
19
19
 
20
20
  export const DefaultAnimatedLabelTextAreasStoryWithPlaceholder: Story = {
21
21
  args: {
22
22
  id: "test",
23
- label: "Label",
23
+ message: "Label",
24
24
  placeholder: "Placeholder"
25
25
  } as IAnimatedLabelTextAreaProps
26
- }
26
+ };
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react"
2
- import FormInputWithAddons, { IFormInputWithAddonsProps } from "./FormInputWithAddons"
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import FormInputWithAddons, { IFormInputWithAddonsProps } from "./FormInputWithAddons";
3
3
 
4
4
  const meta: Meta<typeof FormInputWithAddons> = {
5
5
  title: "Design System/organisms/Form Input With Addons",
@@ -12,10 +12,10 @@ const meta: Meta<typeof FormInputWithAddons> = {
12
12
  url: "https://www.figma.com/file/Rb5fJ8hD3pwvLnidgCaGgB/Agility-UI?type=design&node-id=85-1269&mode=design"
13
13
  }
14
14
  }
15
- }
15
+ };
16
16
 
17
- export default meta
18
- type Story = StoryObj<typeof FormInputWithAddons>
17
+ export default meta;
18
+ type Story = StoryObj<typeof FormInputWithAddons>;
19
19
 
20
20
  export const DefaultFormInputWithAddons: Story = {
21
21
  args: {
@@ -26,7 +26,7 @@ export const DefaultFormInputWithAddons: Story = {
26
26
  labelClass: "text-gray-900",
27
27
  trailIcon: { icon: "IconSearch" }
28
28
  }
29
- }
29
+ };
30
30
  export const FormInputWithAddonBTN: Story = {
31
31
  args: {
32
32
  id: "appSearch",
@@ -39,10 +39,7 @@ export const FormInputWithAddonBTN: Story = {
39
39
  className: "h-5 w-5 text-gray-400"
40
40
  },
41
41
  ctaLabel: "Edit",
42
- align: "right",
43
- onClickHandler: () => {
44
- alert("Button Clicked")
45
- }
42
+ align: "right"
46
43
  }
47
44
  }
48
- }
45
+ };
package/tsconfig.json CHANGED
@@ -1,29 +1,30 @@
1
1
  {
2
- "compilerOptions": {
3
- "target": "es5",
4
- "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": true,
6
- "skipLibCheck": true,
7
- "strict": true,
8
- "forceConsistentCasingInFileNames": true,
9
- "noEmit": true,
10
- "esModuleInterop": true,
11
- "module": "esnext",
12
- "moduleResolution": "node",
13
- "resolveJsonModule": true,
14
- "isolatedModules": true,
15
- "jsx": "preserve",
16
- "incremental": true,
17
- "plugins": [
18
- {
19
- "name": "next"
20
- }
21
- ],
22
- "baseUrl": ".",
23
- "paths": {
24
- "@/*": ["./*"]
25
- }
26
- },
27
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
28
- "exclude": ["node_modules"]
2
+ "compilerOptions": {
3
+ "target": "es5",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "noEmit": true,
10
+ "esModuleInterop": true,
11
+ "module": "esnext",
12
+ "moduleResolution": "node",
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "jsx": "preserve",
16
+ "incremental": true,
17
+ "plugins": [
18
+ {
19
+ "name": "next"
20
+ }
21
+ ],
22
+ "baseUrl": ".",
23
+ "paths": {
24
+ "@/*": ["./*"]
25
+ },
26
+ "types": ["vitest/globals"]
27
+ },
28
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
29
+ "exclude": ["node_modules"]
29
30
  }
package/utils/types.ts CHANGED
@@ -1,3 +1,2 @@
1
- import { HTMLAttributes } from "react"
2
- import React from "react"
3
- export type ClassNameWithAutocomplete = React.ComponentPropsWithoutRef<"div">["className"]
1
+ import React from "react";
2
+ export type ClassNameWithAutocomplete = React.ComponentPropsWithoutRef<"div">["className"];
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ test: {
7
+ globals: true,
8
+ environment: "jsdom",
9
+ setupFiles: "./setupTests.js"
10
+ }
11
+ });