@agilant/toga-blox 1.0.9 → 1.0.10

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agilant/toga-blox",
3
3
  "private": false,
4
- "version": "1.0.9",
4
+ "version": "1.0.10",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "types": "dist/index.d.ts",
@@ -7,28 +7,65 @@ export default {
7
7
  component: Text,
8
8
  argTypes: {
9
9
  size: {
10
- control: "none",
11
- description: "The font size for the text. Use Tailwind CSS classes like 'text-xs', 'text-sm', 'text-md', 'text-lg', 'text-xl', 'text-2xl', 'text-3xl'. Default is 'text-base'.",
10
+ control: {
11
+ type: "select", // Dropdown control
12
+ },
13
+ options: [
14
+ "text-xs",
15
+ "text-sm",
16
+ "text-md",
17
+ "text-lg",
18
+ "text-xl",
19
+ "text-2xl",
20
+ "text-3xl",
21
+ "text-base",
22
+ ], // Define options explicitly
23
+ description:
24
+ "The font size for the text. Use Tailwind CSS classes like 'text-xs', 'text-sm', 'text-md', etc. Default is 'text-base'.",
12
25
  },
13
26
  color: {
14
- control: "none",
15
- description: "The color of the text. Use Tailwind CSS classes like 'text-red-800', 'text-blue-800', 'text-green-800', 'text-slate-950', 'text-black', etc. Default is 'text-black'.",
27
+ control: {
28
+ type: "select", // Dropdown control
29
+ },
30
+ options: [
31
+ "text-red-800",
32
+ "text-blue-800",
33
+ "text-green-800",
34
+ "text-slate-950",
35
+ "text-black",
36
+ ],
37
+ description:
38
+ "The color of the text. Use Tailwind CSS classes like 'text-red-800', 'text-blue-800', 'text-black', etc. Default is 'text-black'.",
16
39
  },
17
40
  tag: {
18
- control: "none",
19
- description: "The type of HTML element the text should be. Options include 'h1', 'h2', 'h3', 'h4', 'h5', 'p', 'span'. Default is 'span'.",
41
+ control: {
42
+ type: "select", // Dropdown control
43
+ },
44
+ options: ["h1", "h2", "h3", "h4", "h5", "p", "span"], // Ensure valid HTML tags are listed
45
+ description:
46
+ "The type of HTML element the text should be. Options include 'h1', 'h2', 'p', etc. Default is 'span'.",
20
47
  },
21
48
  fontFamily: {
22
- control: "none",
23
- description: "The type of font family. Use Tailwind CSS classes like 'font-sans', 'font-mono', 'font-serif'. Default is 'font-sans'.",
49
+ control: {
50
+ type: "select", // Dropdown control
51
+ },
52
+ options: ["font-sans", "font-mono", "font-serif"], // Define the font-family options
53
+ description:
54
+ "The type of font family. Use Tailwind CSS classes like 'font-sans', 'font-mono', etc. Default is 'font-sans'.",
24
55
  },
25
56
  text: {
26
- control: "none",
57
+ control: {
58
+ type: "text", // Text input control
59
+ },
27
60
  description: "The main text displayed on the component.",
61
+ defaultValue: "Testing",
28
62
  },
29
63
  additionalClasses: {
30
- control: "none",
64
+ control: {
65
+ type: "text", // Text input control
66
+ },
31
67
  description: "Additional Tailwind CSS classes to be added.",
68
+ defaultValue: "",
32
69
  },
33
70
  },
34
71
  tags: ["autodocs"],
@@ -7,10 +7,10 @@ describe("<Text />", () => {
7
7
  render(
8
8
  <Text
9
9
  text="Testing"
10
- size="md"
11
- color="red"
10
+ size="text-md"
11
+ color="text-red-500"
12
12
  tag="h1"
13
- fontFamily="sans"
13
+ fontFamily="font-sans"
14
14
  />
15
15
  );
16
16
  });
@@ -23,30 +23,23 @@ describe("<Text />", () => {
23
23
  expect(screen.getByTestId("text")).toHaveTextContent("Testing");
24
24
  });
25
25
 
26
- // Style-based tests might need adjustments
27
-
28
- // test("renders correct font color", () => {
29
- // // Adjust the test based on how the color is applied
30
- // // For example, if using Tailwind, check for the relevant class instead
31
- // const textElement = screen.getByTestId("text");
32
- // expect(textElement).toHaveClass("text-red-500");
33
- // });
26
+ test("renders correct font color", () => {
27
+ const textElement = screen.getByTestId("text");
28
+ expect(textElement).toHaveClass("text-red-500");
29
+ });
34
30
 
35
- FIXME: test("renders correct font size", () => {
36
- // Check for class or style attribute
31
+ test("renders correct font size", () => {
37
32
  const textElement = screen.getByTestId("text");
38
- expect(textElement).toHaveClass("text-md"); // Or the specific class for medium size
33
+ expect(textElement).toHaveClass("text-md");
39
34
  });
40
35
 
41
36
  test("renders correct font family", () => {
42
37
  const textElement = screen.getByTestId("text");
43
- // Check for the presence of the Tailwind CSS class for 'sans' font family
44
38
  expect(textElement).toHaveClass("font-sans");
45
39
  });
46
40
 
47
41
  test("renders correct element type", () => {
48
- // Assuming 'as' prop is set to 'h1' in your test setup
49
42
  const textElement = screen.getByTestId("text");
50
- expect(textElement.tagName).toBe("H1"); // Check that the element is an 'h1'
43
+ expect(textElement.tagName).toBe("H1");
51
44
  });
52
45
  });
@@ -1,120 +1,113 @@
1
1
  import React from "react";
2
-
3
- import Toaster, { ToasterTypes } from ".";
2
+ import Toaster from ".";
4
3
  import { Meta, StoryFn } from "@storybook/react";
5
- import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
6
4
 
7
5
  export default {
8
6
  title: "Components/Toaster",
9
7
  component: Toaster,
10
8
  argTypes: {
11
- color: {
12
- control: "select",
13
- description: "The main color displayed on the toaster",
14
- options: ["green-800", "red-800", "blue-800", "orange-800"],
15
- },
16
-
17
- icon: {
18
- table: {
19
- disable: true,
20
- },
21
- },
22
- title: {
23
- table: {
24
- disable: true,
25
- },
26
- },
27
9
  message: {
28
- control: "text",
29
- description: "The main text displayed on the toaster",
10
+ control: "array",
11
+ description:
12
+ "The main messages displayed on the toaster, passed as an array.",
30
13
  },
31
14
  additionalClasses: {
32
- table: {
33
- disable: true,
34
- },
35
- },
36
- clearText: {
37
15
  control: "text",
38
16
  description:
39
- "The text displayed on the clear message button if set to true",
40
- },
41
- hasClearText: {
42
- control: "boolean",
43
- description: "must be set to true to display the clear text button",
44
- },
45
- fullColor: {
46
- control: "boolean",
47
- description: "toggle the background color of toaster",
17
+ "Additional Tailwind CSS classes for the toaster container.",
48
18
  },
49
- hasBumper: {
19
+ hasClearButton: {
50
20
  control: "boolean",
51
- description: "toggle the left bumper toaster",
21
+ description: "Toggle to show or hide the clear message button.",
52
22
  },
53
23
  clearMessage: {
54
- table: {
55
- disable: true,
56
- },
24
+ action: "Message Cleared!",
25
+ },
26
+ statusProps: {
27
+ control: "object",
28
+ description:
29
+ "Object containing colorClass and optional icon config.",
57
30
  },
58
31
  },
59
-
60
32
  tags: ["autodocs"],
61
33
  parameters: {
62
34
  layout: "centered",
63
35
  },
64
36
  } as Meta;
65
37
 
66
- const minWidth = "min-w-[200px]";
67
-
68
- const Template: StoryFn<ToasterTypes> = (args) => (
69
- <div className="">
70
- <Toaster {...args} />
71
- </div>
72
- );
38
+ const Template: StoryFn = (args) => <Toaster message={[]} {...args} />;
73
39
 
40
+ /**
41
+ * Default
42
+ */
74
43
  export const Default = Template.bind({});
75
44
  Default.args = {
76
- message: "Your action was successful!",
77
- additionalClasses: `border-blue-500 ${minWidth}`,
45
+ message: ["Your action was successful!"],
46
+ statusProps: {
47
+ // Pass the literal Tailwind classes instead of color: "green"
48
+ colorClass: "bg-green-100 border border-green-500 text-green-800",
49
+ },
50
+ additionalClasses: "p-5",
78
51
  };
79
52
 
53
+ /**
54
+ * WithIconFail
55
+ */
80
56
  export const WithIconFail = Template.bind({});
81
57
  WithIconFail.args = {
82
- ...Default.args,
83
- message: "Your action failed!",
84
- color: "red-800",
85
- icon: getFontAwesomeIcon("x"),
86
- additionalClasses: `border-red-500 ${minWidth}`,
58
+ message: ["Your action failed!"],
59
+ statusProps: {
60
+ // Red variant
61
+ colorClass: "bg-red-100 border border-red-500 text-red-800",
62
+ icon: { icon: "x", type: "solid" },
63
+ },
64
+ additionalClasses: "p-5",
87
65
  };
88
66
 
67
+ /**
68
+ * WithIconSuccess
69
+ */
89
70
  export const WithIconSuccess = Template.bind({});
90
71
  WithIconSuccess.args = {
91
- ...Default.args,
92
- color: "green-800",
93
- icon: getFontAwesomeIcon("check"),
94
- additionalClasses: `border-green-500 ${minWidth}`,
72
+ message: ["Action completed successfully!"],
73
+ statusProps: {
74
+ // Green variant
75
+ colorClass: "bg-green-100 border border-green-600 text-green-800",
76
+ icon: { icon: "circleCheck", type: "solid" },
77
+ },
78
+ additionalClasses: "p-5",
95
79
  };
96
80
 
81
+ /**
82
+ * WithIconAlert
83
+ */
97
84
  export const WithIconAlert = Template.bind({});
98
85
  WithIconAlert.args = {
99
- ...Default.args,
100
- message: "Alert, are you sure!",
101
- color: "orange-800",
102
- icon: getFontAwesomeIcon("exclamation"),
103
- additionalClasses: `border-orange-500 ${minWidth}`,
86
+ message: ["Alert: Are you sure?"],
87
+ statusProps: {
88
+ // Gray variant
89
+ colorClass: "bg-yellow-100 border border-yellow-500 text-yellow-800",
90
+ icon: { icon: "triangleExclamation", type: "solid" },
91
+ },
92
+ additionalClasses: "p-5",
104
93
  };
105
94
 
95
+ /**
96
+ * HasClearMessage
97
+ */
106
98
  export const HasClearMessage = Template.bind({});
107
99
  HasClearMessage.args = {
108
- ...Default.args,
109
- clearText: "Clear Message",
110
- color: "blue-800",
111
- hasClearText: true,
112
- clearMessage: () => alert("Message Cleared!"),
113
- };
114
-
115
- export const FullColor = Template.bind({});
116
- FullColor.args = {
117
- ...Default.args,
118
- fullColor: true,
119
- color: "blue-800",
100
+ message: [
101
+ "Message can be cleared and input has different padding from the additionalClasses prop",
102
+ ],
103
+ hasClearButton: true,
104
+ clearMessage: () => {
105
+ alert("Message Cleared!");
106
+ },
107
+ statusProps: {
108
+ // Orange variant
109
+ colorClass: "bg-orange-100 border border-orange-500 text-orange-800",
110
+ icon: { icon: "circleCheck", type: "solid" },
111
+ },
112
+ additionalClasses: "py-2 px-5",
120
113
  };
@@ -1,60 +1,67 @@
1
- import { render, screen, fireEvent } from "@testing-library/react";
2
- import { describe, expect, beforeEach, test, vi } from "vitest";
1
+ import { render, screen } from "@testing-library/react";
2
+ import userEvent from "@testing-library/user-event";
3
+ import { describe, expect, test, vi } from "vitest";
3
4
  import Toaster from "./Toaster";
4
- import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
5
5
 
6
- describe("Toaster Component Tests", () => {
7
- test("renders correctly with minimal props", () => {
8
- render(<Toaster message="Test Message" color="green-500" />);
9
- expect(screen.getByTestId("toaster")).toHaveTextContent("Test Message");
10
- expect(screen.getByTestId("toaster")).toHaveClass("border-green-500");
11
- });
6
+ const testId = "toaster-test-id";
7
+ const testMessage = "Test Message";
12
8
 
13
- test("renders with an icon when provided", () => {
14
- render(
15
- <Toaster
16
- message="Test Message"
17
- color="bg-blue-500"
18
- icon={getFontAwesomeIcon("coffee")}
19
- />
9
+ describe("Toaster Component Tests", () => {
10
+ test("renders the FA icon when passed in props", () => {
11
+ const customStatusProps = {
12
+ icon: { icon: "circleCheck", type: "solid" as "solid" },
13
+ };
14
+ const { container } = render(
15
+ <Toaster message={["Success!"]} statusProps={customStatusProps} />
20
16
  );
21
- expect(screen.getByTestId("toaster")).toBeInTheDocument();
17
+ const iconEl = container.querySelector(".fa-circle-check");
18
+ expect(iconEl).toBeInTheDocument();
22
19
  });
23
-
24
- test("renders the title when provided", () => {
25
- render(
26
- <Toaster
27
- message="Test Message"
28
- color="red-500"
29
- title="Test Title"
30
- />
20
+ test("does not render an icon when icon is not in props", () => {
21
+ const customStatusProps = {};
22
+ const { container } = render(
23
+ <Toaster message={["Success!"]} statusProps={customStatusProps} />
31
24
  );
32
- expect(screen.getByTestId("toaster")).toHaveTextContent("Test Title");
25
+ const iconEl = container.querySelector(".fa-circle-check");
26
+ expect(iconEl).not.toBeInTheDocument();
33
27
  });
34
28
 
35
- test("renders with full color background", () => {
29
+ test("renders correct colors for status", () => {
30
+ const customStatusProps = {
31
+ colorClass: "bg-green-100 border border-green-500 text-green-800",
32
+ };
36
33
  render(
37
- <Toaster
38
- message="Test Message"
39
- color="blue-500"
40
- title="Test Title"
41
- fullColor
42
- />
34
+ <Toaster message={[testMessage]} statusProps={customStatusProps} />
35
+ );
36
+ expect(screen.getByTestId(testId)).toHaveTextContent(testMessage);
37
+ expect(screen.getByTestId(testId)).toHaveClass(
38
+ `${customStatusProps.colorClass}`
43
39
  );
44
- expect(screen.getByTestId("toaster")).toHaveClass("bg-blue-500");
45
40
  });
41
+ test("calls clearMessage callback when the clear button is clicked", async () => {
42
+ // Arrange
43
+ const mockClearMessage = vi.fn();
44
+ const mockAlert = vi
45
+ .spyOn(window, "alert")
46
+ .mockImplementation(() => {});
46
47
 
47
- test("clears the message on clear icon click", async () => {
48
- const clearMessage = vi.fn();
49
48
  render(
50
49
  <Toaster
51
- message="Test Message"
52
- color="orange-500"
53
- clearMessage={clearMessage}
50
+ message={[testMessage]}
51
+ hasClearButton
52
+ clearMessage={mockClearMessage}
54
53
  />
55
54
  );
56
- const clearButton = screen.getByTestId("clearMessage");
57
- fireEvent.click(clearButton);
58
- expect(clearMessage).toHaveBeenCalled();
55
+
56
+ // Act - Click the clear button
57
+ const clearButton = screen.getByTestId("clear-button");
58
+ await userEvent.click(clearButton);
59
+
60
+ // Assert
61
+ expect(mockAlert).toHaveBeenCalledWith("Message Cleared!");
62
+ expect(mockClearMessage).toHaveBeenCalledWith(true);
63
+
64
+ // Cleanup
65
+ mockAlert.mockRestore();
59
66
  });
60
67
  });
@@ -1,70 +1,65 @@
1
1
  import React from "react";
2
- import Button from "../FormButton/FormButton";
3
2
  import { ToasterTypes } from ".";
4
3
  import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
5
4
 
6
5
  const Toaster: React.FC<ToasterTypes> = ({
7
6
  message,
8
- additionalClasses = "",
7
+ additionalClasses,
9
8
  clearMessage,
10
- color,
11
- icon,
12
- fullColor = false,
13
- hasBumper = true,
14
- title = "",
15
- hasClearText,
16
- clearText,
9
+ hasClearButton,
10
+
11
+ statusProps = {
12
+ colorClass: "bg-gray-100 border border-gray-500 text-gay-800",
13
+ icon: { icon: "circleCheck", type: "solid" },
14
+ },
17
15
  }) => {
18
16
  const handleClearMessage = () => {
19
17
  if (clearMessage) {
18
+ alert("Message Cleared!");
20
19
  clearMessage(true);
21
20
  }
22
21
  };
23
22
 
24
- // Simplified Color Handling
25
- const iconColorMap: { [key: string]: string } = {
26
- "green-800": "text-green-800",
27
- "red-800": "text-red-800",
28
- "orange-800": "text-orange-800",
29
- "blue-800": "text-blue-800",
30
- };
31
- const borderClass = `border ${hasBumper ? `border-l-4 border-${color}` : "border-l-1"} `;
32
- const backgroundColorClass = fullColor ? `bg-${color}` : "bg-white";
33
- const textColorClass = fullColor ? "text-white" : "text-black";
23
+ // Pull out colorClass and icon from statusProps
24
+ const { colorClass, icon: maybeIcon } = statusProps;
25
+
26
+ // We'll combine colorClass with other container styles
27
+ const containerClasses = colorClass ?? "";
28
+
29
+ // Your existing custom classes
30
+ const shadowClasses = `shadow-lg shadow-boxShadow rounded-lg`;
31
+ const closeButtonClasses = `cursor-pointer text-xs ml-4`;
34
32
 
35
33
  return (
36
34
  <div
37
- data-testid="toaster"
38
- className={`${borderClass} border-${color} p-4 shadow-lg shadow-boxShadow text-sm ${backgroundColorClass} rounded ${additionalClasses}`}
35
+ data-testid="toaster-test-id"
36
+ role="alert"
37
+ aria-live="polite"
38
+ className={`${shadowClasses} ${containerClasses} ${additionalClasses}`}
39
39
  >
40
- {title ? (
41
- <h3 className="ml-8 font-bold text-xl text-left">{title}</h3>
42
- ) : null}
43
- <div className="flex items-center justify-between">
44
- <span className={`mr-2`}>{icon}</span>
45
- <span className={textColorClass}>{message}</span>
46
- {clearMessage && !hasClearText && (
47
- <span className="cursor-pointer hover:bg-gray-200 py-1 px-2 rounded-md">
48
- <span
49
- data-testid="clearMessage"
40
+ {message.map((msg, index) => (
41
+ <div key={index} className="flex items-center">
42
+ {maybeIcon && (
43
+ <div className="mr-4">
44
+ {getFontAwesomeIcon(maybeIcon.icon, maybeIcon.type)}
45
+ </div>
46
+ )}
47
+
48
+ <p className={index === 0 ? "font-semibold ml-2" : "ml-2"}>
49
+ {msg}
50
+ </p>
51
+
52
+ {hasClearButton && (
53
+ <div
54
+ data-testid="clear-button"
55
+ className={`${closeButtonClasses}`}
50
56
  onClick={handleClearMessage}
51
- className={`cursor-pointer ${textColorClass}`}
52
57
  >
53
- {getFontAwesomeIcon("times")}
54
- </span>
55
- </span>
56
- )}
57
- {hasClearText && clearText && (
58
- <Button
59
- onClick={handleClearMessage}
60
- text={clearText}
61
- shape="outline"
62
- type="button"
63
- isDisabled={false}
64
- additionalClasses="ml-2 px-4"
65
- />
66
- )}
67
- </div>
58
+ {getFontAwesomeIcon("x", "solid")}
59
+ </div>
60
+ )}
61
+ </div>
62
+ ))}
68
63
  </div>
69
64
  );
70
65
  };
@@ -1,12 +1,13 @@
1
+ interface StatusProps {
2
+ // color: string;
3
+ icon?: { icon: string; type: "solid" | "regular" };
4
+ colorClass?: string;
5
+ }
6
+
1
7
  export interface ToasterTypes {
2
- message: string;
8
+ message: string[];
3
9
  additionalClasses?: string;
4
10
  clearMessage?: React.Dispatch<React.SetStateAction<boolean>>;
5
- color: string;
6
- icon?: JSX.Element | null;
7
- fullColor?: boolean;
8
- hasBumper?: boolean;
9
- title?: string;
10
- hasClearText?: boolean;
11
- clearText?: string;
11
+ hasClearButton?: boolean;
12
+ statusProps?: StatusProps;
12
13
  }
@@ -1,5 +1,7 @@
1
1
  /** @type {import('tailwindcss').Config} */
2
2
 
3
+ const colors = require("tailwindcss/colors");
4
+
3
5
  module.exports = {
4
6
  mode: "jit",
5
7
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
@@ -30,6 +32,11 @@ module.exports = {
30
32
  maxWidth: {
31
33
  pageSectionMaxWidth: "1500px",
32
34
  },
35
+ colors: {
36
+ // Add any custom colors here or extend the default palette
37
+ yellow: colors.yellow,
38
+ orange: colors.orange,
39
+ },
33
40
  },
34
41
  fontFamily: {
35
42
  sans: ["ui-sans-serif"],