@fpkit/acss 0.5.12 → 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 +89 -0
- package/libs/{chunk-DV56L5YX.cjs → chunk-2LTJ7HHX.cjs} +4 -4
- package/libs/{chunk-EQ67LF46.js → chunk-2Y7W75TT.js} +3 -3
- package/libs/{chunk-KKLTUJFB.cjs → chunk-3MKLDCKQ.cjs} +5 -5
- package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
- package/libs/{chunk-X3EVB7VS.cjs → chunk-5S4ORA4C.cjs} +3 -3
- package/libs/{chunk-O6QZBB6G.js → chunk-772NRB75.js} +5 -5
- package/libs/chunk-772NRB75.js.map +1 -0
- package/libs/{chunk-6BVXFW7U.cjs → chunk-AHDJGCG5.cjs} +3 -3
- package/libs/{chunk-E3XP6BEX.cjs → chunk-B7F5FS6D.cjs} +3 -3
- 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-GZ4QFPRY.js +9 -0
- package/libs/chunk-GZ4QFPRY.js.map +1 -0
- package/libs/{chunk-LHVJKDMA.cjs → chunk-J32EZPYD.cjs} +3 -3
- 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-LL7HTLMS.cjs → chunk-M5RRNTVX.cjs} +3 -3
- package/libs/{chunk-LIQJ7ZZR.js → chunk-NGTJDDFO.js} +2 -2
- 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-PQ2K3BM6.cjs +17 -0
- package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
- package/libs/{chunk-QCMV4VQZ.js → chunk-QLZWHAMK.js} +2 -2
- package/libs/{chunk-BIP2NY53.js → chunk-RIVUMPOG.js} +2 -2
- package/libs/{chunk-ICCKQ2GC.cjs → chunk-ROZI23GS.cjs} +4 -4
- package/libs/{chunk-NHYXGV3L.js → chunk-SMYRLO3E.js} +2 -2
- package/libs/{chunk-5ZM4XL44.js → chunk-TYRCEX2L.js} +2 -2
- package/libs/chunk-VUH3FXGJ.js +11 -0
- package/libs/chunk-VUH3FXGJ.js.map +1 -0
- package/libs/{chunk-PPOOBUOS.js → chunk-XBA562WW.js} +2 -2
- package/libs/{chunk-QVV34QEH.cjs → chunk-XTQKWY7W.cjs} +3 -3
- package/libs/{chunk-YWOYVRFT.js → chunk-ZANSFMTD.js} +3 -3
- 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 +9 -5
- package/libs/components/breadcrumbs/breadcrumb.d.cts +271 -32
- package/libs/components/breadcrumbs/breadcrumb.d.ts +271 -32
- package/libs/components/breadcrumbs/breadcrumb.js +3 -3
- package/libs/components/button.cjs +4 -4
- package/libs/components/button.d.cts +2 -2
- package/libs/components/button.d.ts +2 -2
- package/libs/components/button.js +2 -2
- 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 +7 -7
- package/libs/components/card.d.cts +277 -33
- package/libs/components/card.d.ts +277 -33
- package/libs/components/card.js +2 -2
- 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 +7 -7
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.d.cts +88 -34
- package/libs/components/dialog/dialog.d.ts +88 -34
- package/libs/components/dialog/dialog.js +5 -5
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/fields.cjs +4 -4
- package/libs/components/form/fields.d.cts +2 -2
- package/libs/components/form/fields.d.ts +2 -2
- package/libs/components/form/fields.js +2 -2
- package/libs/components/form/textarea.cjs +4 -4
- package/libs/components/form/textarea.d.cts +2 -2
- package/libs/components/form/textarea.d.ts +2 -2
- package/libs/components/form/textarea.js +2 -2
- package/libs/components/heading/heading.cjs +3 -3
- package/libs/components/heading/heading.d.cts +3 -14
- package/libs/components/heading/heading.d.ts +3 -14
- package/libs/components/heading/heading.js +2 -2
- package/libs/components/icons/icon.cjs +4 -4
- package/libs/components/icons/icon.d.cts +148 -4
- package/libs/components/icons/icon.d.ts +148 -4
- package/libs/components/icons/icon.js +2 -2
- 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 +4 -4
- package/libs/components/link/link.d.cts +2 -2
- package/libs/components/link/link.d.ts +2 -2
- package/libs/components/link/link.js +2 -2
- package/libs/components/list/list.cjs +5 -5
- package/libs/components/list/list.d.cts +3 -3
- package/libs/components/list/list.d.ts +3 -3
- package/libs/components/list/list.js +2 -2
- package/libs/components/modal.cjs +4 -4
- package/libs/components/modal.js +3 -3
- package/libs/components/nav/nav.cjs +7 -7
- package/libs/components/nav/nav.d.cts +2 -2
- package/libs/components/nav/nav.d.ts +2 -2
- package/libs/components/nav/nav.js +3 -3
- package/libs/components/text/text.cjs +5 -5
- package/libs/components/text/text.d.cts +2 -2
- package/libs/components/text/text.d.ts +2 -2
- package/libs/components/text/text.js +2 -2
- 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 -3
- package/libs/icons.d.cts +1 -1
- package/libs/icons.d.ts +1 -1
- package/libs/icons.js +2 -2
- package/libs/index.cjs +112 -91
- 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 +515 -31
- package/libs/index.d.ts +515 -31
- package/libs/index.js +31 -19
- package/libs/index.js.map +1 -1
- package/libs/ui-645f95b5.d.ts +285 -0
- package/package.json +2 -83
- 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/buttons/button.scss +34 -31
- package/src/components/buttons/button.stories.tsx +35 -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 -7
- 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/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 +10 -2
- 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 -8
- 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 -51
- 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-6TE5QEVE.cjs +0 -13
- package/libs/chunk-6TE5QEVE.cjs.map +0 -1
- package/libs/chunk-7K76RW2A.cjs +0 -18
- package/libs/chunk-7K76RW2A.cjs.map +0 -1
- package/libs/chunk-BSPKFLO4.js +0 -8
- package/libs/chunk-BSPKFLO4.js.map +0 -1
- package/libs/chunk-BV5CLH44.cjs +0 -18
- package/libs/chunk-BV5CLH44.cjs.map +0 -1
- package/libs/chunk-DKGJHKGW.js +0 -9
- package/libs/chunk-DKGJHKGW.js.map +0 -1
- package/libs/chunk-ECLD37WN.cjs +0 -16
- package/libs/chunk-ECLD37WN.cjs.map +0 -1
- package/libs/chunk-HYBZBN4G.js +0 -8
- package/libs/chunk-HYBZBN4G.js.map +0 -1
- package/libs/chunk-KKLTUJFB.cjs.map +0 -1
- package/libs/chunk-M5QL5TAE.cjs +0 -14
- package/libs/chunk-M5QL5TAE.cjs.map +0 -1
- package/libs/chunk-NE6YXTMC.js +0 -7
- package/libs/chunk-NE6YXTMC.js.map +0 -1
- package/libs/chunk-O6QZBB6G.js.map +0 -1
- package/libs/chunk-SXVZSWX6.js +0 -11
- package/libs/chunk-SXVZSWX6.js.map +0 -1
- package/libs/ui-9a6f9f8d.d.ts +0 -24
- package/src/components/cards/README.md +0 -80
- package/src/components/dialog/hooks/useClickOutside.ts +0 -33
- /package/libs/{chunk-DV56L5YX.cjs.map → chunk-2LTJ7HHX.cjs.map} +0 -0
- /package/libs/{chunk-EQ67LF46.js.map → chunk-2Y7W75TT.js.map} +0 -0
- /package/libs/{chunk-X3EVB7VS.cjs.map → chunk-5S4ORA4C.cjs.map} +0 -0
- /package/libs/{chunk-6BVXFW7U.cjs.map → chunk-AHDJGCG5.cjs.map} +0 -0
- /package/libs/{chunk-E3XP6BEX.cjs.map → chunk-B7F5FS6D.cjs.map} +0 -0
- /package/libs/{chunk-LHVJKDMA.cjs.map → chunk-J32EZPYD.cjs.map} +0 -0
- /package/libs/{chunk-LL7HTLMS.cjs.map → chunk-M5RRNTVX.cjs.map} +0 -0
- /package/libs/{chunk-LIQJ7ZZR.js.map → chunk-NGTJDDFO.js.map} +0 -0
- /package/libs/{chunk-QCMV4VQZ.js.map → chunk-QLZWHAMK.js.map} +0 -0
- /package/libs/{chunk-BIP2NY53.js.map → chunk-RIVUMPOG.js.map} +0 -0
- /package/libs/{chunk-ICCKQ2GC.cjs.map → chunk-ROZI23GS.cjs.map} +0 -0
- /package/libs/{chunk-NHYXGV3L.js.map → chunk-SMYRLO3E.js.map} +0 -0
- /package/libs/{chunk-5ZM4XL44.js.map → chunk-TYRCEX2L.js.map} +0 -0
- /package/libs/{chunk-PPOOBUOS.js.map → chunk-XBA562WW.js.map} +0 -0
- /package/libs/{chunk-QVV34QEH.cjs.map → chunk-XTQKWY7W.cjs.map} +0 -0
- /package/libs/{chunk-YWOYVRFT.js.map → chunk-ZANSFMTD.js.map} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
import { IconProps } from "#components/icons/types";
|
|
4
|
+
import DismissButton from "../elements/dismiss-button";
|
|
5
|
+
import {
|
|
6
|
+
AlertScreenReaderText,
|
|
7
|
+
AlertIcon,
|
|
8
|
+
AlertTitle,
|
|
9
|
+
AlertContent,
|
|
10
|
+
AlertActions,
|
|
11
|
+
} from ".";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Valid severity levels for alerts.
|
|
15
|
+
*/
|
|
16
|
+
type Severity = "default" | "info" | "success" | "warning" | "error";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Maps severity levels to ARIA live region types.
|
|
20
|
+
*/
|
|
21
|
+
const SEVERITY_ARIA_LIVE: Record<Severity, "polite" | "assertive"> = {
|
|
22
|
+
default: "polite",
|
|
23
|
+
info: "polite",
|
|
24
|
+
success: "polite",
|
|
25
|
+
warning: "polite",
|
|
26
|
+
error: "assertive",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Props for the AlertView presentation component.
|
|
31
|
+
*/
|
|
32
|
+
export type AlertViewProps = {
|
|
33
|
+
/**
|
|
34
|
+
* The severity level of the alert.
|
|
35
|
+
*/
|
|
36
|
+
severity: Severity;
|
|
37
|
+
/**
|
|
38
|
+
* Visual variant of the alert.
|
|
39
|
+
*/
|
|
40
|
+
variant: "outlined" | "filled" | "soft";
|
|
41
|
+
/**
|
|
42
|
+
* Whether the alert is currently visible (for animations).
|
|
43
|
+
*/
|
|
44
|
+
isVisible: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the alert can be dismissed.
|
|
47
|
+
*/
|
|
48
|
+
dismissible: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Callback when dismiss button is clicked.
|
|
51
|
+
*/
|
|
52
|
+
onDismiss: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Handler for interaction start (hover/focus).
|
|
55
|
+
*/
|
|
56
|
+
onInteractionStart: () => void;
|
|
57
|
+
/**
|
|
58
|
+
* Handler for interaction end (leave/blur).
|
|
59
|
+
*/
|
|
60
|
+
onInteractionEnd: () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Whether to automatically focus the alert.
|
|
63
|
+
*/
|
|
64
|
+
autoFocus: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Optional title for the alert.
|
|
67
|
+
*/
|
|
68
|
+
title?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Semantic heading level for the title (2-6).
|
|
71
|
+
*/
|
|
72
|
+
titleLevel: 2 | 3 | 4 | 5 | 6;
|
|
73
|
+
/**
|
|
74
|
+
* The main message content.
|
|
75
|
+
*/
|
|
76
|
+
children: React.ReactNode;
|
|
77
|
+
/**
|
|
78
|
+
* Content rendering mode for alert children.
|
|
79
|
+
*/
|
|
80
|
+
contentType: "text" | "node";
|
|
81
|
+
/**
|
|
82
|
+
* Custom action buttons to display in the alert.
|
|
83
|
+
*/
|
|
84
|
+
actions?: React.ReactNode;
|
|
85
|
+
/**
|
|
86
|
+
* Whether to hide the severity icon.
|
|
87
|
+
*/
|
|
88
|
+
hideIcon?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Merged props for the Icon component.
|
|
91
|
+
*/
|
|
92
|
+
iconProps: IconProps;
|
|
93
|
+
} & React.ComponentProps<typeof UI>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* AlertView is a pure presentation component that renders the Alert UI structure.
|
|
97
|
+
* It receives all presentation props and behavior handlers from the parent Alert component.
|
|
98
|
+
*
|
|
99
|
+
* This component is focused solely on rendering the visual structure and does not contain
|
|
100
|
+
* any business logic or state management. All behavior is delegated to the parent.
|
|
101
|
+
*
|
|
102
|
+
* @param props - AlertView props including severity, variant, handlers, and content
|
|
103
|
+
* @returns The rendered alert UI structure
|
|
104
|
+
*/
|
|
105
|
+
export const AlertView = React.forwardRef<HTMLDivElement, AlertViewProps>(
|
|
106
|
+
(
|
|
107
|
+
{
|
|
108
|
+
severity,
|
|
109
|
+
variant,
|
|
110
|
+
isVisible,
|
|
111
|
+
dismissible,
|
|
112
|
+
onDismiss,
|
|
113
|
+
onInteractionStart,
|
|
114
|
+
onInteractionEnd,
|
|
115
|
+
autoFocus,
|
|
116
|
+
title,
|
|
117
|
+
titleLevel,
|
|
118
|
+
children,
|
|
119
|
+
contentType,
|
|
120
|
+
actions,
|
|
121
|
+
hideIcon,
|
|
122
|
+
iconProps,
|
|
123
|
+
...props
|
|
124
|
+
},
|
|
125
|
+
ref
|
|
126
|
+
) => {
|
|
127
|
+
return (
|
|
128
|
+
<UI
|
|
129
|
+
as="div"
|
|
130
|
+
ref={ref}
|
|
131
|
+
role="alert"
|
|
132
|
+
aria-live={SEVERITY_ARIA_LIVE[severity]}
|
|
133
|
+
aria-atomic="true"
|
|
134
|
+
className={`alert alert-${severity}`}
|
|
135
|
+
data-alert={severity}
|
|
136
|
+
data-visible={isVisible}
|
|
137
|
+
data-variant={variant}
|
|
138
|
+
tabIndex={autoFocus ? -1 : undefined}
|
|
139
|
+
onMouseEnter={onInteractionStart}
|
|
140
|
+
onMouseLeave={onInteractionEnd}
|
|
141
|
+
onFocus={onInteractionStart}
|
|
142
|
+
onBlur={onInteractionEnd}
|
|
143
|
+
{...props}
|
|
144
|
+
>
|
|
145
|
+
<AlertScreenReaderText severity={severity} />
|
|
146
|
+
<AlertIcon severity={severity} iconProps={iconProps} hideIcon={hideIcon} />
|
|
147
|
+
<UI as="div" className="alert-message">
|
|
148
|
+
<AlertTitle title={title} titleLevel={titleLevel} />
|
|
149
|
+
<AlertContent contentType={contentType}>{children}</AlertContent>
|
|
150
|
+
<AlertActions actions={actions} />
|
|
151
|
+
</UI>
|
|
152
|
+
{dismissible && <DismissButton onDismiss={onDismiss} />}
|
|
153
|
+
</UI>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
AlertView.displayName = "AlertView";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert view components - focused UI presentation components.
|
|
3
|
+
* Each component handles a single visual concern of the Alert.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { AlertScreenReaderText } from "./alert-screen-reader-text";
|
|
7
|
+
export { AlertIcon } from "./alert-icon";
|
|
8
|
+
export { AlertTitle } from "./alert-title";
|
|
9
|
+
export { AlertContent } from "./alert-content";
|
|
10
|
+
export { AlertActions } from "./alert-actions";
|
|
11
|
+
export { AlertView } from "./alert-view";
|
|
12
|
+
export type { AlertViewProps } from "./alert-view";
|
|
@@ -6,59 +6,103 @@ import { Meta } from "@storybook/addon-docs/blocks";
|
|
|
6
6
|
|
|
7
7
|
A lightweight and flexible badge component for displaying small counts, labels,
|
|
8
8
|
or status indicators. The Badge component renders as a superscript element with
|
|
9
|
-
customizable styling.
|
|
9
|
+
customizable styling and comprehensive accessibility features.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- Renders as a `<sup>` element with nested `<span>`
|
|
13
|
+
- Renders as a `<sup>` element with nested `<span>` for proper styling architecture
|
|
14
14
|
- Fully customizable via CSS custom properties
|
|
15
|
-
- Supports rounded
|
|
16
|
-
-
|
|
15
|
+
- Supports `rounded` variant for perfect circular badges
|
|
16
|
+
- Auto-scaling with fixed dimensions for rounded badges (1.5625rem)
|
|
17
|
+
- Content truncation with ellipsis for overflow text
|
|
18
|
+
- ARIA-friendly with `role="status"` for live region announcements
|
|
19
|
+
- Built-in accessibility support with aria-label prop
|
|
17
20
|
- Integrates with FPKit UI component system
|
|
21
|
+
- Comprehensive TypeScript support with full JSDoc documentation
|
|
18
22
|
|
|
19
23
|
## Props
|
|
20
24
|
|
|
21
|
-
The Badge component accepts the following props:
|
|
25
|
+
The Badge component accepts the following props (extends `BadgeProps`):
|
|
22
26
|
|
|
23
|
-
- `children
|
|
24
|
-
- `id?: string` - Optional
|
|
25
|
-
- `styles?:
|
|
26
|
-
- `classes?: string` -
|
|
27
|
-
- `
|
|
27
|
+
- `children?: React.ReactNode` - Content to display inside the badge (typically numbers or short text)
|
|
28
|
+
- `id?: string` - Optional HTML id attribute for the badge element
|
|
29
|
+
- `styles?: React.CSSProperties` - Inline styles to apply to the badge
|
|
30
|
+
- `classes?: string` - CSS class names to apply to the badge
|
|
31
|
+
- `variant?: 'rounded'` - Visual variant of the badge. Use 'rounded' for circular badges with fixed size
|
|
32
|
+
- `aria-label?: string` - Accessible label for screen readers (required for icon-only or number-only badges)
|
|
33
|
+
- `role?: 'status' | 'note'` - ARIA role for the badge (defaults to 'status' for dynamic content)
|
|
28
34
|
- All standard HTML attributes supported by `<sup>` element
|
|
29
35
|
|
|
30
36
|
## Technical Details
|
|
31
37
|
|
|
32
|
-
- Built using React functional components
|
|
33
|
-
- Uses TypeScript for
|
|
34
|
-
- Styled with CSS custom properties
|
|
38
|
+
- Built using React functional components with TypeScript
|
|
39
|
+
- Uses TypeScript with comprehensive JSDoc comments for enhanced IDE support
|
|
40
|
+
- Styled with SCSS/CSS custom properties (units in rem)
|
|
35
41
|
- Leverages base UI component from FPKit
|
|
42
|
+
- Exports `BadgeProps` type for external usage
|
|
43
|
+
- Component display name: 'Badge'
|
|
36
44
|
|
|
37
|
-
##
|
|
45
|
+
## Styling Architecture
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
The Badge uses a **nested structure** (`<sup><span>content</span></sup>`) which is required
|
|
48
|
+
for the SCSS styling system:
|
|
49
|
+
|
|
50
|
+
- **Outer `<sup>` element**: Provides positioning context and base styling
|
|
51
|
+
- **Inner `<span>` element**: Receives visual styling (background, padding, border-radius)
|
|
52
|
+
|
|
53
|
+
This architecture ensures proper styling isolation and allows the badge to work correctly
|
|
54
|
+
when positioned alongside other content.
|
|
55
|
+
|
|
56
|
+
## Rounded Variant Behavior
|
|
57
|
+
|
|
58
|
+
The `rounded` variant creates a **perfect circular badge** with fixed dimensions (1.5625rem).
|
|
59
|
+
Key characteristics:
|
|
60
|
+
|
|
61
|
+
- **Fixed size**: 1.5625rem × 1.5625rem (25px × 25px at base font size)
|
|
62
|
+
- **Perfect circle**: 50% border-radius
|
|
63
|
+
- **Content overflow**: Text exceeding available space is truncated with clip (no ellipsis visible)
|
|
64
|
+
- **Font weight**: Bold (700) for better readability
|
|
65
|
+
- **Font size**: 0.6875rem (11px at base font size)
|
|
66
|
+
|
|
67
|
+
### Best Practices for Rounded Badges
|
|
68
|
+
|
|
69
|
+
✅ **GOOD**: Format large numbers yourself
|
|
70
|
+
```tsx
|
|
71
|
+
<Badge variant="rounded" aria-label="More than 99 notifications">99+</Badge>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
❌ **BAD**: Let unformatted numbers overflow
|
|
75
|
+
```tsx
|
|
76
|
+
<Badge variant="rounded">999</Badge> {/* Will be truncated */}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Usage Examples
|
|
80
|
+
|
|
81
|
+
### Basic Usage with Accessibility
|
|
40
82
|
|
|
41
83
|
```tsx
|
|
42
|
-
import Badge from "
|
|
84
|
+
import { Badge } from "@fpkit/acss";
|
|
43
85
|
|
|
44
86
|
function Example() {
|
|
45
87
|
return (
|
|
46
88
|
<p>
|
|
47
|
-
Messages
|
|
89
|
+
Messages
|
|
90
|
+
<Badge aria-label="3 unread messages">3</Badge>
|
|
48
91
|
</p>
|
|
49
92
|
);
|
|
50
93
|
}
|
|
51
94
|
```
|
|
52
95
|
|
|
53
|
-
### Rounded Badge
|
|
96
|
+
### Rounded Badge Variant
|
|
54
97
|
|
|
55
98
|
```tsx
|
|
56
|
-
import Badge from "
|
|
99
|
+
import { Badge } from "@fpkit/acss";
|
|
57
100
|
|
|
58
101
|
function Example() {
|
|
59
102
|
return (
|
|
60
103
|
<p>
|
|
61
|
-
|
|
104
|
+
Notifications
|
|
105
|
+
<Badge variant="rounded" aria-label="99 or more notifications">99+</Badge>
|
|
62
106
|
</p>
|
|
63
107
|
);
|
|
64
108
|
}
|
|
@@ -67,58 +111,151 @@ function Example() {
|
|
|
67
111
|
### Custom Styled Badge
|
|
68
112
|
|
|
69
113
|
```tsx
|
|
70
|
-
import Badge from "
|
|
114
|
+
import { Badge } from "@fpkit/acss";
|
|
71
115
|
|
|
72
116
|
function Example() {
|
|
73
117
|
return (
|
|
74
118
|
<p>
|
|
75
|
-
|
|
119
|
+
Active Users
|
|
76
120
|
<Badge
|
|
77
|
-
styles={{
|
|
78
|
-
|
|
79
|
-
"--badge-color": "white",
|
|
80
|
-
}}
|
|
81
|
-
aria-label="badge count"
|
|
121
|
+
styles={{ backgroundColor: "green", color: "white" }}
|
|
122
|
+
aria-label="21 active users"
|
|
82
123
|
>
|
|
83
|
-
|
|
124
|
+
21
|
|
84
125
|
</Badge>
|
|
85
126
|
</p>
|
|
86
127
|
);
|
|
87
128
|
}
|
|
88
129
|
```
|
|
89
130
|
|
|
131
|
+
### Multiple Badges
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { Badge } from "@fpkit/acss";
|
|
135
|
+
|
|
136
|
+
function Dashboard() {
|
|
137
|
+
return (
|
|
138
|
+
<div>
|
|
139
|
+
<p>
|
|
140
|
+
Inbox
|
|
141
|
+
<Badge variant="rounded" aria-label="12 unread emails">12</Badge>
|
|
142
|
+
</p>
|
|
143
|
+
<p>
|
|
144
|
+
Tasks
|
|
145
|
+
<Badge variant="rounded" aria-label="5 pending tasks">5</Badge>
|
|
146
|
+
</p>
|
|
147
|
+
<p>
|
|
148
|
+
Alerts
|
|
149
|
+
<Badge variant="rounded" aria-label="1 new alert">1</Badge>
|
|
150
|
+
</p>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
90
156
|
## Styling
|
|
91
157
|
|
|
92
|
-
The component uses CSS custom properties for
|
|
158
|
+
The component uses CSS custom properties for full customization:
|
|
159
|
+
|
|
160
|
+
### Standard Badge CSS Variables
|
|
93
161
|
|
|
94
162
|
```css
|
|
95
|
-
--badge-bg: lightgray;
|
|
96
|
-
--badge-color: currentColor;
|
|
97
|
-
--badge-radius: 0.5rem;
|
|
98
|
-
--badge-padding: 0.3rem;
|
|
99
|
-
--badge-v-align: 0.5rem;
|
|
100
|
-
--badge-fs: var(--fs-1);
|
|
163
|
+
--badge-bg: lightgray; /* Background color */
|
|
164
|
+
--badge-color: currentColor; /* Text color */
|
|
165
|
+
--badge-radius: 0.5rem; /* Border radius */
|
|
166
|
+
--badge-padding: 0.3rem; /* Inner padding */
|
|
167
|
+
--badge-v-align: 0.5rem; /* Vertical alignment */
|
|
168
|
+
--badge-fs: var(--fs-1); /* Font size */
|
|
101
169
|
```
|
|
102
170
|
|
|
103
|
-
|
|
171
|
+
### Rounded Badge CSS Variables
|
|
172
|
+
|
|
173
|
+
When using `variant="rounded"`, these additional variables are set:
|
|
104
174
|
|
|
105
175
|
```css
|
|
106
|
-
--badge-radius:
|
|
107
|
-
--badge-padding: 0
|
|
176
|
+
--badge-radius: 50%; /* Perfect circle */
|
|
177
|
+
--badge-padding: 0; /* No padding (uses width/height instead) */
|
|
178
|
+
--badge-size: 1.5625rem; /* Fixed dimensions for circle */
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Customizing Badge Styles
|
|
182
|
+
|
|
183
|
+
You can override CSS variables using inline styles:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<Badge
|
|
187
|
+
styles={{
|
|
188
|
+
"--badge-bg": "#3b82f6",
|
|
189
|
+
"--badge-color": "white",
|
|
190
|
+
"--badge-padding": "0.5rem",
|
|
191
|
+
} as React.CSSProperties}
|
|
192
|
+
>
|
|
193
|
+
Custom
|
|
194
|
+
</Badge>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Or using standard CSS properties:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
<Badge styles={{ backgroundColor: "#10b981", color: "white" }}>
|
|
201
|
+
NEW
|
|
202
|
+
</Badge>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Accessibility Features
|
|
206
|
+
|
|
207
|
+
The Badge component follows WCAG 2.1 Level AA guidelines and includes:
|
|
208
|
+
|
|
209
|
+
### Built-in Accessibility
|
|
210
|
+
|
|
211
|
+
- **Semantic HTML**: Uses `<sup>` element for proper positioning context
|
|
212
|
+
- **ARIA Role**: Defaults to `role="status"` for dynamic content, making it a live region
|
|
213
|
+
- **Live Regions**: Screen readers automatically announce changes to badge content
|
|
214
|
+
- **Accessible Names**: `aria-label` prop provides context for screen readers
|
|
215
|
+
|
|
216
|
+
### WCAG 2.1 Compliance
|
|
217
|
+
|
|
218
|
+
- **1.4.3 Contrast (Minimum)**: Ensures sufficient color contrast with customizable colors
|
|
219
|
+
- **1.4.4 Resize Text**: Supports text resizing up to 200% using rem units
|
|
220
|
+
- **1.4.12 Text Spacing**: Maintains proper spacing on zoom and text spacing adjustments
|
|
221
|
+
- **4.1.1 Parsing**: Uses semantic HTML elements (`<sup>`, `<span>`)
|
|
222
|
+
- **4.1.2 Name, Role, Value**: Provides meaningful ARIA labels and roles
|
|
223
|
+
|
|
224
|
+
### Accessibility Best Practices
|
|
225
|
+
|
|
226
|
+
✅ **GOOD**: Descriptive aria-label with context
|
|
227
|
+
```tsx
|
|
228
|
+
<Badge variant="rounded" aria-label="12 items in cart">12</Badge>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
✅ **GOOD**: Format numbers and provide full context
|
|
232
|
+
```tsx
|
|
233
|
+
<Badge variant="rounded" aria-label="More than 99 notifications">99+</Badge>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
❌ **BAD**: Number-only badge without context
|
|
237
|
+
```tsx
|
|
238
|
+
<Badge>12</Badge> {/* Screen reader only hears "12" without context */}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
❌ **BAD**: Missing aria-label for icon-only badges
|
|
242
|
+
```tsx
|
|
243
|
+
<Badge variant="rounded">!</Badge> {/* What does "!" mean? */}
|
|
108
244
|
```
|
|
109
245
|
|
|
110
|
-
|
|
246
|
+
### Testing Recommendations
|
|
111
247
|
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
248
|
+
- Test with screen readers (NVDA, JAWS, VoiceOver)
|
|
249
|
+
- Verify keyboard navigation and focus management
|
|
250
|
+
- Check color contrast ratios (minimum 4.5:1 for normal text)
|
|
251
|
+
- Test with 200% zoom and custom text spacing
|
|
252
|
+
- Validate that badge updates are announced by screen readers
|
|
117
253
|
|
|
118
254
|
## Additional Notes
|
|
119
255
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
256
|
+
- **Keep content concise**: Badges work best with 1-3 characters
|
|
257
|
+
- **Format large numbers**: Use "99+" instead of "999" for better UX
|
|
258
|
+
- **Color contrast**: Ensure adequate contrast when customizing colors
|
|
259
|
+
- **Semantic values**: Use meaningful, descriptive content
|
|
260
|
+
- **ARIA labels**: Always include aria-label for number-only or icon-only badges
|
|
261
|
+
- **Units**: All sizing uses rem units (base 16px = 1rem) for better accessibility
|
|
@@ -15,7 +15,25 @@ sup:has(> span) {
|
|
|
15
15
|
color: inherit;
|
|
16
16
|
}
|
|
17
17
|
&[data-badge~="rounded"] {
|
|
18
|
-
--badge-radius:
|
|
19
|
-
--badge-padding: 0
|
|
18
|
+
--badge-radius: 50%;
|
|
19
|
+
--badge-padding: 0;
|
|
20
|
+
--badge-size: 1.5625rem;
|
|
21
|
+
width: var(--badge-size);
|
|
22
|
+
height: var(--badge-size);
|
|
23
|
+
display: inline-flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
line-height: 1;
|
|
27
|
+
font-size: 0.6875rem;
|
|
28
|
+
font-weight: 700;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
span {
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
text-overflow: clip;
|
|
35
|
+
white-space: nowrap;
|
|
36
|
+
padding: 0 0.125rem;
|
|
37
|
+
}
|
|
20
38
|
}
|
|
21
39
|
}
|