Skip to content

Commit 4f40e84

Browse files
BN-19 | Add. FontAwesome Icon Support (#14)
* BN-19 | Add. Font Awesome Icons package * BN-19 | Fix. Remove Unused Regular Icons Package * BN-19 | Refactor. Add Div Abstraction * BN-19 | Add. Stories And Documentation * BN-19 | Fix. Remove Regular Icon Support * BN-19 | Fix. Strip Ansi Missing Issue Co-authored-by: Dev Singh <dev.singh@thoughtworks.com>, Arshiya < arshiya.shehzad@thoughtworks.com> * BN-19 | Refactor. Rename Icon As BahmniIcon --------- Co-authored-by: MOHANKUMAR T <mohan13081999@gmail.com>
1 parent 19036ab commit 4f40e84

File tree

11 files changed

+1171
-2
lines changed

11 files changed

+1171
-2
lines changed

docs/bahmni-icon-guide.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# BahmniIcon Guide
2+
3+
This guide explains how to use FontAwesome icons in the Bahmni Clinical Frontend application.
4+
5+
## Overview
6+
7+
The application uses FontAwesome free solid icons through a custom BahmniIcon component. This allows for consistent icon usage throughout the application and supports specifying icons in configuration.
8+
9+
## Usage
10+
11+
### Basic Usage
12+
13+
Import the BahmniIcon component and use it in your components:
14+
15+
```tsx
16+
import React from "react";
17+
import BahmniIcon from "@components/common/bahmniIcon/BahmniIcon";
18+
19+
const MyComponent: React.FC = () => {
20+
return (
21+
<div>
22+
<h1>
23+
<BahmniIcon name="fa-home" id="home-icon" /> Home
24+
</h1>
25+
<button>
26+
<BahmniIcon name="fa-cog" id="settings-icon" /> Settings
27+
</button>
28+
</div>
29+
);
30+
};
31+
```
32+
33+
### Icon Naming Format
34+
35+
The BahmniIcon component expects names in the format "fa-iconname" or "fas-iconname":
36+
37+
```tsx
38+
// Solid icon format
39+
<BahmniIcon name="fa-home" id="home-icon" />
40+
41+
// Alternative solid icon format
42+
<BahmniIcon name="fas-home" id="home-icon-alt" />
43+
```
44+
45+
### Icon Properties
46+
47+
The BahmniIcon component accepts the following properties:
48+
49+
| Property | Type | Description |
50+
| --------- | ----------------- | --------------------------------------------------------------------- |
51+
| name | string | Icon name in the format "fa-home" or "fas-home" |
52+
| id | string | Unique identifier for the icon (required) |
53+
| size | ICON_SIZE enum | Icon size (XXS, XS, SM, LG, XL, XXL, X1-X10) |
54+
| color | string | Icon color (CSS color value) |
55+
| ariaLabel | string | Accessibility label (defaults to id) |
56+
| padding | ICON_PADDING enum | Padding around the icon (NONE, XXSMALL, XSMALL, SMALL, MEDIUM, LARGE) |
57+
58+
Example with all properties:
59+
60+
```tsx
61+
import { ICON_SIZE, ICON_PADDING } from "@constants/icon";
62+
63+
<BahmniIcon
64+
name="fa-user"
65+
id="user-profile-icon"
66+
size={ICON_SIZE.X2}
67+
color="#0f62fe"
68+
ariaLabel="User profile"
69+
padding={ICON_PADDING.MEDIUM}
70+
/>;
71+
```
72+
73+
### Size Options
74+
75+
The BahmniIcon component supports various sizes through the ICON_SIZE enum:
76+
77+
```tsx
78+
export enum ICON_SIZE {
79+
XXS = "2xs", // Extra extra small
80+
XS = "xs", // Extra small
81+
SM = "sm", // Small
82+
LG = "lg", // Large
83+
XL = "xl", // Extra large
84+
XXL = "2xl", // Extra extra large
85+
X1 = "1x", // 1x (default)
86+
X2 = "2x", // 2x
87+
X3 = "3x", // 3x
88+
X4 = "4x", // 4x
89+
X5 = "5x", // 5x
90+
X6 = "6x", // 6x
91+
X7 = "7x", // 7x
92+
X8 = "8x", // 8x
93+
X9 = "9x", // 9x
94+
X10 = "10x", // 10x
95+
}
96+
```
97+
98+
### Padding Options
99+
100+
The BahmniIcon component supports various padding options through the ICON_PADDING enum:
101+
102+
```tsx
103+
export enum ICON_PADDING {
104+
NONE = "0", // No padding
105+
XXSMALL = "0.125rem", // Extra extra small padding (default)
106+
XSMALL = "0.25rem", // Extra small padding
107+
SMALL = "0.5rem", // Small padding
108+
MEDIUM = "1rem", // Medium padding
109+
LARGE = "1.5rem", // Large padding
110+
}
111+
```
112+
113+
## Using Icons in Configuration
114+
115+
Icons can be specified in configuration using the "fa-home" format. For example, in a dashboard configuration:
116+
117+
```json
118+
{
119+
"dashboards": [
120+
{
121+
"name": "Patient Dashboard",
122+
"icon": "fa-user",
123+
"url": "/patient"
124+
},
125+
{
126+
"name": "Appointments",
127+
"icon": "fa-calendar",
128+
"url": "/appointments"
129+
}
130+
]
131+
}
132+
```
133+
134+
When rendering components based on this configuration, use the BahmniIcon component:
135+
136+
```tsx
137+
import React from "react";
138+
import BahmniIcon from "@components/common/bahmniIcon/BahmniIcon";
139+
140+
interface DashboardItemProps {
141+
dashboard: {
142+
name: string;
143+
icon?: string;
144+
url: string;
145+
};
146+
}
147+
148+
const DashboardItem: React.FC<DashboardItemProps> = ({ dashboard }) => {
149+
return (
150+
<div className="dashboard-item">
151+
{dashboard.icon && (
152+
<BahmniIcon
153+
name={dashboard.icon}
154+
id={`${dashboard.name.toLowerCase()}-icon`}
155+
size={ICON_SIZE.LG}
156+
/>
157+
)}
158+
<span>{dashboard.name}</span>
159+
</div>
160+
);
161+
};
162+
```
163+
164+
## Accessibility Best Practices
165+
166+
When using icons, it's important to ensure they are accessible to all users, including those using screen readers:
167+
168+
1. **Always provide an `id` and `ariaLabel`**: The `id` is required and the `ariaLabel` defaults to the `id` if not provided. Use descriptive labels that explain the purpose of the icon.
169+
170+
```tsx
171+
// Good
172+
<BahmniIcon name="fa-search" id="search-button-icon" ariaLabel="Search for patients" />
173+
174+
// Not recommended (uses id as ariaLabel)
175+
<BahmniIcon name="fa-search" id="search-icon" />
176+
```
177+
178+
2. **For decorative icons**, you can use the same approach but with a more descriptive label:
179+
180+
```tsx
181+
<BahmniIcon name="fa-star" id="rating-star-icon" ariaLabel="Rating star" />
182+
```
183+
184+
3. **For icons that are part of a button or interactive element**, ensure the parent element also has appropriate accessibility attributes:
185+
186+
```tsx
187+
<button aria-label="Search for patients">
188+
<BahmniIcon name="fa-search" id="search-icon" ariaLabel="Search icon" />
189+
Search
190+
</button>
191+
```
192+
193+
4. **For icons without visible text**, make sure the aria-label is descriptive of the action:
194+
195+
```tsx
196+
<button aria-label="Close dialog">
197+
<BahmniIcon name="fa-times" id="close-icon" ariaLabel="Close" />
198+
</button>
199+
```
200+
201+
## Available Icons
202+
203+
For a complete list of available icons, refer to the FontAwesome documentation:
204+
205+
- [Solid Icons](https://fontawesome.com/icons?d=gallery&s=solid&m=free)
206+
207+
## Implementation Details
208+
209+
The FontAwesome integration consists of:
210+
211+
1. FontAwesome packages:
212+
213+
- @fortawesome/react-fontawesome
214+
- @fortawesome/fontawesome-svg-core
215+
- @fortawesome/free-solid-svg-icons
216+
217+
2. Configuration (src/fontawesome.ts):
218+
219+
- Initializes the FontAwesome library
220+
- Adds all solid icons
221+
222+
3. BahmniIcon Component (src/components/common/bahmniIcon/BahmniIcon.tsx):
223+
224+
- Renders FontAwesome icons
225+
- Supports customization through props
226+
227+
4. Application Initialization (src/index.tsx):
228+
- Initializes FontAwesome when the application starts
229+
230+
## Storybook Examples
231+
232+
The BahmniIcon component includes a comprehensive set of Storybook examples that demonstrate various usage patterns and configurations. To view these examples, run the Storybook development server and navigate to the BahmniIcon component section.
233+
234+
Examples include:
235+
236+
- Basic usage
237+
- Size variations
238+
- Color variations
239+
- Padding variations
240+
- Accessibility examples
241+
- Common icon usage patterns

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
},
1919
"dependencies": {
2020
"@carbon/react": "^1.78.2",
21+
"@fortawesome/fontawesome-svg-core": "^6.7.2",
22+
"@fortawesome/free-solid-svg-icons": "^6.7.2",
23+
"@fortawesome/react-fontawesome": "^0.2.2",
2124
"@testing-library/react-hooks": "^8.0.1",
2225
"ajv": "^8.17.1",
2326
"axios": "^1.8.4",
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React from 'react';
2+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3+
import { IconName } from '@fortawesome/fontawesome-svg-core';
4+
import { ICON_SIZE, ICON_PADDING } from '@constants/icon';
5+
6+
interface BahmniIconProps {
7+
name: string; // Format: "fa-home"
8+
size?: ICON_SIZE;
9+
color?: string;
10+
id: string;
11+
ariaLabel?: string;
12+
padding?: ICON_PADDING;
13+
}
14+
15+
/**
16+
* Icon component that renders FontAwesome icons with customizable size, color, and padding.
17+
*
18+
* @component
19+
* @example
20+
* // Basic usage with solid icon (default)
21+
* <Icon name="fa-home" id="home-icon" />
22+
*
23+
* // Regular icon (option 1)
24+
* <Icon name="fa-regular-user" id="user-icon" />
25+
*
26+
* // Regular icon (option 2)
27+
* <Icon name="far-user" id="user-icon-alt" />
28+
*
29+
* // With custom size, color and padding
30+
* <Icon
31+
* name="fa-cog"
32+
* id="settings-icon"
33+
* size={ICON_SIZE.X2}
34+
* color="#0f62fe"
35+
* padding={ICON_PADDING.MEDIUM}
36+
* ariaLabel="Settings"
37+
* />
38+
*
39+
* @param {Object} props - Component props
40+
* @param {string} props.name - Icon name in the format "fa-home", "fa-regular-user", or "far-user"
41+
* @param {ICON_SIZE} [props.size] - Icon size from ICON_SIZE enum (XXS, XS, SM, LG, XL, XXL, X1-X10)
42+
* @param {string} [props.color] - Icon color as CSS color value
43+
* @param {string} props.id - Unique identifier for the icon (used for testing and accessibility)
44+
* @param {string} [props.ariaLabel] - Accessibility label (defaults to id if not provided)
45+
* @param {ICON_PADDING} [props.padding=ICON_PADDING.XXSMALL] - Padding around the icon from ICON_PADDING enum
46+
* @returns {React.ReactElement} React component
47+
*/
48+
const BahmniIcon: React.FC<BahmniIconProps> = ({
49+
name,
50+
size = ICON_SIZE.XS,
51+
color,
52+
id,
53+
ariaLabel = id,
54+
padding = ICON_PADDING.XXSMALL,
55+
}) => {
56+
if (!name || !/^fas?-[a-zA-Z0-9_-]+$/.test(name)) {
57+
return <></>;
58+
}
59+
return (
60+
<div style={{ padding: padding }} id={id} aria-label={ariaLabel}>
61+
<FontAwesomeIcon
62+
icon={['fas', name as IconName]}
63+
size={size}
64+
color={color}
65+
data-testid={id}
66+
/>
67+
</div>
68+
);
69+
};
70+
71+
export default BahmniIcon;

0 commit comments

Comments
 (0)