@metrifox/angular-sdk 0.0.2-beta.1 → 0.0.2-beta.2

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 CHANGED
@@ -1,46 +1,44 @@
1
- # @metrifox/angular-sdk
1
+ # MetriFox Angular SDK
2
2
 
3
3
  A fully-configurable **Angular SDK** providing ready-to-use components for SaaS and billing platforms including customer portals, pricing tables, and more.
4
4
 
5
- This is the official Angular version of the Metrifox SDK, mirroring the functionality of [@metrifox/react-sdk](https://www.npmjs.com/package/@metrifox/react-sdk).
5
+ ---
6
6
 
7
- [![npm version](https://img.shields.io/npm/v/@metrifox/angular-sdk.svg)](https://www.npmjs.com/package/@metrifox/angular-sdk)
8
- [![license](https://img.shields.io/npm/l/@metrifox/angular-sdk.svg)](https://github.com/metrifox/metrifox-angular-sdk/blob/main/LICENSE)
7
+ ## ⚠️ Version notice – breaking changes
9
8
 
10
- ## Features
9
+ **If you are upgrading from an earlier version of the SDK, please read this.**
11
10
 
12
- - 🎨 **Fully Customizable** - Extensive theming support to match your brand
13
- - 📦 **Standalone Components** - Modern Angular standalone components (no NgModule required)
14
- - 🔥 **TypeScript** - Full type safety with comprehensive TypeScript definitions
15
- - 🚀 **Easy Integration** - Simple setup with minimal configuration
16
- - 📱 **Responsive** - Mobile-friendly components out of the box
17
- - ♿ **Accessible** - WCAG compliant components
18
- - 🌙 **Dark Mode** - Built-in dark mode support
19
- - ⚡ **Tree-shakeable** - Only import what you need
11
+ This release introduces a **new theme structure** for both **Customer Portal** and **Pricing Table**. The theme API has been reorganized and is **not backward compatible** with previous versions.
20
12
 
21
- ## Requirements
13
+ - **Theme is now a single object** passed via `MetrifoxService.initialize({ theme })` with two keys: `customerPortal` and `pricingTable`. The previous top-level `pricingTableTheme` option is **deprecated**; use `theme.pricingTable` instead.
14
+ - **Customer Portal theme** uses a new grouped shape: `general`, `tabs`, `sections`, `buttons`, `lineItems`, `tables`, `modals`, and `plans`. Property names and nesting have changed from older versions.
15
+ - **Pricing Table theme** now strictly follows the same nested structure as Customer Portal: all plan-related keys must be under `plans` (e.g. `plans.planCards`, `plans.planToggle`). Top-level plan keys are no longer supported.
16
+ - **Both components** accept an optional `theme` input per instance to override or extend the global theme from `MetrifoxService.initialize`.
22
17
 
23
- - Angular 17.0.0 or higher (compatible with Angular 17, 18, and 19)
24
- - RxJS 7.0.0 or higher
18
+ If you were using custom themes before, you will need to **migrate your theme objects** to the new structure. Omit any keys you don't need; the SDK merges your values with defaults. See the [Styling](#styling) section below for the full theme shapes and examples.
19
+
20
+ ---
25
21
 
26
22
  ## Installation
27
23
 
28
24
  ```bash
29
- # Using pnpm (recommended)
30
- pnpm add @metrifox/angular-sdk
31
-
32
- # Using npm
25
+ # using npm
33
26
  npm install @metrifox/angular-sdk
34
27
 
35
- # Using yarn
28
+ # or pnpm
29
+ pnpm add @metrifox/angular-sdk
30
+
31
+ # or yarn
36
32
  yarn add @metrifox/angular-sdk
37
33
  ```
38
34
 
39
- ## Quick Start
35
+ ---
36
+
37
+ ## Setup
40
38
 
41
- ### 1. Provide the SDK (required for components)
39
+ ### 1. Provide the SDK
42
40
 
43
- For standalone apps that use `<metrifox-customer-portal>` or `<metrifox-pricing-table>`, register the SDK in your app config so the components can inject `MetrifoxService`:
41
+ Register the SDK providers in your app config:
44
42
 
45
43
  ```typescript
46
44
  // app.config.ts (Standalone)
@@ -56,7 +54,7 @@ export const appConfig: ApplicationConfig = {
56
54
 
57
55
  ### 2. Initialize the SDK
58
56
 
59
- Initialize Metrifox before using any components (e.g. in your root component’s `ngOnInit` or in a guard):
57
+ Before using any components, initialize the SDK once with your Client key:
60
58
 
61
59
  ```typescript
62
60
  import { MetrifoxService } from "@metrifox/angular-sdk";
@@ -66,22 +64,6 @@ MetrifoxService.initialize({
66
64
  });
67
65
  ```
68
66
 
69
- Or using the module approach:
70
-
71
- ```typescript
72
- // app.module.ts
73
- import { MetrifoxModule } from "@metrifox/angular-sdk";
74
-
75
- @NgModule({
76
- imports: [
77
- MetrifoxModule.forRoot({
78
- clientKey: "your-metrifox-client-key",
79
- }),
80
- ],
81
- })
82
- export class AppModule {}
83
- ```
84
-
85
67
  ### 3. Import Styles
86
68
 
87
69
  Add the SDK styles to your `angular.json`:
@@ -98,345 +80,343 @@ Or import in your global `styles.css`:
98
80
  @import "@metrifox/angular-sdk/styles.css";
99
81
  ```
100
82
 
101
- ### 4. Use Components
83
+ > Compatible with **Angular 17, 18, and 19**. All components are standalone (no NgModule required).
102
84
 
103
- ```typescript
104
- import { Component } from "@angular/core";
105
- import { CustomerPortalComponent } from "@metrifox/angular-sdk";
106
-
107
- @Component({
108
- selector: "app-billing",
109
- standalone: true,
110
- imports: [CustomerPortalComponent],
111
- template: ` <metrifox-customer-portal [customerKey]="'cust_123'" /> `,
112
- })
113
- export class BillingComponent {}
114
- ```
85
+ ---
115
86
 
116
- ## Components
87
+ ## Widgets
117
88
 
118
- ### CustomerPortal
89
+ ## `CustomerPortal`
119
90
 
120
- Displays a customizable customer dashboard with plans, subscriptions, billing, and more.
91
+ Displays a customizable customer dashboard with plans, subscriptions, billing, credits, and more.
121
92
 
122
93
  ```typescript
94
+ import { Component } from "@angular/core";
123
95
  import { CustomerPortalComponent, SectionConfig } from "@metrifox/angular-sdk";
124
96
 
125
97
  @Component({
98
+ selector: "app-billing",
126
99
  standalone: true,
127
100
  imports: [CustomerPortalComponent],
128
101
  template: `
129
102
  <metrifox-customer-portal
130
- [customerKey]="customerKey"
103
+ [customerKey]="'your-customer-key'"
131
104
  [sectionsConfig]="sections"
132
- (dataLoaded)="onDataLoaded($event)"
133
- (error)="onError($event)"
134
- >
135
- </metrifox-customer-portal>
105
+ />
136
106
  `,
137
107
  })
138
- export class MyComponent {
139
- customerKey = "cust_123";
140
-
108
+ export class BillingComponent {
141
109
  sections: SectionConfig[] = [
142
110
  { key: "subscription" },
143
111
  { key: "plan" },
144
- { key: "upcomingInvoice" },
145
- { key: "billingHistory" },
146
- { key: "paymentOverview" },
147
- { key: "entitlementUsage" },
148
- { key: "walletBalance" },
112
+ { key: "billingHistory", hidden: true },
149
113
  ];
150
-
151
- onDataLoaded(data: CustomerData) {
152
- console.log("Customer data loaded:", data);
153
- }
154
-
155
- onError(error: MetrifoxErrorEvent) {
156
- console.error("Error:", error);
157
- }
158
114
  }
159
115
  ```
160
116
 
161
- #### CustomerPortal Inputs
117
+ Optional **`theme`** input: pass a `CustomerPortalTheme` object to override or extend the global theme from `MetrifoxService.initialize` for this instance only.
118
+
119
+ #### Section Configuration
120
+
121
+ The `sectionsConfig` input controls what appears in the portal.
122
+
123
+ | Property | Type | Description |
124
+ | ----------- | ----------------- | --------------------------------------------------- |
125
+ | `key` | `SectionKey` | Unique key of the section (see list below) |
126
+ | `hidden` | `boolean` | Hide this section when `true` |
127
+ | `component` | `Type<any>` | Replace the default section with your own component |
128
+ | `props` | `Record<string, unknown>` | Extra props passed to the custom or default section |
162
129
 
163
- | Property | Type | Required | Description |
164
- | ---------------- | ----------------- | -------- | ---------------------------------- |
165
- | `customerKey` | `string` | Yes | Unique identifier for the customer |
166
- | `sectionsConfig` | `SectionConfig[]` | No | Configuration for portal sections |
130
+ #### Built-in Section Keys
167
131
 
168
- #### CustomerPortal Outputs
132
+ | Key | Description |
133
+ | ------------------ | ----------------------------- |
134
+ | `upcomingInvoice` | Displays next invoice details |
135
+ | `subscription` | Active subscription overview |
136
+ | `creditBalance` | Shows user wallet balance |
137
+ | `entitlementUsage` | Displays resource usage |
138
+ | `paymentOverview` | Payment summary and methods |
139
+ | `billingHistory` | List of past transactions |
140
+ | `plan` | Current plan details |
169
141
 
170
- | Event | Type | Description |
171
- | ------------ | -------------------- | ------------------------------------ |
172
- | `dataLoaded` | `CustomerData` | Emitted when customer data is loaded |
173
- | `error` | `MetrifoxErrorEvent` | Emitted when an error occurs |
142
+ #### Section Anchors
174
143
 
175
- #### Available Sections
144
+ Each portal section renders inside a `<section id="...">` wrapper so you can link directly to segments of a customer portal view. The default anchor IDs are:
176
145
 
177
- - `subscription` - Active subscription overview
178
- - `plan` - Current plan details
179
- - `upcomingInvoice` - Next invoice details
180
- - `billingHistory` - List of past transactions
181
- - `paymentOverview` - Payment methods
182
- - `entitlementUsage` - Feature/resource usage
183
- - `walletBalance` - Credit/wallet balance
146
+ | Anchor ID | Section Key |
147
+ | -------------------- | ------------------ |
148
+ | `#upcoming-invoice` | `upcomingInvoice` |
149
+ | `#subscription` | `subscription` |
150
+ | `#credit-balance` | `creditBalance` |
151
+ | `#entitlement-usage` | `entitlementUsage` |
152
+ | `#payment-overview` | `paymentOverview` |
153
+ | `#billing-history` | `billingHistory` |
154
+ | `#plan` | `plan` |
184
155
 
185
- ### PricingTable
156
+ Use these anchors when embedding the SDK or sharing deep links (e.g., `https://app.example.com/portal#billing-history`).
186
157
 
187
- Displays subscription plans and one-time purchases.
158
+ ---
159
+
160
+ ## Pricing Table
161
+
162
+ Displays subscription plans and one-time purchases in a configurable pricing table component.
188
163
 
189
164
  ```typescript
190
- import { PricingTableComponent, PlanSelectEvent } from "@metrifox/angular-sdk";
165
+ import { Component } from "@angular/core";
166
+ import { PricingTableComponent } from "@metrifox/angular-sdk";
191
167
 
192
168
  @Component({
169
+ selector: "app-pricing",
193
170
  standalone: true,
194
171
  imports: [PricingTableComponent],
195
172
  template: `
196
173
  <metrifox-pricing-table
197
- [checkoutUsername]="username"
198
- [productKey]="productKey"
199
- [plansOnly]="false"
200
- [showTabHeader]="true"
201
- (planSelected)="onPlanSelect($event)"
202
- (purchaseSelected)="onPurchaseSelect($event)"
203
- >
204
- </metrifox-pricing-table>
174
+ [checkoutUsername]="'your-checkout-username'"
175
+ [productKey]="'your-product-key'"
176
+ />
205
177
  `,
206
178
  })
207
- export class PricingComponent {
208
- username = "your-checkout-username";
209
- productKey = "your-product-key";
179
+ export class PricingComponent {}
180
+ ```
210
181
 
211
- onPlanSelect(event: PlanSelectEvent) {
212
- console.log("Plan selected:", event.plan);
213
- console.log("Action:", event.action); // 'upgrade' | 'downgrade' | 'new' | 'current'
214
- }
182
+ ---
215
183
 
216
- onPurchaseSelect(event: PurchaseSelectEvent) {
217
- console.log("Purchase selected:", event.purchase);
218
- }
184
+ #### Props
185
+
186
+ The inputs control how the pricing table is configured.
187
+
188
+ | Property | Type | Required | Default | Description |
189
+ | --------------------- | ------------------ | -------- | ------- | -------------------------------------------------------------------------------- |
190
+ | `checkoutUsername` | `string` | Yes | — | Unique username used for checkout. This can be found in **Settings → Checkout**. |
191
+ | `productKey` | `string` | Yes | — | Unique product identifier. This can be found on the product page. |
192
+ | `plansOnly` | `boolean` | No | `false` | Controls whether only subscription plans are rendered. |
193
+ | `singlePurchasesOnly` | `boolean` | No | `false` | Controls whether only single purchases are rendered. |
194
+ | `showTabHeader` | `boolean` | No | `true` | Controls whether the tab header for switching between offerings is rendered. |
195
+ | `theme` | `PricingTableTheme`| No | — | Optional theme override for this instance (merged with global theme from `MetrifoxService.initialize`). |
196
+
197
+ > **Note:** If both `plansOnly` and `singlePurchasesOnly` are `false` or undefined, both plans and single purchases are displayed.
198
+
199
+ ## Styling
200
+
201
+ Import the SDK's global styles (see [Setup](#setup) step 3).
202
+
203
+ > This is required for proper styling of all components.
204
+
205
+ ### Theme configuration (new structure)
206
+
207
+ Theming is driven by a single `theme` object passed to `MetrifoxService.initialize`. It has two top-level keys: `customerPortal` and `pricingTable`. Any value you omit falls back to the SDK default. You can also pass an optional `theme` input to `<metrifox-customer-portal>` or `<metrifox-pricing-table>` to override or extend the global theme for that instance.
208
+
209
+ ```typescript
210
+ // Passed to MetrifoxService.initialize({ theme })
211
+ theme?: {
212
+ customerPortal?: CustomerPortalTheme
213
+ pricingTable?: PricingTableTheme
219
214
  }
220
215
  ```
221
216
 
222
- #### PricingTable Inputs
217
+ > **Deprecated:** The previous root-level `pricingTableTheme` option is no longer supported. Use `theme.pricingTable` instead.
223
218
 
224
- | Property | Type | Required | Default | Description |
225
- | --------------------- | --------- | -------- | ------- | -------------------------------------------- |
226
- | `checkoutUsername` | `string` | Yes | - | Username for checkout |
227
- | `productKey` | `string` | Yes | - | Product identifier |
228
- | `plansOnly` | `boolean` | No | `false` | Show only subscription plans |
229
- | `singlePurchasesOnly` | `boolean` | No | `false` | Show only one-time purchases |
230
- | `showTabHeader` | `boolean` | No | `true` | Show tab header for switching |
231
- | `customerKey` | `string` | No | - | Current customer (to highlight current plan) |
219
+ ---
232
220
 
233
- #### PricingTable Outputs
221
+ ### Customer Portal theme (`CustomerPortalTheme`)
234
222
 
235
- | Event | Type | Description |
236
- | ------------------ | --------------------- | ----------------------------------- |
237
- | `planSelected` | `PlanSelectEvent` | Emitted when a plan is selected |
238
- | `purchaseSelected` | `PurchaseSelectEvent` | Emitted when a purchase is selected |
239
- | `dataLoaded` | `PricingData` | Emitted when pricing data is loaded |
240
- | `error` | `MetrifoxErrorEvent` | Emitted when an error occurs |
223
+ All properties are optional. The shape is grouped by area of the UI:
241
224
 
242
- ## Theming
225
+ | Group | Description |
226
+ | ----- | ----------- |
227
+ | `general` | Page-level: link color, background, border radius, font family, container padding |
228
+ | `tabs` | Tab bar (e.g. Wallet balance tabs): background, border, active/inactive states |
229
+ | `sections` | Section cards: background, padding, borders, content/summaryBalance sub-styles, header/label/value typography, usage bars, empty text |
230
+ | `buttons` | Primary and secondary buttons: background, border (color/width/radius), typography |
231
+ | `lineItems` | Subscription line items: parentRow/childRow background, border, typography (label/quantity) |
232
+ | `tables` | Tables (e.g. billing history): header/row colors, border, cell padding, expand icon, typography |
233
+ | `modals` | Modal overlay, background, border, close button; header/title/description typography; footer primary/secondary buttons |
234
+ | `plans` | Plan cards when shown in portal: currentPlanCard, planCards (border as `{ color, width, radius }`), planFeatures, planButton, planToggle, planTags |
243
235
 
244
- Configure themes during initialization:
236
+ **Example minimal override:**
245
237
 
246
238
  ```typescript
247
- import { MetrifoxService, MetrifoxTheme } from "@metrifox/angular-sdk";
248
-
249
- const theme: MetrifoxTheme = {
250
- customerPortal: {
251
- tabs: {
252
- background: "#111827",
253
- borderColor: "#243044",
254
- activeBackground: "#1f2937",
255
- activeTextColor: "#3b82f6",
256
- inactiveTextColor: "#9ca3af",
257
- },
258
- card: {
259
- titleBackground: "#1f2937",
260
- contentBackground: "#111827",
261
- titleColor: "#f9fafb",
262
- details: {
263
- labelColor: "#cbd5e1",
264
- valueColor: "#ffffff",
265
- },
266
- },
267
- button: {
268
- background: "#3b82f6",
269
- textColor: "#ffffff",
270
- },
239
+ customerPortal: {
240
+ general: { linkColor: "#2563eb", backgroundColor: "#ffffff" },
241
+ tabs: {
242
+ tabBackground: "#ffffff",
243
+ tabBorderColor: "#e5e7eb",
244
+ activeTabBackground: "#2563eb",
245
+ activeTabTextColor: "#ffffff",
246
+ inactiveTabTextColor: "#6b7280",
271
247
  },
272
- pricingTable: {
273
- card: {
248
+ sections: {
249
+ background: "#ffffff",
250
+ content: { background: "#f4f4f5", borderRadius: "8px" },
251
+ header: { fontSize: "16px", fontWeight: "600", color: "#52525b" },
252
+ label: { fontSize: "13px", color: "#71717a" },
253
+ value: { fontSize: "16px", color: "#52525b" },
254
+ },
255
+ buttons: {
256
+ primary: { backgroundColor: "#2563eb", border: { radius: "8px" }, typography: { color: "#ffffff" } },
257
+ secondary: { backgroundColor: "#e4e4e7", typography: { color: "#3f3f46" } },
258
+ },
259
+ plans: {
260
+ planCards: {
274
261
  background: "#ffffff",
275
- borderColor: "#e5e7eb",
276
- header: {
277
- textColor: "#111827",
278
- },
279
- price: {
280
- amountColor: "#111827",
281
- },
282
- },
283
- button: {
284
- background: "#2563eb",
285
- textColor: "#ffffff",
262
+ border: { color: "#e5e7eb", width: "1px", radius: "8px" },
263
+ header: { background: "#e5e7eb", textColor: "#111827" },
264
+ description: { textColor: "#6b7280", textButtonColor: "#2563eb" },
265
+ price: { amountColor: "#111827", primaryTextColor: "#6b7280", secondaryTextColor: "#9ca3af" },
286
266
  },
267
+ planButton: { background: "#2563eb", textColor: "#ffffff" },
268
+ planToggle: { background: "#e5e7eb", activeBackground: "#1f2937", activeText: "#ffffff", inactiveText: "#6b7280" },
287
269
  },
288
- };
289
-
290
- MetrifoxService.initialize({
291
- clientKey: "your-client-key",
292
- theme,
293
- });
270
+ }
294
271
  ```
295
272
 
296
- ### Dark Mode
273
+ ---
274
+
275
+ ### Font customization
297
276
 
298
- The SDK supports dark mode out of the box:
277
+ The SDK accepts **any font-family string** in your theme. The SDK applies it via CSS, but **your app must load the font** (Google Fonts, @font-face, etc.) before the SDK renders.
299
278
 
300
- 1. **Automatic** - Follows system preference (`prefers-color-scheme: dark`)
301
- 2. **Manual** - Add `metrifox-dark` class or `data-theme="dark"` attribute
279
+ **How it works:**
280
+
281
+ 1. **Load the font in your app** (HTML, CSS, or framework-specific):
302
282
 
303
283
  ```html
304
- <!-- Manual dark mode -->
305
- <div class="metrifox-dark">
306
- <metrifox-customer-portal [customerKey]="key" />
307
- </div>
284
+ <!-- Option A: Google Fonts in your index.html <head> -->
285
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
308
286
  ```
309
287
 
310
- ## Using the Service Directly
288
+ ```css
289
+ /* Option B: @font-face in your global CSS */
290
+ @font-face {
291
+ font-family: 'MyCustomFont';
292
+ src: url('/fonts/custom.woff2') format('woff2');
293
+ }
294
+ ```
311
295
 
312
- Access Metrifox APIs programmatically:
296
+ 2. **Pass the font-family to the SDK theme:**
313
297
 
314
298
  ```typescript
315
- import { Component, inject } from '@angular/core';
316
- import { MetrifoxService } from '@metrifox/angular-sdk';
317
-
318
- @Component({ ... })
319
- export class MyComponent {
320
- private metrifoxService = inject(MetrifoxService);
321
-
322
- loadCustomer() {
323
- this.metrifoxService.getCustomerData('cust_123').subscribe({
324
- next: (data) => console.log('Customer:', data),
325
- error: (err) => console.error('Error:', err)
326
- });
327
- }
328
-
329
- updateSubscription() {
330
- this.metrifoxService.updateSubscription('cust_123', {
331
- planId: 'plan_pro',
332
- proration: 'create_prorations'
333
- }).subscribe({
334
- next: (result) => {
335
- if (result.checkoutUrl) {
336
- window.location.href = result.checkoutUrl;
337
- }
299
+ MetrifoxService.initialize({
300
+ clientKey: "your-client-key",
301
+ theme: {
302
+ customerPortal: {
303
+ general: {
304
+ // Any font-family string works
305
+ fontFamily: '"Space Grotesk", "Inter", sans-serif'
306
+ // or: 'MyCustomFont, sans-serif'
307
+ // or: 'system-ui, -apple-system, sans-serif'
338
308
  }
339
- });
309
+ }
340
310
  }
311
+ });
312
+ ```
341
313
 
342
- checkFeatureAccess() {
343
- this.metrifoxService.checkAccess('cust_123', 'api_calls').subscribe({
344
- next: ({ hasAccess, remaining, limit }) => {
345
- console.log(`Access: ${hasAccess}, Remaining: ${remaining}/${limit}`);
346
- }
347
- });
348
- }
314
+ If no `fontFamily` is provided, the SDK inherits the font from the host page. This means the SDK works with whatever font your app already uses — no extra configuration needed.
349
315
 
350
- recordUsage() {
351
- this.metrifoxService.recordUsage('cust_123', 'api_calls', 1).subscribe({
352
- next: () => console.log('Usage recorded')
353
- });
354
- }
355
- }
356
- ```
316
+ > **Important:** When using Google Fonts or custom fonts, load them in your app **before** the SDK initializes to prevent flash of unstyled text (FOUT).
357
317
 
358
- ## Custom Components
318
+ ---
359
319
 
360
- Replace any section with your own component:
320
+ ### Pricing Table theme (`PricingTableTheme`)
361
321
 
362
- ```typescript
363
- // my-custom-plan.component.ts
364
- import { Component, Input } from "@angular/core";
365
- import {
366
- CustomSectionComponentBase,
367
- CustomerData,
368
- } from "@metrifox/angular-sdk";
322
+ The Pricing Table theme follows the same nested structure as Customer Portal. All plan-related keys must be nested under `plans`.
369
323
 
370
- @Component({
371
- selector: "app-custom-plan",
372
- standalone: true,
373
- template: `
374
- <div class="custom-plan">
375
- <h3>{{ customerData?.plan?.name }}</h3>
376
- <p>Custom property: {{ customProp }}</p>
377
- </div>
378
- `,
379
- })
380
- export class MyCustomPlanComponent implements CustomSectionComponentBase {
381
- @Input() customerData?: CustomerData;
382
- @Input() customerKey?: string;
383
- @Input() customProp?: string;
384
- }
324
+ | Key | Description |
325
+ | --- | ----------- |
326
+ | `plans` | Container for all plan-related styling |
327
+ | `plans.currentPlanCard` | Current-plan highlight: header (background, textColor), gradientColor, description, borderRadius |
328
+ | `plans.planCards` | Card style: background, border (`{ color, width, radius }`), header, description (textColor, textButtonColor), price (amountColor, primaryTextColor, secondaryTextColor, textButtonColor, background, borderColor) |
329
+ | `plans.planFeatures` | Feature list: textColor, iconColor |
330
+ | `plans.planButton` | CTA button: background, textColor; optional secondaryBackground, secondaryTextColor, textButtonColor |
331
+ | `plans.planToggle` | Monthly/Yearly toggle: background, activeBackground, activeText, inactiveText |
332
+ | `plans.planTags` | Tags (e.g. free trial): freeTrialBackground, freeTrialText |
333
+ | `tabs` | Tabs (e.g. Plans vs Single purchases): inactiveText, activeText, indicator, borderColor |
334
+ | `checkoutBar` | Bottom checkout bar: background, borderColor, textColor, buttonBackground, buttonTextColor |
385
335
 
386
- // Usage
387
- @Component({
388
- template: `
389
- <metrifox-customer-portal
390
- [customerKey]="'cust_123'"
391
- [sectionsConfig]="sections"
392
- >
393
- </metrifox-customer-portal>
394
- `,
395
- })
396
- export class BillingComponent {
397
- sections: SectionConfig[] = [
398
- { key: "subscription" },
399
- {
400
- key: "plan",
401
- component: MyCustomPlanComponent,
402
- props: { customProp: "Hello!" },
336
+ **Example – minimal override:**
337
+
338
+ ```typescript
339
+ pricingTable: {
340
+ plans: {
341
+ planCards: {
342
+ background: "#ffffff",
343
+ border: { color: "#e5e7eb", width: "1px", radius: "8px" },
344
+ header: { background: "#e5e7eb", textColor: "#111827" },
345
+ description: { textColor: "#6b7280", textButtonColor: "#2563eb" },
346
+ price: { amountColor: "#111827", primaryTextColor: "#6b7280", secondaryTextColor: "#9ca3af" },
403
347
  },
404
- ];
348
+ planButton: { background: "#2563eb", textColor: "#ffffff" },
349
+ planToggle: { background: "#e5e7eb", activeBackground: "#1f2937", activeText: "#ffffff", inactiveText: "#6b7280" },
350
+ },
351
+ tabs: { activeText: "#2563eb", indicator: "#2563eb", borderColor: "#9ca3af" },
352
+ checkoutBar: {
353
+ background: "#f9fafb",
354
+ borderColor: "#e5e7eb",
355
+ textColor: "#3f3f46",
356
+ buttonBackground: "#2563eb",
357
+ buttonTextColor: "#ffffff",
358
+ },
405
359
  }
406
360
  ```
407
361
 
408
- ## TypeScript Support
362
+ When the Pricing Table is embedded inside the Customer Portal, it automatically uses `theme.customerPortal.plans` for plan styling so both components stay consistent.
363
+
364
+ ---
409
365
 
410
- The SDK is fully typed. Import types as needed:
366
+ ### Full example
411
367
 
412
368
  ```typescript
413
- import type {
414
- // Configuration
415
- MetrifoxConfig,
416
- MetrifoxTheme,
417
-
418
- // Customer Portal
419
- CustomerPortalTheme,
420
- SectionConfig,
421
- SectionKey,
422
-
423
- // Pricing Table
424
- PricingTableTheme,
425
- PlanSelectEvent,
426
- PurchaseSelectEvent,
427
-
428
- // Data Models
429
- CustomerData,
430
- SubscriptionData,
431
- PricingData,
432
- PricingPlan,
433
-
434
- // Events
435
- MetrifoxErrorEvent,
436
- } from "@metrifox/angular-sdk";
369
+ import { MetrifoxService } from "@metrifox/angular-sdk";
370
+
371
+ MetrifoxService.initialize({
372
+ clientKey: "your-client-key",
373
+ theme: {
374
+ customerPortal: {
375
+ general: { linkColor: "#2563eb", backgroundColor: "#ffffff" },
376
+ tabs: {
377
+ tabBackground: "#ffffff",
378
+ activeTabBackground: "#2563eb",
379
+ activeTabTextColor: "#ffffff",
380
+ inactiveTabTextColor: "#6b7280",
381
+ },
382
+ sections: {
383
+ background: "#ffffff",
384
+ content: { background: "#f4f4f5", borderRadius: "8px" },
385
+ },
386
+ buttons: {
387
+ primary: { backgroundColor: "#2563eb", typography: { color: "#ffffff" } },
388
+ },
389
+ },
390
+ pricingTable: {
391
+ plans: {
392
+ planCards: { background: "#ffffff", border: { color: "#e5e7eb", radius: "8px" } },
393
+ planButton: { background: "#2563eb", textColor: "#ffffff" },
394
+ },
395
+ tabs: { activeText: "#2563eb", indicator: "#2563eb" },
396
+ checkoutBar: { buttonBackground: "#2563eb", buttonTextColor: "#ffffff" },
397
+ },
398
+ },
399
+ });
400
+ ```
401
+
402
+ Per-component overrides (optional):
403
+
404
+ ```html
405
+ <metrifox-customer-portal
406
+ [customerKey]="'cust_123'"
407
+ [theme]="{ general: { linkColor: '#1d4ed8' } }"
408
+ />
409
+
410
+ <metrifox-pricing-table
411
+ [checkoutUsername]="'checkout_user'"
412
+ [productKey]="'prod_key'"
413
+ [theme]="{ plans: { planCards: { background: '#f8fafc' } } }"
414
+ />
437
415
  ```
438
416
 
439
- ## Migration from React SDK
417
+ ---
418
+
419
+ ### Migration from React SDK
440
420
 
441
421
  | React | Angular |
442
422
  | ----------------------- | ------------------------------ |
@@ -445,43 +425,53 @@ import type {
445
425
  | `<PricingTable />` | `<metrifox-pricing-table>` |
446
426
  | `customerKey` prop | `[customerKey]` input |
447
427
  | `onPlanSelect` callback | `(planSelected)` output |
428
+ | `theme` prop | `[theme]` input |
429
+
430
+ ---
448
431
 
449
- ## Testing with the demo playground
432
+ ## Local Development
450
433
 
451
- The [metrifox-sdk-demo](https://github.com/metrifox/metrifox-sdk-demo) repo includes an **Angular SDK demo playground** that works like the React SDK demo: sidebar (Customer Portal / Pricing Table), config panel (API keys + Theme options), and live preview.
434
+ ### Using [yalc](https://github.com/wclr/yalc)
452
435
 
453
- To run the package against the demo playground:
436
+ For local SDK testing:
454
437
 
455
- 1. **Build the Angular SDK** (this repo):
438
+ ```bash
439
+ # In SDK project
440
+ pnpm build
441
+ npx yalc publish
442
+
443
+ # In consuming app
444
+ npx yalc add @metrifox/angular-sdk
445
+ npm install
446
+ ```
456
447
 
457
- ```bash
458
- pnpm install
459
- pnpm run build
460
- ```
448
+ #### Auto-update during development
461
449
 
462
- 2. **Run the demo** (in [metrifox-sdk-demo/angular-sdk](https://github.com/metrifox/metrifox-sdk-demo/tree/main/angular-sdk)):
450
+ ```bash
451
+ # In SDK project
452
+ pnpm build # rebuild
453
+ npx yalc publish # re-publish to yalc
463
454
 
464
- ```bash
465
- cd path/to/metrifox-sdk-demo/angular-sdk
466
- npm install
467
- npm run dev
468
- ```
455
+ # In consuming project
456
+ npx yalc update @metrifox/angular-sdk
457
+ ```
469
458
 
470
- The demo’s `package.json` points to `file:../../metrifox-angular-sdk/dist`, so it uses your local build. Open `http://localhost:4200` and use the config panel to set Client Key, Customer Key (for the portal), and Theme options.
459
+ #### Clean up
471
460
 
472
- ## Browser Support
461
+ ```bash
462
+ npx yalc remove @metrifox/angular-sdk
463
+ npm install
464
+ ```
473
465
 
474
- - Chrome (latest)
475
- - Firefox (latest)
476
- - Safari (latest)
477
- - Edge (latest)
466
+ ---
478
467
 
479
468
  ## Support
480
469
 
481
- - 📧 Email: support@metrifox.com
482
- - 📚 Documentation: https://docs.metrifox.com
483
- - 🐛 Issues: https://github.com/metrifox/metrifox-angular-sdk/issues
470
+ 📘 **Full Documentation:**
471
+ For detailed guides, API references, and live examples, visit [docs.metrifox.com](https://docs.metrifox.com).
472
+
473
+ ---
484
474
 
485
- ## License
475
+ ## 📄 License
486
476
 
487
- MIT © [Metrifox](https://metrifox.com)
477
+ MIT © [MetriFox](https://metrifox.com)