react-status-tracker 1.0.0
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 +156 -0
- package/dist/StatusTracker.d.ts +14 -0
- package/dist/index.cjs.js +94 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +92 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# React Status Tracker
|
|
2
|
+
|
|
3
|
+
**React Status Tracker** is a reusable **status / step / workflow tracker** component for React applications.
|
|
4
|
+
It supports both **horizontal and vertical layouts** and is built using **Material UI (MUI)**.
|
|
5
|
+
|
|
6
|
+
This component can be used for:
|
|
7
|
+
- Workflow tracking
|
|
8
|
+
- Order or shipment status
|
|
9
|
+
- Approval pipelines
|
|
10
|
+
- Process steps
|
|
11
|
+
- Progress visualization
|
|
12
|
+
|
|
13
|
+
It supports **active and inactive steps**, an optional **flagged (error) state**, full **TypeScript support**, and extensive **customization options** for colors and sizes.
|
|
14
|
+
The component is **lightweight**, **production-ready**, and **compatible with MUI v5**.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install react-status-tracker
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Peer Dependencies
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @mui/material @mui/system @mui/utils @emotion/react @emotion/styled
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Usage Example
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Box } from "@mui/material";
|
|
36
|
+
import StatusTracker from "react-status-tracker";
|
|
37
|
+
|
|
38
|
+
const steps = [
|
|
39
|
+
"TESTING",
|
|
40
|
+
"TESTING COMPLETE",
|
|
41
|
+
"TESTING REVIEW",
|
|
42
|
+
"TESTING APPROVED",
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export default function Example() {
|
|
46
|
+
return (
|
|
47
|
+
<Box sx={{ p: 4 }}>
|
|
48
|
+
<StatusTracker steps={steps} currentStatus="TESTING REVIEW" />
|
|
49
|
+
</Box>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Vertical Layout Example
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<StatusTracker
|
|
60
|
+
steps={steps}
|
|
61
|
+
currentStatus="TESTING REVIEW"
|
|
62
|
+
orientation="vertical"
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Flagged (Error) State Example
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<StatusTracker
|
|
72
|
+
steps={steps}
|
|
73
|
+
currentStatus="TESTING REVIEW"
|
|
74
|
+
flagged
|
|
75
|
+
/>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Custom Styling Example
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<StatusTracker
|
|
84
|
+
steps={steps}
|
|
85
|
+
currentStatus="TESTING REVIEW"
|
|
86
|
+
activeColor="#2e7d32"
|
|
87
|
+
inactiveColor="#e0e0e0"
|
|
88
|
+
circleSize={24}
|
|
89
|
+
lineThickness={3}
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Props
|
|
96
|
+
|
|
97
|
+
| Prop Name | Type | Description | Default |
|
|
98
|
+
|------------------|------------------------------|-------------------------------------------|----------------|
|
|
99
|
+
| steps | string[] | Ordered list of step labels | Required |
|
|
100
|
+
| currentStatus | string | Current active step | Required |
|
|
101
|
+
| orientation | horizontal \| vertical | Layout direction | horizontal |
|
|
102
|
+
| flagged | boolean | Error or alert state | false |
|
|
103
|
+
| activeColor | string | Active step color | - |
|
|
104
|
+
| inactiveColor | string | Inactive step color | #ccc |
|
|
105
|
+
| circleSize | number | Step indicator size | 20 |
|
|
106
|
+
| lineThickness | number | Connector thickness | 2 |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Behavior Notes
|
|
111
|
+
|
|
112
|
+
- All steps before and including the current status are marked active
|
|
113
|
+
- Connector lines leading into the current step are active
|
|
114
|
+
- If the provided currentStatus does not exist in the steps array, the first step is selected
|
|
115
|
+
- Text labels never affect alignment
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## TypeScript Support
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import type { StatusTrackerProps } from "react-status-tracker";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Compatibility
|
|
128
|
+
|
|
129
|
+
- React 18+
|
|
130
|
+
- React 19+
|
|
131
|
+
- Material UI v5.x
|
|
132
|
+
- Emotion v11
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Common Use Cases
|
|
137
|
+
|
|
138
|
+
- Order tracking
|
|
139
|
+
- Shipment workflows
|
|
140
|
+
- Approval pipelines
|
|
141
|
+
- Task progression
|
|
142
|
+
- Multi-step form indicators
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Planned Enhancements
|
|
147
|
+
|
|
148
|
+
- Animated progress
|
|
149
|
+
- Icons inside steps
|
|
150
|
+
- Clickable steps
|
|
151
|
+
- Tooltip support
|
|
152
|
+
- SVG-based rendering option
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
**Developed by Mohamed Ruwaid**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type Orientation = "horizontal" | "vertical";
|
|
3
|
+
export interface StatusTrackerProps {
|
|
4
|
+
steps: string[];
|
|
5
|
+
currentStatus: string;
|
|
6
|
+
flagged?: boolean;
|
|
7
|
+
orientation?: Orientation;
|
|
8
|
+
activeColor?: string;
|
|
9
|
+
inactiveColor?: string;
|
|
10
|
+
circleSize?: number;
|
|
11
|
+
lineThickness?: number;
|
|
12
|
+
}
|
|
13
|
+
declare const StatusTracker: React.FC<StatusTrackerProps>;
|
|
14
|
+
export default StatusTracker;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var material = require('@mui/material');
|
|
5
|
+
|
|
6
|
+
var StatusTracker = function (_a) {
|
|
7
|
+
var steps = _a.steps, currentStatus = _a.currentStatus, _b = _a.flagged, flagged = _b === void 0 ? false : _b, _c = _a.orientation, orientation = _c === void 0 ? "horizontal" : _c, activeColor = _a.activeColor, _d = _a.inactiveColor, inactiveColor = _d === void 0 ? "#ccc" : _d, _e = _a.circleSize, circleSize = _e === void 0 ? 20 : _e, _f = _a.lineThickness, lineThickness = _f === void 0 ? 2 : _f;
|
|
8
|
+
var currentIndex = steps.indexOf(currentStatus);
|
|
9
|
+
var safeIndex = currentIndex === -1 ? 0 : currentIndex;
|
|
10
|
+
var resolvedActiveColor = activeColor !== null && activeColor !== void 0 ? activeColor : (flagged ? "#D32F2F" : "#1976D2");
|
|
11
|
+
var isVertical = orientation === "vertical";
|
|
12
|
+
return (jsxRuntime.jsx(material.Card, { sx: { borderRadius: 2, boxShadow: 2 }, children: jsxRuntime.jsx(material.CardContent, { sx: { p: 3 }, children: jsxRuntime.jsx(material.Box, { sx: {
|
|
13
|
+
boxSizing: "border-box",
|
|
14
|
+
isolation: "isolate",
|
|
15
|
+
display: "flex",
|
|
16
|
+
flexDirection: isVertical ? "column" : "row",
|
|
17
|
+
gap: isVertical ? 3 : 0,
|
|
18
|
+
}, children: steps.map(function (step, index) {
|
|
19
|
+
var isActive = index <= safeIndex;
|
|
20
|
+
/* =======================
|
|
21
|
+
VERTICAL MODE
|
|
22
|
+
======================= */
|
|
23
|
+
if (isVertical) {
|
|
24
|
+
return (jsxRuntime.jsxs(material.Box, { sx: {
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "flex-start",
|
|
27
|
+
}, children: [jsxRuntime.jsxs(material.Box, { sx: {
|
|
28
|
+
width: circleSize,
|
|
29
|
+
display: "flex",
|
|
30
|
+
flexDirection: "column",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
position: "relative",
|
|
33
|
+
}, children: [index > 0 && (jsxRuntime.jsx(material.Box, { sx: {
|
|
34
|
+
position: "absolute",
|
|
35
|
+
top: -24,
|
|
36
|
+
width: lineThickness,
|
|
37
|
+
height: 24,
|
|
38
|
+
bgcolor: isActive ? resolvedActiveColor : inactiveColor
|
|
39
|
+
} })), jsxRuntime.jsx(material.Box, { sx: {
|
|
40
|
+
width: circleSize,
|
|
41
|
+
height: circleSize,
|
|
42
|
+
borderRadius: "50%",
|
|
43
|
+
bgcolor: isActive
|
|
44
|
+
? resolvedActiveColor
|
|
45
|
+
: inactiveColor,
|
|
46
|
+
zIndex: 1,
|
|
47
|
+
} })] }), jsxRuntime.jsx(material.Typography, { sx: {
|
|
48
|
+
ml: 2,
|
|
49
|
+
mt: "2px",
|
|
50
|
+
fontSize: "10px",
|
|
51
|
+
textTransform: "uppercase",
|
|
52
|
+
letterSpacing: "0.5px",
|
|
53
|
+
fontWeight: isActive ? "bold" : "normal",
|
|
54
|
+
color: "text.primary",
|
|
55
|
+
}, children: step })] }, step));
|
|
56
|
+
}
|
|
57
|
+
/* =======================
|
|
58
|
+
HORIZONTAL MODE
|
|
59
|
+
======================= */
|
|
60
|
+
return (jsxRuntime.jsxs(material.Box, { sx: {
|
|
61
|
+
display: "flex",
|
|
62
|
+
flexDirection: "column",
|
|
63
|
+
alignItems: "center",
|
|
64
|
+
flex: 1,
|
|
65
|
+
position: "relative",
|
|
66
|
+
}, children: [index > 0 && (jsxRuntime.jsx(material.Box, { sx: {
|
|
67
|
+
position: "absolute",
|
|
68
|
+
left: "calc(-50% + ".concat(circleSize / 2, "px)"),
|
|
69
|
+
top: circleSize / 2 - lineThickness / 2,
|
|
70
|
+
width: "calc(100% - ".concat(circleSize, "px)"),
|
|
71
|
+
height: lineThickness,
|
|
72
|
+
bgcolor: isActive ? resolvedActiveColor : inactiveColor
|
|
73
|
+
} })), jsxRuntime.jsx(material.Box, { sx: {
|
|
74
|
+
width: circleSize,
|
|
75
|
+
height: circleSize,
|
|
76
|
+
borderRadius: "50%",
|
|
77
|
+
bgcolor: isActive
|
|
78
|
+
? resolvedActiveColor
|
|
79
|
+
: inactiveColor,
|
|
80
|
+
zIndex: 1,
|
|
81
|
+
} }), jsxRuntime.jsx(material.Typography, { sx: {
|
|
82
|
+
mt: 1.5,
|
|
83
|
+
fontSize: "10px",
|
|
84
|
+
textTransform: "uppercase",
|
|
85
|
+
letterSpacing: "0.5px",
|
|
86
|
+
fontWeight: isActive ? "bold" : "normal",
|
|
87
|
+
textAlign: "center",
|
|
88
|
+
minWidth: 80,
|
|
89
|
+
}, children: step })] }, step));
|
|
90
|
+
}) }) }) }));
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
exports.StatusTracker = StatusTracker;
|
|
94
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/StatusTracker.tsx"],"sourcesContent":["import React from \"react\";\r\nimport { Card, CardContent, Box, Typography } from \"@mui/material\";\r\n\r\nexport type Orientation = \"horizontal\" | \"vertical\";\r\n\r\nexport interface StatusTrackerProps {\r\n steps: string[];\r\n currentStatus: string;\r\n flagged?: boolean;\r\n orientation?: Orientation;\r\n activeColor?: string;\r\n inactiveColor?: string;\r\n circleSize?: number;\r\n lineThickness?: number;\r\n}\r\n\r\nconst StatusTracker: React.FC<StatusTrackerProps> = ({\r\n steps,\r\n currentStatus,\r\n flagged = false,\r\n orientation = \"horizontal\",\r\n activeColor,\r\n inactiveColor = \"#ccc\",\r\n circleSize = 20,\r\n lineThickness = 2,\r\n}) => {\r\n const currentIndex = steps.indexOf(currentStatus);\r\n const safeIndex = currentIndex === -1 ? 0 : currentIndex;\r\n\r\n const resolvedActiveColor = activeColor ?? (flagged ? \"#D32F2F\" : \"#1976D2\");\r\n const isVertical = orientation === \"vertical\";\r\n\r\n return (\r\n <Card sx={{ borderRadius: 2, boxShadow: 2 }}>\r\n <CardContent sx={{ p: 3 }}>\r\n <Box\r\n sx={{\r\n boxSizing: \"border-box\",\r\n isolation: \"isolate\",\r\n display: \"flex\",\r\n flexDirection: isVertical ? \"column\" : \"row\",\r\n gap: isVertical ? 3 : 0,\r\n }}\r\n >\r\n\r\n {steps.map((step, index) => {\r\n const isActive = index <= safeIndex;\r\n\r\n /* =======================\r\n VERTICAL MODE\r\n ======================= */\r\n if (isVertical) {\r\n return (\r\n <Box\r\n key={step}\r\n sx={{\r\n display: \"flex\",\r\n alignItems: \"flex-start\",\r\n }}\r\n >\r\n {/* LEFT COLUMN — geometry */}\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n position: \"relative\",\r\n }}\r\n >\r\n {index > 0 && (\r\n <Box\r\n sx={{\r\n position: \"absolute\",\r\n top: -24,\r\n width: lineThickness,\r\n height: 24,\r\n bgcolor: isActive ? resolvedActiveColor : inactiveColor\r\n }}\r\n />\r\n )}\r\n\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n height: circleSize,\r\n borderRadius: \"50%\",\r\n bgcolor: isActive\r\n ? resolvedActiveColor\r\n : inactiveColor,\r\n zIndex: 1,\r\n }}\r\n />\r\n </Box>\r\n\r\n {/* RIGHT COLUMN — label */}\r\n <Typography\r\n sx={{\r\n ml: 2,\r\n mt: \"2px\",\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n fontWeight: isActive ? \"bold\" : \"normal\",\r\n color: \"text.primary\",\r\n }}\r\n >\r\n {step}\r\n </Typography>\r\n </Box>\r\n );\r\n }\r\n\r\n /* =======================\r\n HORIZONTAL MODE\r\n ======================= */\r\n return (\r\n <Box\r\n key={step}\r\n sx={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n flex: 1,\r\n position: \"relative\",\r\n }}\r\n >\r\n {index > 0 && (\r\n <Box\r\n sx={{\r\n position: \"absolute\",\r\n left: `calc(-50% + ${circleSize / 2}px)`,\r\n top: circleSize / 2 - lineThickness / 2,\r\n width: `calc(100% - ${circleSize}px)`,\r\n height: lineThickness,\r\n bgcolor: isActive ? resolvedActiveColor : inactiveColor\r\n }}\r\n />\r\n )}\r\n\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n height: circleSize,\r\n borderRadius: \"50%\",\r\n bgcolor: isActive\r\n ? resolvedActiveColor\r\n : inactiveColor,\r\n zIndex: 1,\r\n }}\r\n />\r\n\r\n <Typography\r\n sx={{\r\n mt: 1.5,\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n fontWeight: isActive ? \"bold\" : \"normal\",\r\n textAlign: \"center\",\r\n minWidth: 80,\r\n }}\r\n >\r\n {step}\r\n </Typography>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n </CardContent>\r\n </Card>\r\n );\r\n};\r\n\r\nexport default StatusTracker;\r\n"],"names":["_jsx","Card","CardContent","Box","_jsxs","Typography"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Card, CardContent, Box, Typography } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
var StatusTracker = function (_a) {
|
|
5
|
+
var steps = _a.steps, currentStatus = _a.currentStatus, _b = _a.flagged, flagged = _b === void 0 ? false : _b, _c = _a.orientation, orientation = _c === void 0 ? "horizontal" : _c, activeColor = _a.activeColor, _d = _a.inactiveColor, inactiveColor = _d === void 0 ? "#ccc" : _d, _e = _a.circleSize, circleSize = _e === void 0 ? 20 : _e, _f = _a.lineThickness, lineThickness = _f === void 0 ? 2 : _f;
|
|
6
|
+
var currentIndex = steps.indexOf(currentStatus);
|
|
7
|
+
var safeIndex = currentIndex === -1 ? 0 : currentIndex;
|
|
8
|
+
var resolvedActiveColor = activeColor !== null && activeColor !== void 0 ? activeColor : (flagged ? "#D32F2F" : "#1976D2");
|
|
9
|
+
var isVertical = orientation === "vertical";
|
|
10
|
+
return (jsx(Card, { sx: { borderRadius: 2, boxShadow: 2 }, children: jsx(CardContent, { sx: { p: 3 }, children: jsx(Box, { sx: {
|
|
11
|
+
boxSizing: "border-box",
|
|
12
|
+
isolation: "isolate",
|
|
13
|
+
display: "flex",
|
|
14
|
+
flexDirection: isVertical ? "column" : "row",
|
|
15
|
+
gap: isVertical ? 3 : 0,
|
|
16
|
+
}, children: steps.map(function (step, index) {
|
|
17
|
+
var isActive = index <= safeIndex;
|
|
18
|
+
/* =======================
|
|
19
|
+
VERTICAL MODE
|
|
20
|
+
======================= */
|
|
21
|
+
if (isVertical) {
|
|
22
|
+
return (jsxs(Box, { sx: {
|
|
23
|
+
display: "flex",
|
|
24
|
+
alignItems: "flex-start",
|
|
25
|
+
}, children: [jsxs(Box, { sx: {
|
|
26
|
+
width: circleSize,
|
|
27
|
+
display: "flex",
|
|
28
|
+
flexDirection: "column",
|
|
29
|
+
alignItems: "center",
|
|
30
|
+
position: "relative",
|
|
31
|
+
}, children: [index > 0 && (jsx(Box, { sx: {
|
|
32
|
+
position: "absolute",
|
|
33
|
+
top: -24,
|
|
34
|
+
width: lineThickness,
|
|
35
|
+
height: 24,
|
|
36
|
+
bgcolor: isActive ? resolvedActiveColor : inactiveColor
|
|
37
|
+
} })), jsx(Box, { sx: {
|
|
38
|
+
width: circleSize,
|
|
39
|
+
height: circleSize,
|
|
40
|
+
borderRadius: "50%",
|
|
41
|
+
bgcolor: isActive
|
|
42
|
+
? resolvedActiveColor
|
|
43
|
+
: inactiveColor,
|
|
44
|
+
zIndex: 1,
|
|
45
|
+
} })] }), jsx(Typography, { sx: {
|
|
46
|
+
ml: 2,
|
|
47
|
+
mt: "2px",
|
|
48
|
+
fontSize: "10px",
|
|
49
|
+
textTransform: "uppercase",
|
|
50
|
+
letterSpacing: "0.5px",
|
|
51
|
+
fontWeight: isActive ? "bold" : "normal",
|
|
52
|
+
color: "text.primary",
|
|
53
|
+
}, children: step })] }, step));
|
|
54
|
+
}
|
|
55
|
+
/* =======================
|
|
56
|
+
HORIZONTAL MODE
|
|
57
|
+
======================= */
|
|
58
|
+
return (jsxs(Box, { sx: {
|
|
59
|
+
display: "flex",
|
|
60
|
+
flexDirection: "column",
|
|
61
|
+
alignItems: "center",
|
|
62
|
+
flex: 1,
|
|
63
|
+
position: "relative",
|
|
64
|
+
}, children: [index > 0 && (jsx(Box, { sx: {
|
|
65
|
+
position: "absolute",
|
|
66
|
+
left: "calc(-50% + ".concat(circleSize / 2, "px)"),
|
|
67
|
+
top: circleSize / 2 - lineThickness / 2,
|
|
68
|
+
width: "calc(100% - ".concat(circleSize, "px)"),
|
|
69
|
+
height: lineThickness,
|
|
70
|
+
bgcolor: isActive ? resolvedActiveColor : inactiveColor
|
|
71
|
+
} })), jsx(Box, { sx: {
|
|
72
|
+
width: circleSize,
|
|
73
|
+
height: circleSize,
|
|
74
|
+
borderRadius: "50%",
|
|
75
|
+
bgcolor: isActive
|
|
76
|
+
? resolvedActiveColor
|
|
77
|
+
: inactiveColor,
|
|
78
|
+
zIndex: 1,
|
|
79
|
+
} }), jsx(Typography, { sx: {
|
|
80
|
+
mt: 1.5,
|
|
81
|
+
fontSize: "10px",
|
|
82
|
+
textTransform: "uppercase",
|
|
83
|
+
letterSpacing: "0.5px",
|
|
84
|
+
fontWeight: isActive ? "bold" : "normal",
|
|
85
|
+
textAlign: "center",
|
|
86
|
+
minWidth: 80,
|
|
87
|
+
}, children: step })] }, step));
|
|
88
|
+
}) }) }) }));
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export { StatusTracker };
|
|
92
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/StatusTracker.tsx"],"sourcesContent":["import React from \"react\";\r\nimport { Card, CardContent, Box, Typography } from \"@mui/material\";\r\n\r\nexport type Orientation = \"horizontal\" | \"vertical\";\r\n\r\nexport interface StatusTrackerProps {\r\n steps: string[];\r\n currentStatus: string;\r\n flagged?: boolean;\r\n orientation?: Orientation;\r\n activeColor?: string;\r\n inactiveColor?: string;\r\n circleSize?: number;\r\n lineThickness?: number;\r\n}\r\n\r\nconst StatusTracker: React.FC<StatusTrackerProps> = ({\r\n steps,\r\n currentStatus,\r\n flagged = false,\r\n orientation = \"horizontal\",\r\n activeColor,\r\n inactiveColor = \"#ccc\",\r\n circleSize = 20,\r\n lineThickness = 2,\r\n}) => {\r\n const currentIndex = steps.indexOf(currentStatus);\r\n const safeIndex = currentIndex === -1 ? 0 : currentIndex;\r\n\r\n const resolvedActiveColor = activeColor ?? (flagged ? \"#D32F2F\" : \"#1976D2\");\r\n const isVertical = orientation === \"vertical\";\r\n\r\n return (\r\n <Card sx={{ borderRadius: 2, boxShadow: 2 }}>\r\n <CardContent sx={{ p: 3 }}>\r\n <Box\r\n sx={{\r\n boxSizing: \"border-box\",\r\n isolation: \"isolate\",\r\n display: \"flex\",\r\n flexDirection: isVertical ? \"column\" : \"row\",\r\n gap: isVertical ? 3 : 0,\r\n }}\r\n >\r\n\r\n {steps.map((step, index) => {\r\n const isActive = index <= safeIndex;\r\n\r\n /* =======================\r\n VERTICAL MODE\r\n ======================= */\r\n if (isVertical) {\r\n return (\r\n <Box\r\n key={step}\r\n sx={{\r\n display: \"flex\",\r\n alignItems: \"flex-start\",\r\n }}\r\n >\r\n {/* LEFT COLUMN — geometry */}\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n position: \"relative\",\r\n }}\r\n >\r\n {index > 0 && (\r\n <Box\r\n sx={{\r\n position: \"absolute\",\r\n top: -24,\r\n width: lineThickness,\r\n height: 24,\r\n bgcolor: isActive ? resolvedActiveColor : inactiveColor\r\n }}\r\n />\r\n )}\r\n\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n height: circleSize,\r\n borderRadius: \"50%\",\r\n bgcolor: isActive\r\n ? resolvedActiveColor\r\n : inactiveColor,\r\n zIndex: 1,\r\n }}\r\n />\r\n </Box>\r\n\r\n {/* RIGHT COLUMN — label */}\r\n <Typography\r\n sx={{\r\n ml: 2,\r\n mt: \"2px\",\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n fontWeight: isActive ? \"bold\" : \"normal\",\r\n color: \"text.primary\",\r\n }}\r\n >\r\n {step}\r\n </Typography>\r\n </Box>\r\n );\r\n }\r\n\r\n /* =======================\r\n HORIZONTAL MODE\r\n ======================= */\r\n return (\r\n <Box\r\n key={step}\r\n sx={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n flex: 1,\r\n position: \"relative\",\r\n }}\r\n >\r\n {index > 0 && (\r\n <Box\r\n sx={{\r\n position: \"absolute\",\r\n left: `calc(-50% + ${circleSize / 2}px)`,\r\n top: circleSize / 2 - lineThickness / 2,\r\n width: `calc(100% - ${circleSize}px)`,\r\n height: lineThickness,\r\n bgcolor: isActive ? resolvedActiveColor : inactiveColor\r\n }}\r\n />\r\n )}\r\n\r\n <Box\r\n sx={{\r\n width: circleSize,\r\n height: circleSize,\r\n borderRadius: \"50%\",\r\n bgcolor: isActive\r\n ? resolvedActiveColor\r\n : inactiveColor,\r\n zIndex: 1,\r\n }}\r\n />\r\n\r\n <Typography\r\n sx={{\r\n mt: 1.5,\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n fontWeight: isActive ? \"bold\" : \"normal\",\r\n textAlign: \"center\",\r\n minWidth: 80,\r\n }}\r\n >\r\n {step}\r\n </Typography>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n </CardContent>\r\n </Card>\r\n );\r\n};\r\n\r\nexport default StatusTracker;\r\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-status-tracker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A reusable status tracker component for React with horizontal and vertical modes",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
|
|
7
|
+
"main": "dist/index.cjs.js",
|
|
8
|
+
"module": "dist/index.esm.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
|
|
11
|
+
"files": ["dist"],
|
|
12
|
+
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "rollup -c",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^18 || ^19",
|
|
20
|
+
"react-dom": "^18 || ^19",
|
|
21
|
+
|
|
22
|
+
"@mui/material": "^5.15.0",
|
|
23
|
+
"@mui/system": "^5.15.0",
|
|
24
|
+
"@mui/utils": "^5.15.0",
|
|
25
|
+
|
|
26
|
+
"@emotion/react": "^11.11.0",
|
|
27
|
+
"@emotion/styled": "^11.11.0"
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"react": "^18.2.0",
|
|
32
|
+
"react-dom": "^18.2.0",
|
|
33
|
+
|
|
34
|
+
"@mui/material": "^5.15.0",
|
|
35
|
+
"@mui/system": "^5.15.0",
|
|
36
|
+
"@mui/utils": "^5.15.0",
|
|
37
|
+
|
|
38
|
+
"@emotion/react": "^11.11.0",
|
|
39
|
+
"@emotion/styled": "^11.11.0",
|
|
40
|
+
|
|
41
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
42
|
+
"@types/react": "^18.2.45",
|
|
43
|
+
"@types/react-dom": "^18.2.18",
|
|
44
|
+
"rollup": "^4.54.0",
|
|
45
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
46
|
+
"tslib": "^2.8.1",
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
"keywords": [
|
|
51
|
+
"react",
|
|
52
|
+
"status-tracker",
|
|
53
|
+
"mui",
|
|
54
|
+
"stepper",
|
|
55
|
+
"workflow"
|
|
56
|
+
]
|
|
57
|
+
}
|