@ttoss/components 2.11.6 → 2.11.7
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.
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { BadgeProps } from '@ttoss/ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Visual variant for the icon wrapper.
|
|
6
|
+
*/
|
|
7
|
+
type EnhancedTitleVariant = 'spotlight-accent' | 'spotlight-primary' | 'primary' | 'secondary' | 'accent' | 'positive' | 'negative' | 'informative' | 'muted';
|
|
8
|
+
/**
|
|
9
|
+
* Badge configuration for top and bottom badge sections.
|
|
10
|
+
*/
|
|
11
|
+
interface EnhancedTitleBadge {
|
|
12
|
+
/**
|
|
13
|
+
* Icon to display in the badge.
|
|
14
|
+
*/
|
|
15
|
+
icon?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Badge label text.
|
|
18
|
+
*/
|
|
19
|
+
label: string;
|
|
20
|
+
/**
|
|
21
|
+
* Badge visual variant.
|
|
22
|
+
*/
|
|
23
|
+
variant?: BadgeProps['variant'];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Props for the EnhancedTitle component.
|
|
27
|
+
*/
|
|
28
|
+
interface EnhancedTitleProps {
|
|
29
|
+
/**
|
|
30
|
+
* Visual variant for the icon wrapper.
|
|
31
|
+
* @default 'primary'
|
|
32
|
+
*/
|
|
33
|
+
variant?: EnhancedTitleVariant;
|
|
34
|
+
/**
|
|
35
|
+
* Icon to display next to the title.
|
|
36
|
+
*/
|
|
37
|
+
icon?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Main title text (heading).
|
|
40
|
+
*/
|
|
41
|
+
title: string;
|
|
42
|
+
/**
|
|
43
|
+
* Optional subtitle/description text.
|
|
44
|
+
*/
|
|
45
|
+
description?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Optional text displayed next to the title (e.g., price, metadata).
|
|
48
|
+
*/
|
|
49
|
+
frontTitle?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Badges to display above the title.
|
|
52
|
+
*/
|
|
53
|
+
topBadges?: EnhancedTitleBadge[];
|
|
54
|
+
/**
|
|
55
|
+
* Badges to display below the title.
|
|
56
|
+
*/
|
|
57
|
+
bottomBadges?: EnhancedTitleBadge[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* EnhancedTitle component renders a structured title section with icon, badges, and metadata.
|
|
62
|
+
*
|
|
63
|
+
* This component is useful for displaying rich title sections with status indicators,
|
|
64
|
+
* feature tags, and supplementary information in a consistent layout.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```tsx
|
|
68
|
+
* <EnhancedTitle
|
|
69
|
+
* icon="fluent:shield-24-filled"
|
|
70
|
+
* title="Starter Plan"
|
|
71
|
+
* frontTitle="R$ 49,90/mês"
|
|
72
|
+
* description="Perfect for small teams"
|
|
73
|
+
* variant="primary"
|
|
74
|
+
* topBadges={[
|
|
75
|
+
* { label: 'Active', variant: 'positive', icon: 'fluent:checkmark-circle-24-filled' }
|
|
76
|
+
* ]}
|
|
77
|
+
* bottomBadges={[
|
|
78
|
+
* { label: 'OneClick Tracking', icon: 'fluent:checkmark-24-filled' }
|
|
79
|
+
* ]}
|
|
80
|
+
* />
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```tsx
|
|
85
|
+
* <EnhancedTitle
|
|
86
|
+
* title="Pro Plan"
|
|
87
|
+
* frontTitle="$99/month"
|
|
88
|
+
* variant="accent"
|
|
89
|
+
* topBadges={[
|
|
90
|
+
* { label: 'Most Popular', variant: 'informative' }
|
|
91
|
+
* ]}
|
|
92
|
+
* />
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare const EnhancedTitle: ({ variant, icon, title, description, frontTitle, topBadges, bottomBadges, }: EnhancedTitleProps) => react_jsx_runtime.JSX.Element;
|
|
96
|
+
|
|
97
|
+
export { EnhancedTitle, type EnhancedTitleBadge, type EnhancedTitleProps, type EnhancedTitleVariant };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { IconType } from '@ttoss/react-icons';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base metric properties shared by all metric types.
|
|
6
|
+
*/
|
|
7
|
+
interface BaseMetric {
|
|
8
|
+
/**
|
|
9
|
+
* Label displayed above the metric value.
|
|
10
|
+
*/
|
|
11
|
+
label: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional tooltip text or action handler for additional context.
|
|
14
|
+
* When a string is provided, it displays a simple tooltip.
|
|
15
|
+
* When a function is provided, it's called when the tooltip icon is clicked.
|
|
16
|
+
*/
|
|
17
|
+
tooltip?: string | (() => void);
|
|
18
|
+
/**
|
|
19
|
+
* Icon to display alongside the metric.
|
|
20
|
+
*/
|
|
21
|
+
icon?: IconType;
|
|
22
|
+
/**
|
|
23
|
+
* Optional click handler to make the metric card interactive.
|
|
24
|
+
*/
|
|
25
|
+
onClick?: () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Optional help article action handler.
|
|
28
|
+
*/
|
|
29
|
+
helpArticleAction?: () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Date-based metric for displaying dates like expiration or renewal.
|
|
33
|
+
*/
|
|
34
|
+
interface DateMetric extends BaseMetric {
|
|
35
|
+
type: 'date';
|
|
36
|
+
/**
|
|
37
|
+
* The date value to display.
|
|
38
|
+
*/
|
|
39
|
+
date: string;
|
|
40
|
+
/**
|
|
41
|
+
* Optional message showing remaining days.
|
|
42
|
+
*/
|
|
43
|
+
remainingDaysMessage?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether to show a warning indicator.
|
|
46
|
+
*/
|
|
47
|
+
isWarning?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Percentage-based metric with progress bar.
|
|
51
|
+
*/
|
|
52
|
+
interface PercentageMetric extends BaseMetric {
|
|
53
|
+
type: 'percentage';
|
|
54
|
+
/**
|
|
55
|
+
* Current value.
|
|
56
|
+
*/
|
|
57
|
+
current: number;
|
|
58
|
+
/**
|
|
59
|
+
* Maximum value. Use null for unlimited.
|
|
60
|
+
*/
|
|
61
|
+
max: number | null;
|
|
62
|
+
/**
|
|
63
|
+
* Custom formatter for displaying values.
|
|
64
|
+
*/
|
|
65
|
+
formatValue?: (value: number) => string;
|
|
66
|
+
/**
|
|
67
|
+
* Percentage threshold at which to show an alert.
|
|
68
|
+
*/
|
|
69
|
+
showAlertThreshold?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Number-based metric for displaying counts.
|
|
73
|
+
*/
|
|
74
|
+
interface NumberMetric extends BaseMetric {
|
|
75
|
+
type: 'number';
|
|
76
|
+
/**
|
|
77
|
+
* Current value.
|
|
78
|
+
*/
|
|
79
|
+
current: number;
|
|
80
|
+
/**
|
|
81
|
+
* Maximum value. Use null for unlimited.
|
|
82
|
+
*/
|
|
83
|
+
max: number | null;
|
|
84
|
+
/**
|
|
85
|
+
* Custom formatter for displaying values.
|
|
86
|
+
*/
|
|
87
|
+
formatValue?: (value: number) => string;
|
|
88
|
+
/**
|
|
89
|
+
* Optional footer text below the metric.
|
|
90
|
+
*/
|
|
91
|
+
footerText?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Union type for all supported metric types.
|
|
95
|
+
*/
|
|
96
|
+
type Metric = DateMetric | PercentageMetric | NumberMetric;
|
|
97
|
+
/**
|
|
98
|
+
* Props for the MetricCard component.
|
|
99
|
+
*/
|
|
100
|
+
interface MetricCardProps {
|
|
101
|
+
/**
|
|
102
|
+
* The metric configuration to display.
|
|
103
|
+
*/
|
|
104
|
+
metric: Metric;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the card is in loading state.
|
|
107
|
+
*/
|
|
108
|
+
isLoading?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* MetricCard component displays a metric in a consistent card layout.
|
|
113
|
+
*
|
|
114
|
+
* It supports three metric types:
|
|
115
|
+
* - **date**: displays a date and optional remaining-days message
|
|
116
|
+
* - **percentage**: displays current/max values and a progress bar
|
|
117
|
+
* - **number**: displays current/max values and an optional footer text
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```tsx
|
|
121
|
+
* <MetricCard
|
|
122
|
+
* metric={{
|
|
123
|
+
* type: 'date',
|
|
124
|
+
* label: 'Renewal date',
|
|
125
|
+
* date: '31/12/2025',
|
|
126
|
+
* icon: 'fluent:calendar-24-regular',
|
|
127
|
+
* remainingDaysMessage: '10 days remaining',
|
|
128
|
+
* }}
|
|
129
|
+
* />
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* <MetricCard
|
|
135
|
+
* metric={{
|
|
136
|
+
* type: 'percentage',
|
|
137
|
+
* label: 'Plan usage',
|
|
138
|
+
* current: 350,
|
|
139
|
+
* max: 1000,
|
|
140
|
+
* icon: 'fluent:gauge-24-regular',
|
|
141
|
+
* showAlertThreshold: 80,
|
|
142
|
+
* }}
|
|
143
|
+
* />
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare const MetricCard: ({ metric, isLoading }: MetricCardProps) => react_jsx_runtime.JSX.Element | null;
|
|
147
|
+
|
|
148
|
+
export { type BaseMetric, type DateMetric, type Metric, MetricCard, type MetricCardProps, type NumberMetric, type PercentageMetric };
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { __name } from "../chunk-V4MHYKRI.js";
|
|
4
|
+
|
|
5
|
+
// src/components/EnhancedTitle/EnhancedTitle.tsx
|
|
6
|
+
import { Icon } from "@ttoss/react-icons";
|
|
7
|
+
import { Badge, Flex, Heading, Stack, Text } from "@ttoss/ui";
|
|
8
|
+
|
|
9
|
+
// src/components/EnhancedTitle/EnhancedTitle.styles.ts
|
|
10
|
+
import { keyframes } from "@ttoss/ui";
|
|
11
|
+
var gradientFlow = keyframes({
|
|
12
|
+
"0%": {
|
|
13
|
+
backgroundPosition: "0% 50%"
|
|
14
|
+
},
|
|
15
|
+
"50%": {
|
|
16
|
+
backgroundPosition: "100% 50%"
|
|
17
|
+
},
|
|
18
|
+
"100%": {
|
|
19
|
+
backgroundPosition: "0% 50%"
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
var getAccentGradientBackground = /* @__PURE__ */__name(t => {
|
|
23
|
+
const theme = t;
|
|
24
|
+
const start = theme.colors?.action?.background?.accent?.default || theme.colors?.input?.background?.accent?.default;
|
|
25
|
+
if (!start) return void 0;
|
|
26
|
+
const middle = theme.colors?.action?.background?.accent?.active || theme.colors?.input?.background?.accent?.active || start;
|
|
27
|
+
return `linear-gradient(270deg, ${start}, ${middle}, ${start})`;
|
|
28
|
+
}, "getAccentGradientBackground");
|
|
29
|
+
var getPrimaryGradientBackground = /* @__PURE__ */__name(t => {
|
|
30
|
+
const theme = t;
|
|
31
|
+
const start = theme.colors?.action?.background?.primary?.default;
|
|
32
|
+
if (!start) return void 0;
|
|
33
|
+
const middle = theme.colors?.action?.background?.secondary?.default || start;
|
|
34
|
+
return `linear-gradient(270deg, ${start}, ${middle}, ${start})`;
|
|
35
|
+
}, "getPrimaryGradientBackground");
|
|
36
|
+
var getEnhancedTitleIconSx = /* @__PURE__ */__name(variant => {
|
|
37
|
+
const variantStyles = {
|
|
38
|
+
"spotlight-accent": {
|
|
39
|
+
backgroundColor: "input.background.accent.default",
|
|
40
|
+
color: "action.text.accent.default",
|
|
41
|
+
borderColor: "display.border.muted.default",
|
|
42
|
+
background: getAccentGradientBackground,
|
|
43
|
+
backgroundSize: "400% 400%",
|
|
44
|
+
animation: `${gradientFlow} 6s ease infinite`
|
|
45
|
+
},
|
|
46
|
+
"spotlight-primary": {
|
|
47
|
+
backgroundColor: "action.background.primary.default",
|
|
48
|
+
color: "display.text.accent.default",
|
|
49
|
+
borderColor: "display.border.muted.default",
|
|
50
|
+
background: getPrimaryGradientBackground,
|
|
51
|
+
backgroundSize: "400% 400%",
|
|
52
|
+
animation: `${gradientFlow} 6s ease infinite`
|
|
53
|
+
},
|
|
54
|
+
primary: {
|
|
55
|
+
backgroundColor: "action.background.primary.default",
|
|
56
|
+
color: "action.text.primary.default",
|
|
57
|
+
borderColor: "display.border.muted.default"
|
|
58
|
+
},
|
|
59
|
+
secondary: {
|
|
60
|
+
backgroundColor: "action.background.secondary.default",
|
|
61
|
+
color: "action.text.primary.default",
|
|
62
|
+
borderColor: "display.border.muted.default"
|
|
63
|
+
},
|
|
64
|
+
accent: {
|
|
65
|
+
backgroundColor: "action.background.accent.default",
|
|
66
|
+
color: "action.text.accent.default",
|
|
67
|
+
borderColor: "display.border.muted.default"
|
|
68
|
+
},
|
|
69
|
+
positive: {
|
|
70
|
+
backgroundColor: "display.bg.positive.boldest",
|
|
71
|
+
color: "display.fg.positive.bolder",
|
|
72
|
+
borderColor: "display.border.muted.default"
|
|
73
|
+
},
|
|
74
|
+
negative: {
|
|
75
|
+
backgroundColor: "display.bg.negative.boldest",
|
|
76
|
+
color: "display.fg.negative.bolder",
|
|
77
|
+
borderColor: "display.border.muted.default"
|
|
78
|
+
},
|
|
79
|
+
informative: {
|
|
80
|
+
backgroundColor: "display.bg.informative.boldest",
|
|
81
|
+
color: "display.fg.informative.bolder",
|
|
82
|
+
borderColor: "display.border.muted.default"
|
|
83
|
+
},
|
|
84
|
+
muted: {
|
|
85
|
+
backgroundColor: "display.bg.muted.boldest",
|
|
86
|
+
color: "display.fg.muted.bolder",
|
|
87
|
+
borderColor: "display.border.muted.default"
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
flexShrink: 0,
|
|
92
|
+
alignItems: "center",
|
|
93
|
+
justifyContent: "center",
|
|
94
|
+
borderRadius: "2xl",
|
|
95
|
+
border: "md",
|
|
96
|
+
width: "56px",
|
|
97
|
+
height: "56px",
|
|
98
|
+
...variantStyles[variant]
|
|
99
|
+
};
|
|
100
|
+
}, "getEnhancedTitleIconSx");
|
|
101
|
+
|
|
102
|
+
// src/components/EnhancedTitle/EnhancedTitle.tsx
|
|
103
|
+
var EnhancedTitle = /* @__PURE__ */__name(({
|
|
104
|
+
variant = "spotlight-primary",
|
|
105
|
+
icon,
|
|
106
|
+
title,
|
|
107
|
+
description,
|
|
108
|
+
frontTitle,
|
|
109
|
+
topBadges = [],
|
|
110
|
+
bottomBadges = []
|
|
111
|
+
}) => {
|
|
112
|
+
return /* @__PURE__ */React.createElement(Stack, {
|
|
113
|
+
sx: {
|
|
114
|
+
paddingY: "6",
|
|
115
|
+
paddingX: "6",
|
|
116
|
+
width: "full"
|
|
117
|
+
}
|
|
118
|
+
}, /* @__PURE__ */React.createElement(Flex, {
|
|
119
|
+
sx: {
|
|
120
|
+
gap: "6",
|
|
121
|
+
alignItems: "flex-start",
|
|
122
|
+
flexDirection: ["column", "row"]
|
|
123
|
+
}
|
|
124
|
+
}, icon && /* @__PURE__ */React.createElement(Flex, {
|
|
125
|
+
sx: getEnhancedTitleIconSx(variant)
|
|
126
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
127
|
+
icon,
|
|
128
|
+
width: 24,
|
|
129
|
+
height: 24
|
|
130
|
+
})), /* @__PURE__ */React.createElement(Flex, {
|
|
131
|
+
sx: {
|
|
132
|
+
flexDirection: "column",
|
|
133
|
+
gap: ["4", "5"],
|
|
134
|
+
flex: 1
|
|
135
|
+
}
|
|
136
|
+
}, topBadges.length > 0 && /* @__PURE__ */React.createElement(Flex, {
|
|
137
|
+
sx: {
|
|
138
|
+
flexWrap: "wrap",
|
|
139
|
+
gap: "2",
|
|
140
|
+
alignItems: "center"
|
|
141
|
+
}
|
|
142
|
+
}, topBadges.map((badge, index) => {
|
|
143
|
+
return /* @__PURE__ */React.createElement(Badge, {
|
|
144
|
+
key: index,
|
|
145
|
+
icon: badge.icon,
|
|
146
|
+
variant: badge.variant ?? "muted",
|
|
147
|
+
sx: {
|
|
148
|
+
borderRadius: "full"
|
|
149
|
+
}
|
|
150
|
+
}, badge.label);
|
|
151
|
+
})), /* @__PURE__ */React.createElement(Flex, {
|
|
152
|
+
sx: {
|
|
153
|
+
flexDirection: ["column", "row"],
|
|
154
|
+
alignItems: ["flex-start", "baseline"],
|
|
155
|
+
gap: ["1", "3"]
|
|
156
|
+
}
|
|
157
|
+
}, /* @__PURE__ */React.createElement(Heading, {
|
|
158
|
+
as: "h2",
|
|
159
|
+
sx: {
|
|
160
|
+
fontSize: "4xl",
|
|
161
|
+
fontWeight: "semibold",
|
|
162
|
+
color: "display.text.primary.default"
|
|
163
|
+
}
|
|
164
|
+
}, title), frontTitle && /* @__PURE__ */React.createElement(Text, {
|
|
165
|
+
sx: {
|
|
166
|
+
fontSize: "xl",
|
|
167
|
+
color: "display.text.secondary.default"
|
|
168
|
+
}
|
|
169
|
+
}, frontTitle)), description && /* @__PURE__ */React.createElement(Text, {
|
|
170
|
+
sx: {
|
|
171
|
+
fontSize: "md",
|
|
172
|
+
color: "display.text.secondary.default"
|
|
173
|
+
}
|
|
174
|
+
}, description), bottomBadges.length > 0 && /* @__PURE__ */React.createElement(Flex, {
|
|
175
|
+
sx: {
|
|
176
|
+
flexWrap: "wrap",
|
|
177
|
+
gap: "2"
|
|
178
|
+
}
|
|
179
|
+
}, bottomBadges.map((badge, index) => {
|
|
180
|
+
return /* @__PURE__ */React.createElement(Badge, {
|
|
181
|
+
key: index,
|
|
182
|
+
icon: badge.icon ?? "fluent:checkmark-24-filled",
|
|
183
|
+
variant: badge.variant ?? "muted",
|
|
184
|
+
sx: {
|
|
185
|
+
borderRadius: "full"
|
|
186
|
+
}
|
|
187
|
+
}, badge.label);
|
|
188
|
+
})))));
|
|
189
|
+
}, "EnhancedTitle");
|
|
190
|
+
export { EnhancedTitle };
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { __name } from "../chunk-V4MHYKRI.js";
|
|
4
|
+
|
|
5
|
+
// src/components/MetricCard/MetricCard.tsx
|
|
6
|
+
import { defineMessages, useI18n } from "@ttoss/react-i18n";
|
|
7
|
+
import { Icon } from "@ttoss/react-icons";
|
|
8
|
+
import { Box, Card, Flex, Text, TooltipIcon } from "@ttoss/ui";
|
|
9
|
+
var messages = defineMessages({
|
|
10
|
+
ofMax: {
|
|
11
|
+
id: "oYpm71",
|
|
12
|
+
defaultMessage: [{
|
|
13
|
+
"type": 0,
|
|
14
|
+
"value": "of "
|
|
15
|
+
}, {
|
|
16
|
+
"type": 1,
|
|
17
|
+
"value": "max"
|
|
18
|
+
}]
|
|
19
|
+
},
|
|
20
|
+
percentageUsed: {
|
|
21
|
+
id: "zr0OS6",
|
|
22
|
+
defaultMessage: [{
|
|
23
|
+
"type": 1,
|
|
24
|
+
"value": "percentage"
|
|
25
|
+
}, {
|
|
26
|
+
"type": 0,
|
|
27
|
+
"value": "% used"
|
|
28
|
+
}]
|
|
29
|
+
},
|
|
30
|
+
unlimited: {
|
|
31
|
+
id: "rskBv4",
|
|
32
|
+
defaultMessage: [{
|
|
33
|
+
"type": 0,
|
|
34
|
+
"value": "Unlimited"
|
|
35
|
+
}]
|
|
36
|
+
},
|
|
37
|
+
infinity: {
|
|
38
|
+
id: "0EjvY6",
|
|
39
|
+
defaultMessage: [{
|
|
40
|
+
"type": 0,
|
|
41
|
+
"value": "∞"
|
|
42
|
+
}]
|
|
43
|
+
},
|
|
44
|
+
nearLimit: {
|
|
45
|
+
id: "1DbX9V",
|
|
46
|
+
defaultMessage: [{
|
|
47
|
+
"type": 0,
|
|
48
|
+
"value": "Near limit"
|
|
49
|
+
}]
|
|
50
|
+
},
|
|
51
|
+
reachedLimit: {
|
|
52
|
+
id: "4NwCn9",
|
|
53
|
+
defaultMessage: [{
|
|
54
|
+
"type": 0,
|
|
55
|
+
"value": "Reached limit"
|
|
56
|
+
}]
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
var MetricIconWrapper = /* @__PURE__ */__name(({
|
|
60
|
+
icon
|
|
61
|
+
}) => {
|
|
62
|
+
return /* @__PURE__ */React.createElement(Flex, {
|
|
63
|
+
sx: {
|
|
64
|
+
alignItems: "center",
|
|
65
|
+
justifyContent: "center",
|
|
66
|
+
borderRadius: "full",
|
|
67
|
+
border: "md",
|
|
68
|
+
borderColor: "display.border.muted.default",
|
|
69
|
+
backgroundColor: "display.background.muted.default",
|
|
70
|
+
color: "display.text.secondary.default",
|
|
71
|
+
width: "48px",
|
|
72
|
+
height: "48px",
|
|
73
|
+
flexShrink: 0
|
|
74
|
+
}
|
|
75
|
+
}, icon && /* @__PURE__ */React.createElement(Icon, {
|
|
76
|
+
icon
|
|
77
|
+
}));
|
|
78
|
+
}, "MetricIconWrapper");
|
|
79
|
+
var MetricCardHeader = /* @__PURE__ */__name(({
|
|
80
|
+
label,
|
|
81
|
+
tooltip,
|
|
82
|
+
isClickable
|
|
83
|
+
}) => {
|
|
84
|
+
const isTooltipAction = typeof tooltip === "function";
|
|
85
|
+
const tooltipText = typeof tooltip === "string" ? tooltip : void 0;
|
|
86
|
+
return /* @__PURE__ */React.createElement(Flex, {
|
|
87
|
+
sx: {
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
gap: "2"
|
|
90
|
+
}
|
|
91
|
+
}, /* @__PURE__ */React.createElement(Text, {
|
|
92
|
+
sx: {
|
|
93
|
+
fontSize: "sm",
|
|
94
|
+
fontWeight: "medium",
|
|
95
|
+
color: "display.text.secondary.default"
|
|
96
|
+
}
|
|
97
|
+
}, label), tooltipText && /* @__PURE__ */React.createElement(TooltipIcon, {
|
|
98
|
+
icon: "fluent:info-24-regular",
|
|
99
|
+
tooltip: {
|
|
100
|
+
children: tooltipText
|
|
101
|
+
},
|
|
102
|
+
variant: "info"
|
|
103
|
+
}), isTooltipAction && /* @__PURE__ */React.createElement(Text, {
|
|
104
|
+
onClick: /* @__PURE__ */__name(e => {
|
|
105
|
+
e.stopPropagation();
|
|
106
|
+
tooltip();
|
|
107
|
+
}, "onClick"),
|
|
108
|
+
sx: {
|
|
109
|
+
fontSize: "sm",
|
|
110
|
+
color: "display.text.secondary.default",
|
|
111
|
+
cursor: "pointer",
|
|
112
|
+
":hover": {
|
|
113
|
+
color: "action.text.primary.default"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
117
|
+
icon: "fluent:info-24-regular",
|
|
118
|
+
inline: true
|
|
119
|
+
})), isClickable && /* @__PURE__ */React.createElement(Text, {
|
|
120
|
+
sx: {
|
|
121
|
+
fontSize: "sm",
|
|
122
|
+
color: "display.text.secondary.default"
|
|
123
|
+
}
|
|
124
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
125
|
+
icon: "fluent:open-24-regular",
|
|
126
|
+
inline: true
|
|
127
|
+
})));
|
|
128
|
+
}, "MetricCardHeader");
|
|
129
|
+
var DateMetricContent = /* @__PURE__ */__name(({
|
|
130
|
+
metric
|
|
131
|
+
}) => {
|
|
132
|
+
return /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement(Text, {
|
|
133
|
+
sx: {
|
|
134
|
+
fontSize: "2xl",
|
|
135
|
+
fontWeight: "bold",
|
|
136
|
+
color: "display.text.primary.default"
|
|
137
|
+
}
|
|
138
|
+
}, metric.date), metric.remainingDaysMessage && /* @__PURE__ */React.createElement(Flex, {
|
|
139
|
+
sx: {
|
|
140
|
+
alignItems: "center",
|
|
141
|
+
gap: "2"
|
|
142
|
+
}
|
|
143
|
+
}, /* @__PURE__ */React.createElement(Text, {
|
|
144
|
+
sx: {
|
|
145
|
+
fontSize: "sm",
|
|
146
|
+
color: metric.isWarning ? "feedback.text.caution.default" : "display.text.secondary.default"
|
|
147
|
+
}
|
|
148
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
149
|
+
icon: metric.isWarning ? "fluent:warning-24-regular" : "fluent:clock-24-regular",
|
|
150
|
+
inline: true
|
|
151
|
+
})), /* @__PURE__ */React.createElement(Text, {
|
|
152
|
+
sx: {
|
|
153
|
+
fontSize: "sm",
|
|
154
|
+
color: metric.isWarning ? "feedback.text.caution.default" : "display.text.secondary.default"
|
|
155
|
+
}
|
|
156
|
+
}, metric.remainingDaysMessage)));
|
|
157
|
+
}, "DateMetricContent");
|
|
158
|
+
var PercentageMetricContent = /* @__PURE__ */__name(({
|
|
159
|
+
metric
|
|
160
|
+
}) => {
|
|
161
|
+
const {
|
|
162
|
+
intl
|
|
163
|
+
} = useI18n();
|
|
164
|
+
const percentage = metric.max === null || metric.max <= 0 ? null : Math.min(Math.round(metric.current / metric.max * 100), 100);
|
|
165
|
+
const formatValue = metric.formatValue || (val => {
|
|
166
|
+
return val.toString();
|
|
167
|
+
});
|
|
168
|
+
const showAlert = percentage !== null && metric.showAlertThreshold !== void 0 && percentage >= metric.showAlertThreshold;
|
|
169
|
+
const isOverLimit = percentage !== null && percentage >= 100;
|
|
170
|
+
const maxText = metric.max !== null ? formatValue(metric.max) : intl.formatMessage(messages.infinity);
|
|
171
|
+
return /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement(Flex, {
|
|
172
|
+
sx: {
|
|
173
|
+
alignItems: "baseline",
|
|
174
|
+
justifyContent: "space-between",
|
|
175
|
+
gap: "2"
|
|
176
|
+
}
|
|
177
|
+
}, /* @__PURE__ */React.createElement(Text, {
|
|
178
|
+
sx: {
|
|
179
|
+
fontSize: "2xl",
|
|
180
|
+
fontWeight: "bold",
|
|
181
|
+
color: "display.text.primary.default"
|
|
182
|
+
}
|
|
183
|
+
}, formatValue(metric.current)), /* @__PURE__ */React.createElement(Text, {
|
|
184
|
+
sx: {
|
|
185
|
+
fontSize: "sm",
|
|
186
|
+
color: "display.text.secondary.default"
|
|
187
|
+
}
|
|
188
|
+
}, intl.formatMessage(messages.ofMax, {
|
|
189
|
+
max: maxText
|
|
190
|
+
}))), /* @__PURE__ */React.createElement(Box, {
|
|
191
|
+
sx: {
|
|
192
|
+
width: "full",
|
|
193
|
+
height: "8px",
|
|
194
|
+
backgroundColor: "display.background.secondary.default",
|
|
195
|
+
borderRadius: "full",
|
|
196
|
+
overflow: "hidden"
|
|
197
|
+
}
|
|
198
|
+
}, /* @__PURE__ */React.createElement(Box, {
|
|
199
|
+
sx: {
|
|
200
|
+
height: "full",
|
|
201
|
+
width: percentage !== null ? `${percentage}%` : "100%",
|
|
202
|
+
backgroundColor: "action.background.primary.default",
|
|
203
|
+
borderRadius: "full",
|
|
204
|
+
transition: "width 0.5s ease-out"
|
|
205
|
+
}
|
|
206
|
+
})), /* @__PURE__ */React.createElement(Flex, {
|
|
207
|
+
sx: {
|
|
208
|
+
alignItems: "center",
|
|
209
|
+
justifyContent: "space-between",
|
|
210
|
+
fontSize: "xs"
|
|
211
|
+
}
|
|
212
|
+
}, /* @__PURE__ */React.createElement(Text, {
|
|
213
|
+
sx: {
|
|
214
|
+
color: "display.text.secondary.default"
|
|
215
|
+
}
|
|
216
|
+
}, percentage !== null ? intl.formatMessage(messages.percentageUsed, {
|
|
217
|
+
percentage
|
|
218
|
+
}) : intl.formatMessage(messages.unlimited)), showAlert && !isOverLimit && /* @__PURE__ */React.createElement(Flex, {
|
|
219
|
+
sx: {
|
|
220
|
+
alignItems: "center",
|
|
221
|
+
gap: "1",
|
|
222
|
+
color: "feedback.text.caution.default"
|
|
223
|
+
}
|
|
224
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
225
|
+
icon: "fluent:warning-24-regular"
|
|
226
|
+
}), /* @__PURE__ */React.createElement(Text, {
|
|
227
|
+
sx: {
|
|
228
|
+
fontWeight: "medium"
|
|
229
|
+
}
|
|
230
|
+
}, intl.formatMessage(messages.nearLimit))), showAlert && isOverLimit && /* @__PURE__ */React.createElement(Flex, {
|
|
231
|
+
sx: {
|
|
232
|
+
alignItems: "center",
|
|
233
|
+
gap: "1",
|
|
234
|
+
color: "feedback.text.negative.default"
|
|
235
|
+
}
|
|
236
|
+
}, /* @__PURE__ */React.createElement(Icon, {
|
|
237
|
+
icon: "fluent:warning-24-regular"
|
|
238
|
+
}), /* @__PURE__ */React.createElement(Text, {
|
|
239
|
+
sx: {
|
|
240
|
+
fontWeight: "medium",
|
|
241
|
+
color: "feedback.text.negative.default"
|
|
242
|
+
}
|
|
243
|
+
}, intl.formatMessage(messages.reachedLimit)))));
|
|
244
|
+
}, "PercentageMetricContent");
|
|
245
|
+
var NumberMetricContent = /* @__PURE__ */__name(({
|
|
246
|
+
metric
|
|
247
|
+
}) => {
|
|
248
|
+
const {
|
|
249
|
+
intl
|
|
250
|
+
} = useI18n();
|
|
251
|
+
const formatValue = metric.formatValue || (val => {
|
|
252
|
+
return val.toString();
|
|
253
|
+
});
|
|
254
|
+
const maxText = metric.max !== null ? formatValue(metric.max) : intl.formatMessage(messages.infinity);
|
|
255
|
+
return /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement(Flex, {
|
|
256
|
+
sx: {
|
|
257
|
+
alignItems: "baseline",
|
|
258
|
+
gap: "3"
|
|
259
|
+
}
|
|
260
|
+
}, /* @__PURE__ */React.createElement(Text, {
|
|
261
|
+
sx: {
|
|
262
|
+
fontSize: "2xl",
|
|
263
|
+
fontWeight: "bold",
|
|
264
|
+
color: "display.text.primary.default"
|
|
265
|
+
}
|
|
266
|
+
}, formatValue(metric.current)), /* @__PURE__ */React.createElement(Text, {
|
|
267
|
+
sx: {
|
|
268
|
+
fontSize: "sm",
|
|
269
|
+
color: "display.text.secondary.default"
|
|
270
|
+
}
|
|
271
|
+
}, intl.formatMessage(messages.ofMax, {
|
|
272
|
+
max: maxText
|
|
273
|
+
}))), metric.footerText && /* @__PURE__ */React.createElement(Text, {
|
|
274
|
+
sx: {
|
|
275
|
+
fontSize: "xs",
|
|
276
|
+
color: "display.text.secondary.default",
|
|
277
|
+
lineHeight: "relaxed",
|
|
278
|
+
maxWidth: "300px"
|
|
279
|
+
}
|
|
280
|
+
}, metric.footerText));
|
|
281
|
+
}, "NumberMetricContent");
|
|
282
|
+
var MetricCard = /* @__PURE__ */__name(({
|
|
283
|
+
metric,
|
|
284
|
+
isLoading = false
|
|
285
|
+
}) => {
|
|
286
|
+
if (isLoading) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const isClickable = Boolean(metric.onClick || metric.helpArticleAction);
|
|
290
|
+
return /* @__PURE__ */React.createElement(Card, {
|
|
291
|
+
onClick: metric.onClick || metric.helpArticleAction,
|
|
292
|
+
sx: {
|
|
293
|
+
backgroundColor: "display.background.muted.default",
|
|
294
|
+
padding: "6",
|
|
295
|
+
cursor: isClickable ? "pointer" : "default",
|
|
296
|
+
transition: "all 0.2s ease",
|
|
297
|
+
minWidth: ["full", "full", "400px"],
|
|
298
|
+
":hover": {
|
|
299
|
+
transform: "scale(1.01)"
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}, /* @__PURE__ */React.createElement(Flex, {
|
|
303
|
+
sx: {
|
|
304
|
+
gap: "4",
|
|
305
|
+
width: "full"
|
|
306
|
+
}
|
|
307
|
+
}, /* @__PURE__ */React.createElement(MetricIconWrapper, {
|
|
308
|
+
icon: metric.icon
|
|
309
|
+
}), /* @__PURE__ */React.createElement(Flex, {
|
|
310
|
+
sx: {
|
|
311
|
+
flex: 1,
|
|
312
|
+
flexDirection: "column",
|
|
313
|
+
gap: "2"
|
|
314
|
+
}
|
|
315
|
+
}, /* @__PURE__ */React.createElement(MetricCardHeader, {
|
|
316
|
+
label: metric.label,
|
|
317
|
+
tooltip: metric.tooltip,
|
|
318
|
+
isClickable
|
|
319
|
+
}), metric.type === "date" && /* @__PURE__ */React.createElement(DateMetricContent, {
|
|
320
|
+
metric
|
|
321
|
+
}), metric.type === "percentage" && /* @__PURE__ */React.createElement(PercentageMetricContent, {
|
|
322
|
+
metric
|
|
323
|
+
}), metric.type === "number" && /* @__PURE__ */React.createElement(NumberMetricContent, {
|
|
324
|
+
metric
|
|
325
|
+
}))));
|
|
326
|
+
}, "MetricCard");
|
|
327
|
+
export { MetricCard };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/components",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.7",
|
|
4
4
|
"description": "React components for ttoss ecosystem.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ttoss",
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
"types": "./dist/Markdown/index.d.ts",
|
|
55
55
|
"default": "./dist/esm/Markdown/index.js"
|
|
56
56
|
},
|
|
57
|
-
"./MetricCard": {
|
|
58
|
-
"types": "./dist/MetricCard/index.d.ts",
|
|
59
|
-
"default": "./dist/esm/MetricCard/index.js"
|
|
60
|
-
},
|
|
61
57
|
"./Menu": {
|
|
62
58
|
"types": "./dist/Menu/index.d.ts",
|
|
63
59
|
"default": "./dist/esm/Menu/index.js"
|
|
64
60
|
},
|
|
61
|
+
"./MetricCard": {
|
|
62
|
+
"types": "./dist/MetricCard/index.d.ts",
|
|
63
|
+
"default": "./dist/esm/MetricCard/index.js"
|
|
64
|
+
},
|
|
65
65
|
"./Modal": {
|
|
66
66
|
"types": "./dist/Modal/index.d.ts",
|
|
67
67
|
"default": "./dist/esm/Modal/index.js"
|
|
@@ -137,12 +137,12 @@
|
|
|
137
137
|
"tsup": "^8.5.1",
|
|
138
138
|
"tsx": "^4.19.2",
|
|
139
139
|
"@ttoss/config": "^1.35.12",
|
|
140
|
-
"@ttoss/react-hooks": "^2.1.11",
|
|
141
140
|
"@ttoss/i18n-cli": "^0.7.38",
|
|
142
|
-
"@ttoss/react-i18n": "^2.0.25",
|
|
143
141
|
"@ttoss/react-icons": "^0.5.6",
|
|
144
|
-
"@ttoss/
|
|
145
|
-
"@ttoss/
|
|
142
|
+
"@ttoss/react-hooks": "^2.1.11",
|
|
143
|
+
"@ttoss/react-i18n": "^2.0.25",
|
|
144
|
+
"@ttoss/test-utils": "^4.0.2",
|
|
145
|
+
"@ttoss/ui": "^6.4.0"
|
|
146
146
|
},
|
|
147
147
|
"keywords": [
|
|
148
148
|
"React",
|