athameui 0.0.12 → 0.0.14
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/components/Accordion/Accordion.tsx +23 -23
- package/components/Accordion/AccordionItem.tsx +7 -1
- package/components/Avatar/Avatar.tsx +6 -1
- package/components/Button/Button.tsx +11 -0
- package/components/Button/ScrollToTopButton.tsx +2 -1
- package/components/Carousel/Carousel.tsx +159 -37
- package/components/Checkbox/Checkbox.tsx +51 -0
- package/components/Checkbox/index.ts +1 -0
- package/components/FormField/FormField.tsx +24 -0
- package/components/FormTextInput/FormTextInput.tsx +11 -0
- package/components/Layout/Main.tsx +11 -2
- package/components/Modal/Modal.tsx +9 -2
- package/components/SlideOut/SlideOut.tsx +31 -2
- package/components/index.ts +1 -0
- package/dist/athameui.cjs +410 -262
- package/dist/athameui.cjs.map +1 -1
- package/dist/athameui.mjs +406 -248
- package/dist/athameui.mjs.map +1 -1
- package/dist/components/Accordion/AccordionItem.d.ts.map +1 -1
- package/dist/components/Avatar/Avatar.d.ts.map +1 -1
- package/dist/components/Button/Button.d.ts +5 -0
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Button/ScrollToTopButton.d.ts.map +1 -1
- package/dist/components/Carousel/Carousel.d.ts +5 -1
- package/dist/components/Carousel/Carousel.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +14 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -0
- package/dist/components/FormField/FormField.d.ts +3 -0
- package/dist/components/FormField/FormField.d.ts.map +1 -1
- package/dist/components/FormTextInput/FormTextInput.d.ts +6 -1
- package/dist/components/FormTextInput/FormTextInput.d.ts.map +1 -1
- package/dist/components/Layout/Main.d.ts +2 -1
- package/dist/components/Layout/Main.d.ts.map +1 -1
- package/dist/components/Modal/Modal.d.ts.map +1 -1
- package/dist/components/SlideOut/SlideOut.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/styles/components/carousel.css +28 -4
- package/dist/styles/components/checkbox.css +60 -0
- package/dist/styles/components/form-input.css +2 -1
- package/dist/styles/components/main.css +17 -2
- package/dist/styles/index.d.ts +0 -1
- package/dist/styles/index.d.ts.map +1 -1
- package/dist/styles/index.ts +0 -1
- package/dist/styles/theme.css +1 -0
- package/dist/styles/tokens.css +16 -17
- package/dist/styles/tokens.d.ts +209 -26
- package/dist/styles/tokens.d.ts.map +1 -1
- package/dist/styles/tokens.ts +190 -165
- package/package.json +1 -1
- package/styles/components/carousel.css +28 -4
- package/styles/components/checkbox.css +60 -0
- package/styles/components/form-input.css +2 -1
- package/styles/components/main.css +17 -2
- package/styles/index.ts +0 -1
- package/styles/theme.css +1 -0
- package/styles/tokens.css +16 -17
- package/styles/tokens.ts +190 -165
- package/dist/styles/breakpoints.d.ts +0 -29
- package/dist/styles/breakpoints.d.ts.map +0 -1
- package/dist/styles/breakpoints.ts +0 -34
- package/styles/breakpoints.ts +0 -34
|
@@ -80,29 +80,29 @@ export const Accordion = ({
|
|
|
80
80
|
<div className={accordionClasses} css={sx?.accordion}>
|
|
81
81
|
{childrenFirst && children}
|
|
82
82
|
<List>
|
|
83
|
-
{items.map((item) =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
83
|
+
{items.map((item) =>
|
|
84
|
+
CustomAccordionItem ? (
|
|
85
|
+
<CustomAccordionItem
|
|
86
|
+
key={item.id}
|
|
87
|
+
expanded={expandedItems.includes(item.id)}
|
|
88
|
+
onToggle={expandToggle}
|
|
89
|
+
{...item}
|
|
90
|
+
/>
|
|
91
|
+
) : (
|
|
92
|
+
<AccordionItem
|
|
93
|
+
key={item.id}
|
|
94
|
+
sx={sx}
|
|
95
|
+
item={item}
|
|
96
|
+
expanded={expandedItems.includes(item.id)}
|
|
97
|
+
onToggle={expandToggle}
|
|
98
|
+
className={
|
|
99
|
+
className?.accordionItem
|
|
100
|
+
? { ...className.accordionItem }
|
|
101
|
+
: undefined
|
|
102
|
+
}
|
|
103
|
+
/>
|
|
104
|
+
),
|
|
105
|
+
)}
|
|
106
106
|
</List>
|
|
107
107
|
{!childrenFirst && children}
|
|
108
108
|
</div>
|
|
@@ -103,14 +103,20 @@ export const AccordionItem = ({
|
|
|
103
103
|
textPosition={headingTextPosition}
|
|
104
104
|
onClick={onToggleHandler}
|
|
105
105
|
disabled={disabled}
|
|
106
|
+
aria-expanded={expanded}
|
|
107
|
+
aria-controls={`accordion-content-${item.id}`}
|
|
106
108
|
sx={sx?.accordionHeading}
|
|
107
109
|
dark
|
|
108
110
|
>
|
|
109
111
|
<div className={titleClasses}>{item.heading}</div>
|
|
110
112
|
</Button>
|
|
111
113
|
<div
|
|
114
|
+
id={`accordion-content-${item.id}`}
|
|
112
115
|
className={expansionClasses}
|
|
113
|
-
style={{
|
|
116
|
+
style={{
|
|
117
|
+
height: expanded ? contentHeight : 0,
|
|
118
|
+
visibility: expanded ? "visible" : "hidden",
|
|
119
|
+
}}
|
|
114
120
|
>
|
|
115
121
|
<div ref={contentRef} className={contentWrapperClasses}>
|
|
116
122
|
{item.content}
|
|
@@ -34,7 +34,12 @@ export const Avatar = ({
|
|
|
34
34
|
// const imageClasses = cx(".ath-avatar-image", className?.image);
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
|
-
<div
|
|
37
|
+
<div
|
|
38
|
+
css={sx?.avatar}
|
|
39
|
+
className={avatarClasses}
|
|
40
|
+
role="img"
|
|
41
|
+
aria-label={displayName}
|
|
42
|
+
>
|
|
38
43
|
<div css={sx?.initials} className={initialsClasses}>
|
|
39
44
|
{initials[0]}
|
|
40
45
|
{initials[1]}
|
|
@@ -30,11 +30,16 @@ export type ButtonProps = {
|
|
|
30
30
|
type?: "button" | "submit" | "reset";
|
|
31
31
|
variant?: ButtonVariant;
|
|
32
32
|
wrap?: boolean;
|
|
33
|
+
"aria-controls"?: string;
|
|
34
|
+
"aria-expanded"?: boolean;
|
|
35
|
+
"aria-label"?: string;
|
|
36
|
+
"aria-pressed"?: boolean;
|
|
33
37
|
|
|
34
38
|
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
35
39
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
36
40
|
onFocus?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
37
41
|
onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
|
|
42
|
+
onMouseDown?: MouseEventHandler<HTMLButtonElement>;
|
|
38
43
|
onMouseEnter?: MouseEventHandler<HTMLButtonElement>;
|
|
39
44
|
onMouseLeave?: MouseEventHandler<HTMLButtonElement>;
|
|
40
45
|
};
|
|
@@ -59,6 +64,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
59
64
|
onClick,
|
|
60
65
|
onFocus,
|
|
61
66
|
onKeyDown,
|
|
67
|
+
onMouseDown,
|
|
62
68
|
onMouseEnter,
|
|
63
69
|
onMouseLeave,
|
|
64
70
|
...other
|
|
@@ -100,6 +106,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
100
106
|
onBlur?.(e);
|
|
101
107
|
};
|
|
102
108
|
|
|
109
|
+
const onMouseDownHandler: MouseEventHandler<HTMLButtonElement> = (e) => {
|
|
110
|
+
onMouseDown?.(e);
|
|
111
|
+
};
|
|
112
|
+
|
|
103
113
|
const onMouseEnterHandler: MouseEventHandler<HTMLButtonElement> = (e) => {
|
|
104
114
|
onMouseEnter?.(e);
|
|
105
115
|
};
|
|
@@ -122,6 +132,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
122
132
|
onBlur={onBlurHandler}
|
|
123
133
|
onMouseEnter={onMouseEnterHandler}
|
|
124
134
|
onMouseLeave={onMouseLeaveHandler}
|
|
135
|
+
onMouseDown={onMouseDownHandler}
|
|
125
136
|
{...other}
|
|
126
137
|
>
|
|
127
138
|
{icon ? (
|
|
@@ -50,7 +50,8 @@ export const ScrollToTopButton = ({
|
|
|
50
50
|
data-testid="ath-scroll-to-top-button"
|
|
51
51
|
onClick={scrollToTop}
|
|
52
52
|
variant={variant ?? "secondary"}
|
|
53
|
-
title={title ?? "Back to
|
|
53
|
+
title={title ?? "Back to top"}
|
|
54
|
+
aria-label="Back to top"
|
|
54
55
|
dark={dark}
|
|
55
56
|
>
|
|
56
57
|
<HugeiconsIcon icon={CircleArrowUp02Icon} width="50" height="50" />
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
isValidElement,
|
|
4
|
+
useState,
|
|
5
|
+
useRef,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
type DragEvent,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
2
10
|
import { CSSObject } from "@emotion/react";
|
|
3
11
|
import { cx } from "../../utils/cx";
|
|
4
12
|
import { Button } from "../Button/Button";
|
|
13
|
+
import { FormLabel } from "../FormLabel/FormLabel";
|
|
5
14
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
6
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
ArrowLeftIcon,
|
|
17
|
+
ArrowRightIcon,
|
|
18
|
+
Delete02Icon,
|
|
19
|
+
} from "@hugeicons/core-free-icons";
|
|
7
20
|
|
|
8
21
|
export type CarouselProps = {
|
|
9
22
|
children?: ReactNode;
|
|
@@ -11,6 +24,10 @@ export type CarouselProps = {
|
|
|
11
24
|
carousel?: string | false | null | undefined;
|
|
12
25
|
};
|
|
13
26
|
emptyMessage?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
onRemove?: (index: number) => void;
|
|
29
|
+
onReorder?: (from: number, to: number) => void;
|
|
30
|
+
removeLabel?: string | ((index: number) => string);
|
|
14
31
|
sx?: {
|
|
15
32
|
carousel?: CSSObject;
|
|
16
33
|
};
|
|
@@ -20,16 +37,76 @@ export const Carousel = ({
|
|
|
20
37
|
children,
|
|
21
38
|
className,
|
|
22
39
|
emptyMessage = "Nothing here yet",
|
|
40
|
+
label,
|
|
41
|
+
onRemove,
|
|
42
|
+
onReorder,
|
|
43
|
+
removeLabel = "Remove item",
|
|
23
44
|
sx,
|
|
24
45
|
}: CarouselProps) => {
|
|
25
46
|
const [isHovered, setIsHovered] = useState(false);
|
|
47
|
+
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
|
48
|
+
const [showRightArrow, setShowRightArrow] = useState(false);
|
|
49
|
+
const [dropIndex, setDropIndex] = useState<number | null>(null);
|
|
26
50
|
const carouselRef = useRef<HTMLDivElement>(null);
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
32
|
-
|
|
51
|
+
const dragIndex = useRef<number | null>(null);
|
|
52
|
+
const carouselClasses = cx("ath-carousel", className?.carousel);
|
|
53
|
+
const items = Children.toArray(children);
|
|
54
|
+
const itemCount = items.length;
|
|
55
|
+
const interactive = Boolean(onRemove || onReorder);
|
|
56
|
+
|
|
57
|
+
const finishDrag = () => {
|
|
58
|
+
dragIndex.current = null;
|
|
59
|
+
setDropIndex(null);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleDragStart = (index: number) => (event: DragEvent<HTMLDivElement>) => {
|
|
63
|
+
const target = event.target;
|
|
64
|
+
if (
|
|
65
|
+
target instanceof Element &&
|
|
66
|
+
target.closest(".ath-carousel-remove, .ath-carousel-remove-button")
|
|
67
|
+
) {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
dragIndex.current = index;
|
|
72
|
+
event.dataTransfer.effectAllowed = "move";
|
|
73
|
+
event.dataTransfer.setData("text/plain", String(index));
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const handleDragOver = (index: number) => (event: DragEvent<HTMLDivElement>) => {
|
|
77
|
+
if (!onReorder) return;
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
event.dataTransfer.dropEffect = "move";
|
|
80
|
+
if (dropIndex !== index) setDropIndex(index);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleDrop = (index: number) => (event: DragEvent<HTMLDivElement>) => {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
const from = dragIndex.current;
|
|
86
|
+
finishDrag();
|
|
87
|
+
if (from == null || !onReorder) return;
|
|
88
|
+
onReorder(from, index);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
useLayoutEffect(() => {
|
|
92
|
+
const el = carouselRef.current;
|
|
93
|
+
if (!el) return;
|
|
94
|
+
|
|
95
|
+
const updateArrows = () => {
|
|
96
|
+
const hidden = el.scrollWidth - el.clientWidth;
|
|
97
|
+
setShowLeftArrow(el.scrollLeft > 1);
|
|
98
|
+
setShowRightArrow(hidden - el.scrollLeft > 1);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
updateArrows();
|
|
102
|
+
el.addEventListener("scroll", updateArrows, { passive: true });
|
|
103
|
+
const observer = new ResizeObserver(updateArrows);
|
|
104
|
+
observer.observe(el);
|
|
105
|
+
return () => {
|
|
106
|
+
el.removeEventListener("scroll", updateArrows);
|
|
107
|
+
observer.disconnect();
|
|
108
|
+
};
|
|
109
|
+
}, [itemCount]);
|
|
33
110
|
|
|
34
111
|
const scrollByPage = (direction: -1 | 1) => {
|
|
35
112
|
const el = carouselRef.current;
|
|
@@ -40,13 +117,6 @@ export const Carousel = ({
|
|
|
40
117
|
});
|
|
41
118
|
};
|
|
42
119
|
|
|
43
|
-
const handleLeftArrowClick = () => {
|
|
44
|
-
scrollByPage(-1);
|
|
45
|
-
};
|
|
46
|
-
const handleRightArrowClick = () => {
|
|
47
|
-
scrollByPage(1);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
120
|
const handleMouseEnter = () => {
|
|
51
121
|
setIsHovered(true);
|
|
52
122
|
};
|
|
@@ -55,33 +125,85 @@ export const Carousel = ({
|
|
|
55
125
|
};
|
|
56
126
|
|
|
57
127
|
return (
|
|
58
|
-
<div
|
|
128
|
+
<div
|
|
129
|
+
className="ath-carousel-container"
|
|
130
|
+
style={{ minWidth: itemCount === 1 ? "" : 0 }}
|
|
131
|
+
>
|
|
132
|
+
{label && <FormLabel label={label} dark />}
|
|
59
133
|
<div
|
|
60
|
-
className={
|
|
61
|
-
|
|
134
|
+
className={cx(
|
|
135
|
+
"ath-carousel-wrapper",
|
|
136
|
+
isHovered && "ath-carousel-hover",
|
|
137
|
+
label && "ath-carousel-label",
|
|
138
|
+
)}
|
|
62
139
|
onMouseEnter={handleMouseEnter}
|
|
63
140
|
onMouseLeave={handleMouseLeave}
|
|
64
|
-
ref={carouselRef}
|
|
65
141
|
>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)
|
|
76
|
-
|
|
142
|
+
{showLeftArrow && (
|
|
143
|
+
<Button
|
|
144
|
+
className={{ button: "ath-carousel-arrow ath-carousel-left-arrow" }}
|
|
145
|
+
onClick={() => scrollByPage(-1)}
|
|
146
|
+
aria-label={
|
|
147
|
+
label ? `Scroll ${label} backward` : "Scroll backward"
|
|
148
|
+
}
|
|
149
|
+
icon={<HugeiconsIcon icon={ArrowLeftIcon} size={36} />}
|
|
150
|
+
/>
|
|
151
|
+
)}
|
|
152
|
+
<div className={carouselClasses} css={sx?.carousel} ref={carouselRef}>
|
|
153
|
+
{itemCount > 0 ? (
|
|
154
|
+
interactive ? (
|
|
155
|
+
items.map((child, index) => (
|
|
156
|
+
<div
|
|
157
|
+
key={isValidElement(child) ? (child.key ?? index) : index}
|
|
158
|
+
className={cx(
|
|
159
|
+
"ath-carousel-slot",
|
|
160
|
+
onReorder && dropIndex === index && "ath-carousel-slot-target",
|
|
161
|
+
)}
|
|
162
|
+
draggable={Boolean(onReorder)}
|
|
163
|
+
onDragStart={onReorder ? handleDragStart(index) : undefined}
|
|
164
|
+
onDragOver={onReorder ? handleDragOver(index) : undefined}
|
|
165
|
+
onDrop={onReorder ? handleDrop(index) : undefined}
|
|
166
|
+
onDragEnd={onReorder ? finishDrag : undefined}
|
|
167
|
+
>
|
|
168
|
+
{onRemove && (
|
|
169
|
+
<Button
|
|
170
|
+
variant="ghost"
|
|
171
|
+
size="small"
|
|
172
|
+
type="button"
|
|
173
|
+
className={{ button: "ath-carousel-remove-button" }}
|
|
174
|
+
icon={<HugeiconsIcon icon={Delete02Icon} size={16} />}
|
|
175
|
+
aria-label={
|
|
176
|
+
typeof removeLabel === "function"
|
|
177
|
+
? removeLabel(index)
|
|
178
|
+
: removeLabel
|
|
179
|
+
}
|
|
180
|
+
onMouseDown={(event) => event.stopPropagation()}
|
|
181
|
+
onClick={(event) => {
|
|
182
|
+
event.stopPropagation();
|
|
183
|
+
onRemove(index);
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
186
|
+
)}
|
|
187
|
+
{child}
|
|
188
|
+
</div>
|
|
189
|
+
))
|
|
190
|
+
) : (
|
|
191
|
+
children
|
|
192
|
+
)
|
|
193
|
+
) : (
|
|
194
|
+
<div className="ath-carousel-empty">{emptyMessage}</div>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
{showRightArrow && (
|
|
198
|
+
<Button
|
|
199
|
+
className={{
|
|
200
|
+
button: "ath-carousel-arrow ath-carousel-right-arrow",
|
|
201
|
+
}}
|
|
202
|
+
onClick={() => scrollByPage(1)}
|
|
203
|
+
aria-label={label ? `Scroll ${label} forward` : "Scroll forward"}
|
|
204
|
+
icon={<HugeiconsIcon icon={ArrowRightIcon} size={36} />}
|
|
205
|
+
/>
|
|
77
206
|
)}
|
|
78
|
-
<Button
|
|
79
|
-
className={{ button: "ath-carousel-arrow ath-carousel-right-arrow" }}
|
|
80
|
-
onClick={handleRightArrowClick}
|
|
81
|
-
onMouseEnter={handleMouseEnter}
|
|
82
|
-
onMouseLeave={handleMouseLeave}
|
|
83
|
-
icon={<HugeiconsIcon icon={ArrowRightIcon} size={36} />}
|
|
84
|
-
/>
|
|
85
207
|
</div>
|
|
86
208
|
</div>
|
|
87
209
|
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { CSSObject } from "@emotion/react";
|
|
3
|
+
import { cx } from "../../utils/cx";
|
|
4
|
+
|
|
5
|
+
export type CheckboxProps = {
|
|
6
|
+
checked: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
dark?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
id?: string;
|
|
11
|
+
label?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
sx?: CSSObject;
|
|
14
|
+
onChange: (checked: boolean) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const Checkbox = ({
|
|
18
|
+
checked,
|
|
19
|
+
className,
|
|
20
|
+
dark = false,
|
|
21
|
+
disabled = false,
|
|
22
|
+
id,
|
|
23
|
+
label,
|
|
24
|
+
name,
|
|
25
|
+
sx,
|
|
26
|
+
onChange,
|
|
27
|
+
}: CheckboxProps) => {
|
|
28
|
+
return (
|
|
29
|
+
<label
|
|
30
|
+
className={cx(
|
|
31
|
+
"ath-checkbox",
|
|
32
|
+
dark && "ath-checkbox-dark",
|
|
33
|
+
disabled && "ath-checkbox-disabled",
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
css={sx}
|
|
37
|
+
htmlFor={id}
|
|
38
|
+
>
|
|
39
|
+
<input
|
|
40
|
+
id={id}
|
|
41
|
+
className="ath-checkbox-input"
|
|
42
|
+
type="checkbox"
|
|
43
|
+
name={name}
|
|
44
|
+
checked={checked}
|
|
45
|
+
disabled={disabled}
|
|
46
|
+
onChange={(event) => onChange(event.target.checked)}
|
|
47
|
+
/>
|
|
48
|
+
{label && <span className="ath-checkbox-label">{label}</span>}
|
|
49
|
+
</label>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Checkbox";
|
|
@@ -23,6 +23,7 @@ export type FormFieldProps = {
|
|
|
23
23
|
error?: string;
|
|
24
24
|
helperText?: string | ReactNode;
|
|
25
25
|
id?: string;
|
|
26
|
+
inputMode?: React.HTMLAttributes<HTMLInputElement>["inputMode"];
|
|
26
27
|
label?: string | ReactNode;
|
|
27
28
|
labelPosition?: "left" | "right" | "above" | "below";
|
|
28
29
|
name?: string;
|
|
@@ -57,6 +58,8 @@ export type FormFieldProps = {
|
|
|
57
58
|
| React.ChangeEvent<HTMLInputElement>
|
|
58
59
|
| React.ChangeEvent<HTMLTextAreaElement>,
|
|
59
60
|
) => void;
|
|
61
|
+
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
62
|
+
onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
60
63
|
onKeyDown?: React.KeyboardEventHandler<
|
|
61
64
|
HTMLInputElement | HTMLTextAreaElement
|
|
62
65
|
>;
|
|
@@ -72,6 +75,7 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
72
75
|
error,
|
|
73
76
|
helperText,
|
|
74
77
|
id,
|
|
78
|
+
inputMode,
|
|
75
79
|
label,
|
|
76
80
|
labelPosition = "above",
|
|
77
81
|
name,
|
|
@@ -85,6 +89,8 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
85
89
|
value,
|
|
86
90
|
|
|
87
91
|
onChange,
|
|
92
|
+
onBlur,
|
|
93
|
+
onFocus,
|
|
88
94
|
onKeyDown,
|
|
89
95
|
...other
|
|
90
96
|
}) => {
|
|
@@ -167,16 +173,29 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
167
173
|
/>
|
|
168
174
|
) : null;
|
|
169
175
|
|
|
176
|
+
const describedBy =
|
|
177
|
+
[
|
|
178
|
+
error && name ? `${name}-error` : "",
|
|
179
|
+
helperText && name ? `${name}-helper` : "",
|
|
180
|
+
]
|
|
181
|
+
.filter(Boolean)
|
|
182
|
+
.join(" ") || undefined;
|
|
183
|
+
|
|
170
184
|
const inputElement =
|
|
171
185
|
type === "textarea" ? (
|
|
172
186
|
<textarea
|
|
173
187
|
autoComplete={autoComplete}
|
|
174
188
|
autoFocus={autoFocus}
|
|
175
189
|
ref={textAreaRef}
|
|
190
|
+
id={id}
|
|
176
191
|
name={name}
|
|
192
|
+
aria-invalid={error ? true : undefined}
|
|
193
|
+
aria-describedby={describedBy}
|
|
177
194
|
onChange={handleTextAreaChange}
|
|
178
195
|
disabled={disabled}
|
|
179
196
|
readOnly={readOnly}
|
|
197
|
+
onBlur={onBlur}
|
|
198
|
+
onFocus={onFocus}
|
|
180
199
|
onKeyDown={onKeyDown}
|
|
181
200
|
tabIndex={disabled ? -1 : tabIndex}
|
|
182
201
|
className={textAreaClasses}
|
|
@@ -190,10 +209,13 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
190
209
|
autoComplete={autoComplete}
|
|
191
210
|
autoFocus={autoFocus}
|
|
192
211
|
name={name}
|
|
212
|
+
inputMode={inputMode}
|
|
193
213
|
type={type}
|
|
194
214
|
onChange={handleInputChange}
|
|
195
215
|
disabled={disabled}
|
|
196
216
|
readOnly={readOnly}
|
|
217
|
+
onBlur={onBlur}
|
|
218
|
+
onFocus={onFocus}
|
|
197
219
|
onKeyDown={onKeyDown}
|
|
198
220
|
tabIndex={disabled ? -1 : tabIndex}
|
|
199
221
|
className={{ input: inputClasses }}
|
|
@@ -202,6 +224,8 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
202
224
|
placeholder={placeholder}
|
|
203
225
|
size={size}
|
|
204
226
|
id={id}
|
|
227
|
+
aria-invalid={error ? true : undefined}
|
|
228
|
+
aria-describedby={describedBy}
|
|
205
229
|
{...other}
|
|
206
230
|
/>
|
|
207
231
|
);
|
|
@@ -2,6 +2,8 @@ import { CSSObject } from "@emotion/react";
|
|
|
2
2
|
import { cx } from "../../utils/cx";
|
|
3
3
|
|
|
4
4
|
type FormTextInputProps = {
|
|
5
|
+
"aria-describedby"?: string;
|
|
6
|
+
"aria-invalid"?: boolean;
|
|
5
7
|
autoComplete?: string;
|
|
6
8
|
autoFocus?: boolean;
|
|
7
9
|
className?: {
|
|
@@ -11,6 +13,7 @@ type FormTextInputProps = {
|
|
|
11
13
|
disabled?: boolean;
|
|
12
14
|
error?: string;
|
|
13
15
|
id?: string;
|
|
16
|
+
inputMode?: React.HTMLAttributes<HTMLInputElement>["inputMode"];
|
|
14
17
|
name?: string;
|
|
15
18
|
placeholder?: string;
|
|
16
19
|
readOnly?: boolean;
|
|
@@ -31,6 +34,8 @@ type FormTextInputProps = {
|
|
|
31
34
|
value?: string | number;
|
|
32
35
|
|
|
33
36
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
37
|
+
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
|
38
|
+
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
34
39
|
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
|
|
35
40
|
};
|
|
36
41
|
|
|
@@ -42,6 +47,7 @@ export const FormTextInput = ({
|
|
|
42
47
|
error,
|
|
43
48
|
disabled,
|
|
44
49
|
id,
|
|
50
|
+
inputMode,
|
|
45
51
|
name,
|
|
46
52
|
placeholder,
|
|
47
53
|
readOnly,
|
|
@@ -52,6 +58,8 @@ export const FormTextInput = ({
|
|
|
52
58
|
value,
|
|
53
59
|
|
|
54
60
|
onChange,
|
|
61
|
+
onBlur,
|
|
62
|
+
onFocus,
|
|
55
63
|
onKeyDown,
|
|
56
64
|
...other
|
|
57
65
|
}: FormTextInputProps) => {
|
|
@@ -79,12 +87,15 @@ export const FormTextInput = ({
|
|
|
79
87
|
css={sx?.input}
|
|
80
88
|
disabled={disabled}
|
|
81
89
|
name={name}
|
|
90
|
+
inputMode={inputMode}
|
|
82
91
|
placeholder={placeholder}
|
|
83
92
|
readOnly={readOnly}
|
|
84
93
|
tabIndex={disabled ? -1 : tabIndex}
|
|
85
94
|
type={type}
|
|
86
95
|
value={value}
|
|
87
96
|
onChange={onChangeHandler}
|
|
97
|
+
onBlur={onBlur}
|
|
98
|
+
onFocus={onFocus}
|
|
88
99
|
onKeyDown={onKeyDown}
|
|
89
100
|
id={id}
|
|
90
101
|
{...other}
|
|
@@ -8,14 +8,19 @@ type MainProps = {
|
|
|
8
8
|
main?: string | false | null | undefined;
|
|
9
9
|
mainContent?: string | false | null | undefined;
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
width?: "full" | "wide" | "medium" | "narrow";
|
|
12
12
|
sx?: {
|
|
13
13
|
main?: CSSObject;
|
|
14
14
|
mainContent?: CSSObject;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export const Main = ({
|
|
18
|
+
export const Main = ({
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
sx,
|
|
22
|
+
width = "wide",
|
|
23
|
+
}: MainProps) => {
|
|
19
24
|
const mainClasses = cx(
|
|
20
25
|
"ath-main",
|
|
21
26
|
typeof className === "object" && className !== null ? className.main : "",
|
|
@@ -26,6 +31,10 @@ export const Main = ({ children, className, sx }: MainProps) => {
|
|
|
26
31
|
typeof className === "object" && className !== null
|
|
27
32
|
? className.mainContent
|
|
28
33
|
: "",
|
|
34
|
+
width === "full" ? "full" : "",
|
|
35
|
+
width === "wide" ? "wide" : "",
|
|
36
|
+
width === "medium" ? "medium" : "",
|
|
37
|
+
width === "narrow" ? "narrow" : "",
|
|
29
38
|
);
|
|
30
39
|
|
|
31
40
|
return (
|
|
@@ -52,6 +52,9 @@ export const Modal: React.FC<ModalProps> = ({
|
|
|
52
52
|
trapFocus = true,
|
|
53
53
|
initialFocusRef,
|
|
54
54
|
finalFocusRef,
|
|
55
|
+
ariaLabel,
|
|
56
|
+
ariaLabelledBy,
|
|
57
|
+
ariaDescribedBy,
|
|
55
58
|
sx,
|
|
56
59
|
|
|
57
60
|
onClose,
|
|
@@ -176,14 +179,18 @@ export const Modal: React.FC<ModalProps> = ({
|
|
|
176
179
|
css={sx?.modal}
|
|
177
180
|
className={modalClasses}
|
|
178
181
|
role="dialog"
|
|
182
|
+
aria-modal="true"
|
|
183
|
+
aria-labelledby={ariaLabelledBy || titleId}
|
|
184
|
+
aria-label={ariaLabelledBy || titleId ? undefined : ariaLabel}
|
|
185
|
+
aria-describedby={ariaDescribedBy}
|
|
179
186
|
{...other}
|
|
180
187
|
>
|
|
181
188
|
{(title || showCloseButton) && (
|
|
182
189
|
<div css={sx?.header} className={headerClasses}>
|
|
183
190
|
{title && (
|
|
184
|
-
<
|
|
191
|
+
<h2 css={sx?.title} className={titleClasses} id={titleId}>
|
|
185
192
|
{title}
|
|
186
|
-
</
|
|
193
|
+
</h2>
|
|
187
194
|
)}
|
|
188
195
|
{showCloseButton && (
|
|
189
196
|
<Button
|