@ttoss/react-billing 0.1.2 → 0.1.4
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 +74 -1
- package/dist/esm/index.js +328 -35
- package/dist/index.d.ts +263 -4
- package/package.json +4 -3
- package/dist/index.d.cts +0 -48
- package/dist/index.js +0 -354
package/README.md
CHANGED
|
@@ -1,7 +1,80 @@
|
|
|
1
1
|
# @ttoss/react-billing
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Billing UI components for React apps.
|
|
4
|
+
|
|
5
|
+
Built on top of `@ttoss/ui`.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
pnpm add @ttoss/react-billing
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
This package expects your app to be wrapped with `@ttoss/ui` `ThemeProvider`.
|
|
16
|
+
|
|
17
|
+
### PlanCard
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { PlanCard } from '@ttoss/react-billing';
|
|
21
|
+
|
|
22
|
+
export const Example = () => (
|
|
23
|
+
<PlanCard
|
|
24
|
+
title="Pro"
|
|
25
|
+
subtitle="Best for teams"
|
|
26
|
+
price={{
|
|
27
|
+
value: 'R$ 99,00',
|
|
28
|
+
interval: 'month',
|
|
29
|
+
description: 'Billed monthly',
|
|
30
|
+
}}
|
|
31
|
+
metadata={[
|
|
32
|
+
{ title: 'Seats', value: '5', icon: 'fluent:people-24-regular' },
|
|
33
|
+
{
|
|
34
|
+
title: 'Support',
|
|
35
|
+
value: 'Priority',
|
|
36
|
+
icon: 'fluent:chat-help-24-regular',
|
|
37
|
+
},
|
|
38
|
+
]}
|
|
39
|
+
features={[{ label: 'Unlimited projects' }, { label: 'SSO' }]}
|
|
40
|
+
buttonProps={{ label: 'Choose plan', variant: 'accent' }}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### SubscriptionCard
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { SubscriptionCard } from '@ttoss/react-billing';
|
|
49
|
+
|
|
50
|
+
export const Example = () => (
|
|
51
|
+
<SubscriptionCard
|
|
52
|
+
planName="Pro"
|
|
53
|
+
price={{ value: 'R$ 99,00', interval: 'month' }}
|
|
54
|
+
status={{ status: 'active', interval: 'Monthly' }}
|
|
55
|
+
features={[{ label: 'Unlimited projects' }, { label: 'SSO' }]}
|
|
56
|
+
actions={[{ label: 'Manage', onClick: () => {}, variant: 'accent' }]}
|
|
57
|
+
metrics={[
|
|
58
|
+
{
|
|
59
|
+
type: 'date',
|
|
60
|
+
label: 'Renews on',
|
|
61
|
+
date: '2025-01-15',
|
|
62
|
+
icon: 'fluent:calendar-24-regular',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'percentage',
|
|
66
|
+
label: 'Usage',
|
|
67
|
+
current: 75,
|
|
68
|
+
max: 100,
|
|
69
|
+
icon: 'fluent:data-usage-24-regular',
|
|
70
|
+
},
|
|
71
|
+
]}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
```
|
|
4
75
|
|
|
5
76
|
## Exports
|
|
6
77
|
|
|
7
78
|
- `PlanCard`
|
|
79
|
+
- `SubscriptionCard`
|
|
80
|
+
- Types: `PlanCardProps`, `PlanCardVariant`, `PlanCardPrice`, `PlanCardMetadata`, `PlanCardButtonProps`, `PlanCardMetadataSlotService` (and related slot types)
|
package/dist/esm/index.js
CHANGED
|
@@ -6,10 +6,10 @@ var __name = (target, value) => __defProp(target, "name", {
|
|
|
6
6
|
configurable: true
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
// src/components/PlanCard.tsx
|
|
9
|
+
// src/components/planCard/PlanCard.tsx
|
|
10
10
|
import { Box as Box4, Card } from "@ttoss/ui";
|
|
11
11
|
|
|
12
|
-
// src/components/PlanCardCtaSlot.tsx
|
|
12
|
+
// src/components/planCard/PlanCardCtaSlot.tsx
|
|
13
13
|
import { Button, Flex } from "@ttoss/ui";
|
|
14
14
|
var PlanCardCtaSlot = /* @__PURE__ */__name(({
|
|
15
15
|
buttonProps
|
|
@@ -18,11 +18,12 @@ var PlanCardCtaSlot = /* @__PURE__ */__name(({
|
|
|
18
18
|
label: ctaLabel = "Assine agora",
|
|
19
19
|
sx: buttonSx,
|
|
20
20
|
leftIcon,
|
|
21
|
-
variant,
|
|
21
|
+
variant: buttonVariant,
|
|
22
22
|
...restButtonProps
|
|
23
23
|
} = buttonProps ?? {};
|
|
24
24
|
return /* @__PURE__ */React.createElement(Flex, {
|
|
25
25
|
sx: {
|
|
26
|
+
marginTop: "auto",
|
|
26
27
|
paddingY: "2",
|
|
27
28
|
paddingX: "6",
|
|
28
29
|
width: "full",
|
|
@@ -30,7 +31,7 @@ var PlanCardCtaSlot = /* @__PURE__ */__name(({
|
|
|
30
31
|
}
|
|
31
32
|
}, /* @__PURE__ */React.createElement(Button, {
|
|
32
33
|
...restButtonProps,
|
|
33
|
-
variant:
|
|
34
|
+
variant: buttonVariant ?? "accent",
|
|
34
35
|
leftIcon,
|
|
35
36
|
sx: {
|
|
36
37
|
width: "full",
|
|
@@ -41,17 +42,48 @@ var PlanCardCtaSlot = /* @__PURE__ */__name(({
|
|
|
41
42
|
}, ctaLabel));
|
|
42
43
|
}, "PlanCardCtaSlot");
|
|
43
44
|
|
|
44
|
-
// src/components/PlanCardFeaturesSlot.tsx
|
|
45
|
+
// src/components/planCard/PlanCardFeaturesSlot.tsx
|
|
45
46
|
import { Icon } from "@ttoss/react-icons";
|
|
46
47
|
import { Box, Flex as Flex2, Stack, Text } from "@ttoss/ui";
|
|
47
48
|
import * as React2 from "react";
|
|
49
|
+
|
|
50
|
+
// src/components/planCard/PlanCardVariants.ts
|
|
51
|
+
var normalizeVariant = /* @__PURE__ */__name(variantType => {
|
|
52
|
+
if (variantType === "default") return "primary";
|
|
53
|
+
if (variantType === "enterprise") return "secondary";
|
|
54
|
+
return variantType ?? "primary";
|
|
55
|
+
}, "normalizeVariant");
|
|
56
|
+
var getPlanCardVariantStyles = /* @__PURE__ */__name(variantType => {
|
|
57
|
+
const variant = normalizeVariant(variantType);
|
|
58
|
+
const variants = {
|
|
59
|
+
primary: {
|
|
60
|
+
// Primary is the default PlanCard styling (previously `muted`).
|
|
61
|
+
backgroundColor: "display.background.primary.default",
|
|
62
|
+
color: "display.text.primary.default",
|
|
63
|
+
secondaryColor: "display.text.secondary.default",
|
|
64
|
+
borderColor: "display.border.muted.default",
|
|
65
|
+
positiveColor: "feedback.text.positive.default"
|
|
66
|
+
},
|
|
67
|
+
secondary: {
|
|
68
|
+
// Secondary matches the old `enterprise` look.
|
|
69
|
+
backgroundColor: "display.background.primary.active",
|
|
70
|
+
color: "action.text.primary.default",
|
|
71
|
+
secondaryColor: "action.text.primary.default",
|
|
72
|
+
borderColor: "display.border.muted.default",
|
|
73
|
+
positiveColor: "action.text.primary.default"
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
return variants[variant] ?? variants.primary;
|
|
77
|
+
}, "getPlanCardVariantStyles");
|
|
78
|
+
|
|
79
|
+
// src/components/planCard/PlanCardFeaturesSlot.tsx
|
|
48
80
|
var featuresTitle = "RECURSOS";
|
|
49
81
|
var PlanCardFeaturesSlot = /* @__PURE__ */__name(({
|
|
50
82
|
features,
|
|
51
|
-
variant = "
|
|
83
|
+
variant = "primary"
|
|
52
84
|
}) => {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
85
|
+
const variantStyles = getPlanCardVariantStyles(variant);
|
|
86
|
+
const featurePositiveColor = variantStyles.positiveColor;
|
|
55
87
|
return /* @__PURE__ */React2.createElement(Box, {
|
|
56
88
|
sx: {
|
|
57
89
|
paddingY: "4",
|
|
@@ -69,7 +101,7 @@ var PlanCardFeaturesSlot = /* @__PURE__ */__name(({
|
|
|
69
101
|
}, /* @__PURE__ */React2.createElement(Flex2, {
|
|
70
102
|
sx: {
|
|
71
103
|
letterSpacing: "widest",
|
|
72
|
-
color:
|
|
104
|
+
color: variantStyles.color
|
|
73
105
|
}
|
|
74
106
|
}, featuresTitle), /* @__PURE__ */React2.createElement(Flex2, {
|
|
75
107
|
sx: {
|
|
@@ -86,7 +118,7 @@ var PlanCardFeaturesSlot = /* @__PURE__ */__name(({
|
|
|
86
118
|
key: index,
|
|
87
119
|
sx: {
|
|
88
120
|
fontSize: "sm",
|
|
89
|
-
color:
|
|
121
|
+
color: featurePositiveColor,
|
|
90
122
|
alignItems: "center",
|
|
91
123
|
gap: "3"
|
|
92
124
|
}
|
|
@@ -95,22 +127,22 @@ var PlanCardFeaturesSlot = /* @__PURE__ */__name(({
|
|
|
95
127
|
}), /* @__PURE__ */React2.createElement(Text, {
|
|
96
128
|
sx: {
|
|
97
129
|
fontSize: "sm",
|
|
98
|
-
color:
|
|
130
|
+
color: featurePositiveColor,
|
|
99
131
|
alignItems: "center"
|
|
100
132
|
}
|
|
101
133
|
}, String(feature)));
|
|
102
134
|
}))));
|
|
103
135
|
}, "PlanCardFeaturesSlot");
|
|
104
136
|
|
|
105
|
-
// src/components/PlanCardHeaderSlot.tsx
|
|
137
|
+
// src/components/planCard/PlanCardHeaderSlot.tsx
|
|
106
138
|
import { Box as Box2, Flex as Flex3, Heading, Text as Text2 } from "@ttoss/ui";
|
|
107
139
|
var PlanCardHeaderSlot = /* @__PURE__ */__name(({
|
|
108
140
|
title,
|
|
109
141
|
subtitle,
|
|
110
142
|
hasTopTag,
|
|
111
|
-
variant = "
|
|
143
|
+
variant = "primary"
|
|
112
144
|
}) => {
|
|
113
|
-
const
|
|
145
|
+
const variantStyles = getPlanCardVariantStyles(variant);
|
|
114
146
|
return /* @__PURE__ */React.createElement(Box2, {
|
|
115
147
|
sx: {
|
|
116
148
|
paddingY: hasTopTag ? "4" : "8",
|
|
@@ -127,24 +159,24 @@ var PlanCardHeaderSlot = /* @__PURE__ */__name(({
|
|
|
127
159
|
}, /* @__PURE__ */React.createElement(Heading, {
|
|
128
160
|
sx: {
|
|
129
161
|
fontSize: "3xl",
|
|
130
|
-
color:
|
|
162
|
+
color: variantStyles.color
|
|
131
163
|
}
|
|
132
164
|
}, title), subtitle && /* @__PURE__ */React.createElement(Text2, {
|
|
133
165
|
sx: {
|
|
134
166
|
fontSize: "sm",
|
|
135
|
-
color:
|
|
167
|
+
color: variantStyles.secondaryColor
|
|
136
168
|
}
|
|
137
169
|
}, subtitle)));
|
|
138
170
|
}, "PlanCardHeaderSlot");
|
|
139
171
|
|
|
140
|
-
// src/components/PlanCardMetadataSlot.tsx
|
|
172
|
+
// src/components/planCard/PlanCardMetadataSlot.tsx
|
|
141
173
|
import { Icon as Icon2 } from "@ttoss/react-icons";
|
|
142
174
|
import { Flex as Flex4, Stack as Stack2, Text as Text3 } from "@ttoss/ui";
|
|
143
175
|
var PlanCardMetadataSlot = /* @__PURE__ */__name(({
|
|
144
176
|
metadata,
|
|
145
|
-
variant = "
|
|
177
|
+
variant = "primary"
|
|
146
178
|
}) => {
|
|
147
|
-
const
|
|
179
|
+
const variantStyles = getPlanCardVariantStyles(variant);
|
|
148
180
|
return /* @__PURE__ */React.createElement(Stack2, {
|
|
149
181
|
sx: {
|
|
150
182
|
width: "full",
|
|
@@ -163,14 +195,14 @@ var PlanCardMetadataSlot = /* @__PURE__ */__name(({
|
|
|
163
195
|
sx: {
|
|
164
196
|
gap: "4",
|
|
165
197
|
alignItems: "center",
|
|
166
|
-
color:
|
|
198
|
+
color: variantStyles.secondaryColor,
|
|
167
199
|
width: "full"
|
|
168
200
|
}
|
|
169
201
|
}, service.icon && /* @__PURE__ */React.createElement(Icon2, {
|
|
170
202
|
icon: service.icon
|
|
171
203
|
}), /* @__PURE__ */React.createElement(Text3, {
|
|
172
204
|
sx: {
|
|
173
|
-
color:
|
|
205
|
+
color: variantStyles.secondaryColor
|
|
174
206
|
}
|
|
175
207
|
}, service.label + String.fromCharCode(58))), service.parameters.map(parameter => {
|
|
176
208
|
return /* @__PURE__ */React.createElement(Flex4, {
|
|
@@ -205,13 +237,13 @@ var PlanCardMetadataSlot = /* @__PURE__ */__name(({
|
|
|
205
237
|
}));
|
|
206
238
|
}, "PlanCardMetadataSlot");
|
|
207
239
|
|
|
208
|
-
// src/components/PlanCardPriceSlot.tsx
|
|
240
|
+
// src/components/planCard/PlanCardPriceSlot.tsx
|
|
209
241
|
import { Flex as Flex5, Text as Text4 } from "@ttoss/ui";
|
|
210
242
|
var PlanCardPriceSlot = /* @__PURE__ */__name(({
|
|
211
243
|
price,
|
|
212
|
-
variant = "
|
|
244
|
+
variant = "primary"
|
|
213
245
|
}) => {
|
|
214
|
-
const
|
|
246
|
+
const variantStyles = getPlanCardVariantStyles(variant);
|
|
215
247
|
return /* @__PURE__ */React.createElement(Flex5, {
|
|
216
248
|
sx: {
|
|
217
249
|
paddingY: "6",
|
|
@@ -231,22 +263,22 @@ var PlanCardPriceSlot = /* @__PURE__ */__name(({
|
|
|
231
263
|
sx: {
|
|
232
264
|
fontSize: "4xl",
|
|
233
265
|
fontWeight: "bold",
|
|
234
|
-
color:
|
|
266
|
+
color: variantStyles.color
|
|
235
267
|
}
|
|
236
268
|
}, price.value), /* @__PURE__ */React.createElement(Text4, {
|
|
237
269
|
sx: {
|
|
238
270
|
fontSize: "sm",
|
|
239
|
-
color:
|
|
271
|
+
color: variantStyles.secondaryColor
|
|
240
272
|
}
|
|
241
273
|
}, price.interval)), price.description && /* @__PURE__ */React.createElement(Text4, {
|
|
242
274
|
sx: {
|
|
243
275
|
fontSize: "md",
|
|
244
|
-
color:
|
|
276
|
+
color: variantStyles.secondaryColor
|
|
245
277
|
}
|
|
246
278
|
}, price.description));
|
|
247
279
|
}, "PlanCardPriceSlot");
|
|
248
280
|
|
|
249
|
-
// src/components/PlanCardTopTagSlot.tsx
|
|
281
|
+
// src/components/planCard/PlanCardTopTagSlot.tsx
|
|
250
282
|
import { Box as Box3 } from "@ttoss/ui";
|
|
251
283
|
var PlanCardTopTagSlot = /* @__PURE__ */__name(({
|
|
252
284
|
children
|
|
@@ -258,10 +290,11 @@ var PlanCardTopTagSlot = /* @__PURE__ */__name(({
|
|
|
258
290
|
}, children);
|
|
259
291
|
}, "PlanCardTopTagSlot");
|
|
260
292
|
|
|
261
|
-
// src/components/PlanCard.tsx
|
|
293
|
+
// src/components/planCard/PlanCard.tsx
|
|
262
294
|
var PlanCard = /* @__PURE__ */__name(props => {
|
|
263
295
|
const {
|
|
264
|
-
variant = "
|
|
296
|
+
variant = "primary",
|
|
297
|
+
topTag,
|
|
265
298
|
title,
|
|
266
299
|
subtitle,
|
|
267
300
|
metadata = [],
|
|
@@ -272,20 +305,24 @@ var PlanCard = /* @__PURE__ */__name(props => {
|
|
|
272
305
|
...cardProps
|
|
273
306
|
} = props;
|
|
274
307
|
const effectiveMetadataVariant = metadataVariant ?? variant;
|
|
308
|
+
const variantStyles = getPlanCardVariantStyles(variant);
|
|
275
309
|
return /* @__PURE__ */React.createElement(Card, {
|
|
276
310
|
...cardProps,
|
|
277
311
|
sx: {
|
|
312
|
+
display: "flex",
|
|
313
|
+
flexDirection: "column",
|
|
278
314
|
width: "full",
|
|
279
315
|
maxWidth: "410px",
|
|
280
|
-
backgroundColor:
|
|
316
|
+
backgroundColor: variantStyles.backgroundColor,
|
|
317
|
+
borderColor: variantStyles.borderColor,
|
|
281
318
|
...cardProps.sx
|
|
282
319
|
}
|
|
283
|
-
},
|
|
320
|
+
}, topTag && /* @__PURE__ */React.createElement(PlanCardTopTagSlot, {
|
|
284
321
|
variant
|
|
285
|
-
},
|
|
322
|
+
}, topTag), /* @__PURE__ */React.createElement(PlanCardHeaderSlot, {
|
|
286
323
|
title,
|
|
287
324
|
subtitle,
|
|
288
|
-
hasTopTag: Boolean(
|
|
325
|
+
hasTopTag: Boolean(topTag),
|
|
289
326
|
variant
|
|
290
327
|
}), metadata.length > 0 && /* @__PURE__ */React.createElement(Box4, {
|
|
291
328
|
sx: {
|
|
@@ -307,4 +344,260 @@ var PlanCard = /* @__PURE__ */__name(props => {
|
|
|
307
344
|
variant
|
|
308
345
|
}));
|
|
309
346
|
}, "PlanCard");
|
|
310
|
-
|
|
347
|
+
|
|
348
|
+
// src/components/subscriptionPanel/SubscriptionPanel.tsx
|
|
349
|
+
import { EnhancedTitle } from "@ttoss/components/EnhancedTitle";
|
|
350
|
+
import { MetricCard } from "@ttoss/components/MetricCard";
|
|
351
|
+
import { Card as Card2, Flex as Flex7, Spinner } from "@ttoss/ui";
|
|
352
|
+
|
|
353
|
+
// src/components/subscriptionPanel/SubscriptionPanel.styles.ts
|
|
354
|
+
import { keyframes } from "@ttoss/ui";
|
|
355
|
+
var gradientFlow = keyframes({
|
|
356
|
+
"0%": {
|
|
357
|
+
backgroundPosition: "0% 50%"
|
|
358
|
+
},
|
|
359
|
+
"50%": {
|
|
360
|
+
backgroundPosition: "100% 50%"
|
|
361
|
+
},
|
|
362
|
+
"100%": {
|
|
363
|
+
backgroundPosition: "0% 50%"
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
var getAccentGradientBackground = /* @__PURE__ */__name(t => {
|
|
367
|
+
const theme = t;
|
|
368
|
+
const start = theme.colors?.action?.background?.accent?.default || theme.colors?.input?.background?.accent?.default;
|
|
369
|
+
if (!start) return void 0;
|
|
370
|
+
const middle = theme.colors?.action?.background?.accent?.active || theme.colors?.input?.background?.accent?.active || start;
|
|
371
|
+
return `linear-gradient(270deg, ${start}, ${middle}, ${start})`;
|
|
372
|
+
}, "getAccentGradientBackground");
|
|
373
|
+
var getPrimaryGradientBackground = /* @__PURE__ */__name(t => {
|
|
374
|
+
const theme = t;
|
|
375
|
+
const start = theme.colors?.action?.background?.primary?.default;
|
|
376
|
+
if (!start) return void 0;
|
|
377
|
+
const middle = theme.colors?.action?.background?.secondary?.default || start;
|
|
378
|
+
return `linear-gradient(270deg, ${start}, ${middle}, ${start})`;
|
|
379
|
+
}, "getPrimaryGradientBackground");
|
|
380
|
+
var getVariantStyles = /* @__PURE__ */__name(variantType => {
|
|
381
|
+
const variants = {
|
|
382
|
+
"spotlight-accent": {
|
|
383
|
+
backgroundColor: "input.background.accent.default",
|
|
384
|
+
color: "action.text.accent.default",
|
|
385
|
+
borderColor: "display.border.muted.default",
|
|
386
|
+
gradientBackground: getAccentGradientBackground
|
|
387
|
+
},
|
|
388
|
+
"spotlight-primary": {
|
|
389
|
+
backgroundColor: "action.background.primary.default",
|
|
390
|
+
color: "display.text.accent.default",
|
|
391
|
+
borderColor: "display.border.muted.default",
|
|
392
|
+
gradientBackground: getPrimaryGradientBackground
|
|
393
|
+
},
|
|
394
|
+
primary: {
|
|
395
|
+
backgroundColor: "action.background.primary.default",
|
|
396
|
+
color: "action.text.primary.default",
|
|
397
|
+
borderColor: "display.border.muted.default",
|
|
398
|
+
gradientBackground: void 0
|
|
399
|
+
},
|
|
400
|
+
secondary: {
|
|
401
|
+
backgroundColor: "action.background.secondary.default",
|
|
402
|
+
color: "action.text.primary.default",
|
|
403
|
+
borderColor: "display.border.muted.default",
|
|
404
|
+
gradientBackground: void 0
|
|
405
|
+
},
|
|
406
|
+
accent: {
|
|
407
|
+
backgroundColor: "action.background.accent.default",
|
|
408
|
+
color: "action.text.accent.default",
|
|
409
|
+
borderColor: "display.border.muted.default",
|
|
410
|
+
gradientBackground: void 0
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
return variants[variantType] || variants["spotlight-accent"];
|
|
414
|
+
}, "getVariantStyles");
|
|
415
|
+
var getSubscriptionPanelAccentBarSx = /* @__PURE__ */__name((variant = "spotlight-accent") => {
|
|
416
|
+
const variantStyles = getVariantStyles(variant);
|
|
417
|
+
const isSpotlight = variant.startsWith("spotlight-");
|
|
418
|
+
const gradientBg = variant === "spotlight-accent" ? getAccentGradientBackground : getPrimaryGradientBackground;
|
|
419
|
+
return {
|
|
420
|
+
height: "12px",
|
|
421
|
+
width: "full",
|
|
422
|
+
borderTopLeftRadius: "lg",
|
|
423
|
+
borderTopRightRadius: "lg",
|
|
424
|
+
backgroundColor: variantStyles.backgroundColor,
|
|
425
|
+
color: variantStyles.color,
|
|
426
|
+
borderColor: variantStyles.borderColor,
|
|
427
|
+
...(isSpotlight ? {
|
|
428
|
+
background: gradientBg,
|
|
429
|
+
backgroundSize: "400% 400%",
|
|
430
|
+
animation: `${gradientFlow} 6s ease infinite`
|
|
431
|
+
} : {})
|
|
432
|
+
};
|
|
433
|
+
}, "getSubscriptionPanelAccentBarSx");
|
|
434
|
+
var SubscriptionPanelAccentBarSx = getSubscriptionPanelAccentBarSx("spotlight-accent");
|
|
435
|
+
|
|
436
|
+
// src/components/subscriptionPanel/SubscriptionPanelActionsSlot.tsx
|
|
437
|
+
import { Icon as Icon3 } from "@ttoss/react-icons";
|
|
438
|
+
import { Button as Button2, Flex as Flex6 } from "@ttoss/ui";
|
|
439
|
+
var SubscriptionPanelActionsSlot = /* @__PURE__ */__name(({
|
|
440
|
+
actions
|
|
441
|
+
}) => {
|
|
442
|
+
if (actions.length === 0) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
return /* @__PURE__ */React.createElement(Flex6, {
|
|
446
|
+
sx: {
|
|
447
|
+
gap: "3",
|
|
448
|
+
flexDirection: ["column", "row"],
|
|
449
|
+
flexShrink: 0,
|
|
450
|
+
paddingX: "6",
|
|
451
|
+
paddingBottom: "6"
|
|
452
|
+
}
|
|
453
|
+
}, actions.map((action, index) => {
|
|
454
|
+
const {
|
|
455
|
+
label,
|
|
456
|
+
onClick,
|
|
457
|
+
leftIcon,
|
|
458
|
+
isLoading,
|
|
459
|
+
variant = "secondary",
|
|
460
|
+
disabled,
|
|
461
|
+
...buttonProps
|
|
462
|
+
} = action;
|
|
463
|
+
return /* @__PURE__ */React.createElement(Button2, {
|
|
464
|
+
key: index,
|
|
465
|
+
onClick,
|
|
466
|
+
variant,
|
|
467
|
+
disabled: disabled || isLoading,
|
|
468
|
+
leftIcon: isLoading ? void 0 : leftIcon,
|
|
469
|
+
sx: {
|
|
470
|
+
gap: "2",
|
|
471
|
+
justifyContent: "center",
|
|
472
|
+
minWidth: "fit-content"
|
|
473
|
+
},
|
|
474
|
+
...buttonProps
|
|
475
|
+
}, isLoading ? /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement(Icon3, {
|
|
476
|
+
icon: "fluent:spinner-ios-20-regular"
|
|
477
|
+
}), "Processando...") : label);
|
|
478
|
+
}));
|
|
479
|
+
}, "SubscriptionPanelActionsSlot");
|
|
480
|
+
|
|
481
|
+
// src/components/subscriptionPanel/SubscriptionPanel.tsx
|
|
482
|
+
var renderMetricCard = /* @__PURE__ */__name(params => {
|
|
483
|
+
const {
|
|
484
|
+
metric,
|
|
485
|
+
index,
|
|
486
|
+
isLoading
|
|
487
|
+
} = params;
|
|
488
|
+
return /* @__PURE__ */React.createElement(MetricCard, {
|
|
489
|
+
key: index,
|
|
490
|
+
metric,
|
|
491
|
+
isLoading
|
|
492
|
+
});
|
|
493
|
+
}, "renderMetricCard");
|
|
494
|
+
var SubscriptionPanel = /* @__PURE__ */__name(({
|
|
495
|
+
variant = "accent",
|
|
496
|
+
icon,
|
|
497
|
+
planName,
|
|
498
|
+
price,
|
|
499
|
+
status,
|
|
500
|
+
features = [],
|
|
501
|
+
actions = [],
|
|
502
|
+
metrics = [],
|
|
503
|
+
isLoading = false
|
|
504
|
+
}) => {
|
|
505
|
+
if (isLoading) {
|
|
506
|
+
return /* @__PURE__ */React.createElement(Card2, {
|
|
507
|
+
sx: {
|
|
508
|
+
width: "full",
|
|
509
|
+
height: "400px",
|
|
510
|
+
alignItems: "center",
|
|
511
|
+
justifyContent: "center"
|
|
512
|
+
}
|
|
513
|
+
}, /* @__PURE__ */React.createElement(Spinner, null));
|
|
514
|
+
}
|
|
515
|
+
return /* @__PURE__ */React.createElement(Card2, {
|
|
516
|
+
sx: {
|
|
517
|
+
width: "full"
|
|
518
|
+
}
|
|
519
|
+
}, /* @__PURE__ */React.createElement(Flex7, {
|
|
520
|
+
sx: getSubscriptionPanelAccentBarSx(variant)
|
|
521
|
+
}), /* @__PURE__ */React.createElement(Flex7, {
|
|
522
|
+
sx: {
|
|
523
|
+
width: "full",
|
|
524
|
+
paddingX: "6",
|
|
525
|
+
paddingY: "6",
|
|
526
|
+
flexDirection: "column"
|
|
527
|
+
}
|
|
528
|
+
}, /* @__PURE__ */React.createElement(Flex7, {
|
|
529
|
+
sx: {
|
|
530
|
+
paddingY: "10",
|
|
531
|
+
paddingX: "3",
|
|
532
|
+
width: "full",
|
|
533
|
+
flexDirection: ["column", "column", "row"],
|
|
534
|
+
alignItems: ["stretch", "stretch", "center"],
|
|
535
|
+
justifyContent: "space-between",
|
|
536
|
+
gap: "6",
|
|
537
|
+
borderBottom: "sm",
|
|
538
|
+
borderBottomColor: "display.border.muted.default"
|
|
539
|
+
}
|
|
540
|
+
}, /* @__PURE__ */React.createElement(EnhancedTitle, {
|
|
541
|
+
variant,
|
|
542
|
+
icon,
|
|
543
|
+
title: planName,
|
|
544
|
+
frontTitle: price.interval ? `${price.value}/${price.interval}` : price.value,
|
|
545
|
+
topBadges: [
|
|
546
|
+
// Status badge
|
|
547
|
+
...(status.status === "active" ? [{
|
|
548
|
+
label: "Ativo",
|
|
549
|
+
variant: "positive",
|
|
550
|
+
icon: "fluent:checkmark-circle-24-filled"
|
|
551
|
+
}] : status.status === "inactive" ? [{
|
|
552
|
+
label: "Inativo",
|
|
553
|
+
variant: "muted",
|
|
554
|
+
icon: "fluent:dismiss-circle-24-filled"
|
|
555
|
+
}] : [{
|
|
556
|
+
label: "Cancelado",
|
|
557
|
+
variant: "negative",
|
|
558
|
+
icon: "fluent:error-circle-24-filled"
|
|
559
|
+
}]),
|
|
560
|
+
// Interval badge
|
|
561
|
+
...(status.interval ? [{
|
|
562
|
+
label: status.interval,
|
|
563
|
+
variant: "informative"
|
|
564
|
+
}] : []),
|
|
565
|
+
// Scheduled update badge
|
|
566
|
+
...(status.hasScheduledUpdate ? [{
|
|
567
|
+
label: "Altera\xE7\xE3o Agendada",
|
|
568
|
+
variant: "informative",
|
|
569
|
+
icon: "fluent:clock-24-regular"
|
|
570
|
+
}] : []),
|
|
571
|
+
// Cancellation badge
|
|
572
|
+
...(status.hasCancellation ? [{
|
|
573
|
+
label: "Renova\xE7\xE3o Cancelada",
|
|
574
|
+
variant: "negative",
|
|
575
|
+
icon: "fluent:dismiss-circle-24-regular"
|
|
576
|
+
}] : [])],
|
|
577
|
+
bottomBadges: features.map(feature => {
|
|
578
|
+
return {
|
|
579
|
+
label: feature.label,
|
|
580
|
+
icon: typeof feature.icon === "string" ? feature.icon : "fluent:checkmark-24-filled",
|
|
581
|
+
variant: "muted"
|
|
582
|
+
};
|
|
583
|
+
})
|
|
584
|
+
}), actions.length > 0 && /* @__PURE__ */React.createElement(SubscriptionPanelActionsSlot, {
|
|
585
|
+
actions
|
|
586
|
+
})), metrics.length > 0 && /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement(Flex7, {
|
|
587
|
+
sx: {
|
|
588
|
+
paddingY: "10",
|
|
589
|
+
paddingX: "3",
|
|
590
|
+
width: "full",
|
|
591
|
+
flexWrap: "wrap",
|
|
592
|
+
gap: "10",
|
|
593
|
+
justifyContent: "center"
|
|
594
|
+
}
|
|
595
|
+
}, metrics.map((metric, index) => {
|
|
596
|
+
return renderMetricCard({
|
|
597
|
+
metric,
|
|
598
|
+
index,
|
|
599
|
+
isLoading
|
|
600
|
+
});
|
|
601
|
+
})))));
|
|
602
|
+
}, "SubscriptionPanel");
|
|
603
|
+
export { PlanCard, SubscriptionPanel };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,17 @@ import { IconType } from '@ttoss/react-icons';
|
|
|
3
3
|
import { CardProps, ButtonProps } from '@ttoss/ui';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
|
|
6
|
+
type PlanCardVariantType = 'primary' | 'secondary'
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Use `primary`.
|
|
9
|
+
*/
|
|
10
|
+
| 'default'
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use `secondary`.
|
|
13
|
+
*/
|
|
14
|
+
| 'enterprise';
|
|
15
|
+
type PlanCardVariant = PlanCardVariantType;
|
|
16
|
+
|
|
6
17
|
type PlanCardMetadataSlotParameter = {
|
|
7
18
|
name: string;
|
|
8
19
|
value: React.ReactNode;
|
|
@@ -14,14 +25,12 @@ type PlanCardMetadataSlotService = {
|
|
|
14
25
|
id?: string;
|
|
15
26
|
key?: string;
|
|
16
27
|
};
|
|
17
|
-
type PlanCardMetadataSlotVariant =
|
|
28
|
+
type PlanCardMetadataSlotVariant = PlanCardVariantType;
|
|
18
29
|
interface PlanCardMetadataSlotProps {
|
|
19
30
|
metadata: PlanCardMetadataSlotService[];
|
|
20
31
|
variant?: PlanCardMetadataSlotVariant;
|
|
21
32
|
}
|
|
22
33
|
|
|
23
|
-
type PlanCardVariant = 'default' | 'enterprise';
|
|
24
|
-
|
|
25
34
|
type PlanCardMetadata = PlanCardMetadataSlotService[];
|
|
26
35
|
type PlanCardPrice = {
|
|
27
36
|
value: string | number;
|
|
@@ -45,4 +54,254 @@ interface PlanCardProps extends Omit<CardProps, 'children'> {
|
|
|
45
54
|
}
|
|
46
55
|
declare const PlanCard: (props: PlanCardProps) => react_jsx_runtime.JSX.Element;
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
type SubscriptionPanelVariant = 'spotlight-accent' | 'spotlight-primary' | 'primary' | 'secondary' | 'accent';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Subscription status indicating the current state of the subscription.
|
|
61
|
+
*/
|
|
62
|
+
type SubscriptionStatus = 'active' | 'inactive' | 'cancelled';
|
|
63
|
+
/**
|
|
64
|
+
* Base metric properties shared by all metric types.
|
|
65
|
+
*/
|
|
66
|
+
interface BaseMetric {
|
|
67
|
+
/**
|
|
68
|
+
* Label displayed above the metric value.
|
|
69
|
+
*/
|
|
70
|
+
label: string;
|
|
71
|
+
/**
|
|
72
|
+
* Optional tooltip text or action handler for additional context.
|
|
73
|
+
* When a string is provided, it displays a simple tooltip.
|
|
74
|
+
* When a function is provided, it's called when the tooltip icon is clicked (e.g., to open help articles).
|
|
75
|
+
*/
|
|
76
|
+
tooltip?: string | (() => void);
|
|
77
|
+
/**
|
|
78
|
+
* Icon to display alongside the metric.
|
|
79
|
+
*/
|
|
80
|
+
icon?: IconType;
|
|
81
|
+
/**
|
|
82
|
+
* Optional click handler to make the metric card interactive.
|
|
83
|
+
*/
|
|
84
|
+
onClick?: () => void;
|
|
85
|
+
/**
|
|
86
|
+
* Optional help article action handler.
|
|
87
|
+
*/
|
|
88
|
+
helpArticleAction?: () => void;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Date-based metric for displaying dates like expiration or renewal.
|
|
92
|
+
*/
|
|
93
|
+
interface DateMetric extends BaseMetric {
|
|
94
|
+
type: 'date';
|
|
95
|
+
/**
|
|
96
|
+
* The date value to display.
|
|
97
|
+
*/
|
|
98
|
+
date: string;
|
|
99
|
+
/**
|
|
100
|
+
* Optional message showing remaining days.
|
|
101
|
+
*/
|
|
102
|
+
remainingDaysMessage?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Whether to show a warning indicator.
|
|
105
|
+
*/
|
|
106
|
+
isWarning?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Percentage-based metric with progress bar.
|
|
110
|
+
*/
|
|
111
|
+
interface PercentageMetric extends BaseMetric {
|
|
112
|
+
type: 'percentage';
|
|
113
|
+
/**
|
|
114
|
+
* Current value.
|
|
115
|
+
*/
|
|
116
|
+
current: number;
|
|
117
|
+
/**
|
|
118
|
+
* Maximum value. Use null for unlimited.
|
|
119
|
+
*/
|
|
120
|
+
max: number | null;
|
|
121
|
+
/**
|
|
122
|
+
* Custom formatter for displaying values.
|
|
123
|
+
*/
|
|
124
|
+
formatValue?: (value: number) => string;
|
|
125
|
+
/**
|
|
126
|
+
* Percentage threshold at which to show an alert.
|
|
127
|
+
*/
|
|
128
|
+
showAlertThreshold?: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Number-based metric for displaying counts.
|
|
132
|
+
*/
|
|
133
|
+
interface NumberMetric extends BaseMetric {
|
|
134
|
+
type: 'number';
|
|
135
|
+
/**
|
|
136
|
+
* Current value.
|
|
137
|
+
*/
|
|
138
|
+
current: number;
|
|
139
|
+
/**
|
|
140
|
+
* Maximum value. Use null for unlimited.
|
|
141
|
+
*/
|
|
142
|
+
max: number | null;
|
|
143
|
+
/**
|
|
144
|
+
* Custom formatter for displaying values.
|
|
145
|
+
*/
|
|
146
|
+
formatValue?: (value: number) => string;
|
|
147
|
+
/**
|
|
148
|
+
* Optional footer text below the metric.
|
|
149
|
+
*/
|
|
150
|
+
footerText?: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Union type for all metric types.
|
|
154
|
+
*/
|
|
155
|
+
type MetricType = DateMetric | PercentageMetric | NumberMetric;
|
|
156
|
+
/**
|
|
157
|
+
* Status badge configuration.
|
|
158
|
+
*/
|
|
159
|
+
interface SubscriptionPanelStatusBadgeProps {
|
|
160
|
+
/**
|
|
161
|
+
* The subscription status.
|
|
162
|
+
*/
|
|
163
|
+
status: SubscriptionStatus;
|
|
164
|
+
/**
|
|
165
|
+
* Billing interval (e.g., "Mensal", "Anual").
|
|
166
|
+
*/
|
|
167
|
+
interval?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Whether the subscription has a pending cancellation.
|
|
170
|
+
*/
|
|
171
|
+
hasCancellation?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Whether the subscription has a scheduled update.
|
|
174
|
+
*/
|
|
175
|
+
hasScheduledUpdate?: boolean;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Feature tag displayed in the card header.
|
|
179
|
+
*/
|
|
180
|
+
interface SubscriptionPanelFeatureTag {
|
|
181
|
+
/**
|
|
182
|
+
* Label text for the feature.
|
|
183
|
+
*/
|
|
184
|
+
label: string;
|
|
185
|
+
/**
|
|
186
|
+
* Optional icon for the feature.
|
|
187
|
+
*/
|
|
188
|
+
icon?: IconType;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Action button configuration.
|
|
192
|
+
*/
|
|
193
|
+
interface SubscriptionPanelAction extends Omit<ButtonProps, 'children'> {
|
|
194
|
+
/**
|
|
195
|
+
* Button label text.
|
|
196
|
+
*/
|
|
197
|
+
label: string;
|
|
198
|
+
/**
|
|
199
|
+
* Click handler for the action.
|
|
200
|
+
*/
|
|
201
|
+
onClick: () => void;
|
|
202
|
+
/**
|
|
203
|
+
* Optional icon for the button.
|
|
204
|
+
*/
|
|
205
|
+
leftIcon?: IconType;
|
|
206
|
+
/**
|
|
207
|
+
* Whether the action is currently loading.
|
|
208
|
+
*/
|
|
209
|
+
isLoading?: boolean;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Price configuration.
|
|
213
|
+
*/
|
|
214
|
+
interface SubscriptionPanelPrice {
|
|
215
|
+
/**
|
|
216
|
+
* Price value (e.g., "R$ 5,00").
|
|
217
|
+
*/
|
|
218
|
+
value: string;
|
|
219
|
+
/**
|
|
220
|
+
* Price interval (e.g., "mês", "ano").
|
|
221
|
+
*/
|
|
222
|
+
interval?: string;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Main SubscriptionPanel props.
|
|
226
|
+
*/
|
|
227
|
+
interface SubscriptionPanelProps {
|
|
228
|
+
/**
|
|
229
|
+
* Visual variant for the accent bar and header icon.
|
|
230
|
+
* @default 'spotlight'
|
|
231
|
+
*/
|
|
232
|
+
variant?: SubscriptionPanelVariant;
|
|
233
|
+
/**
|
|
234
|
+
* Plan icon to display. Can be a ReactNode or an IconType string.
|
|
235
|
+
*/
|
|
236
|
+
icon?: string;
|
|
237
|
+
/**
|
|
238
|
+
* Name of the subscription plan.
|
|
239
|
+
*/
|
|
240
|
+
planName: string;
|
|
241
|
+
/**
|
|
242
|
+
* Price configuration.
|
|
243
|
+
*/
|
|
244
|
+
price: SubscriptionPanelPrice;
|
|
245
|
+
/**
|
|
246
|
+
* Status badge configuration.
|
|
247
|
+
*/
|
|
248
|
+
status: SubscriptionPanelStatusBadgeProps;
|
|
249
|
+
/**
|
|
250
|
+
* Feature tags to display.
|
|
251
|
+
*/
|
|
252
|
+
features?: SubscriptionPanelFeatureTag[];
|
|
253
|
+
/**
|
|
254
|
+
* Action buttons.
|
|
255
|
+
*/
|
|
256
|
+
actions?: SubscriptionPanelAction[];
|
|
257
|
+
/**
|
|
258
|
+
* Metrics to display in the card.
|
|
259
|
+
*/
|
|
260
|
+
metrics?: MetricType[];
|
|
261
|
+
/**
|
|
262
|
+
* Whether the card is in a loading state.
|
|
263
|
+
*/
|
|
264
|
+
isLoading?: boolean;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* SubscriptionPanel displays comprehensive subscription information including
|
|
269
|
+
* plan details, status, actions, and various metrics.
|
|
270
|
+
*
|
|
271
|
+
* It supports three types of metrics:
|
|
272
|
+
* - **Date**: For displaying dates like expiration or renewal
|
|
273
|
+
* - **Percentage**: For usage-based metrics with progress bars
|
|
274
|
+
* - **Number**: For count-based metrics
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```tsx
|
|
278
|
+
* <SubscriptionPanel
|
|
279
|
+
* planName="Premium Plan"
|
|
280
|
+
* price={{ value: "R$ 99,00", interval: "mês" }}
|
|
281
|
+
* status={{ status: "active", interval: "Mensal" }}
|
|
282
|
+
* features={[{ label: "Feature 1" }, { label: "Feature 2" }]}
|
|
283
|
+
* actions={[
|
|
284
|
+
* { label: "Upgrade", onClick: () => {}, variant: "accent" },
|
|
285
|
+
* { label: "Cancel", onClick: () => {}, variant: "danger" },
|
|
286
|
+
* ]}
|
|
287
|
+
* metrics={[
|
|
288
|
+
* { type: "date", label: "Expira em", date: "15/01/2025", icon: "fluent:calendar-24-regular" },
|
|
289
|
+
* { type: "percentage", label: "Uso", current: 75, max: 100, icon: "fluent:data-usage-24-regular" },
|
|
290
|
+
* ]}
|
|
291
|
+
* />
|
|
292
|
+
* ```
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```tsx
|
|
296
|
+
* // Compact mode for smaller spaces
|
|
297
|
+
* <SubscriptionPanel
|
|
298
|
+
* planName="Basic Plan"
|
|
299
|
+
* price={{ value: "R$ 29,00", interval: "mês" }}
|
|
300
|
+
* status={{ status: "active" }}
|
|
301
|
+
* compact
|
|
302
|
+
* />
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
declare const SubscriptionPanel: ({ variant, icon, planName, price, status, features, actions, metrics, isLoading, }: SubscriptionPanelProps) => react_jsx_runtime.JSX.Element;
|
|
306
|
+
|
|
307
|
+
export { PlanCard, type PlanCardButtonProps, type PlanCardMetadata, type PlanCardMetadataSlotParameter, type PlanCardMetadataSlotProps, type PlanCardMetadataSlotService, type PlanCardMetadataSlotVariant, type PlanCardPrice, type PlanCardProps, type PlanCardVariant, SubscriptionPanel };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/react-billing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Billing UI components for React apps.",
|
|
5
5
|
"author": "Giovane Guimarães",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@ttoss/
|
|
24
|
-
"@ttoss/
|
|
23
|
+
"@ttoss/react-icons": "^0.5.6",
|
|
24
|
+
"@ttoss/ui": "^6.4.0",
|
|
25
|
+
"@ttoss/components": "^2.11.6"
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"react": ">=16.8.0"
|
package/dist/index.d.cts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { IconType } from '@ttoss/react-icons';
|
|
3
|
-
import { CardProps, ButtonProps } from '@ttoss/ui';
|
|
4
|
-
import * as React from 'react';
|
|
5
|
-
|
|
6
|
-
type PlanCardMetadataSlotParameter = {
|
|
7
|
-
name: string;
|
|
8
|
-
value: React.ReactNode;
|
|
9
|
-
};
|
|
10
|
-
type PlanCardMetadataSlotService = {
|
|
11
|
-
label: string;
|
|
12
|
-
icon?: IconType;
|
|
13
|
-
parameters: PlanCardMetadataSlotParameter[];
|
|
14
|
-
id?: string;
|
|
15
|
-
key?: string;
|
|
16
|
-
};
|
|
17
|
-
type PlanCardMetadataSlotVariant = 'default' | 'enterprise';
|
|
18
|
-
interface PlanCardMetadataSlotProps {
|
|
19
|
-
metadata: PlanCardMetadataSlotService[];
|
|
20
|
-
variant?: PlanCardMetadataSlotVariant;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type PlanCardVariant = 'default' | 'enterprise';
|
|
24
|
-
|
|
25
|
-
type PlanCardMetadata = PlanCardMetadataSlotService[];
|
|
26
|
-
type PlanCardPrice = {
|
|
27
|
-
value: string | number;
|
|
28
|
-
interval: string;
|
|
29
|
-
description?: string;
|
|
30
|
-
};
|
|
31
|
-
type PlanCardButtonProps = Omit<ButtonProps, 'children'> & {
|
|
32
|
-
label?: string;
|
|
33
|
-
leftIcon?: IconType;
|
|
34
|
-
};
|
|
35
|
-
interface PlanCardProps extends Omit<CardProps, 'children'> {
|
|
36
|
-
variant?: PlanCardVariant;
|
|
37
|
-
topTag?: React.ReactNode;
|
|
38
|
-
title: string;
|
|
39
|
-
subtitle?: string;
|
|
40
|
-
metadata?: PlanCardMetadata;
|
|
41
|
-
metadataVariant?: PlanCardMetadataSlotVariant;
|
|
42
|
-
price: PlanCardPrice;
|
|
43
|
-
features?: unknown[];
|
|
44
|
-
buttonProps?: PlanCardButtonProps;
|
|
45
|
-
}
|
|
46
|
-
declare const PlanCard: (props: PlanCardProps) => react_jsx_runtime.JSX.Element;
|
|
47
|
-
|
|
48
|
-
export { PlanCard, type PlanCardButtonProps, type PlanCardMetadata, type PlanCardMetadataSlotParameter, type PlanCardMetadataSlotProps, type PlanCardMetadataSlotService, type PlanCardMetadataSlotVariant, type PlanCardPrice, type PlanCardProps, type PlanCardVariant };
|
package/dist/index.js
DELETED
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
var __create = Object.create;
|
|
6
|
-
var __defProp = Object.defineProperty;
|
|
7
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
-
var __name = (target, value) => __defProp(target, "name", {
|
|
12
|
-
value,
|
|
13
|
-
configurable: true
|
|
14
|
-
});
|
|
15
|
-
var __export = (target, all) => {
|
|
16
|
-
for (var name in all) __defProp(target, name, {
|
|
17
|
-
get: all[name],
|
|
18
|
-
enumerable: true
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
var __copyProps = (to, from, except, desc) => {
|
|
22
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
-
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
24
|
-
get: () => from[key],
|
|
25
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return to;
|
|
29
|
-
};
|
|
30
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
31
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
32
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
33
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
34
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
35
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
36
|
-
value: mod,
|
|
37
|
-
enumerable: true
|
|
38
|
-
}) : target, mod));
|
|
39
|
-
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
|
|
40
|
-
value: true
|
|
41
|
-
}), mod);
|
|
42
|
-
|
|
43
|
-
// src/index.ts
|
|
44
|
-
var index_exports = {};
|
|
45
|
-
__export(index_exports, {
|
|
46
|
-
PlanCard: () => PlanCard
|
|
47
|
-
});
|
|
48
|
-
module.exports = __toCommonJS(index_exports);
|
|
49
|
-
|
|
50
|
-
// src/components/PlanCard.tsx
|
|
51
|
-
var import_ui7 = require("@ttoss/ui");
|
|
52
|
-
|
|
53
|
-
// src/components/PlanCardCtaSlot.tsx
|
|
54
|
-
var import_ui = require("@ttoss/ui");
|
|
55
|
-
var PlanCardCtaSlot = /* @__PURE__ */__name(({
|
|
56
|
-
buttonProps
|
|
57
|
-
}) => {
|
|
58
|
-
const {
|
|
59
|
-
label: ctaLabel = "Assine agora",
|
|
60
|
-
sx: buttonSx,
|
|
61
|
-
leftIcon,
|
|
62
|
-
variant,
|
|
63
|
-
...restButtonProps
|
|
64
|
-
} = buttonProps ?? {};
|
|
65
|
-
return /* @__PURE__ */React.createElement(import_ui.Flex, {
|
|
66
|
-
sx: {
|
|
67
|
-
paddingY: "2",
|
|
68
|
-
paddingX: "6",
|
|
69
|
-
width: "full",
|
|
70
|
-
justifyContent: "center"
|
|
71
|
-
}
|
|
72
|
-
}, /* @__PURE__ */React.createElement(import_ui.Button, {
|
|
73
|
-
...restButtonProps,
|
|
74
|
-
variant: variant ?? "accent",
|
|
75
|
-
leftIcon,
|
|
76
|
-
sx: {
|
|
77
|
-
width: "full",
|
|
78
|
-
justifyContent: "center",
|
|
79
|
-
fontWeight: "semibold",
|
|
80
|
-
...buttonSx
|
|
81
|
-
}
|
|
82
|
-
}, ctaLabel));
|
|
83
|
-
}, "PlanCardCtaSlot");
|
|
84
|
-
|
|
85
|
-
// src/components/PlanCardFeaturesSlot.tsx
|
|
86
|
-
var import_react_icons = require("@ttoss/react-icons");
|
|
87
|
-
var import_ui2 = require("@ttoss/ui");
|
|
88
|
-
var React2 = __toESM(require("react"), 1);
|
|
89
|
-
var featuresTitle = "RECURSOS";
|
|
90
|
-
var PlanCardFeaturesSlot = /* @__PURE__ */__name(({
|
|
91
|
-
features,
|
|
92
|
-
variant = "default"
|
|
93
|
-
}) => {
|
|
94
|
-
const isEnterprise = variant === "enterprise";
|
|
95
|
-
const featureColor = isEnterprise ? "white" : "feedback.text.positive.default";
|
|
96
|
-
return /* @__PURE__ */React2.createElement(import_ui2.Box, {
|
|
97
|
-
sx: {
|
|
98
|
-
paddingY: "4",
|
|
99
|
-
paddingX: "6",
|
|
100
|
-
width: "full",
|
|
101
|
-
borderTop: "md",
|
|
102
|
-
borderBottom: "md",
|
|
103
|
-
borderColor: "display.border.muted.default"
|
|
104
|
-
}
|
|
105
|
-
}, /* @__PURE__ */React2.createElement(import_ui2.Stack, {
|
|
106
|
-
sx: {
|
|
107
|
-
gap: "5",
|
|
108
|
-
paddingY: "3"
|
|
109
|
-
}
|
|
110
|
-
}, /* @__PURE__ */React2.createElement(import_ui2.Flex, {
|
|
111
|
-
sx: {
|
|
112
|
-
letterSpacing: "widest",
|
|
113
|
-
color: isEnterprise ? "white" : "text"
|
|
114
|
-
}
|
|
115
|
-
}, featuresTitle), /* @__PURE__ */React2.createElement(import_ui2.Flex, {
|
|
116
|
-
sx: {
|
|
117
|
-
flexDirection: "column",
|
|
118
|
-
gap: "3"
|
|
119
|
-
}
|
|
120
|
-
}, features.map((feature, index) => {
|
|
121
|
-
if (/* @__PURE__ */React2.isValidElement(feature)) {
|
|
122
|
-
return /* @__PURE__ */React2.createElement(React2.Fragment, {
|
|
123
|
-
key: index
|
|
124
|
-
}, feature);
|
|
125
|
-
}
|
|
126
|
-
return /* @__PURE__ */React2.createElement(import_ui2.Flex, {
|
|
127
|
-
key: index,
|
|
128
|
-
sx: {
|
|
129
|
-
fontSize: "sm",
|
|
130
|
-
color: featureColor,
|
|
131
|
-
alignItems: "center",
|
|
132
|
-
gap: "3"
|
|
133
|
-
}
|
|
134
|
-
}, /* @__PURE__ */React2.createElement(import_react_icons.Icon, {
|
|
135
|
-
icon: "fluent:checkmark-24-filled"
|
|
136
|
-
}), /* @__PURE__ */React2.createElement(import_ui2.Text, {
|
|
137
|
-
sx: {
|
|
138
|
-
fontSize: "sm",
|
|
139
|
-
color: featureColor,
|
|
140
|
-
alignItems: "center"
|
|
141
|
-
}
|
|
142
|
-
}, String(feature)));
|
|
143
|
-
}))));
|
|
144
|
-
}, "PlanCardFeaturesSlot");
|
|
145
|
-
|
|
146
|
-
// src/components/PlanCardHeaderSlot.tsx
|
|
147
|
-
var import_ui3 = require("@ttoss/ui");
|
|
148
|
-
var PlanCardHeaderSlot = /* @__PURE__ */__name(({
|
|
149
|
-
title,
|
|
150
|
-
subtitle,
|
|
151
|
-
hasTopTag,
|
|
152
|
-
variant = "default"
|
|
153
|
-
}) => {
|
|
154
|
-
const isEnterprise = variant === "enterprise";
|
|
155
|
-
return /* @__PURE__ */React.createElement(import_ui3.Box, {
|
|
156
|
-
sx: {
|
|
157
|
-
paddingY: hasTopTag ? "4" : "8",
|
|
158
|
-
paddingX: "8",
|
|
159
|
-
width: "full"
|
|
160
|
-
}
|
|
161
|
-
}, /* @__PURE__ */React.createElement(import_ui3.Flex, {
|
|
162
|
-
sx: {
|
|
163
|
-
flexDirection: "column",
|
|
164
|
-
gap: "2",
|
|
165
|
-
width: "full",
|
|
166
|
-
alignItems: "center"
|
|
167
|
-
}
|
|
168
|
-
}, /* @__PURE__ */React.createElement(import_ui3.Heading, {
|
|
169
|
-
sx: {
|
|
170
|
-
fontSize: "3xl",
|
|
171
|
-
color: isEnterprise ? "white" : "text"
|
|
172
|
-
}
|
|
173
|
-
}, title), subtitle && /* @__PURE__ */React.createElement(import_ui3.Text, {
|
|
174
|
-
sx: {
|
|
175
|
-
fontSize: "sm",
|
|
176
|
-
color: isEnterprise ? "white" : "display.text.secondary.default"
|
|
177
|
-
}
|
|
178
|
-
}, subtitle)));
|
|
179
|
-
}, "PlanCardHeaderSlot");
|
|
180
|
-
|
|
181
|
-
// src/components/PlanCardMetadataSlot.tsx
|
|
182
|
-
var import_react_icons2 = require("@ttoss/react-icons");
|
|
183
|
-
var import_ui4 = require("@ttoss/ui");
|
|
184
|
-
var PlanCardMetadataSlot = /* @__PURE__ */__name(({
|
|
185
|
-
metadata,
|
|
186
|
-
variant = "default"
|
|
187
|
-
}) => {
|
|
188
|
-
const isEnterprise = variant === "enterprise";
|
|
189
|
-
return /* @__PURE__ */React.createElement(import_ui4.Stack, {
|
|
190
|
-
sx: {
|
|
191
|
-
width: "full",
|
|
192
|
-
gap: "6"
|
|
193
|
-
}
|
|
194
|
-
}, metadata.map(service => {
|
|
195
|
-
const serviceKey = service.id ?? service.key ?? service.label;
|
|
196
|
-
return /* @__PURE__ */React.createElement(import_ui4.Flex, {
|
|
197
|
-
key: serviceKey,
|
|
198
|
-
sx: {
|
|
199
|
-
gap: "3",
|
|
200
|
-
flexDirection: "column",
|
|
201
|
-
width: "full"
|
|
202
|
-
}
|
|
203
|
-
}, /* @__PURE__ */React.createElement(import_ui4.Flex, {
|
|
204
|
-
sx: {
|
|
205
|
-
gap: "4",
|
|
206
|
-
alignItems: "center",
|
|
207
|
-
color: isEnterprise ? "white" : "display.text.secondary.default",
|
|
208
|
-
width: "full"
|
|
209
|
-
}
|
|
210
|
-
}, service.icon && /* @__PURE__ */React.createElement(import_react_icons2.Icon, {
|
|
211
|
-
icon: service.icon
|
|
212
|
-
}), /* @__PURE__ */React.createElement(import_ui4.Text, {
|
|
213
|
-
sx: {
|
|
214
|
-
color: isEnterprise ? "white" : "display.text.secondary.default"
|
|
215
|
-
}
|
|
216
|
-
}, service.label + String.fromCharCode(58))), service.parameters.map(parameter => {
|
|
217
|
-
return /* @__PURE__ */React.createElement(import_ui4.Flex, {
|
|
218
|
-
key: parameter.name,
|
|
219
|
-
sx: {
|
|
220
|
-
paddingX: "6",
|
|
221
|
-
paddingY: "4",
|
|
222
|
-
backgroundColor: "display.background.muted.default",
|
|
223
|
-
borderRadius: "lg",
|
|
224
|
-
width: "full"
|
|
225
|
-
}
|
|
226
|
-
}, /* @__PURE__ */React.createElement(import_ui4.Flex, {
|
|
227
|
-
sx: {
|
|
228
|
-
width: "full",
|
|
229
|
-
display: "flex",
|
|
230
|
-
alignItems: "center",
|
|
231
|
-
justifyContent: "space-between",
|
|
232
|
-
gap: "2"
|
|
233
|
-
}
|
|
234
|
-
}, /* @__PURE__ */React.createElement(import_ui4.Text, {
|
|
235
|
-
sx: {
|
|
236
|
-
fontSize: "sm",
|
|
237
|
-
textAlign: "center"
|
|
238
|
-
}
|
|
239
|
-
}, parameter.name), /* @__PURE__ */React.createElement(import_ui4.Text, {
|
|
240
|
-
sx: {
|
|
241
|
-
fontWeight: "semibold",
|
|
242
|
-
fontSize: "lg"
|
|
243
|
-
}
|
|
244
|
-
}, parameter.value)));
|
|
245
|
-
}));
|
|
246
|
-
}));
|
|
247
|
-
}, "PlanCardMetadataSlot");
|
|
248
|
-
|
|
249
|
-
// src/components/PlanCardPriceSlot.tsx
|
|
250
|
-
var import_ui5 = require("@ttoss/ui");
|
|
251
|
-
var PlanCardPriceSlot = /* @__PURE__ */__name(({
|
|
252
|
-
price,
|
|
253
|
-
variant = "default"
|
|
254
|
-
}) => {
|
|
255
|
-
const isEnterprise = variant === "enterprise";
|
|
256
|
-
return /* @__PURE__ */React.createElement(import_ui5.Flex, {
|
|
257
|
-
sx: {
|
|
258
|
-
paddingY: "6",
|
|
259
|
-
paddingX: "8",
|
|
260
|
-
width: "full",
|
|
261
|
-
alignItems: "center",
|
|
262
|
-
flexDirection: "column",
|
|
263
|
-
gap: "3"
|
|
264
|
-
}
|
|
265
|
-
}, /* @__PURE__ */React.createElement(import_ui5.Flex, {
|
|
266
|
-
sx: {
|
|
267
|
-
alignItems: "baseline",
|
|
268
|
-
gap: "4",
|
|
269
|
-
justifyContent: "center"
|
|
270
|
-
}
|
|
271
|
-
}, /* @__PURE__ */React.createElement(import_ui5.Text, {
|
|
272
|
-
sx: {
|
|
273
|
-
fontSize: "4xl",
|
|
274
|
-
fontWeight: "bold",
|
|
275
|
-
color: isEnterprise ? "white" : "display.text.primary.default"
|
|
276
|
-
}
|
|
277
|
-
}, price.value), /* @__PURE__ */React.createElement(import_ui5.Text, {
|
|
278
|
-
sx: {
|
|
279
|
-
fontSize: "sm",
|
|
280
|
-
color: isEnterprise ? "white" : "display.text.secondary.default"
|
|
281
|
-
}
|
|
282
|
-
}, price.interval)), price.description && /* @__PURE__ */React.createElement(import_ui5.Text, {
|
|
283
|
-
sx: {
|
|
284
|
-
fontSize: "md",
|
|
285
|
-
color: isEnterprise ? "white" : "display.text.secondary.default"
|
|
286
|
-
}
|
|
287
|
-
}, price.description));
|
|
288
|
-
}, "PlanCardPriceSlot");
|
|
289
|
-
|
|
290
|
-
// src/components/PlanCardTopTagSlot.tsx
|
|
291
|
-
var import_ui6 = require("@ttoss/ui");
|
|
292
|
-
var PlanCardTopTagSlot = /* @__PURE__ */__name(({
|
|
293
|
-
children
|
|
294
|
-
}) => {
|
|
295
|
-
return /* @__PURE__ */React.createElement(import_ui6.Box, {
|
|
296
|
-
sx: {
|
|
297
|
-
padding: "4"
|
|
298
|
-
}
|
|
299
|
-
}, children);
|
|
300
|
-
}, "PlanCardTopTagSlot");
|
|
301
|
-
|
|
302
|
-
// src/components/PlanCard.tsx
|
|
303
|
-
var PlanCard = /* @__PURE__ */__name(props => {
|
|
304
|
-
const {
|
|
305
|
-
variant = "default",
|
|
306
|
-
title,
|
|
307
|
-
subtitle,
|
|
308
|
-
metadata = [],
|
|
309
|
-
metadataVariant,
|
|
310
|
-
price,
|
|
311
|
-
features = [],
|
|
312
|
-
buttonProps,
|
|
313
|
-
...cardProps
|
|
314
|
-
} = props;
|
|
315
|
-
const effectiveMetadataVariant = metadataVariant ?? variant;
|
|
316
|
-
return /* @__PURE__ */React.createElement(import_ui7.Card, {
|
|
317
|
-
...cardProps,
|
|
318
|
-
sx: {
|
|
319
|
-
width: "full",
|
|
320
|
-
maxWidth: "410px",
|
|
321
|
-
backgroundColor: variant === "enterprise" ? "display.background.primary.active" : "display.background.primary.default",
|
|
322
|
-
...cardProps.sx
|
|
323
|
-
}
|
|
324
|
-
}, props.topTag && /* @__PURE__ */React.createElement(PlanCardTopTagSlot, {
|
|
325
|
-
variant
|
|
326
|
-
}, props.topTag), /* @__PURE__ */React.createElement(PlanCardHeaderSlot, {
|
|
327
|
-
title,
|
|
328
|
-
subtitle,
|
|
329
|
-
hasTopTag: Boolean(props.topTag),
|
|
330
|
-
variant
|
|
331
|
-
}), metadata.length > 0 && /* @__PURE__ */React.createElement(import_ui7.Box, {
|
|
332
|
-
sx: {
|
|
333
|
-
paddingY: "4",
|
|
334
|
-
paddingX: "8",
|
|
335
|
-
width: "full"
|
|
336
|
-
}
|
|
337
|
-
}, /* @__PURE__ */React.createElement(PlanCardMetadataSlot, {
|
|
338
|
-
metadata,
|
|
339
|
-
variant: effectiveMetadataVariant
|
|
340
|
-
})), /* @__PURE__ */React.createElement(PlanCardPriceSlot, {
|
|
341
|
-
price,
|
|
342
|
-
variant
|
|
343
|
-
}), features.length > 0 && /* @__PURE__ */React.createElement(PlanCardFeaturesSlot, {
|
|
344
|
-
features,
|
|
345
|
-
variant
|
|
346
|
-
}), /* @__PURE__ */React.createElement(PlanCardCtaSlot, {
|
|
347
|
-
buttonProps,
|
|
348
|
-
variant
|
|
349
|
-
}));
|
|
350
|
-
}, "PlanCard");
|
|
351
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
352
|
-
0 && (module.exports = {
|
|
353
|
-
PlanCard
|
|
354
|
-
});
|