@slyxup/ui 2.4.0 → 2.5.1
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/LICENSE +21 -0
- package/README.md +116 -16
- package/dist/components/BillingPortal/BillingPortal.d.ts +18 -16
- package/dist/components/BillingPortal/BillingPortal.d.ts.map +1 -1
- package/dist/components/BillingPortal/BillingPortal.js +9 -55
- package/dist/components/BillingPortal/BillingPortal.js.map +1 -1
- package/dist/components/CopyField.d.ts +9 -0
- package/dist/components/CopyField.d.ts.map +1 -0
- package/dist/components/CopyField.js +29 -0
- package/dist/components/CopyField.js.map +1 -0
- package/dist/components/CurrentPlanCard/CurrentPlanCard.d.ts +30 -0
- package/dist/components/CurrentPlanCard/CurrentPlanCard.d.ts.map +1 -0
- package/dist/components/CurrentPlanCard/CurrentPlanCard.js +40 -0
- package/dist/components/CurrentPlanCard/CurrentPlanCard.js.map +1 -0
- package/dist/components/EmptyState.d.ts +10 -0
- package/dist/components/EmptyState.d.ts.map +1 -0
- package/dist/components/EmptyState.js +8 -0
- package/dist/components/EmptyState.js.map +1 -0
- package/dist/components/InvoicesTable/InvoicesTable.d.ts +20 -0
- package/dist/components/InvoicesTable/InvoicesTable.d.ts.map +1 -0
- package/dist/components/InvoicesTable/InvoicesTable.js +33 -0
- package/dist/components/InvoicesTable/InvoicesTable.js.map +1 -0
- package/dist/components/OtpInput.d.ts +15 -0
- package/dist/components/OtpInput.d.ts.map +1 -0
- package/dist/components/OtpInput.js +58 -0
- package/dist/components/OtpInput.js.map +1 -0
- package/dist/components/PasswordStrength.d.ts +11 -0
- package/dist/components/PasswordStrength.d.ts.map +1 -0
- package/dist/components/PasswordStrength.js +34 -0
- package/dist/components/PasswordStrength.js.map +1 -0
- package/dist/components/PlanCard/PlanCard.d.ts +29 -0
- package/dist/components/PlanCard/PlanCard.d.ts.map +1 -0
- package/dist/components/PlanCard/PlanCard.js +46 -0
- package/dist/components/PlanCard/PlanCard.js.map +1 -0
- package/dist/components/PricingTable/PricingTable.d.ts +18 -15
- package/dist/components/PricingTable/PricingTable.d.ts.map +1 -1
- package/dist/components/PricingTable/PricingTable.js +16 -47
- package/dist/components/PricingTable/PricingTable.js.map +1 -1
- package/dist/components/SignIn/SignIn.js +1 -1
- package/dist/components/SignIn/SignIn.js.map +1 -1
- package/dist/components/SignUp/SignUp.js +1 -1
- package/dist/components/SignUp/SignUp.js.map +1 -1
- package/dist/components/SubscriptionStatus/SubscriptionStatus.d.ts +12 -0
- package/dist/components/SubscriptionStatus/SubscriptionStatus.d.ts.map +1 -0
- package/dist/components/SubscriptionStatus/SubscriptionStatus.js +31 -0
- package/dist/components/SubscriptionStatus/SubscriptionStatus.js.map +1 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/scoped-theme.d.ts +10 -0
- package/dist/lib/scoped-theme.d.ts.map +1 -0
- package/dist/lib/scoped-theme.js +20 -0
- package/dist/lib/scoped-theme.js.map +1 -0
- package/dist/react/hooks/useBilling.d.ts +23 -1
- package/dist/react/hooks/useBilling.d.ts.map +1 -1
- package/dist/react/hooks/useBilling.js +43 -4
- package/dist/react/hooks/useBilling.js.map +1 -1
- package/dist/react/provider/SlyxUpProvider.js +1 -1
- package/dist/react/provider/SlyxUpProvider.js.map +1 -1
- package/dist/styles.d.ts +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +91 -0
- package/dist/styles.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js.map +1 -1
- package/package.json +8 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 SlyxUp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# @slyxup/ui
|
|
2
2
|
|
|
3
|
-
Prebuilt, themeable auth + billing components — sign-in cards, user button, password flows, pricing table. Built on [`@slyxup/
|
|
3
|
+
Prebuilt, themeable auth + billing components — sign-in cards, user button, password flows, pricing table. Built on [`@slyxup/core`](../core). **Zero CSS dependencies** — styles are self-contained and injected once.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @slyxup/ui @slyxup/
|
|
8
|
+
npm install @slyxup/ui @slyxup/core
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
> Peer: `react ^18 || ^19`
|
|
@@ -15,13 +15,13 @@ npm install @slyxup/ui @slyxup/react @slyxup/core
|
|
|
15
15
|
Inject the stylesheet once at your app root:
|
|
16
16
|
|
|
17
17
|
```tsx
|
|
18
|
-
import {
|
|
18
|
+
import { SlyxupClient } from '@slyxup/core';
|
|
19
19
|
import { SlyxUpStyles } from '@slyxup/ui';
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const client = new SlyxupClient({ publishableKey: 'pk_test_xxx', apiUrl: '...' });
|
|
22
|
+
|
|
23
|
+
<SlyxUpStyles />
|
|
24
|
+
<App />
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
(Components also auto-inject on first mount if you skip this.)
|
|
@@ -89,7 +89,7 @@ const [open, setOpen] = useState(false);
|
|
|
89
89
|
| `onClose` | no | — | Modal close callback |
|
|
90
90
|
| `onDeleted` | no | — | Fired after the account is deleted |
|
|
91
91
|
|
|
92
|
-
Requires the endpoints shipped in the auth worker (`POST /v1/user/password`, `GET/DELETE /v1/sessions`, `GET/POST /v1/user/2fa/*`, `GET/DELETE /v1/user/accounts`)
|
|
92
|
+
Requires the endpoints shipped in the auth worker (`POST /v1/user/password`, `GET/DELETE /v1/sessions`, `GET/POST /v1/user/2fa/*`, `GET/DELETE /v1/user/accounts`).
|
|
93
93
|
|
|
94
94
|
### Password flows
|
|
95
95
|
|
|
@@ -116,20 +116,25 @@ Redirects to the hosted OAuth flow.
|
|
|
116
116
|
|
|
117
117
|
```tsx
|
|
118
118
|
import { PricingTable } from '@slyxup/ui';
|
|
119
|
-
import {
|
|
119
|
+
import { SlyxupClient } from '@slyxup/core';
|
|
120
120
|
|
|
121
|
-
const {
|
|
122
|
-
const { checkout } = useCheckout();
|
|
121
|
+
const client = new SlyxupClient({ publishableKey: 'pk_test_xxx', apiUrl: '...' });
|
|
123
122
|
|
|
123
|
+
// Fetch plans via client API and handle checkout with Paddle
|
|
124
124
|
<PricingTable
|
|
125
125
|
plans={plans}
|
|
126
126
|
loading={loading}
|
|
127
|
-
|
|
127
|
+
currentPlanId={subscription?.planId ?? (isFreeTier ? freePlanId : null)}
|
|
128
|
+
onSelect={(plan) => checkout(plan.id)}
|
|
128
129
|
/>
|
|
129
130
|
```
|
|
130
131
|
|
|
131
132
|
Clean pricing grid with a "popular" badge driven by `plan.isPopular`.
|
|
132
133
|
|
|
134
|
+
Pass `currentPlanId` to render that plan's button as a disabled "Current plan"
|
|
135
|
+
(`currentLabel` overrides the text) — e.g. the active subscription's plan, or
|
|
136
|
+
the `$0` plan's id while on the free tier.
|
|
137
|
+
|
|
133
138
|
You can also drive checkout directly without React hooks:
|
|
134
139
|
|
|
135
140
|
```ts
|
|
@@ -149,20 +154,94 @@ openPaddleCheckout(priceId, customerEmail?, { userId, planId, projectId });
|
|
|
149
154
|
|
|
150
155
|
```tsx
|
|
151
156
|
import { BillingPortal } from '@slyxup/ui';
|
|
152
|
-
import {
|
|
157
|
+
import { SlyxupClient } from '@slyxup/core';
|
|
153
158
|
|
|
154
|
-
const {
|
|
155
|
-
const { invoices } = useInvoices();
|
|
159
|
+
const client = new SlyxupClient({ publishableKey: 'pk_test_xxx', apiUrl: '...' });
|
|
156
160
|
|
|
157
161
|
<BillingPortal
|
|
158
162
|
subscription={subscription}
|
|
159
163
|
invoices={invoices}
|
|
160
|
-
onCancel={cancelSubscription}
|
|
164
|
+
onCancel={cancelSubscription}
|
|
161
165
|
/>
|
|
162
166
|
```
|
|
163
167
|
|
|
164
168
|
Shows current plan, status, renewal date, invoice history, and an optional cancel action.
|
|
165
169
|
|
|
170
|
+
### Granular billing parts — compose your own layouts
|
|
171
|
+
|
|
172
|
+
Don't need the whole portal? Use the parts directly (same props style on each:
|
|
173
|
+
`theme?`, `style?`, `className?`):
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import {
|
|
177
|
+
PlanCard, // single pricing card (PricingTable renders these)
|
|
178
|
+
CurrentPlanCard, // "your plan" card, incl. free-tier empty state
|
|
179
|
+
InvoicesTable, // invoice history (renders null when empty)
|
|
180
|
+
SubscriptionStatus, // tiny status pill
|
|
181
|
+
} from '@slyxup/ui';
|
|
182
|
+
|
|
183
|
+
// Settings page with only the current plan:
|
|
184
|
+
<CurrentPlanCard
|
|
185
|
+
subscription={subscription} // null = free tier empty state
|
|
186
|
+
onCancel={cancelSubscription}
|
|
187
|
+
theme={{ accent: 'emerald' }}
|
|
188
|
+
/>
|
|
189
|
+
|
|
190
|
+
// Fully custom pricing section:
|
|
191
|
+
{plans.map((p) => (
|
|
192
|
+
<PlanCard
|
|
193
|
+
key={p.id}
|
|
194
|
+
plan={p}
|
|
195
|
+
current={p.id === currentPlanId}
|
|
196
|
+
onSelect={(plan) => checkout(plan.id)}
|
|
197
|
+
/>
|
|
198
|
+
))}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Theming every component
|
|
202
|
+
|
|
203
|
+
Three levels, weakest first:
|
|
204
|
+
|
|
205
|
+
1. **Global** — `applyTheme({ accent: 'violet', mode: 'dark', radius: 12 })`
|
|
206
|
+
(or raw `--slx-*` CSS variables on `:root`).
|
|
207
|
+
2. **Per-component** — `theme={{ accent: '#7c3aed', mode: 'dark' }}` on any
|
|
208
|
+
billing component. Scoped to that subtree via `slyxup-root`; siblings and
|
|
209
|
+
the host app are untouched. `accent` accepts a preset name (`mono`,
|
|
210
|
+
`violet`, `blue`, `emerald`, `amber`, `rose`, `cyan`) or any CSS color.
|
|
211
|
+
3. **Escape hatches** — every component also takes `style?` and `className?`
|
|
212
|
+
(e.g. `style={{ background: '#0a0a0f' }}` for full background control).
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
// Dark dashboard card matching your brand:
|
|
216
|
+
<CurrentPlanCard
|
|
217
|
+
subscription={subscription}
|
|
218
|
+
theme={{ accent: '#7c3aed', mode: 'dark', radius: 14 }}
|
|
219
|
+
style={{ background: '#0a0a0f', border: '1px solid #1f1f2a' }}
|
|
220
|
+
/>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Headless billing hooks — real data for custom designs
|
|
224
|
+
|
|
225
|
+
Build your own UI on live data (no components required):
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import {
|
|
229
|
+
usePlans, // plans for a project
|
|
230
|
+
useSubscription, // active subscription (pass YOUR projectId!)
|
|
231
|
+
useInvoices, // invoice history
|
|
232
|
+
useCheckout, // checkout(planId, { origin }) → opens Paddle
|
|
233
|
+
useTransaction, // verify a transaction: { paid, status }
|
|
234
|
+
} from '@slyxup/ui';
|
|
235
|
+
|
|
236
|
+
const { plans } = usePlans(projectId);
|
|
237
|
+
const { subscription, reload } = useSubscription(projectId);
|
|
238
|
+
const { checkout } = useCheckout();
|
|
239
|
+
await checkout(plan.id, { origin: 'https://your-app.com/billing/done' });
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
> Always pass your own `projectId` to `useSubscription` — subscriptions are
|
|
243
|
+
> scoped per project, and omitting it returns `null`.
|
|
244
|
+
|
|
166
245
|
### `<AdminPanel />` — admin dashboard with sk key
|
|
167
246
|
|
|
168
247
|
A full-featured, responsive admin panel for managing users, sessions, and API keys using a **secret key** (`sk_test_xxx` / `sk_live_xxx`).
|
|
@@ -311,6 +390,27 @@ Or go fully manual with CSS variables on any wrapper — light/dark is automatic
|
|
|
311
390
|
|
|
312
391
|
Extra classes: `.slx-btn-accent` renders the primary button in your accent instead of ink — `<button className="slx-btn slx-btn-accent">`.
|
|
313
392
|
|
|
393
|
+
## Form primitives
|
|
394
|
+
|
|
395
|
+
Small building blocks for custom auth screens — same tokens, same theme:
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
import { OtpInput, PasswordStrength, CopyField, EmptyState, passwordScore } from "@slyxup/ui"
|
|
399
|
+
|
|
400
|
+
// 6-box authenticator / verification code (paste + arrow-key support)
|
|
401
|
+
<OtpInput length={6} onComplete={(code) => verify(code)} />
|
|
402
|
+
|
|
403
|
+
// Strength meter — pair with any password field
|
|
404
|
+
<PasswordStrength password={pw} />
|
|
405
|
+
if (passwordScore(pw) < 2) return "Pick something stronger"
|
|
406
|
+
|
|
407
|
+
// Masked value + copy button (API keys, secrets)
|
|
408
|
+
<CopyField label="Secret key" value="sk_live_abc..." />
|
|
409
|
+
|
|
410
|
+
// Friendly placeholder for empty lists
|
|
411
|
+
<EmptyState title="No keys yet" desc="Create one to get started." action={<button>Create key</button>} />
|
|
412
|
+
```
|
|
413
|
+
|
|
314
414
|
Responsive + accessible by default: auth cards reflow under 460px, UserProfile nav collapses to a horizontal strip under 680px, labeled fields, visible focus rings, `prefers-reduced-motion` respected, semantic buttons throughout.
|
|
315
415
|
|
|
316
416
|
Contrast is engineered, not eyeballed: body/secondary/link/error/success text pass WCAG AA (≥4.5) in both modes, and every gradient surface (avatars, marks, badges, split panels, accent buttons) deepens automatically so white text stays readable under **any** accent — including custom hex colors.
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { SlyxUpTheme } from '../../theme';
|
|
3
|
+
import { type CurrentPlanSubscription } from '../CurrentPlanCard/CurrentPlanCard';
|
|
4
|
+
import { type InvoiceRow } from '../InvoicesTable/InvoicesTable';
|
|
5
|
+
export interface PortalSubscription extends CurrentPlanSubscription {
|
|
2
6
|
id: string;
|
|
3
|
-
|
|
4
|
-
currentPeriodEnd: string | null;
|
|
5
|
-
cancelAtPeriodEnd: boolean;
|
|
6
|
-
}
|
|
7
|
-
interface Invoice {
|
|
8
|
-
id: string;
|
|
9
|
-
amount: number;
|
|
10
|
-
currency: string;
|
|
11
|
-
status: 'paid' | 'pending' | 'overdue' | 'refunded';
|
|
12
|
-
billedAt: string | null;
|
|
7
|
+
planId?: string;
|
|
13
8
|
}
|
|
14
9
|
export interface BillingPortalProps {
|
|
15
|
-
subscription:
|
|
16
|
-
invoices:
|
|
10
|
+
subscription: PortalSubscription | null;
|
|
11
|
+
invoices: InvoiceRow[];
|
|
17
12
|
onCancel?: () => void;
|
|
13
|
+
/** Per-component theme (accent, mode, radius…) — scoped, never global. */
|
|
14
|
+
theme?: SlyxUpTheme;
|
|
15
|
+
style?: CSSProperties;
|
|
16
|
+
className?: string;
|
|
18
17
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Billing section without a full profile: current plan + invoices.
|
|
20
|
+
* Composes CurrentPlanCard + InvoicesTable — use those directly for
|
|
21
|
+
* finer-grained layouts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function BillingPortal({ subscription, invoices, onCancel, theme, style, className, }: BillingPortalProps): import("react").JSX.Element;
|
|
22
24
|
//# sourceMappingURL=BillingPortal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BillingPortal.d.ts","sourceRoot":"","sources":["../../../src/components/BillingPortal/BillingPortal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BillingPortal.d.ts","sourceRoot":"","sources":["../../../src/components/BillingPortal/BillingPortal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,KAAK,EACL,SAAS,GACV,EAAE,kBAAkB,+BAepB"}
|
|
@@ -1,61 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { injectStyles } from '../../styles';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { CurrentPlanCard, } from '../CurrentPlanCard/CurrentPlanCard';
|
|
5
|
+
import { InvoicesTable, } from '../InvoicesTable/InvoicesTable';
|
|
6
|
+
/**
|
|
7
|
+
* Billing section without a full profile: current plan + invoices.
|
|
8
|
+
* Composes CurrentPlanCard + InvoicesTable — use those directly for
|
|
9
|
+
* finer-grained layouts.
|
|
10
|
+
*/
|
|
11
|
+
export function BillingPortal({ subscription, invoices, onCancel, theme, style, className, }) {
|
|
6
12
|
injectStyles();
|
|
7
|
-
|
|
8
|
-
return (_jsxs("div", { className: "slx-card", children: [_jsx("h3", { style: { fontSize: 16, fontWeight: 600 }, children: "No active subscription" }), _jsx("p", { style: { fontSize: 13.5, color: 'var(--slx-muted)', marginTop: 6 }, children: "You don't have a subscription yet. Choose a plan to get started." })] }));
|
|
9
|
-
}
|
|
10
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 18 }, children: [_jsx("div", { className: "slx-card", children: _jsxs("div", { style: {
|
|
11
|
-
display: 'flex',
|
|
12
|
-
justifyContent: 'space-between',
|
|
13
|
-
alignItems: 'center',
|
|
14
|
-
}, children: [_jsxs("div", { children: [_jsx("h3", { style: { fontSize: 15, fontWeight: 600 }, children: "Current plan" }), _jsxs("p", { style: { fontSize: 13, color: 'var(--slx-muted)', marginTop: 4 }, children: ["Status:", ' ', _jsx("span", { style: {
|
|
15
|
-
fontWeight: 650,
|
|
16
|
-
color: subscription.status === 'active' ||
|
|
17
|
-
subscription.status === 'trialing'
|
|
18
|
-
? '#34d399'
|
|
19
|
-
: subscription.status === 'past_due'
|
|
20
|
-
? 'var(--slx-danger)'
|
|
21
|
-
: 'var(--slx-muted)',
|
|
22
|
-
}, children: subscription.status })] }), subscription.currentPeriodEnd && (_jsxs("p", { style: {
|
|
23
|
-
fontSize: 12.5,
|
|
24
|
-
color: 'var(--slx-muted)',
|
|
25
|
-
marginTop: 4,
|
|
26
|
-
}, children: ["Renews", ' ', new Date(subscription.currentPeriodEnd).toLocaleDateString(), subscription.cancelAtPeriodEnd
|
|
27
|
-
? ' (cancels at period end)'
|
|
28
|
-
: ''] }))] }), subscription.status !== 'canceled' &&
|
|
29
|
-
!subscription.cancelAtPeriodEnd &&
|
|
30
|
-
onCancel && (_jsx("button", { type: "button", onClick: onCancel, style: {
|
|
31
|
-
fontSize: 13,
|
|
32
|
-
fontWeight: 550,
|
|
33
|
-
background: 'transparent',
|
|
34
|
-
border: '1px solid var(--slx-border)',
|
|
35
|
-
borderRadius: 'var(--slx-radius)',
|
|
36
|
-
padding: '8px 14px',
|
|
37
|
-
cursor: 'pointer',
|
|
38
|
-
color: 'var(--slx-danger)',
|
|
39
|
-
}, children: "Cancel" }))] }) }), invoices.length > 0 && (_jsxs("div", { className: "slx-card", children: [_jsx("h3", { style: { fontSize: 15, fontWeight: 600, marginBottom: 12 }, children: "Invoices" }), _jsxs("table", { style: { width: '100%', fontSize: 13, borderCollapse: 'collapse' }, children: [_jsx("thead", { children: _jsxs("tr", { style: {
|
|
40
|
-
borderBottom: '1px solid var(--slx-border)',
|
|
41
|
-
textAlign: 'left',
|
|
42
|
-
}, children: [_jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Date" }), _jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Amount" }), _jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Status" })] }) }), _jsx("tbody", { children: invoices.map((inv) => (_jsxs("tr", { style: { borderBottom: '1px solid var(--slx-border)' }, children: [_jsx("td", { style: { padding: '8px 0' }, children: inv.billedAt
|
|
43
|
-
? new Date(inv.billedAt).toLocaleDateString()
|
|
44
|
-
: '—' }), _jsxs("td", { style: { padding: '8px 0' }, children: ["$", (inv.amount / 100).toFixed(2), " ", inv.currency] }), _jsx("td", { style: { padding: '8px 0' }, children: _jsx("span", { style: {
|
|
45
|
-
fontSize: 11.5,
|
|
46
|
-
fontWeight: 600,
|
|
47
|
-
padding: '2px 8px',
|
|
48
|
-
borderRadius: 999,
|
|
49
|
-
background: inv.status === 'paid'
|
|
50
|
-
? 'rgba(52,211,153,.1)'
|
|
51
|
-
: inv.status === 'overdue'
|
|
52
|
-
? 'rgba(214,69,80,.1)'
|
|
53
|
-
: 'rgba(108,108,232,.08)',
|
|
54
|
-
color: inv.status === 'paid'
|
|
55
|
-
? '#34d399'
|
|
56
|
-
: inv.status === 'overdue'
|
|
57
|
-
? 'var(--slx-danger)'
|
|
58
|
-
: 'var(--slx-accent)',
|
|
59
|
-
}, children: inv.status }) })] }, inv.id))) })] })] }))] }));
|
|
13
|
+
return (_jsxs("div", { className: className, style: { display: 'flex', flexDirection: 'column', gap: 18, ...style }, children: [_jsx(CurrentPlanCard, { subscription: subscription, onCancel: onCancel, theme: theme }), _jsx(InvoicesTable, { invoices: invoices, theme: theme })] }));
|
|
60
14
|
}
|
|
61
15
|
//# sourceMappingURL=BillingPortal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BillingPortal.js","sourceRoot":"","sources":["../../../src/components/BillingPortal/BillingPortal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"BillingPortal.js","sourceRoot":"","sources":["../../../src/components/BillingPortal/BillingPortal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EACL,eAAe,GAEhB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,aAAa,GAEd,MAAM,gCAAgC,CAAC;AAiBxC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,KAAK,EACL,SAAS,GACU;IACnB,YAAY,EAAE,CAAC;IACf,OAAO,CACL,eACE,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,aAEtE,KAAC,eAAe,IACd,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,GACZ,EACF,KAAC,aAAa,IAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAI,IAC/C,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface CopyFieldProps {
|
|
2
|
+
value: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
/** Mask the middle of long values (ideal for API keys). Default true. */
|
|
5
|
+
masked?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Read-only value with a copy button — API keys, tokens, webhook secrets. */
|
|
8
|
+
export declare function CopyField({ value, label, masked }: CopyFieldProps): import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=CopyField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyField.d.ts","sourceRoot":"","sources":["../../src/components/CopyField.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAa,EAAE,EAAE,cAAc,+BA+CxE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { CheckIcon } from '../icons';
|
|
4
|
+
import { injectStyles } from '../styles';
|
|
5
|
+
/** Read-only value with a copy button — API keys, tokens, webhook secrets. */
|
|
6
|
+
export function CopyField({ value, label, masked = true }) {
|
|
7
|
+
injectStyles();
|
|
8
|
+
const [copied, setCopied] = useState(false);
|
|
9
|
+
const display = masked && value.length > 16
|
|
10
|
+
? `${value.slice(0, 10)}…${value.slice(-4)}`
|
|
11
|
+
: value;
|
|
12
|
+
async function copy() {
|
|
13
|
+
try {
|
|
14
|
+
await navigator.clipboard.writeText(value);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
const ta = document.createElement('textarea');
|
|
18
|
+
ta.value = value;
|
|
19
|
+
document.body.appendChild(ta);
|
|
20
|
+
ta.select();
|
|
21
|
+
document.execCommand('copy');
|
|
22
|
+
ta.remove();
|
|
23
|
+
}
|
|
24
|
+
setCopied(true);
|
|
25
|
+
setTimeout(() => setCopied(false), 1400);
|
|
26
|
+
}
|
|
27
|
+
return (_jsxs("div", { className: "slx-copyfield-wrap", children: [label && (_jsx("p", { className: "slx-label", style: { marginBottom: 6 }, children: label })), _jsxs("div", { className: "slx-copyfield", children: [_jsx("code", { className: "slx-copyfield-value", title: value, children: display }), _jsxs("button", { type: "button", className: "slx-btn-secondary slx-copyfield-btn", onClick: copy, "aria-live": "polite", children: [copied ? _jsx(CheckIcon, {}) : null, copied ? 'Copied' : 'Copy'] })] })] }));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=CopyField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyField.js","sourceRoot":"","sources":["../../src/components/CopyField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAkB;IACvE,YAAY,EAAE,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,MAAM,OAAO,GACX,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE;QACzB,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5C,CAAC,CAAC,KAAK,CAAC;IAEZ,KAAK,UAAU,IAAI;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YAC9C,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;YACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC9B,EAAE,CAAC,MAAM,EAAE,CAAC;YACZ,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC7B,EAAE,CAAC,MAAM,EAAE,CAAC;QACd,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,oBAAoB,aAChC,KAAK,IAAI,CACR,YAAG,SAAS,EAAC,WAAW,EAAC,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,YAChD,KAAK,GACJ,CACL,EACD,eAAK,SAAS,EAAC,eAAe,aAC5B,eAAM,SAAS,EAAC,qBAAqB,EAAC,KAAK,EAAE,KAAK,YAC/C,OAAO,GACH,EACP,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,qCAAqC,EAC/C,OAAO,EAAE,IAAI,eACH,QAAQ,aAEjB,MAAM,CAAC,CAAC,CAAC,KAAC,SAAS,KAAG,CAAC,CAAC,CAAC,IAAI,EAC7B,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,IACpB,IACL,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { SlyxUpTheme } from '../../theme';
|
|
3
|
+
export interface CurrentPlanSubscription {
|
|
4
|
+
planName?: string | null;
|
|
5
|
+
status: string;
|
|
6
|
+
currentPeriodEnd: string | null;
|
|
7
|
+
cancelAtPeriodEnd: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface CurrentPlanCardLabels {
|
|
10
|
+
title?: string;
|
|
11
|
+
cancel?: string;
|
|
12
|
+
emptyTitle?: string;
|
|
13
|
+
emptyText?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CurrentPlanCardProps {
|
|
16
|
+
/** Null = free tier / no subscription (renders the empty state). */
|
|
17
|
+
subscription: CurrentPlanSubscription | null;
|
|
18
|
+
onCancel?: () => void;
|
|
19
|
+
labels?: CurrentPlanCardLabels;
|
|
20
|
+
/** Per-component theme (accent, mode, radius…) — scoped, never global. */
|
|
21
|
+
theme?: SlyxUpTheme;
|
|
22
|
+
style?: CSSProperties;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Standalone "your plan" card — drop it anywhere without mounting a full
|
|
27
|
+
* profile/portal. Shows status, renewal date and cancel action.
|
|
28
|
+
*/
|
|
29
|
+
export declare function CurrentPlanCard({ subscription, onCancel, labels, theme, style, className, }: CurrentPlanCardProps): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=CurrentPlanCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurrentPlanCard.d.ts","sourceRoot":"","sources":["../../../src/components/CurrentPlanCard/CurrentPlanCard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,YAAY,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,KAAK,EACL,KAAK,EACL,SAAS,GACV,EAAE,oBAAoB,+BA4EtB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { injectStyles } from '../../styles';
|
|
4
|
+
import { useScopedTheme } from '../../lib/scoped-theme';
|
|
5
|
+
import { SubscriptionStatus } from '../SubscriptionStatus/SubscriptionStatus';
|
|
6
|
+
/**
|
|
7
|
+
* Standalone "your plan" card — drop it anywhere without mounting a full
|
|
8
|
+
* profile/portal. Shows status, renewal date and cancel action.
|
|
9
|
+
*/
|
|
10
|
+
export function CurrentPlanCard({ subscription, onCancel, labels, theme, style, className, }) {
|
|
11
|
+
injectStyles();
|
|
12
|
+
const ref = useScopedTheme(theme);
|
|
13
|
+
if (!subscription) {
|
|
14
|
+
return (_jsxs("div", { ref: ref, className: `slx-card ${className ?? ''}`, style: style, children: [_jsx("h3", { style: { fontSize: 16, fontWeight: 600 }, children: labels?.emptyTitle ?? 'No active subscription' }), _jsx("p", { style: { fontSize: 13.5, color: 'var(--slx-muted)', marginTop: 6 }, children: labels?.emptyText ??
|
|
15
|
+
"You don't have a subscription yet. Choose a plan to get started." })] }));
|
|
16
|
+
}
|
|
17
|
+
return (_jsx("div", { ref: ref, className: `slx-card ${className ?? ''}`, style: style, children: _jsxs("div", { style: {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
justifyContent: 'space-between',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
}, children: [_jsxs("div", { children: [_jsxs("h3", { style: { fontSize: 15, fontWeight: 600 }, children: [labels?.title ?? 'Current plan', subscription.planName ? ` — ${subscription.planName}` : ''] }), _jsxs("p", { style: { fontSize: 13, color: 'var(--slx-muted)', marginTop: 4 }, children: ["Status: ", _jsx(SubscriptionStatus, { status: subscription.status })] }), subscription.currentPeriodEnd && (_jsxs("p", { style: {
|
|
22
|
+
fontSize: 12.5,
|
|
23
|
+
color: 'var(--slx-muted)',
|
|
24
|
+
marginTop: 4,
|
|
25
|
+
}, children: ["Renews", ' ', new Date(subscription.currentPeriodEnd).toLocaleDateString(), subscription.cancelAtPeriodEnd
|
|
26
|
+
? ' (cancels at period end)'
|
|
27
|
+
: ''] }))] }), subscription.status !== 'canceled' &&
|
|
28
|
+
!subscription.cancelAtPeriodEnd &&
|
|
29
|
+
onCancel && (_jsx("button", { type: "button", onClick: onCancel, style: {
|
|
30
|
+
fontSize: 13,
|
|
31
|
+
fontWeight: 550,
|
|
32
|
+
background: 'transparent',
|
|
33
|
+
border: '1px solid var(--slx-border)',
|
|
34
|
+
borderRadius: 'var(--slx-radius)',
|
|
35
|
+
padding: '8px 14px',
|
|
36
|
+
cursor: 'pointer',
|
|
37
|
+
color: 'var(--slx-danger)',
|
|
38
|
+
}, children: labels?.cancel ?? 'Cancel' }))] }) }));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=CurrentPlanCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurrentPlanCard.js","sourceRoot":"","sources":["../../../src/components/CurrentPlanCard/CurrentPlanCard.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AA2B9E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,KAAK,EACL,KAAK,EACL,SAAS,GACY;IACrB,YAAY,EAAE,CAAC;IACf,MAAM,GAAG,GAAG,cAAc,CAAiB,KAAK,CAAC,CAAC;IAElD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CACL,eAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,SAAS,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,aACnE,aAAI,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,YACzC,MAAM,EAAE,UAAU,IAAI,wBAAwB,GAC5C,EACL,YAAG,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,EAAE,YAClE,MAAM,EAAE,SAAS;wBAChB,kEAAkE,GAClE,IACA,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,cAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,SAAS,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,YACnE,eACE,KAAK,EAAE;gBACL,OAAO,EAAE,MAAM;gBACf,cAAc,EAAE,eAAe;gBAC/B,UAAU,EAAE,QAAQ;aACrB,aAED,0BACE,cAAI,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,aACzC,MAAM,EAAE,KAAK,IAAI,cAAc,EAC/B,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IACxD,EACL,aACE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,EAAE,yBAExD,KAAC,kBAAkB,IAAC,MAAM,EAAE,YAAY,CAAC,MAAM,GAAI,IACzD,EACH,YAAY,CAAC,gBAAgB,IAAI,CAChC,aACE,KAAK,EAAE;gCACL,QAAQ,EAAE,IAAI;gCACd,KAAK,EAAE,kBAAkB;gCACzB,SAAS,EAAE,CAAC;6BACb,uBAEM,GAAG,EACT,IAAI,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,kBAAkB,EAAE,EAC5D,YAAY,CAAC,iBAAiB;oCAC7B,CAAC,CAAC,0BAA0B;oCAC5B,CAAC,CAAC,EAAE,IACJ,CACL,IACG,EACL,YAAY,CAAC,MAAM,KAAK,UAAU;oBACjC,CAAC,YAAY,CAAC,iBAAiB;oBAC/B,QAAQ,IAAI,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE;wBACL,QAAQ,EAAE,EAAE;wBACZ,UAAU,EAAE,GAAG;wBACf,UAAU,EAAE,aAAa;wBACzB,MAAM,EAAE,6BAA6B;wBACrC,YAAY,EAAE,mBAAmB;wBACjC,OAAO,EAAE,UAAU;wBACnB,MAAM,EAAE,SAAS;wBACjB,KAAK,EAAE,mBAAmB;qBAC3B,YAEA,MAAM,EAAE,MAAM,IAAI,QAAQ,GACpB,CACV,IACC,GACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface EmptyStateProps {
|
|
3
|
+
title: string;
|
|
4
|
+
desc?: string;
|
|
5
|
+
action?: ReactNode;
|
|
6
|
+
icon?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** Friendly placeholder for empty lists, states and results. */
|
|
9
|
+
export declare function EmptyState({ title, desc, action, icon }: EmptyStateProps): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../src/components/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,eAAe,+BAcxE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { injectStyles } from '../styles';
|
|
3
|
+
/** Friendly placeholder for empty lists, states and results. */
|
|
4
|
+
export function EmptyState({ title, desc, action, icon }) {
|
|
5
|
+
injectStyles();
|
|
6
|
+
return (_jsxs("div", { className: "slx-empty", children: [icon && (_jsx("div", { className: "slx-empty-icon", "aria-hidden": "true", children: icon })), _jsx("p", { className: "slx-empty-title", children: title }), desc && _jsx("p", { className: "slx-empty-desc", children: desc }), action && _jsx("div", { className: "slx-empty-action", children: action })] }));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=EmptyState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/components/EmptyState.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAmB;IACvE,YAAY,EAAE,CAAC;IACf,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACvB,IAAI,IAAI,CACP,cAAK,SAAS,EAAC,gBAAgB,iBAAa,MAAM,YAC/C,IAAI,GACD,CACP,EACD,YAAG,SAAS,EAAC,iBAAiB,YAAE,KAAK,GAAK,EACzC,IAAI,IAAI,YAAG,SAAS,EAAC,gBAAgB,YAAE,IAAI,GAAK,EAChD,MAAM,IAAI,cAAK,SAAS,EAAC,kBAAkB,YAAE,MAAM,GAAO,IACvD,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { SlyxUpTheme } from '../../theme';
|
|
3
|
+
export interface InvoiceRow {
|
|
4
|
+
id: string;
|
|
5
|
+
amount: number;
|
|
6
|
+
currency: string;
|
|
7
|
+
status: 'paid' | 'pending' | 'overdue' | 'refunded';
|
|
8
|
+
billedAt: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface InvoicesTableProps {
|
|
11
|
+
invoices: InvoiceRow[];
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Per-component theme (accent, mode, radius…) — scoped, never global. */
|
|
14
|
+
theme?: SlyxUpTheme;
|
|
15
|
+
style?: CSSProperties;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Invoice history table. Renders nothing when there are no invoices. */
|
|
19
|
+
export declare function InvoicesTable({ invoices, title, theme, style, className, }: InvoicesTableProps): import("react").JSX.Element | null;
|
|
20
|
+
//# sourceMappingURL=InvoicesTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoicesTable.d.ts","sourceRoot":"","sources":["../../../src/components/InvoicesTable/InvoicesTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IACpD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,KAAkB,EAClB,KAAK,EACL,KAAK,EACL,SAAS,GACV,EAAE,kBAAkB,sCAoEpB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { injectStyles } from '../../styles';
|
|
4
|
+
import { useScopedTheme } from '../../lib/scoped-theme';
|
|
5
|
+
/** Invoice history table. Renders nothing when there are no invoices. */
|
|
6
|
+
export function InvoicesTable({ invoices, title = 'Invoices', theme, style, className, }) {
|
|
7
|
+
injectStyles();
|
|
8
|
+
const ref = useScopedTheme(theme);
|
|
9
|
+
if (invoices.length === 0)
|
|
10
|
+
return null;
|
|
11
|
+
return (_jsxs("div", { ref: ref, className: `slx-card ${className ?? ''}`, style: style, children: [_jsx("h3", { style: { fontSize: 15, fontWeight: 600, marginBottom: 12 }, children: title }), _jsxs("table", { style: { width: '100%', fontSize: 13, borderCollapse: 'collapse' }, children: [_jsx("thead", { children: _jsxs("tr", { style: {
|
|
12
|
+
borderBottom: '1px solid var(--slx-border)',
|
|
13
|
+
textAlign: 'left',
|
|
14
|
+
}, children: [_jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Date" }), _jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Amount" }), _jsx("th", { style: { padding: '6px 0', fontWeight: 550 }, children: "Status" })] }) }), _jsx("tbody", { children: invoices.map((inv) => (_jsxs("tr", { style: { borderBottom: '1px solid var(--slx-border)' }, children: [_jsx("td", { style: { padding: '8px 0' }, children: inv.billedAt
|
|
15
|
+
? new Date(inv.billedAt).toLocaleDateString()
|
|
16
|
+
: '—' }), _jsxs("td", { style: { padding: '8px 0' }, children: ["$", (inv.amount / 100).toFixed(2), " ", inv.currency] }), _jsx("td", { style: { padding: '8px 0' }, children: _jsx("span", { style: {
|
|
17
|
+
fontSize: 11.5,
|
|
18
|
+
fontWeight: 600,
|
|
19
|
+
padding: '2px 8px',
|
|
20
|
+
borderRadius: 999,
|
|
21
|
+
background: inv.status === 'paid'
|
|
22
|
+
? 'rgba(52,211,153,.1)'
|
|
23
|
+
: inv.status === 'overdue'
|
|
24
|
+
? 'rgba(214,69,80,.1)'
|
|
25
|
+
: 'rgba(108,108,232,.08)',
|
|
26
|
+
color: inv.status === 'paid'
|
|
27
|
+
? '#34d399'
|
|
28
|
+
: inv.status === 'overdue'
|
|
29
|
+
? 'var(--slx-danger)'
|
|
30
|
+
: 'var(--slx-accent)',
|
|
31
|
+
}, children: inv.status }) })] }, inv.id))) })] })] }));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=InvoicesTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoicesTable.js","sourceRoot":"","sources":["../../../src/components/InvoicesTable/InvoicesTable.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAmBxD,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,KAAK,GAAG,UAAU,EAClB,KAAK,EACL,KAAK,EACL,SAAS,GACU;IACnB,YAAY,EAAE,CAAC;IACf,MAAM,GAAG,GAAG,cAAc,CAAiB,KAAK,CAAC,CAAC;IAClD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,CACL,eAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,SAAS,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,aACnE,aAAI,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,YAC3D,KAAK,GACH,EACL,iBACE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,aAElE,0BACE,cACE,KAAK,EAAE;gCACL,YAAY,EAAE,6BAA6B;gCAC3C,SAAS,EAAE,MAAM;6BAClB,aAED,aAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,qBAAW,EAC3D,aAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,uBAAa,EAC7D,aAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,uBAAa,IAC1D,GACC,EACR,0BACG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACrB,cAEE,KAAK,EAAE,EAAE,YAAY,EAAE,6BAA6B,EAAE,aAEtD,aAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,YAC5B,GAAG,CAAC,QAAQ;wCACX,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,kBAAkB,EAAE;wCAC7C,CAAC,CAAC,GAAG,GACJ,EACL,cAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,kBAC3B,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAG,GAAG,CAAC,QAAQ,IAC3C,EACL,aAAI,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,YAC7B,eACE,KAAK,EAAE;4CACL,QAAQ,EAAE,IAAI;4CACd,UAAU,EAAE,GAAG;4CACf,OAAO,EAAE,SAAS;4CAClB,YAAY,EAAE,GAAG;4CACjB,UAAU,EACR,GAAG,CAAC,MAAM,KAAK,MAAM;gDACnB,CAAC,CAAC,qBAAqB;gDACvB,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS;oDACxB,CAAC,CAAC,oBAAoB;oDACtB,CAAC,CAAC,uBAAuB;4CAC/B,KAAK,EACH,GAAG,CAAC,MAAM,KAAK,MAAM;gDACnB,CAAC,CAAC,SAAS;gDACX,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS;oDACxB,CAAC,CAAC,mBAAmB;oDACrB,CAAC,CAAC,mBAAmB;yCAC5B,YAEA,GAAG,CAAC,MAAM,GACN,GACJ,KAlCA,GAAG,CAAC,EAAE,CAmCR,CACN,CAAC,GACI,IACF,IACJ,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface OtpInputProps {
|
|
2
|
+
/** Number of boxes (default 6). */
|
|
3
|
+
length?: number;
|
|
4
|
+
/** Controlled value (digits only). Omit for uncontrolled. */
|
|
5
|
+
value?: string;
|
|
6
|
+
onChange?: (value: string) => void;
|
|
7
|
+
/** Fires once every box is filled. */
|
|
8
|
+
onComplete?: (value: string) => void;
|
|
9
|
+
autoFocus?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
label?: string;
|
|
12
|
+
}
|
|
13
|
+
/** One-time-code input — authenticator codes, email verification. Handles paste + backspace navigation. */
|
|
14
|
+
export declare function OtpInput({ length, value, onChange, onComplete, autoFocus, disabled, label, }: OtpInputProps): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=OtpInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OtpInput.d.ts","sourceRoot":"","sources":["../../src/components/OtpInput.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,sCAAsC;IACtC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2GAA2G;AAC3G,wBAAgB,QAAQ,CAAC,EACvB,MAAU,EACV,KAAK,EACL,QAAQ,EACR,UAAU,EACV,SAAS,EACT,QAAQ,EACR,KAAwB,GACzB,EAAE,aAAa,+BAqFf"}
|