@fpkit/acss 0.5.11 → 0.5.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/README.md +514 -18
- package/libs/chunk-23ANBDCR.js +8 -0
- package/libs/chunk-23ANBDCR.js.map +1 -0
- package/libs/chunk-2LTJ7HHX.cjs +18 -0
- package/libs/chunk-2LTJ7HHX.cjs.map +1 -0
- package/libs/chunk-2Y7W75TT.js +9 -0
- package/libs/chunk-2Y7W75TT.js.map +1 -0
- package/libs/chunk-3MKLDCKQ.cjs +31 -0
- package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
- package/libs/chunk-5M57K4SW.js +8 -0
- package/libs/chunk-5M57K4SW.js.map +1 -0
- package/libs/chunk-5S4ORA4C.cjs +15 -0
- package/libs/chunk-5S4ORA4C.cjs.map +1 -0
- package/libs/chunk-772NRB75.js +9 -0
- package/libs/chunk-772NRB75.js.map +1 -0
- package/libs/chunk-AHDJGCG5.cjs +15 -0
- package/libs/chunk-AHDJGCG5.cjs.map +1 -0
- package/libs/chunk-B7F5FS6D.cjs +16 -0
- package/libs/chunk-B7F5FS6D.cjs.map +1 -0
- package/libs/chunk-BHRQBJRY.js +8 -0
- package/libs/chunk-BHRQBJRY.js.map +1 -0
- package/libs/chunk-D4YLRWAO.cjs +18 -0
- package/libs/chunk-D4YLRWAO.cjs.map +1 -0
- package/libs/chunk-ETFLFC2S.js +10 -0
- package/libs/chunk-ETFLFC2S.js.map +1 -0
- package/libs/chunk-G55UJ53G.cjs +16 -0
- package/libs/chunk-G55UJ53G.cjs.map +1 -0
- package/libs/chunk-GZ4QFPRY.js +9 -0
- package/libs/chunk-GZ4QFPRY.js.map +1 -0
- package/libs/chunk-IYUN2EW3.cjs +15 -0
- package/libs/chunk-IYUN2EW3.cjs.map +1 -0
- package/libs/chunk-J32EZPYD.cjs +15 -0
- package/libs/chunk-J32EZPYD.cjs.map +1 -0
- package/libs/chunk-JJ43O4Y5.js +8 -0
- package/libs/chunk-JJ43O4Y5.js.map +1 -0
- package/libs/chunk-KUKIVRC2.js +7 -0
- package/libs/chunk-KUKIVRC2.js.map +1 -0
- package/libs/chunk-L75OQKEI.cjs +13 -0
- package/libs/chunk-L75OQKEI.cjs.map +1 -0
- package/libs/chunk-LT5KZ2QW.cjs +22 -0
- package/libs/chunk-LT5KZ2QW.cjs.map +1 -0
- package/libs/chunk-M5RRNTVX.cjs +15 -0
- package/libs/chunk-M5RRNTVX.cjs.map +1 -0
- package/libs/chunk-NGTJDDFO.js +8 -0
- package/libs/chunk-NGTJDDFO.js.map +1 -0
- package/libs/chunk-OK5QEIMD.cjs +17 -0
- package/libs/chunk-OK5QEIMD.cjs.map +1 -0
- package/libs/chunk-P2DC76ZZ.cjs +18 -0
- package/libs/chunk-P2DC76ZZ.cjs.map +1 -0
- package/libs/chunk-P7TTEYCD.js +7 -0
- package/libs/chunk-P7TTEYCD.js.map +1 -0
- package/libs/chunk-PQ2K3BM6.cjs +17 -0
- package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
- package/libs/chunk-QLZWHAMK.js +8 -0
- package/libs/chunk-QLZWHAMK.js.map +1 -0
- package/libs/chunk-RIVUMPOG.js +8 -0
- package/libs/chunk-RIVUMPOG.js.map +1 -0
- package/libs/chunk-ROZI23GS.cjs +15 -0
- package/libs/chunk-ROZI23GS.cjs.map +1 -0
- package/libs/chunk-S7BABR7Z.cjs +13 -0
- package/libs/chunk-S7BABR7Z.cjs.map +1 -0
- package/libs/chunk-SMYRLO3E.js +8 -0
- package/libs/chunk-SMYRLO3E.js.map +1 -0
- package/libs/chunk-TYRCEX2L.js +8 -0
- package/libs/chunk-TYRCEX2L.js.map +1 -0
- package/libs/chunk-VUH3FXGJ.js +11 -0
- package/libs/chunk-VUH3FXGJ.js.map +1 -0
- package/libs/chunk-XBA562WW.js +8 -0
- package/libs/chunk-XBA562WW.js.map +1 -0
- package/libs/chunk-XTQKWY7W.cjs +32 -0
- package/libs/chunk-XTQKWY7W.cjs.map +1 -0
- package/libs/chunk-ZANSFMTD.js +9 -0
- package/libs/chunk-ZANSFMTD.js.map +1 -0
- package/libs/component-props-a8a2f97e.d.ts +38 -0
- package/libs/components/alert/alert.css +1 -1
- package/libs/components/alert/alert.css.map +1 -1
- package/libs/components/alert/alert.min.css +2 -2
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/breadcrumbs/breadcrumb.cjs +24 -0
- package/libs/components/breadcrumbs/breadcrumb.cjs.map +1 -0
- package/libs/components/breadcrumbs/breadcrumb.d.cts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.d.ts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.js +5 -0
- package/libs/components/breadcrumbs/breadcrumb.js.map +1 -0
- package/libs/components/button.cjs +19 -0
- package/libs/components/button.cjs.map +1 -0
- package/libs/components/button.d.cts +16 -0
- package/libs/components/button.d.ts +16 -0
- package/libs/components/button.js +4 -0
- package/libs/components/button.js.map +1 -0
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/card.cjs +31 -0
- package/libs/components/card.cjs.map +1 -0
- package/libs/components/card.d.cts +302 -0
- package/libs/components/card.d.ts +302 -0
- package/libs/components/card.js +4 -0
- package/libs/components/card.js.map +1 -0
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/dialog/dialog.cjs +22 -0
- package/libs/components/dialog/dialog.cjs.map +1 -0
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.d.cts +105 -0
- package/libs/components/dialog/dialog.d.ts +105 -0
- package/libs/components/dialog/dialog.js +7 -0
- package/libs/components/dialog/dialog.js.map +1 -0
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/fields.cjs +19 -0
- package/libs/components/form/fields.cjs.map +1 -0
- package/libs/components/form/fields.d.cts +24 -0
- package/libs/components/form/fields.d.ts +24 -0
- package/libs/components/form/fields.js +4 -0
- package/libs/components/form/fields.js.map +1 -0
- package/libs/components/form/inputs.cjs +19 -0
- package/libs/components/form/inputs.cjs.map +1 -0
- package/libs/components/form/inputs.d.cts +2 -0
- package/libs/components/form/inputs.d.ts +2 -0
- package/libs/components/form/inputs.js +4 -0
- package/libs/components/form/inputs.js.map +1 -0
- package/libs/components/form/textarea.cjs +19 -0
- package/libs/components/form/textarea.cjs.map +1 -0
- package/libs/components/form/textarea.d.cts +29 -0
- package/libs/components/form/textarea.d.ts +29 -0
- package/libs/components/form/textarea.js +4 -0
- package/libs/components/form/textarea.js.map +1 -0
- package/libs/components/heading/heading.cjs +10 -0
- package/libs/components/heading/heading.cjs.map +1 -0
- package/libs/components/heading/heading.d.cts +3 -0
- package/libs/components/heading/heading.d.ts +3 -0
- package/libs/components/heading/heading.js +4 -0
- package/libs/components/heading/heading.js.map +1 -0
- package/libs/components/icons/icon.cjs +19 -0
- package/libs/components/icons/icon.cjs.map +1 -0
- package/libs/{icons-31ace3de.d.ts → components/icons/icon.d.cts} +151 -61
- package/libs/components/icons/icon.d.ts +445 -0
- package/libs/components/icons/icon.js +4 -0
- package/libs/components/icons/icon.js.map +1 -0
- package/libs/components/images/img.css +1 -1
- package/libs/components/images/img.css.map +1 -1
- package/libs/components/images/img.min.css +2 -2
- package/libs/components/link/link.cjs +19 -0
- package/libs/components/link/link.cjs.map +1 -0
- package/libs/components/link/link.d.cts +19 -0
- package/libs/components/link/link.d.ts +19 -0
- package/libs/components/link/link.js +4 -0
- package/libs/components/link/link.js.map +1 -0
- package/libs/components/list/list.cjs +23 -0
- package/libs/components/list/list.cjs.map +1 -0
- package/libs/components/list/list.d.cts +39 -0
- package/libs/components/list/list.d.ts +39 -0
- package/libs/components/list/list.js +4 -0
- package/libs/components/list/list.js.map +1 -0
- package/libs/components/modal.cjs +14 -0
- package/libs/components/modal.cjs.map +1 -0
- package/libs/components/modal.d.cts +35 -0
- package/libs/components/modal.d.ts +35 -0
- package/libs/components/modal.js +5 -0
- package/libs/components/modal.js.map +1 -0
- package/libs/components/nav/nav.cjs +28 -0
- package/libs/components/nav/nav.cjs.map +1 -0
- package/libs/components/nav/nav.d.cts +44 -0
- package/libs/components/nav/nav.d.ts +44 -0
- package/libs/components/nav/nav.js +5 -0
- package/libs/components/nav/nav.js.map +1 -0
- package/libs/components/popover/popover.cjs +23 -0
- package/libs/components/popover/popover.cjs.map +1 -0
- package/libs/components/popover/popover.d.cts +40 -0
- package/libs/components/popover/popover.d.ts +40 -0
- package/libs/components/popover/popover.js +4 -0
- package/libs/components/popover/popover.js.map +1 -0
- package/libs/components/tables/table.cjs +21 -0
- package/libs/components/tables/table.cjs.map +1 -0
- package/libs/components/tables/table.d.cts +36 -0
- package/libs/components/tables/table.d.ts +36 -0
- package/libs/components/tables/table.js +4 -0
- package/libs/components/tables/table.js.map +1 -0
- package/libs/components/text/text.cjs +23 -0
- package/libs/components/text/text.cjs.map +1 -0
- package/libs/components/text/text.d.cts +30 -0
- package/libs/components/text/text.d.ts +30 -0
- package/libs/components/text/text.js +4 -0
- package/libs/components/text/text.js.map +1 -0
- package/libs/heading-3648c538.d.ts +250 -0
- package/libs/hooks.cjs +7 -0
- package/libs/hooks.d.cts +5 -0
- package/libs/hooks.d.ts +5 -0
- package/libs/hooks.js +3 -0
- package/libs/icons.cjs +3 -2
- package/libs/icons.d.cts +3 -1
- package/libs/icons.d.ts +3 -1
- package/libs/icons.js +2 -1
- package/libs/index.cjs +174 -62
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +529 -446
- package/libs/index.d.ts +529 -446
- package/libs/index.js +36 -7
- package/libs/index.js.map +1 -1
- package/libs/inputs-f3a216db.d.ts +45 -0
- package/libs/ui-645f95b5.d.ts +285 -0
- package/package.json +2 -2
- package/src/components/README-UI.mdx +416 -0
- package/src/components/alert/ACCESSIBILITY.md +319 -0
- package/src/components/alert/README.mdx +475 -19
- package/src/components/alert/alert.scss +113 -6
- package/src/components/alert/alert.stories.tsx +372 -0
- package/src/components/alert/alert.test.tsx +762 -0
- package/src/components/alert/alert.tsx +331 -66
- package/src/components/alert/views/alert-actions.tsx +13 -0
- package/src/components/alert/views/alert-content.tsx +17 -0
- package/src/components/alert/views/alert-icon.tsx +53 -0
- package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
- package/src/components/alert/views/alert-title.tsx +23 -0
- package/src/components/alert/views/alert-view.tsx +158 -0
- package/src/components/alert/views/index.ts +12 -0
- package/src/components/badge/badge.mdx +186 -49
- package/src/components/badge/badge.scss +20 -2
- package/src/components/badge/badge.stories.tsx +160 -14
- package/src/components/badge/badge.test.tsx +179 -0
- package/src/components/badge/badge.tsx +97 -4
- package/src/components/breadcrumbs/README.mdx +364 -45
- package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
- package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +427 -170
- package/src/components/button.ts +2 -0
- package/src/components/buttons/button.scss +34 -31
- package/src/components/buttons/button.stories.tsx +35 -0
- package/src/components/card.ts +2 -0
- package/src/components/cards/README.mdx +657 -0
- package/src/components/cards/card.scss +22 -0
- package/src/components/cards/card.stories.tsx +167 -5
- package/src/components/cards/card.test.tsx +360 -20
- package/src/components/cards/card.tsx +200 -79
- package/src/components/cards/card.types.ts +135 -0
- package/src/components/cards/card.utils.ts +79 -0
- package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
- package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
- package/src/components/details/README.mdx +437 -69
- package/src/components/details/details.scss +16 -0
- package/src/components/details/details.test.tsx +385 -0
- package/src/components/details/details.tsx +101 -69
- package/src/components/details/details.types.ts +76 -0
- package/src/components/dialog/README.mdx +513 -110
- package/src/components/dialog/dialog-modal.tsx +79 -56
- package/src/components/dialog/dialog.scss +53 -3
- package/src/components/dialog/dialog.stories.tsx +10 -7
- package/src/components/dialog/dialog.test.tsx +450 -0
- package/src/components/dialog/dialog.tsx +69 -59
- package/src/components/dialog/dialog.types.ts +133 -0
- package/src/components/dialog/views/dialog-footer.tsx +54 -11
- package/src/components/dialog/views/dialog-header.tsx +20 -15
- package/src/components/heading/heading.stories.tsx +44 -4
- package/src/components/heading/heading.tsx +89 -23
- package/src/components/icons/README.mdx +332 -0
- package/src/components/icons/icon.stories.tsx +74 -1
- package/src/components/icons/icon.tsx +89 -1
- package/src/components/icons/types.ts +47 -0
- package/src/components/images/README.mdx +340 -24
- package/src/components/images/img.scss +19 -3
- package/src/components/images/img.stories.tsx +424 -15
- package/src/components/images/img.test.tsx +354 -25
- package/src/components/images/img.tsx +186 -63
- package/src/components/images/img.types.ts +211 -0
- package/src/components/modal.ts +1 -0
- package/src/components/title/MIGRATION.md +199 -0
- package/src/components/title/README.md +326 -0
- package/src/components/title/README.mdx +452 -0
- package/src/components/title/title.stories.tsx +393 -0
- package/src/components/title/title.test.tsx +251 -0
- package/src/components/title/title.tsx +219 -0
- package/src/components/ui.stories.tsx +894 -0
- package/src/components/ui.test.tsx +559 -0
- package/src/components/ui.tsx +266 -15
- package/src/components/word-count/README.md +240 -0
- package/src/hooks.ts +1 -0
- package/src/index.ts +51 -19
- package/src/sass/_properties.scss +1 -0
- package/src/styles/alert/alert.css +94 -4
- package/src/styles/alert/alert.css.map +1 -1
- package/src/styles/badge/badge.css +20 -2
- package/src/styles/badge/badge.css.map +1 -1
- package/src/styles/buttons/button.css +31 -31
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +16 -0
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +19 -0
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/dialog/dialog.css +43 -2
- package/src/styles/dialog/dialog.css.map +1 -1
- package/src/styles/images/img.css +15 -3
- package/src/styles/images/img.css.map +1 -1
- package/src/styles/index.css +240 -43
- package/src/styles/index.css.map +1 -1
- package/src/test/setup.d.ts +9 -0
- package/src/test/setup.ts +53 -1
- package/libs/chunk-PWVRDQ3R.js +0 -8
- package/libs/chunk-PWVRDQ3R.js.map +0 -1
- package/libs/chunk-SVS4MX3U.cjs +0 -31
- package/libs/chunk-SVS4MX3U.cjs.map +0 -1
- package/src/components/cards/README.md +0 -80
- package/src/components/dialog/hooks/useClickOutside.ts +0 -33
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import UI from "#components/ui";
|
|
3
|
-
import Icon from "#components/icons/icon";
|
|
4
2
|
import { IconProps } from "#components/icons/types";
|
|
5
|
-
import
|
|
3
|
+
import { AlertView } from "./views";
|
|
6
4
|
|
|
7
|
-
//
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// TYPES & CONFIGURATION
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Valid severity levels for alerts.
|
|
11
|
+
* Each severity has associated colors, icons, and ARIA attributes.
|
|
12
|
+
*/
|
|
8
13
|
type Severity = "default" | "info" | "success" | "warning" | "error";
|
|
9
14
|
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* Props for the Alert component.
|
|
12
18
|
*/
|
|
@@ -39,34 +45,158 @@ export type AlertProps = {
|
|
|
39
45
|
onDismiss?: () => void;
|
|
40
46
|
|
|
41
47
|
/**
|
|
42
|
-
* Size of the icon in pixels.
|
|
43
|
-
*
|
|
48
|
+
* Size of the severity icon in pixels.
|
|
49
|
+
* Allows customization of icon size for different contexts.
|
|
50
|
+
* @default 24
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <Alert iconSize={32} severity="error">Larger icon</Alert>
|
|
54
|
+
* <Alert iconSize={16} severity="info">Smaller icon</Alert>
|
|
55
|
+
* ```
|
|
44
56
|
*/
|
|
45
57
|
iconSize?: number;
|
|
46
58
|
|
|
47
59
|
/**
|
|
48
|
-
* Whether to hide the icon.
|
|
60
|
+
* Whether to hide the severity icon.
|
|
61
|
+
* When true, only text content is displayed.
|
|
62
|
+
* @default false
|
|
49
63
|
*/
|
|
50
64
|
hideIcon?: boolean;
|
|
51
65
|
|
|
52
66
|
/**
|
|
53
67
|
* Additional props to pass to the Icon component.
|
|
68
|
+
* Allows fine-grained control over icon appearance.
|
|
69
|
+
* @example
|
|
70
|
+
* ```tsx
|
|
71
|
+
* <Alert iconProps={{ className: 'custom-icon', 'aria-label': 'Custom' }}>
|
|
72
|
+
* Alert with custom icon props
|
|
73
|
+
* </Alert>
|
|
74
|
+
* ```
|
|
54
75
|
*/
|
|
55
76
|
iconProps?: IconProps;
|
|
56
|
-
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Duration in milliseconds before the alert automatically dismisses.
|
|
80
|
+
* Set to 0 or undefined to disable auto-dismiss.
|
|
81
|
+
* @default undefined
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* <Alert autoHideDuration={5000}>Success message</Alert>
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
autoHideDuration?: number;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Whether to pause auto-dismiss when the alert is hovered or focused.
|
|
91
|
+
* Complies with WCAG 2.2.1 (Timing Adjustable).
|
|
92
|
+
* @default true
|
|
93
|
+
*/
|
|
94
|
+
pauseOnHover?: boolean;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Semantic heading level for the title (2-6).
|
|
98
|
+
* When undefined, uses <strong> element instead of heading.
|
|
99
|
+
* Use this to maintain proper heading hierarchy on the page.
|
|
100
|
+
* @default undefined
|
|
101
|
+
* @example
|
|
102
|
+
* ```tsx
|
|
103
|
+
* <Alert titleLevel={2} title="Section Alert">...</Alert>
|
|
104
|
+
* <Alert titleLevel={3} title="Subsection Alert">...</Alert>
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
titleLevel?: 2 | 3 | 4 | 5 | 6;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Custom action buttons to display in the alert.
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* <Alert actions={<><Button>Undo</Button><Button>Dismiss</Button></>}>
|
|
114
|
+
* File deleted
|
|
115
|
+
* </Alert>
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
actions?: React.ReactNode;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Whether to automatically focus the alert when it becomes visible.
|
|
122
|
+
* Useful for critical alerts that require immediate attention.
|
|
123
|
+
* @default false
|
|
124
|
+
*/
|
|
125
|
+
autoFocus?: boolean;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Visual variant of the alert.
|
|
129
|
+
* - outlined: Border with lighter background (default)
|
|
130
|
+
* - filled: Solid colored background
|
|
131
|
+
* - soft: No border, subtle background
|
|
132
|
+
* @default "outlined"
|
|
133
|
+
*/
|
|
134
|
+
variant?: "outlined" | "filled" | "soft";
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Content rendering mode for alert children.
|
|
138
|
+
* Determines how the children content is wrapped in the alert message area.
|
|
139
|
+
* - "text": Wraps children in a paragraph tag (default, for simple text content)
|
|
140
|
+
* - "node": Renders children directly without wrapper (for complex layouts, lists, or custom components)
|
|
141
|
+
* @default "text"
|
|
142
|
+
* @example Simple text content (uses default "text" mode)
|
|
143
|
+
* ```tsx
|
|
144
|
+
* <Alert severity="info">
|
|
145
|
+
* This is a simple text message that will be wrapped in a paragraph.
|
|
146
|
+
* </Alert>
|
|
147
|
+
* ```
|
|
148
|
+
* @example Complex content with list
|
|
149
|
+
* ```tsx
|
|
150
|
+
* <Alert severity="warning" contentType="node">
|
|
151
|
+
* <p>Please review the following items:</p>
|
|
152
|
+
* <ul>
|
|
153
|
+
* <li>Check your email settings</li>
|
|
154
|
+
* <li>Update your password</li>
|
|
155
|
+
* <li>Enable two-factor authentication</li>
|
|
156
|
+
* </ul>
|
|
157
|
+
* </Alert>
|
|
158
|
+
* ```
|
|
159
|
+
* @example Custom component layout
|
|
160
|
+
* ```tsx
|
|
161
|
+
* <Alert severity="success" contentType="node">
|
|
162
|
+
* <div className="custom-layout">
|
|
163
|
+
* <p>Operation completed successfully!</p>
|
|
164
|
+
* <div className="stats">
|
|
165
|
+
* <span>Items processed: 150</span>
|
|
166
|
+
* <span>Time elapsed: 2.5s</span>
|
|
167
|
+
* </div>
|
|
168
|
+
* </div>
|
|
169
|
+
* </Alert>
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
contentType?: "text" | "node";
|
|
173
|
+
} & Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'children'>;
|
|
57
174
|
|
|
58
175
|
/**
|
|
59
|
-
* Alert is a
|
|
176
|
+
* Alert is a fully accessible component for displaying status messages with different severity levels.
|
|
60
177
|
* It supports multiple severity types (default, info, success, warning, error) and can include
|
|
61
178
|
* optional titles and dismissal functionality.
|
|
62
179
|
*
|
|
63
180
|
* Features:
|
|
64
181
|
* - Multiple severity levels with matching visual indicators
|
|
65
|
-
* -
|
|
182
|
+
* - Three variants: outlined (default), filled, and soft
|
|
183
|
+
* - Auto-dismiss with configurable duration and pause on hover/focus
|
|
184
|
+
* - Optional title with configurable heading levels (h2-h6) for proper document structure
|
|
185
|
+
* - Action buttons support for interactive alerts
|
|
66
186
|
* - Accessible by default with appropriate ARIA attributes
|
|
67
|
-
* -
|
|
187
|
+
* - Screen reader announcements for severity levels
|
|
188
|
+
* - Keyboard support (ESC to dismiss)
|
|
189
|
+
* - WCAG 2.1 Level AA compliant
|
|
190
|
+
*
|
|
191
|
+
* Accessibility Features:
|
|
192
|
+
* - Visually hidden severity text for screen readers (WCAG 1.1.1, 1.4.1)
|
|
193
|
+
* - Configurable heading levels to maintain document hierarchy (WCAG 1.3.1)
|
|
194
|
+
* - Visible focus indicators for keyboard navigation (WCAG 2.4.7)
|
|
195
|
+
* - Adequate color contrast for all variants (WCAG 1.4.3)
|
|
196
|
+
* - 44×44px minimum touch target size for dismiss button (WCAG 2.5.5)
|
|
197
|
+
* - Pause auto-dismiss on hover/focus (WCAG 2.2.1)
|
|
68
198
|
*
|
|
69
|
-
* @example
|
|
199
|
+
* @example Basic Usage
|
|
70
200
|
* ```tsx
|
|
71
201
|
* <Alert
|
|
72
202
|
* open={true}
|
|
@@ -79,9 +209,150 @@ export type AlertProps = {
|
|
|
79
209
|
* </Alert>
|
|
80
210
|
* ```
|
|
81
211
|
*
|
|
212
|
+
* @example With Heading Level (for proper document structure)
|
|
213
|
+
* ```tsx
|
|
214
|
+
* <Alert
|
|
215
|
+
* open={true}
|
|
216
|
+
* severity="error"
|
|
217
|
+
* title="Error Title"
|
|
218
|
+
* titleLevel={2}
|
|
219
|
+
* dismissible={true}
|
|
220
|
+
* >
|
|
221
|
+
* Error message
|
|
222
|
+
* </Alert>
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @example Auto-dismiss with Pause on Hover
|
|
226
|
+
* ```tsx
|
|
227
|
+
* <Alert
|
|
228
|
+
* open={true}
|
|
229
|
+
* severity="success"
|
|
230
|
+
* autoHideDuration={5000}
|
|
231
|
+
* pauseOnHover={true}
|
|
232
|
+
* >
|
|
233
|
+
* This will auto-dismiss in 5 seconds, but pauses when hovered
|
|
234
|
+
* </Alert>
|
|
235
|
+
* ```
|
|
236
|
+
*
|
|
82
237
|
* @see {@link AlertProps} for available configuration options
|
|
83
238
|
*/
|
|
84
239
|
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// CUSTOM HOOK (Behavior Management)
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Custom hook that manages all Alert component behavior in one cohesive unit.
|
|
246
|
+
* Consolidates visibility, auto-dismiss, keyboard, and focus management.
|
|
247
|
+
*
|
|
248
|
+
* @param open - Whether the alert should be open
|
|
249
|
+
* @param onDismiss - Callback when alert is dismissed
|
|
250
|
+
* @param dismissible - Whether the alert can be dismissed
|
|
251
|
+
* @param autoHideDuration - Duration before auto-dismiss (ms)
|
|
252
|
+
* @param pauseOnHover - Whether to pause auto-dismiss on hover/focus
|
|
253
|
+
* @param autoFocus - Whether to auto-focus the alert
|
|
254
|
+
* @param alertRef - Ref to the alert DOM element
|
|
255
|
+
* @returns Object with visibility state, handlers, and event callbacks
|
|
256
|
+
*/
|
|
257
|
+
const useAlertBehavior = ({
|
|
258
|
+
open,
|
|
259
|
+
onDismiss,
|
|
260
|
+
dismissible,
|
|
261
|
+
autoHideDuration,
|
|
262
|
+
pauseOnHover,
|
|
263
|
+
autoFocus,
|
|
264
|
+
alertRef,
|
|
265
|
+
}: {
|
|
266
|
+
open: boolean;
|
|
267
|
+
onDismiss?: () => void;
|
|
268
|
+
dismissible: boolean;
|
|
269
|
+
autoHideDuration?: number;
|
|
270
|
+
pauseOnHover: boolean;
|
|
271
|
+
autoFocus: boolean;
|
|
272
|
+
alertRef: React.RefObject<HTMLDivElement>;
|
|
273
|
+
}) => {
|
|
274
|
+
const [isVisible, setIsVisible] = React.useState(open);
|
|
275
|
+
const [shouldRender, setShouldRender] = React.useState(open);
|
|
276
|
+
const [isPaused, setIsPaused] = React.useState(false);
|
|
277
|
+
|
|
278
|
+
// Dismiss handler with animation timing
|
|
279
|
+
const handleDismiss = React.useCallback((): void => {
|
|
280
|
+
setIsVisible(false);
|
|
281
|
+
// Wait for animation to complete before unmounting
|
|
282
|
+
setTimeout(() => {
|
|
283
|
+
setShouldRender(false);
|
|
284
|
+
onDismiss?.();
|
|
285
|
+
}, 300); // Match CSS transition duration
|
|
286
|
+
}, [onDismiss]);
|
|
287
|
+
|
|
288
|
+
// Visibility management - sync with open prop
|
|
289
|
+
React.useEffect(() => {
|
|
290
|
+
if (open) {
|
|
291
|
+
setShouldRender(true);
|
|
292
|
+
setIsVisible(true);
|
|
293
|
+
} else {
|
|
294
|
+
setIsVisible(false);
|
|
295
|
+
}
|
|
296
|
+
}, [open]);
|
|
297
|
+
|
|
298
|
+
// Auto-dismiss timer with pause support
|
|
299
|
+
React.useEffect(() => {
|
|
300
|
+
if (!autoHideDuration || !isVisible || isPaused) return;
|
|
301
|
+
|
|
302
|
+
const timer = setTimeout(() => {
|
|
303
|
+
handleDismiss();
|
|
304
|
+
}, autoHideDuration);
|
|
305
|
+
|
|
306
|
+
return () => clearTimeout(timer);
|
|
307
|
+
}, [autoHideDuration, isVisible, isPaused, handleDismiss]);
|
|
308
|
+
|
|
309
|
+
// ESC key support for dismissible alerts
|
|
310
|
+
React.useEffect(() => {
|
|
311
|
+
if (!dismissible || !isVisible) return;
|
|
312
|
+
|
|
313
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
314
|
+
if (e.key === "Escape") {
|
|
315
|
+
handleDismiss();
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
320
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
321
|
+
}, [dismissible, isVisible, handleDismiss]);
|
|
322
|
+
|
|
323
|
+
// Auto-focus for critical alerts
|
|
324
|
+
React.useEffect(() => {
|
|
325
|
+
if (autoFocus && isVisible && alertRef.current) {
|
|
326
|
+
alertRef.current.focus();
|
|
327
|
+
}
|
|
328
|
+
}, [autoFocus, isVisible, alertRef]);
|
|
329
|
+
|
|
330
|
+
// Pause/resume handlers (memoized for stable references)
|
|
331
|
+
const pause = React.useCallback(() => {
|
|
332
|
+
if (pauseOnHover && autoHideDuration) {
|
|
333
|
+
setIsPaused(true);
|
|
334
|
+
}
|
|
335
|
+
}, [pauseOnHover, autoHideDuration]);
|
|
336
|
+
|
|
337
|
+
const resume = React.useCallback(() => {
|
|
338
|
+
if (pauseOnHover && autoHideDuration) {
|
|
339
|
+
setIsPaused(false);
|
|
340
|
+
}
|
|
341
|
+
}, [pauseOnHover, autoHideDuration]);
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
isVisible,
|
|
345
|
+
shouldRender,
|
|
346
|
+
handleDismiss,
|
|
347
|
+
handleInteractionStart: pause,
|
|
348
|
+
handleInteractionEnd: resume,
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// ============================================================================
|
|
353
|
+
// MAIN COMPONENT
|
|
354
|
+
// ============================================================================
|
|
355
|
+
|
|
85
356
|
const Alert: React.FC<AlertProps> = ({
|
|
86
357
|
open,
|
|
87
358
|
severity = "default",
|
|
@@ -92,70 +363,64 @@ const Alert: React.FC<AlertProps> = ({
|
|
|
92
363
|
iconSize,
|
|
93
364
|
iconProps,
|
|
94
365
|
hideIcon,
|
|
366
|
+
autoHideDuration,
|
|
367
|
+
pauseOnHover = true,
|
|
368
|
+
titleLevel = 3,
|
|
369
|
+
actions,
|
|
370
|
+
autoFocus = false,
|
|
371
|
+
variant = "outlined",
|
|
372
|
+
contentType = "text",
|
|
95
373
|
...props
|
|
96
374
|
}) => {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
React.useEffect(() => {
|
|
100
|
-
setIsVisible(open);
|
|
101
|
-
}, [open]);
|
|
102
|
-
|
|
103
|
-
if (!isVisible) return null;
|
|
375
|
+
const alertRef = React.useRef<HTMLDivElement>(null);
|
|
104
376
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
377
|
+
// Use consolidated behavior hook
|
|
378
|
+
const {
|
|
379
|
+
isVisible,
|
|
380
|
+
shouldRender,
|
|
381
|
+
handleDismiss,
|
|
382
|
+
handleInteractionStart,
|
|
383
|
+
handleInteractionEnd,
|
|
384
|
+
} = useAlertBehavior({
|
|
385
|
+
open,
|
|
386
|
+
onDismiss,
|
|
387
|
+
dismissible,
|
|
388
|
+
autoHideDuration,
|
|
389
|
+
pauseOnHover,
|
|
390
|
+
autoFocus,
|
|
391
|
+
alertRef,
|
|
392
|
+
});
|
|
109
393
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* These props set the fill color to white and the size to 32 pixels.
|
|
113
|
-
*/
|
|
114
|
-
const defaultIconProps: IconProps = {
|
|
115
|
-
size: iconSize || 32,
|
|
116
|
-
};
|
|
394
|
+
// Early return if component shouldn't render
|
|
395
|
+
if (!shouldRender) return null;
|
|
117
396
|
|
|
118
|
-
//
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
success: "polite",
|
|
123
|
-
warning: "polite",
|
|
124
|
-
error: "assertive",
|
|
125
|
-
} as const;
|
|
126
|
-
|
|
127
|
-
const mergedIconProps = { ...defaultIconProps, ...iconProps };
|
|
128
|
-
|
|
129
|
-
// Update the severityIcons object with the type
|
|
130
|
-
const severityIcons: Record<Severity, JSX.Element> = {
|
|
131
|
-
info: <Icon.InfoSolid {...mergedIconProps} />,
|
|
132
|
-
success: <Icon.SuccessSolid {...mergedIconProps} />,
|
|
133
|
-
warning: <Icon.WarnSolid {...mergedIconProps} />,
|
|
134
|
-
error: <Icon.AlertSolid {...mergedIconProps} />,
|
|
135
|
-
default: <Icon.AlertSquareSolid {...mergedIconProps} />,
|
|
397
|
+
// Merge icon props with defaults
|
|
398
|
+
const mergedIconProps: IconProps = {
|
|
399
|
+
size: iconSize || 16,
|
|
400
|
+
...iconProps,
|
|
136
401
|
};
|
|
137
402
|
|
|
138
403
|
return (
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
404
|
+
<AlertView
|
|
405
|
+
ref={alertRef}
|
|
406
|
+
severity={severity}
|
|
407
|
+
variant={variant}
|
|
408
|
+
isVisible={isVisible}
|
|
409
|
+
dismissible={dismissible}
|
|
410
|
+
onDismiss={handleDismiss}
|
|
411
|
+
onInteractionStart={handleInteractionStart}
|
|
412
|
+
onInteractionEnd={handleInteractionEnd}
|
|
413
|
+
autoFocus={autoFocus}
|
|
414
|
+
title={title}
|
|
415
|
+
titleLevel={titleLevel}
|
|
416
|
+
contentType={contentType}
|
|
417
|
+
actions={actions}
|
|
418
|
+
hideIcon={hideIcon}
|
|
419
|
+
iconProps={mergedIconProps}
|
|
146
420
|
{...props}
|
|
147
421
|
>
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
{title && (
|
|
151
|
-
<UI as="h3" className="alert-title">
|
|
152
|
-
{title}
|
|
153
|
-
</UI>
|
|
154
|
-
)}
|
|
155
|
-
<UI as="div">{children}</UI>
|
|
156
|
-
</UI>
|
|
157
|
-
{dismissible && <DismissButton onDismiss={handleDismiss} />}
|
|
158
|
-
</UI>
|
|
422
|
+
{children}
|
|
423
|
+
</AlertView>
|
|
159
424
|
);
|
|
160
425
|
};
|
|
161
426
|
export default Alert;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Renders optional action buttons within the alert.
|
|
6
|
+
*
|
|
7
|
+
* @param actions - Action button elements to display
|
|
8
|
+
* @returns Actions container, or null if no actions provided
|
|
9
|
+
*/
|
|
10
|
+
export const AlertActions: React.FC<{ actions?: React.ReactNode }> = ({ actions }) => {
|
|
11
|
+
if (!actions) return null;
|
|
12
|
+
return <UI as="div" className="alert-actions">{actions}</UI>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Renders the alert message content.
|
|
6
|
+
* Supports both simple text (wrapped in <p>) and complex node structures.
|
|
7
|
+
*
|
|
8
|
+
* @param children - The content to render
|
|
9
|
+
* @param contentType - How to wrap the content ("text" or "node")
|
|
10
|
+
* @returns Wrapped content
|
|
11
|
+
*/
|
|
12
|
+
export const AlertContent: React.FC<{
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
contentType: "text" | "node";
|
|
15
|
+
}> = ({ children, contentType }) => {
|
|
16
|
+
return contentType === "node" ? <>{children}</> : <UI as="p">{children}</UI>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
import Icon from "#components/icons/icon";
|
|
4
|
+
import { IconProps } from "#components/icons/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Valid severity levels for alerts.
|
|
8
|
+
*/
|
|
9
|
+
type Severity = "default" | "info" | "success" | "warning" | "error";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pure function to get the appropriate icon for a severity level.
|
|
13
|
+
*
|
|
14
|
+
* @param severity - The alert severity level
|
|
15
|
+
* @param iconProps - Props to pass to the Icon component
|
|
16
|
+
* @returns The icon element for the severity
|
|
17
|
+
*/
|
|
18
|
+
const getSeverityIcon = (
|
|
19
|
+
severity: Severity,
|
|
20
|
+
iconProps: IconProps
|
|
21
|
+
): JSX.Element => {
|
|
22
|
+
const severityIcons: Record<Severity, JSX.Element> = {
|
|
23
|
+
info: <Icon.InfoSolid {...iconProps} />,
|
|
24
|
+
success: <Icon.SuccessSolid {...iconProps} />,
|
|
25
|
+
warning: <Icon.WarnSolid {...iconProps} />,
|
|
26
|
+
error: <Icon.AlertSolid {...iconProps} />,
|
|
27
|
+
default: <Icon.AlertSquareSolid {...iconProps} />,
|
|
28
|
+
};
|
|
29
|
+
return severityIcons[severity];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Renders the severity icon with proper ARIA attributes.
|
|
34
|
+
* Icon is hidden from screen readers as the text provides context.
|
|
35
|
+
*
|
|
36
|
+
* @param severity - The alert severity level
|
|
37
|
+
* @param iconProps - Props to pass to the Icon component
|
|
38
|
+
* @param hideIcon - Whether to hide the icon
|
|
39
|
+
* @returns Icon element, or null if hidden
|
|
40
|
+
*/
|
|
41
|
+
export const AlertIcon: React.FC<{
|
|
42
|
+
severity: Severity;
|
|
43
|
+
iconProps: IconProps;
|
|
44
|
+
hideIcon?: boolean;
|
|
45
|
+
}> = ({ severity, iconProps, hideIcon }) => {
|
|
46
|
+
if (hideIcon) return null;
|
|
47
|
+
const icon = getSeverityIcon(severity, iconProps);
|
|
48
|
+
return (
|
|
49
|
+
<UI aria-hidden="true" className="alert-icon">
|
|
50
|
+
{icon}
|
|
51
|
+
</UI>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Valid severity levels for alerts.
|
|
5
|
+
*/
|
|
6
|
+
type Severity = "default" | "info" | "success" | "warning" | "error";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Screen reader announcement text for each severity level.
|
|
10
|
+
*/
|
|
11
|
+
const SEVERITY_SCREEN_READER_TEXT: Record<Severity, string> = {
|
|
12
|
+
default: "",
|
|
13
|
+
info: "Information: ",
|
|
14
|
+
success: "Success: ",
|
|
15
|
+
warning: "Warning: ",
|
|
16
|
+
error: "Error: ",
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Renders visually hidden severity text for screen readers.
|
|
21
|
+
* Provides context about the alert type without visual clutter.
|
|
22
|
+
*
|
|
23
|
+
* @param severity - The alert severity level
|
|
24
|
+
* @returns Hidden text for screen readers, or null if no text needed
|
|
25
|
+
*/
|
|
26
|
+
export const AlertScreenReaderText: React.FC<{ severity: Severity }> = ({ severity }) => {
|
|
27
|
+
const text = SEVERITY_SCREEN_READER_TEXT[severity];
|
|
28
|
+
if (!text) return null;
|
|
29
|
+
return <span className="sr-only">{text}</span>;
|
|
30
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Renders the alert title with configurable heading level.
|
|
6
|
+
* Uses semantic heading (h2-h6) or strong element based on titleLevel prop.
|
|
7
|
+
*
|
|
8
|
+
* @param title - The title text to display
|
|
9
|
+
* @param titleLevel - Semantic heading level (2-6)
|
|
10
|
+
* @returns Title element, or null if no title provided
|
|
11
|
+
*/
|
|
12
|
+
export const AlertTitle: React.FC<{
|
|
13
|
+
title?: string;
|
|
14
|
+
titleLevel: 2 | 3 | 4 | 5 | 6;
|
|
15
|
+
}> = ({ title, titleLevel }) => {
|
|
16
|
+
if (!title) return null;
|
|
17
|
+
const TitleElement = titleLevel ? (`h${titleLevel}` as const) : "strong";
|
|
18
|
+
return (
|
|
19
|
+
<UI as={TitleElement} className="alert-title">
|
|
20
|
+
{title}
|
|
21
|
+
</UI>
|
|
22
|
+
);
|
|
23
|
+
};
|