athameui 0.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/README.md +7 -0
- package/components/Accordion/Accordion.tsx +81 -0
- package/components/Accordion/AccordionItem.tsx +65 -0
- package/components/Accordion/index.ts +2 -0
- package/components/Button/BackToTopButton.tsx +53 -0
- package/components/Button/Button.tsx +114 -0
- package/components/Button/ButtonGroup.tsx +13 -0
- package/components/Button/ButtonPrimitive.tsx +16 -0
- package/components/Button/button.variants.ts +30 -0
- package/components/Button/index.ts +3 -0
- package/components/Button/stories/Buttons.stories.tsx +81 -0
- package/components/Header/Header.tsx +12 -0
- package/components/Header/index.ts +1 -0
- package/components/List/List.tsx +44 -0
- package/components/List/ListItem.tsx +52 -0
- package/components/index.ts +5 -0
- package/dist/athameui.cjs +188 -0
- package/dist/athameui.cjs.map +1 -0
- package/dist/athameui.mjs +181 -0
- package/dist/athameui.mjs.map +1 -0
- package/dist/components/Accordion/Accordion.d.ts +15 -0
- package/dist/components/Accordion/Accordion.d.ts.map +1 -0
- package/dist/components/Accordion/AccordionItem.d.ts +15 -0
- package/dist/components/Accordion/AccordionItem.d.ts.map +1 -0
- package/dist/components/Accordion/index.d.ts +3 -0
- package/dist/components/Accordion/index.d.ts.map +1 -0
- package/dist/components/Button/BackToTopButton.d.ts +7 -0
- package/dist/components/Button/BackToTopButton.d.ts.map +1 -0
- package/dist/components/Button/Button.d.ts +48 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/ButtonGroup.d.ts +8 -0
- package/dist/components/Button/ButtonGroup.d.ts.map +1 -0
- package/dist/components/Button/ButtonPrimitive.d.ts +3 -0
- package/dist/components/Button/ButtonPrimitive.d.ts.map +1 -0
- package/dist/components/Button/button.variants.d.ts +29 -0
- package/dist/components/Button/button.variants.d.ts.map +1 -0
- package/dist/components/Button/index.d.ts +4 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Header/Header.d.ts +7 -0
- package/dist/components/Header/Header.d.ts.map +1 -0
- package/dist/components/Header/index.d.ts +2 -0
- package/dist/components/Header/index.d.ts.map +1 -0
- package/dist/components/List/List.d.ts +18 -0
- package/dist/components/List/List.d.ts.map +1 -0
- package/dist/components/List/ListItem.d.ts +20 -0
- package/dist/components/List/ListItem.d.ts.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/utils/cx.d.ts +2 -0
- package/dist/utils/cx.d.ts.map +1 -0
- package/main.ts +1 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# athameUI 🗡️
|
|
2
|
+
|
|
3
|
+
A sharp React component library that's a cut above... sorry, not sorry.
|
|
4
|
+
|
|
5
|
+
This project is still very much a work in progress. Primarily, I'm using it for one of my other projects, so, for the time being, I'm only creating components as I need them.
|
|
6
|
+
|
|
7
|
+
But feel free to look about. You can clone it and try it out, if you feel so inclined.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { AccordionItem } from "./AccordionItem";
|
|
4
|
+
import type { AccordionItemType } from "./AccordionItem";
|
|
5
|
+
import { cx } from "../../utils/cx";
|
|
6
|
+
|
|
7
|
+
type AccordionProps = {
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
items: AccordionItemType[];
|
|
10
|
+
childrenFirst?: boolean;
|
|
11
|
+
expand?: "one" | "any";
|
|
12
|
+
className?:
|
|
13
|
+
| string
|
|
14
|
+
| {
|
|
15
|
+
accordion?: string | false | null | undefined;
|
|
16
|
+
accordionItem?: string | false | null | undefined;
|
|
17
|
+
}
|
|
18
|
+
| false
|
|
19
|
+
| undefined
|
|
20
|
+
| null;
|
|
21
|
+
expandToggleCallback?: (expandedItems: (string | number)[]) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Accordion = ({
|
|
25
|
+
children,
|
|
26
|
+
className,
|
|
27
|
+
items,
|
|
28
|
+
childrenFirst,
|
|
29
|
+
expand = "one",
|
|
30
|
+
|
|
31
|
+
expandToggleCallback,
|
|
32
|
+
}: AccordionProps) => {
|
|
33
|
+
const [expandedItems, setExpandedItems] = useState<(string | number)[]>([]);
|
|
34
|
+
const classes = cx(
|
|
35
|
+
"ath-accordion",
|
|
36
|
+
typeof className === "object" && className !== null
|
|
37
|
+
? className.accordion
|
|
38
|
+
: className
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const expandToggle = (itemId: string | number) => {
|
|
42
|
+
console.log(
|
|
43
|
+
"Rendering AccordionItem:",
|
|
44
|
+
itemId,
|
|
45
|
+
"Expanded:",
|
|
46
|
+
expandedItems.includes(itemId)
|
|
47
|
+
);
|
|
48
|
+
if (expandedItems.includes(itemId)) {
|
|
49
|
+
setExpandedItems(expandedItems.filter((id) => id !== itemId));
|
|
50
|
+
} else {
|
|
51
|
+
if (expand === "one") {
|
|
52
|
+
setExpandedItems([itemId]);
|
|
53
|
+
} else if (expand === "any") {
|
|
54
|
+
setExpandedItems([...expandedItems, itemId]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (expandToggleCallback) {
|
|
58
|
+
expandToggleCallback(expandedItems);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className={classes}>
|
|
64
|
+
{childrenFirst && children}
|
|
65
|
+
{items.map((item) => (
|
|
66
|
+
<AccordionItem
|
|
67
|
+
key={item.id}
|
|
68
|
+
item={item}
|
|
69
|
+
expanded={expandedItems.includes(item.id)}
|
|
70
|
+
onToggle={expandToggle}
|
|
71
|
+
className={
|
|
72
|
+
typeof className === "object" && className !== null
|
|
73
|
+
? className.accordionItem
|
|
74
|
+
: undefined
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
))}
|
|
78
|
+
{!childrenFirst && children}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import { Button } from "../Button/Button";
|
|
4
|
+
import { cx } from "../../utils/cx";
|
|
5
|
+
|
|
6
|
+
export type AccordionItemType = {
|
|
7
|
+
id: string | number;
|
|
8
|
+
heading: string;
|
|
9
|
+
content: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type AccordionItemProps = {
|
|
13
|
+
item: AccordionItemType;
|
|
14
|
+
expanded: boolean;
|
|
15
|
+
onToggle: (id: string | number) => void;
|
|
16
|
+
className?:
|
|
17
|
+
| string
|
|
18
|
+
| { accordionItem?: string | false | null | undefined }
|
|
19
|
+
| false
|
|
20
|
+
| undefined
|
|
21
|
+
| null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const AccordionItem = ({
|
|
25
|
+
item,
|
|
26
|
+
expanded,
|
|
27
|
+
onToggle,
|
|
28
|
+
className,
|
|
29
|
+
}: AccordionItemProps) => {
|
|
30
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
const contentHeight = contentRef.current?.scrollHeight;
|
|
32
|
+
|
|
33
|
+
const classes = cx(
|
|
34
|
+
"ath-accordion-item",
|
|
35
|
+
typeof className === "object" && className !== null
|
|
36
|
+
? className.accordionItem
|
|
37
|
+
: className
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className={classes}>
|
|
42
|
+
<Button
|
|
43
|
+
className="ath-accordion-item-heading"
|
|
44
|
+
variant="ghost"
|
|
45
|
+
size="full"
|
|
46
|
+
textAlign="left"
|
|
47
|
+
onClick={() => onToggle(item.id)}
|
|
48
|
+
dark
|
|
49
|
+
>
|
|
50
|
+
<h4>{item.heading}</h4>
|
|
51
|
+
</Button>
|
|
52
|
+
<div
|
|
53
|
+
className={cx(
|
|
54
|
+
"ath-accordion-expansion-wrapper",
|
|
55
|
+
expanded && "expanded"
|
|
56
|
+
)}
|
|
57
|
+
style={{ height: expanded ? contentHeight : 0 }}
|
|
58
|
+
>
|
|
59
|
+
<div ref={contentRef} className="ath-accordion-item-content">
|
|
60
|
+
{item.content}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Button } from "./Button";
|
|
4
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
5
|
+
import { CircleArrowUp02Icon } from "@hugeicons/core-free-icons";
|
|
6
|
+
import type { ButtonProps } from "./Button";
|
|
7
|
+
import { cx } from "../../utils/cx";
|
|
8
|
+
|
|
9
|
+
type BackToTopButtonProps = ButtonProps & {
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const BackToTopButton = (props: BackToTopButtonProps) => {
|
|
14
|
+
const { className, variant, dark = false, testId, title } = props;
|
|
15
|
+
const [visible, setVisible] = useState(false);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const handleScroll = () => {
|
|
19
|
+
const scrollPosition = window.scrollY;
|
|
20
|
+
if (scrollPosition < 300) {
|
|
21
|
+
setVisible(false);
|
|
22
|
+
} else {
|
|
23
|
+
setVisible(true);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
window.addEventListener("scroll", handleScroll);
|
|
28
|
+
return () => {
|
|
29
|
+
window.removeEventListener("scroll", handleScroll);
|
|
30
|
+
};
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
const scrollToTop = () => {
|
|
34
|
+
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (!visible) return null;
|
|
38
|
+
|
|
39
|
+
const classes = cx("ath-back-to-top-button", className);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Button
|
|
43
|
+
className={classes}
|
|
44
|
+
data-testid={`${testId} "ath-back-to-top-button"`}
|
|
45
|
+
onClick={scrollToTop}
|
|
46
|
+
variant={variant ?? "secondary"}
|
|
47
|
+
title={title ?? "Back to Top"}
|
|
48
|
+
dark={dark}
|
|
49
|
+
>
|
|
50
|
+
<HugeiconsIcon icon={CircleArrowUp02Icon} width="50" height="50" />
|
|
51
|
+
</Button>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ButtonPrimitive, type ButtonPrimitiveProps } from "./ButtonPrimitive";
|
|
3
|
+
import { cx } from "../../utils/cx";
|
|
4
|
+
import { buttonVariants, ButtonSize, ButtonVariant } from "./button.variants";
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
KeyboardEventHandler,
|
|
8
|
+
MouseEventHandler,
|
|
9
|
+
ReactElement,
|
|
10
|
+
} from "react";
|
|
11
|
+
import { forwardRef } from "react";
|
|
12
|
+
|
|
13
|
+
export type ButtonProps = Omit<ButtonPrimitiveProps, "className"> & {
|
|
14
|
+
children?: ReactElement | string;
|
|
15
|
+
className?:
|
|
16
|
+
| string
|
|
17
|
+
| { button?: string | false | null | undefined }
|
|
18
|
+
| false
|
|
19
|
+
| undefined
|
|
20
|
+
| null;
|
|
21
|
+
type?: "button" | "submit" | "reset";
|
|
22
|
+
variant?: ButtonVariant;
|
|
23
|
+
size?: ButtonSize;
|
|
24
|
+
dark?: boolean;
|
|
25
|
+
iconOnly?: boolean;
|
|
26
|
+
icon?: ReactElement | string;
|
|
27
|
+
title?: string;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
autoFocus?: boolean;
|
|
30
|
+
tabIndex?: number;
|
|
31
|
+
testId?: string;
|
|
32
|
+
textAlign?: "left" | "center" | "right";
|
|
33
|
+
|
|
34
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
35
|
+
onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
|
|
36
|
+
onFocus?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
37
|
+
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
41
|
+
(
|
|
42
|
+
{
|
|
43
|
+
children,
|
|
44
|
+
className,
|
|
45
|
+
variant = "primary",
|
|
46
|
+
size = "medium",
|
|
47
|
+
dark = false,
|
|
48
|
+
disabled = false,
|
|
49
|
+
icon,
|
|
50
|
+
iconOnly,
|
|
51
|
+
tabIndex,
|
|
52
|
+
testId,
|
|
53
|
+
type = "button",
|
|
54
|
+
title,
|
|
55
|
+
autoFocus = false,
|
|
56
|
+
textAlign = "center",
|
|
57
|
+
|
|
58
|
+
onBlur,
|
|
59
|
+
onClick,
|
|
60
|
+
onFocus,
|
|
61
|
+
onKeyDown,
|
|
62
|
+
...rest
|
|
63
|
+
},
|
|
64
|
+
ref
|
|
65
|
+
) => {
|
|
66
|
+
const classes = cx(
|
|
67
|
+
"ath-button",
|
|
68
|
+
buttonVariants.size[size],
|
|
69
|
+
buttonVariants.variant[variant],
|
|
70
|
+
buttonVariants.textAlign[textAlign],
|
|
71
|
+
dark ? buttonVariants.dark : "",
|
|
72
|
+
typeof className === "object" && className !== null
|
|
73
|
+
? className.button
|
|
74
|
+
: className
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const onClickHandler: MouseEventHandler<HTMLButtonElement> = (e) => {
|
|
78
|
+
onClick?.(e);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<ButtonPrimitive
|
|
83
|
+
ref={ref}
|
|
84
|
+
type={type}
|
|
85
|
+
title={title}
|
|
86
|
+
className={classes}
|
|
87
|
+
disabled={disabled}
|
|
88
|
+
autoFocus={autoFocus}
|
|
89
|
+
tabIndex={disabled ? -1 : tabIndex}
|
|
90
|
+
data-testid={testId}
|
|
91
|
+
onClick={onClickHandler}
|
|
92
|
+
onKeyDown={onKeyDown}
|
|
93
|
+
onFocus={onFocus}
|
|
94
|
+
onBlur={onBlur}
|
|
95
|
+
{...rest}
|
|
96
|
+
>
|
|
97
|
+
{icon ? (
|
|
98
|
+
<>
|
|
99
|
+
{typeof icon === "string" ? (
|
|
100
|
+
<span aria-hidden="true">{icon}</span>
|
|
101
|
+
) : (
|
|
102
|
+
icon
|
|
103
|
+
)}
|
|
104
|
+
{!iconOnly && children}
|
|
105
|
+
</>
|
|
106
|
+
) : (
|
|
107
|
+
<>{children}</>
|
|
108
|
+
)}
|
|
109
|
+
</ButtonPrimitive>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
Button.displayName = "Button";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type ButtonGroupProps = {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
gap?: string;
|
|
4
|
+
direction?: "row" | "column";
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const ButtonGroup = ({
|
|
8
|
+
children,
|
|
9
|
+
gap = "2",
|
|
10
|
+
direction = "row",
|
|
11
|
+
}: ButtonGroupProps) => {
|
|
12
|
+
return <div className={`flex flex-${direction} gap-${gap}`}>{children}</div>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
|
|
4
|
+
export type ButtonPrimitiveProps =
|
|
5
|
+
React.ButtonHTMLAttributes<HTMLButtonElement> & {};
|
|
6
|
+
|
|
7
|
+
export const ButtonPrimitive = forwardRef<
|
|
8
|
+
HTMLButtonElement,
|
|
9
|
+
ButtonPrimitiveProps
|
|
10
|
+
>(({ children, ...rest }, ref) => {
|
|
11
|
+
return (
|
|
12
|
+
<button ref={ref} {...rest}>
|
|
13
|
+
{children}
|
|
14
|
+
</button>
|
|
15
|
+
);
|
|
16
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// button.variants.ts
|
|
2
|
+
export const buttonVariants = {
|
|
3
|
+
size: {
|
|
4
|
+
small: "ath-button-small",
|
|
5
|
+
medium: "ath-button-medium",
|
|
6
|
+
large: "ath-button-large",
|
|
7
|
+
full: "ath-button-full",
|
|
8
|
+
},
|
|
9
|
+
variant: {
|
|
10
|
+
primary: "ath-button-primary",
|
|
11
|
+
secondary: "ath-button-secondary",
|
|
12
|
+
tertiary: "ath-button-tertiary",
|
|
13
|
+
danger: "ath-button-danger",
|
|
14
|
+
warning: "ath-button-warning",
|
|
15
|
+
success: "ath-button-success",
|
|
16
|
+
outline: "ath-button-outline",
|
|
17
|
+
ghost: "ath-button-ghost",
|
|
18
|
+
},
|
|
19
|
+
textAlign: {
|
|
20
|
+
left: "ath-button-text-left",
|
|
21
|
+
center: "ath-button-text-center",
|
|
22
|
+
right: "ath-button-text-right",
|
|
23
|
+
},
|
|
24
|
+
dark: "ath-button-dark",
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type ButtonSize = keyof typeof buttonVariants.size;
|
|
28
|
+
export type ButtonVariant = keyof typeof buttonVariants.variant;
|
|
29
|
+
export type ButtonDark = keyof typeof buttonVariants.dark;
|
|
30
|
+
export type ButtonTextAlign = keyof typeof buttonVariants.textAlign;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Button } from "../Button";
|
|
3
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
4
|
+
import { SmileDizzyIcon } from "@hugeicons/core-free-icons";
|
|
5
|
+
import styles from "../Button.module.css";
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Button> = {
|
|
8
|
+
component: Button,
|
|
9
|
+
title: "Components/Button",
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story, context) => {
|
|
12
|
+
const { dark } = context.args;
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
style={{
|
|
16
|
+
padding: "2rem",
|
|
17
|
+
backgroundColor: dark
|
|
18
|
+
? "var(--color-background-dark)"
|
|
19
|
+
: "var(--color-background-light)",
|
|
20
|
+
}}
|
|
21
|
+
>
|
|
22
|
+
<Story aria-label="Button example" data-aria="Button example" />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
tags: ["autodocs"],
|
|
28
|
+
argTypes: {
|
|
29
|
+
children: {
|
|
30
|
+
description: `<code>ReactElement<any, string | JSXElementConstructor<any>> |</code> `,
|
|
31
|
+
type: undefined,
|
|
32
|
+
},
|
|
33
|
+
className: {
|
|
34
|
+
control: false,
|
|
35
|
+
},
|
|
36
|
+
iconOnly: {
|
|
37
|
+
control: "boolean",
|
|
38
|
+
},
|
|
39
|
+
dark: {
|
|
40
|
+
control: "boolean",
|
|
41
|
+
},
|
|
42
|
+
icon: {
|
|
43
|
+
control: "radio",
|
|
44
|
+
options: ["No Icon", "w/ Icon"],
|
|
45
|
+
mapping: {
|
|
46
|
+
"No Icon": "",
|
|
47
|
+
"w/ Icon": (
|
|
48
|
+
<HugeiconsIcon
|
|
49
|
+
className={styles.buttonSVGIcon}
|
|
50
|
+
icon={SmileDizzyIcon}
|
|
51
|
+
/>
|
|
52
|
+
),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
type: {
|
|
56
|
+
control: false,
|
|
57
|
+
|
|
58
|
+
description: `
|
|
59
|
+
\`"button"\` \`"submit"\` \`"reset"\`
|
|
60
|
+
|
|
61
|
+
**Default:** \`"button"\`
|
|
62
|
+
`,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
export default meta;
|
|
67
|
+
|
|
68
|
+
export const Default: StoryObj<typeof Button> = {
|
|
69
|
+
args: {
|
|
70
|
+
children: "Click me",
|
|
71
|
+
className: "",
|
|
72
|
+
variant: "primary",
|
|
73
|
+
dark: false,
|
|
74
|
+
size: "medium",
|
|
75
|
+
type: "button",
|
|
76
|
+
title: "Title Example",
|
|
77
|
+
icon: "w/ Icon",
|
|
78
|
+
iconOnly: true,
|
|
79
|
+
testId: "test-id",
|
|
80
|
+
},
|
|
81
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { cx } from "../../utils/cx";
|
|
2
|
+
|
|
3
|
+
type HeaderProps = {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const Header = ({ children, className }: HeaderProps) => {
|
|
9
|
+
const classes = cx("ath-header", className);
|
|
10
|
+
|
|
11
|
+
return <header className={classes}>{children}</header>;
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Header";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
type ListProps = {
|
|
4
|
+
children?: ReactNode[];
|
|
5
|
+
addClasses?: {
|
|
6
|
+
list?: string;
|
|
7
|
+
ul?: string;
|
|
8
|
+
ol?: string;
|
|
9
|
+
};
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
ariaLabelledBy?: string;
|
|
12
|
+
ariaDescribedBy?: string;
|
|
13
|
+
role?: "list" | "menu" | "menubar" | "tablist" | "tree" | "grid";
|
|
14
|
+
dataTestId?: string;
|
|
15
|
+
ordered?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const List: React.FC<ListProps> = ({
|
|
19
|
+
addClasses,
|
|
20
|
+
children,
|
|
21
|
+
ariaLabel,
|
|
22
|
+
ariaLabelledBy,
|
|
23
|
+
ariaDescribedBy,
|
|
24
|
+
role = "list",
|
|
25
|
+
dataTestId,
|
|
26
|
+
ordered = false,
|
|
27
|
+
}) => {
|
|
28
|
+
const ListType = ordered ? "ol" : "ul";
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<ListType
|
|
32
|
+
className={`bn-list font-medium m-0 w-full flex flex-col list-none ps-0 ${
|
|
33
|
+
addClasses?.list || ""
|
|
34
|
+
} ${ordered ? addClasses?.ol || "" : addClasses?.ul || ""}`}
|
|
35
|
+
role={role}
|
|
36
|
+
aria-label={ariaLabel}
|
|
37
|
+
aria-labelledby={ariaLabelledBy}
|
|
38
|
+
aria-describedby={ariaDescribedBy}
|
|
39
|
+
data-testid={dataTestId}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</ListType>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
type ListItemProps = {
|
|
2
|
+
children?: React.ReactNode;
|
|
3
|
+
addClasses?: {
|
|
4
|
+
li?: string;
|
|
5
|
+
};
|
|
6
|
+
useHover?: boolean;
|
|
7
|
+
role?: "listitem" | "menuitem" | "tab" | "treeitem" | "option";
|
|
8
|
+
ariaLabel?: string;
|
|
9
|
+
ariaDescribedBy?: string;
|
|
10
|
+
ariaSelected?: boolean;
|
|
11
|
+
ariaExpanded?: boolean;
|
|
12
|
+
ariaLevel?: number;
|
|
13
|
+
tabIndex?: number;
|
|
14
|
+
dataTestId?: string;
|
|
15
|
+
onClick?: (event: React.MouseEvent<HTMLLIElement>) => void;
|
|
16
|
+
onKeyDown?: (event: React.KeyboardEvent<HTMLLIElement>) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const ListItem: React.FC<ListItemProps> = ({
|
|
20
|
+
children,
|
|
21
|
+
addClasses,
|
|
22
|
+
role = "listitem",
|
|
23
|
+
ariaLabel,
|
|
24
|
+
ariaDescribedBy,
|
|
25
|
+
ariaSelected,
|
|
26
|
+
ariaExpanded,
|
|
27
|
+
ariaLevel,
|
|
28
|
+
tabIndex,
|
|
29
|
+
dataTestId,
|
|
30
|
+
onClick,
|
|
31
|
+
onKeyDown,
|
|
32
|
+
}) => {
|
|
33
|
+
return (
|
|
34
|
+
<li
|
|
35
|
+
className={`bn-list-item rounded-md border border-solid border-color-secondary-50 hover:bg-secondary-50 ${
|
|
36
|
+
addClasses?.li || ""
|
|
37
|
+
}`}
|
|
38
|
+
role={role}
|
|
39
|
+
aria-label={ariaLabel}
|
|
40
|
+
aria-describedby={ariaDescribedBy}
|
|
41
|
+
aria-selected={ariaSelected}
|
|
42
|
+
aria-expanded={ariaExpanded}
|
|
43
|
+
aria-level={ariaLevel}
|
|
44
|
+
tabIndex={tabIndex}
|
|
45
|
+
data-testid={dataTestId}
|
|
46
|
+
onClick={onClick}
|
|
47
|
+
onKeyDown={onKeyDown}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</li>
|
|
51
|
+
);
|
|
52
|
+
};
|