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.
Files changed (64) hide show
  1. package/components/Accordion/Accordion.tsx +23 -23
  2. package/components/Accordion/AccordionItem.tsx +7 -1
  3. package/components/Avatar/Avatar.tsx +6 -1
  4. package/components/Button/Button.tsx +11 -0
  5. package/components/Button/ScrollToTopButton.tsx +2 -1
  6. package/components/Carousel/Carousel.tsx +159 -37
  7. package/components/Checkbox/Checkbox.tsx +51 -0
  8. package/components/Checkbox/index.ts +1 -0
  9. package/components/FormField/FormField.tsx +24 -0
  10. package/components/FormTextInput/FormTextInput.tsx +11 -0
  11. package/components/Layout/Main.tsx +11 -2
  12. package/components/Modal/Modal.tsx +9 -2
  13. package/components/SlideOut/SlideOut.tsx +31 -2
  14. package/components/index.ts +1 -0
  15. package/dist/athameui.cjs +410 -262
  16. package/dist/athameui.cjs.map +1 -1
  17. package/dist/athameui.mjs +406 -248
  18. package/dist/athameui.mjs.map +1 -1
  19. package/dist/components/Accordion/AccordionItem.d.ts.map +1 -1
  20. package/dist/components/Avatar/Avatar.d.ts.map +1 -1
  21. package/dist/components/Button/Button.d.ts +5 -0
  22. package/dist/components/Button/Button.d.ts.map +1 -1
  23. package/dist/components/Button/ScrollToTopButton.d.ts.map +1 -1
  24. package/dist/components/Carousel/Carousel.d.ts +5 -1
  25. package/dist/components/Carousel/Carousel.d.ts.map +1 -1
  26. package/dist/components/Checkbox/Checkbox.d.ts +14 -0
  27. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
  28. package/dist/components/Checkbox/index.d.ts +2 -0
  29. package/dist/components/Checkbox/index.d.ts.map +1 -0
  30. package/dist/components/FormField/FormField.d.ts +3 -0
  31. package/dist/components/FormField/FormField.d.ts.map +1 -1
  32. package/dist/components/FormTextInput/FormTextInput.d.ts +6 -1
  33. package/dist/components/FormTextInput/FormTextInput.d.ts.map +1 -1
  34. package/dist/components/Layout/Main.d.ts +2 -1
  35. package/dist/components/Layout/Main.d.ts.map +1 -1
  36. package/dist/components/Modal/Modal.d.ts.map +1 -1
  37. package/dist/components/SlideOut/SlideOut.d.ts.map +1 -1
  38. package/dist/components/index.d.ts +1 -0
  39. package/dist/components/index.d.ts.map +1 -1
  40. package/dist/styles/components/carousel.css +28 -4
  41. package/dist/styles/components/checkbox.css +60 -0
  42. package/dist/styles/components/form-input.css +2 -1
  43. package/dist/styles/components/main.css +17 -2
  44. package/dist/styles/index.d.ts +0 -1
  45. package/dist/styles/index.d.ts.map +1 -1
  46. package/dist/styles/index.ts +0 -1
  47. package/dist/styles/theme.css +1 -0
  48. package/dist/styles/tokens.css +16 -17
  49. package/dist/styles/tokens.d.ts +209 -26
  50. package/dist/styles/tokens.d.ts.map +1 -1
  51. package/dist/styles/tokens.ts +190 -165
  52. package/package.json +1 -1
  53. package/styles/components/carousel.css +28 -4
  54. package/styles/components/checkbox.css +60 -0
  55. package/styles/components/form-input.css +2 -1
  56. package/styles/components/main.css +17 -2
  57. package/styles/index.ts +0 -1
  58. package/styles/theme.css +1 -0
  59. package/styles/tokens.css +16 -17
  60. package/styles/tokens.ts +190 -165
  61. package/dist/styles/breakpoints.d.ts +0 -29
  62. package/dist/styles/breakpoints.d.ts.map +0 -1
  63. package/dist/styles/breakpoints.ts +0 -34
  64. 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
- <div key={item.id}>
85
- {CustomAccordionItem ? (
86
- <CustomAccordionItem
87
- expanded={expandedItems.includes(item.id)}
88
- onToggle={expandToggle}
89
- {...item}
90
- />
91
- ) : (
92
- <AccordionItem
93
- sx={sx}
94
- item={item}
95
- expanded={expandedItems.includes(item.id)}
96
- onToggle={expandToggle}
97
- className={
98
- className?.accordionItem
99
- ? { ...className.accordionItem }
100
- : undefined
101
- }
102
- />
103
- )}
104
- </div>
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={{ height: expanded ? contentHeight : 0 }}
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 css={sx?.avatar} className={avatarClasses}>
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 Top"}
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 { Children, useState, useRef, type ReactNode } from "react";
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 { ArrowLeftIcon, ArrowRightIcon } from "@hugeicons/core-free-icons";
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 carouselClasses = cx(
28
- "ath-carousel",
29
- isHovered ? "ath-carousel-hover" : "",
30
- className?.carousel,
31
- );
32
- const hasItems = Children.count(children) > 0;
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 className="ath-carousel-wrapper">
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={carouselClasses}
61
- css={sx?.carousel}
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
- <Button
67
- className={{ button: "ath-carousel-arrow ath-carousel-left-arrow" }}
68
- onClick={handleLeftArrowClick}
69
- onMouseEnter={handleMouseEnter}
70
- onMouseLeave={handleMouseLeave}
71
- icon={<HugeiconsIcon icon={ArrowLeftIcon} size={36} />}
72
- />
73
- {hasItems ? (
74
- children
75
- ) : (
76
- <div className="ath-carousel-empty">{emptyMessage}</div>
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 = ({ children, className, sx }: MainProps) => {
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
- <h1 css={sx?.title} className={titleClasses} id={titleId}>
191
+ <h2 css={sx?.title} className={titleClasses} id={titleId}>
185
192
  {title}
186
- </h1>
193
+ </h2>
187
194
  )}
188
195
  {showCloseButton && (
189
196
  <Button