@temboplus/frontend-react-core 0.1.3-beta.0 → 0.1.3-beta.10
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/dist/InfoCircleOutlined-B7d2aRfV.js +7 -0
- package/dist/InfoCircleOutlined-B7d2aRfV.js.map +1 -0
- package/dist/InfoCircleOutlined-DYs90hdV.js +7 -0
- package/dist/InfoCircleOutlined-DYs90hdV.js.map +1 -0
- package/dist/ZoomOutOutlined-CW-jqBMI.js +2 -0
- package/dist/ZoomOutOutlined-CW-jqBMI.js.map +1 -0
- package/dist/ZoomOutOutlined-Pw8hpWWK.js +2 -0
- package/dist/ZoomOutOutlined-Pw8hpWWK.js.map +1 -0
- package/dist/alerts/index.cjs.js +2 -0
- package/dist/alerts/index.cjs.js.map +1 -0
- package/dist/alerts/index.d.ts +1 -0
- package/dist/alerts/index.js +2 -0
- package/dist/alerts/index.js.map +1 -0
- package/dist/dialogs/index.cjs.js +2 -0
- package/dist/dialogs/index.cjs.js.map +1 -0
- package/dist/dialogs/index.d.ts +1 -0
- package/dist/dialogs/index.js +2 -0
- package/dist/dialogs/index.js.map +1 -0
- package/dist/features/alerts/alert.d.ts +12 -0
- package/dist/features/alerts/alert.js +95 -0
- package/dist/features/alerts/index.d.ts +1 -0
- package/dist/features/alerts/index.js +1 -0
- package/dist/features/dialogs/index.d.ts +1 -0
- package/dist/features/dialogs/index.js +1 -0
- package/dist/features/dialogs/modal-provider.d.ts +3 -0
- package/dist/features/dialogs/modal-provider.js +6 -0
- package/dist/features/dialogs/tembo-confirm.d.ts +63 -0
- package/dist/features/dialogs/tembo-confirm.js +111 -0
- package/dist/features/input-validation/account-name-validator.d.ts +13 -0
- package/dist/features/input-validation/account-name-validator.js +28 -0
- package/dist/features/input-validation/account-number-validator.d.ts +13 -0
- package/dist/features/input-validation/account-number-validator.js +65 -0
- package/dist/{antd-validators.d.ts → features/input-validation/amount-validator.d.ts} +1 -62
- package/dist/features/input-validation/amount-validator.js +100 -0
- package/dist/features/input-validation/index.d.ts +5 -0
- package/dist/features/input-validation/index.js +5 -0
- package/dist/features/input-validation/phone-number-validator.d.ts +25 -0
- package/dist/features/input-validation/phone-number-validator.js +79 -0
- package/dist/features/input-validation/swift-code-validator.d.ts +13 -0
- package/dist/features/input-validation/swift-code-validator.js +38 -0
- package/dist/features/notifications/index.d.ts +3 -0
- package/dist/features/notifications/index.js +3 -0
- package/dist/features/notifications/tembo-notify.d.ts +50 -0
- package/dist/features/notifications/tembo-notify.js +140 -0
- package/dist/features/notifications/toast-config.d.ts +12 -0
- package/dist/features/notifications/toast-config.js +60 -0
- package/dist/features/notifications/toast-container.d.ts +19 -0
- package/dist/features/notifications/toast-container.js +89 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/notifications/index.cjs.js +2 -0
- package/dist/notifications/index.cjs.js.map +1 -0
- package/dist/notifications/index.d.ts +1 -0
- package/dist/notifications/index.js +2 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/providers.d.ts +37 -0
- package/dist/providers.js +32 -0
- package/dist/tembo-notify-Bp14qngd.js +2 -0
- package/dist/tembo-notify-Bp14qngd.js.map +1 -0
- package/dist/tembo-notify-h5Xn66oA.js +2 -0
- package/dist/tembo-notify-h5Xn66oA.js.map +1 -0
- package/dist/theme/colors.d.ts +278 -0
- package/dist/theme/colors.js +212 -0
- package/dist/theme/constants.d.ts +143 -0
- package/dist/theme/constants.js +82 -0
- package/dist/theme/index.cjs.js +2 -0
- package/dist/theme/index.cjs.js.map +1 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme-provider.d.ts +99 -0
- package/dist/theme/theme-provider.js +404 -0
- package/dist/theme-provider-Ca4P0Hcp.js +11 -0
- package/dist/theme-provider-Ca4P0Hcp.js.map +1 -0
- package/dist/theme-provider-RhAw3jw_.js +11 -0
- package/dist/theme-provider-RhAw3jw_.js.map +1 -0
- package/dist/validation/index.cjs.js +2 -0
- package/dist/validation/index.cjs.js.map +1 -0
- package/dist/validation/index.d.ts +1 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +31 -7
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Amount } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for monetary amounts using the Amount class.
|
|
4
|
+
* Validates format, currency, and range constraints with currency-specific defaults.
|
|
5
|
+
* Only allows positive amounts (including zero).
|
|
6
|
+
*
|
|
7
|
+
* **Default Range Constraints by Currency:**
|
|
8
|
+
* - **TZS (Tanzanian Shilling)**: Min: 1,000 TZS, Max: 1,000,000 TZS
|
|
9
|
+
* - **KES (Kenyan Shilling)**: Min: 40 KES, Max: 40,000,000 KES
|
|
10
|
+
* - **Other Currencies**: Min: 1, Max: 1,000,000 (in respective currency units)
|
|
11
|
+
*
|
|
12
|
+
* These defaults are applied only when `min` and/or `max` options are not explicitly provided.
|
|
13
|
+
* You can override these defaults by providing explicit `min` and `max` values in the options.
|
|
14
|
+
* Set `min` or `max` to `null` to completely disable that constraint.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Configuration options for amount validation
|
|
17
|
+
* @returns Validator function for AntD form rules
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Basic validation with TZS currency (uses default min: 1,000 TZS, max: 1,000,000 TZS)
|
|
21
|
+
* rules: [{ required: true, validator: AMOUNT_VALIDATOR() }]
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Basic validation with KES currency (uses default min: 40 KES, max: 40,000,000 KES)
|
|
25
|
+
* rules: [{ required: true, validator: AMOUNT_VALIDATOR({ currencyCode: 'KES' }) }]
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Override default ranges with custom min/max values
|
|
29
|
+
* rules: [{
|
|
30
|
+
* required: true,
|
|
31
|
+
* validator: AMOUNT_VALIDATOR({
|
|
32
|
+
* currencyCode: 'USD',
|
|
33
|
+
* min: 1, // Custom minimum (overrides default)
|
|
34
|
+
* max: 10000, // Custom maximum (overrides default)
|
|
35
|
+
* })
|
|
36
|
+
* }]
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Disable range validation by setting min and max to null
|
|
40
|
+
* rules: [{
|
|
41
|
+
* required: true,
|
|
42
|
+
* validator: AMOUNT_VALIDATOR({
|
|
43
|
+
* currencyCode: 'USD',
|
|
44
|
+
* min: null, // No minimum constraint
|
|
45
|
+
* max: null, // No maximum constraint
|
|
46
|
+
* })
|
|
47
|
+
* }]
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Disable only minimum constraint, keep maximum
|
|
51
|
+
* rules: [{
|
|
52
|
+
* required: true,
|
|
53
|
+
* validator: AMOUNT_VALIDATOR({
|
|
54
|
+
* currencyCode: 'TZS',
|
|
55
|
+
* min: null, // No minimum constraint
|
|
56
|
+
* // max uses default (1,000,000 TZS)
|
|
57
|
+
* })
|
|
58
|
+
* }]
|
|
59
|
+
*/
|
|
60
|
+
export const AMOUNT_VALIDATOR = (options = {}) => {
|
|
61
|
+
const { currencyCode = "TZS", invalidFormatMessage, minMessage, maxMessage, } = options;
|
|
62
|
+
const { min: defaultMin, max: defaultMax } = Amount.getTransactionLimits(currencyCode);
|
|
63
|
+
// Use provided values, or fall back to currency-specific defaults
|
|
64
|
+
// If explicitly set to null, no constraint will be applied
|
|
65
|
+
const min = options.min !== undefined ? options.min : defaultMin;
|
|
66
|
+
const max = options.max !== undefined ? options.max : defaultMax;
|
|
67
|
+
return (rule, value) => {
|
|
68
|
+
// Convert value to string for processing
|
|
69
|
+
const amountString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
70
|
+
// If field is empty/undefined/null
|
|
71
|
+
if (!amountString) {
|
|
72
|
+
if (rule.required) {
|
|
73
|
+
return Promise.reject(new Error("Amount is required."));
|
|
74
|
+
}
|
|
75
|
+
return Promise.resolve(undefined);
|
|
76
|
+
}
|
|
77
|
+
// Try to create Amount instance
|
|
78
|
+
const amountInstance = Amount.from(amountString, currencyCode);
|
|
79
|
+
if (!amountInstance) {
|
|
80
|
+
return Promise.reject(new Error(invalidFormatMessage ||
|
|
81
|
+
`Invalid amount format. Please enter a valid monetary amount (e.g., "1000", "1,234.56").`));
|
|
82
|
+
}
|
|
83
|
+
// Reject negative amounts (always not allowed)
|
|
84
|
+
if (amountInstance.isNegative()) {
|
|
85
|
+
return Promise.reject(new Error("Negative amounts are not allowed. Please enter a positive amount."));
|
|
86
|
+
}
|
|
87
|
+
// Check minimum constraint (only if min is not null)
|
|
88
|
+
if (min !== null && amountInstance.lessThan(min)) {
|
|
89
|
+
return Promise.reject(new Error(minMessage ||
|
|
90
|
+
`Amount must be at least ${(defaultMin === null || defaultMin === void 0 ? void 0 : defaultMin.label) || min}. Please enter a higher amount.`));
|
|
91
|
+
}
|
|
92
|
+
// Check maximum constraint (only if max is not null)
|
|
93
|
+
if (max !== null && amountInstance.greaterThan(max)) {
|
|
94
|
+
return Promise.reject(new Error(maxMessage ||
|
|
95
|
+
`Amount must not exceed ${(defaultMax === null || defaultMax === void 0 ? void 0 : defaultMax.label) || max}. Please enter a lower amount.`));
|
|
96
|
+
}
|
|
97
|
+
// Return the formatted numeric value (normalized)
|
|
98
|
+
return Promise.resolve(amountInstance.formattedNumericValue);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ISO2CountryCode } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for general phone numbers that validates format and country.
|
|
4
|
+
* Uses PhoneNumberFactory.canCreate() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export declare const PHONE_NUMBER_VALIDATOR: (countryCode?: ISO2CountryCode) => (rule: any, value: string | null | undefined) => Promise<string | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a validator for mobile phone numbers eligible for payout operations.
|
|
16
|
+
* Uses PhoneNumberFactory.checkPayoutEligibility() for validation.
|
|
17
|
+
*
|
|
18
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
19
|
+
* @returns Validator function for AntD form rules
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // In form rules
|
|
23
|
+
* rules: [{ required: true, validator: MOBILE_PHONE_VALIDATOR('TZ') }]
|
|
24
|
+
*/
|
|
25
|
+
export declare const MOBILE_PHONE_VALIDATOR: (countryCode?: ISO2CountryCode) => (rule: any, value: string | null | undefined) => Promise<string | undefined>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Country, PhoneNumberFactory } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for general phone numbers that validates format and country.
|
|
4
|
+
* Uses PhoneNumberFactory.canCreate() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export const PHONE_NUMBER_VALIDATOR = (countryCode) => {
|
|
14
|
+
return (rule, value) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const phoneString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
17
|
+
// If field is empty/undefined/null
|
|
18
|
+
if (!phoneString) {
|
|
19
|
+
if (rule.required) {
|
|
20
|
+
return Promise.reject(new Error("Phone number is required."));
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
const isValid = PhoneNumberFactory.canCreate(phoneString, {
|
|
25
|
+
defaultCountry: countryCode,
|
|
26
|
+
});
|
|
27
|
+
if (isValid) {
|
|
28
|
+
// Return normalized phone number
|
|
29
|
+
const phoneInstance = PhoneNumberFactory.create(phoneString, {
|
|
30
|
+
defaultCountry: countryCode,
|
|
31
|
+
});
|
|
32
|
+
return Promise.resolve((phoneInstance === null || phoneInstance === void 0 ? void 0 : phoneInstance.e164Format) || phoneString);
|
|
33
|
+
}
|
|
34
|
+
if (countryCode) {
|
|
35
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
36
|
+
return Promise.reject(new Error(`Invalid ${countryName} phone number format. Please enter a valid ${countryName} phone number.`));
|
|
37
|
+
}
|
|
38
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Creates a validator for mobile phone numbers eligible for payout operations.
|
|
43
|
+
* Uses PhoneNumberFactory.checkPayoutEligibility() for validation.
|
|
44
|
+
*
|
|
45
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
46
|
+
* @returns Validator function for AntD form rules
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // In form rules
|
|
50
|
+
* rules: [{ required: true, validator: MOBILE_PHONE_VALIDATOR('TZ') }]
|
|
51
|
+
*/
|
|
52
|
+
export const MOBILE_PHONE_VALIDATOR = (countryCode) => {
|
|
53
|
+
return (rule, value) => {
|
|
54
|
+
var _a;
|
|
55
|
+
const phoneString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
56
|
+
// If field is empty/undefined/null
|
|
57
|
+
if (!phoneString) {
|
|
58
|
+
if (rule.required) {
|
|
59
|
+
return Promise.reject(new Error("Mobile phone number is required."));
|
|
60
|
+
}
|
|
61
|
+
return Promise.resolve(undefined);
|
|
62
|
+
}
|
|
63
|
+
const phoneInstance = PhoneNumberFactory.create(phoneString, {
|
|
64
|
+
defaultCountry: countryCode,
|
|
65
|
+
});
|
|
66
|
+
if (!phoneInstance) {
|
|
67
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
68
|
+
}
|
|
69
|
+
const isEligibleForPayout = PhoneNumberFactory.checkPayoutEligibility(phoneInstance);
|
|
70
|
+
if (isEligibleForPayout) {
|
|
71
|
+
return Promise.resolve((phoneInstance === null || phoneInstance === void 0 ? void 0 : phoneInstance.e164Format) || phoneString);
|
|
72
|
+
}
|
|
73
|
+
if (countryCode) {
|
|
74
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
75
|
+
return Promise.reject(new Error(`Invalid ${countryName} phone number format. Please enter a valid ${countryName} phone number.`));
|
|
76
|
+
}
|
|
77
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
78
|
+
};
|
|
79
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ISO2CountryCode } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for SWIFT/BIC codes specific to a country.
|
|
4
|
+
* Uses BankValidation.validateSwiftCode() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: SWIFT_CODE_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export declare const SWIFT_CODE_VALIDATOR: (countryCode?: ISO2CountryCode) => (rule: any, value: string | null | undefined) => Promise<string | undefined>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BankValidation, Country } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for SWIFT/BIC codes specific to a country.
|
|
4
|
+
* Uses BankValidation.validateSwiftCode() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: SWIFT_CODE_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export const SWIFT_CODE_VALIDATOR = (countryCode) => {
|
|
14
|
+
return (rule, value) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const swiftCodeString = value === null || value === void 0 ? void 0 : value.toString().trim().toUpperCase();
|
|
17
|
+
// If field is empty/undefined/null
|
|
18
|
+
if (!swiftCodeString) {
|
|
19
|
+
if (rule.required) {
|
|
20
|
+
return Promise.reject(new Error("SWIFT code is required."));
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
if (countryCode) {
|
|
25
|
+
const isValid = BankValidation.validateSwiftCode(swiftCodeString, countryCode);
|
|
26
|
+
if (isValid) {
|
|
27
|
+
return Promise.resolve(swiftCodeString);
|
|
28
|
+
}
|
|
29
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
30
|
+
return Promise.reject(new Error(`Invalid ${countryName} SWIFT code. Please enter a valid ${countryName} bank SWIFT/BIC code.`));
|
|
31
|
+
}
|
|
32
|
+
const isValid = BankValidation.validateSwiftCodeForAnyCountry(swiftCodeString);
|
|
33
|
+
if (isValid) {
|
|
34
|
+
return Promise.resolve(swiftCodeString);
|
|
35
|
+
}
|
|
36
|
+
return Promise.reject(new Error(`Invalid SWIFT code. Please enter a valid supported bank SWIFT/BIC code.`));
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ToastOptions, ToastContent, Id } from 'react-toastify';
|
|
2
|
+
import { TemboColorPalette, TemboUIConstants } from '../../theme/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Message input - can be simple string or object with title and description
|
|
5
|
+
*/
|
|
6
|
+
export type NotifyMessage = ToastContent | {
|
|
7
|
+
title?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
};
|
|
10
|
+
export interface NotifyOptions extends Omit<ToastOptions, 'type'> {
|
|
11
|
+
toastId?: Id;
|
|
12
|
+
duration?: number | false;
|
|
13
|
+
onClick?: () => void;
|
|
14
|
+
onClose?: () => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* TemboNotify - Unified notification system
|
|
18
|
+
*/
|
|
19
|
+
export declare class TemboNotify {
|
|
20
|
+
private static configs;
|
|
21
|
+
static init(colors: TemboColorPalette, constants: TemboUIConstants): void;
|
|
22
|
+
private static getConfigs;
|
|
23
|
+
/**
|
|
24
|
+
* Format message content for display
|
|
25
|
+
* - title only → bold
|
|
26
|
+
* - description only → weight 500
|
|
27
|
+
* - title + description → stacked
|
|
28
|
+
*/
|
|
29
|
+
private static formatMessage;
|
|
30
|
+
private static buildOptions;
|
|
31
|
+
private static getSuccessConfig;
|
|
32
|
+
private static getErrorConfig;
|
|
33
|
+
private static getWarningConfig;
|
|
34
|
+
private static getInfoConfig;
|
|
35
|
+
private static getLoadingConfig;
|
|
36
|
+
static success(message: NotifyMessage, options?: NotifyOptions): Id;
|
|
37
|
+
static error(message: NotifyMessage, options?: NotifyOptions): Id;
|
|
38
|
+
static warning(message: NotifyMessage, options?: NotifyOptions): Id;
|
|
39
|
+
static info(message: NotifyMessage, options?: NotifyOptions): Id;
|
|
40
|
+
static loading(message: NotifyMessage, options?: Omit<NotifyOptions, 'duration'>): Id;
|
|
41
|
+
static update(id: Id, options: {
|
|
42
|
+
type?: 'success' | 'error' | 'warning' | 'info';
|
|
43
|
+
message?: NotifyMessage;
|
|
44
|
+
autoClose?: number | false;
|
|
45
|
+
render?: ToastContent;
|
|
46
|
+
}): void;
|
|
47
|
+
static dismiss(id?: Id): void;
|
|
48
|
+
static dismissAll(): void;
|
|
49
|
+
static isActive(id: Id): boolean;
|
|
50
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { toast } from 'react-toastify';
|
|
4
|
+
import { buildToastConfigs } from './toast-config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Simple fallback config when TemboNotify.init hasn't been called yet.
|
|
7
|
+
*/
|
|
8
|
+
const FALLBACK_BASE_CONFIG = {
|
|
9
|
+
position: 'top-right',
|
|
10
|
+
autoClose: 4000, // ~4 seconds for everything except loading
|
|
11
|
+
hideProgressBar: true,
|
|
12
|
+
closeOnClick: true,
|
|
13
|
+
pauseOnHover: true,
|
|
14
|
+
draggable: true,
|
|
15
|
+
closeButton: false,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* TemboNotify - Unified notification system
|
|
19
|
+
*/
|
|
20
|
+
export class TemboNotify {
|
|
21
|
+
static init(colors, constants) {
|
|
22
|
+
this.configs = buildToastConfigs(colors, constants);
|
|
23
|
+
}
|
|
24
|
+
static getConfigs() {
|
|
25
|
+
return this.configs;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Format message content for display
|
|
29
|
+
* - title only → bold
|
|
30
|
+
* - description only → weight 500
|
|
31
|
+
* - title + description → stacked
|
|
32
|
+
*/
|
|
33
|
+
static formatMessage(message) {
|
|
34
|
+
if (message && typeof message === 'object' && !('$$typeof' in message)) {
|
|
35
|
+
const hasTitle = !!message.title;
|
|
36
|
+
const hasDescription = !!message.description;
|
|
37
|
+
if (hasTitle && hasDescription) {
|
|
38
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx("div", { style: { fontWeight: 600, fontSize: 14 }, children: message.title }), _jsx("div", { style: { fontSize: 13, fontWeight: 400, opacity: 0.95 }, children: message.description })] }));
|
|
39
|
+
}
|
|
40
|
+
if (hasTitle && !hasDescription) {
|
|
41
|
+
return (_jsx("div", { style: { fontWeight: 600, fontSize: 14 }, children: message.title }));
|
|
42
|
+
}
|
|
43
|
+
if (!hasTitle && hasDescription) {
|
|
44
|
+
return (_jsx("div", { style: { fontSize: 13, fontWeight: 500 }, children: message.description }));
|
|
45
|
+
}
|
|
46
|
+
// Empty object case
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
return message;
|
|
50
|
+
}
|
|
51
|
+
static buildOptions(baseConfig, options) {
|
|
52
|
+
const _a = options || {}, { duration, toastId, onClick, onClose } = _a, restOptions = __rest(_a, ["duration", "toastId", "onClick", "onClose"]);
|
|
53
|
+
const effectiveBase = baseConfig !== null && baseConfig !== void 0 ? baseConfig : FALLBACK_BASE_CONFIG;
|
|
54
|
+
return Object.assign(Object.assign(Object.assign({}, effectiveBase), restOptions), { // includes custom icon if provided
|
|
55
|
+
toastId, autoClose: duration !== undefined
|
|
56
|
+
? duration || false
|
|
57
|
+
: effectiveBase.autoClose, onClick,
|
|
58
|
+
onClose });
|
|
59
|
+
}
|
|
60
|
+
static getSuccessConfig() {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
const configs = this.getConfigs();
|
|
63
|
+
return (_b = (_a = configs === null || configs === void 0 ? void 0 : configs.successConfig) !== null && _a !== void 0 ? _a : configs === null || configs === void 0 ? void 0 : configs.baseConfig) !== null && _b !== void 0 ? _b : undefined;
|
|
64
|
+
}
|
|
65
|
+
static getErrorConfig() {
|
|
66
|
+
var _a, _b;
|
|
67
|
+
const configs = this.getConfigs();
|
|
68
|
+
return (_b = (_a = configs === null || configs === void 0 ? void 0 : configs.errorConfig) !== null && _a !== void 0 ? _a : configs === null || configs === void 0 ? void 0 : configs.baseConfig) !== null && _b !== void 0 ? _b : undefined;
|
|
69
|
+
}
|
|
70
|
+
static getWarningConfig() {
|
|
71
|
+
var _a, _b;
|
|
72
|
+
const configs = this.getConfigs();
|
|
73
|
+
return (_b = (_a = configs === null || configs === void 0 ? void 0 : configs.warningConfig) !== null && _a !== void 0 ? _a : configs === null || configs === void 0 ? void 0 : configs.baseConfig) !== null && _b !== void 0 ? _b : undefined;
|
|
74
|
+
}
|
|
75
|
+
static getInfoConfig() {
|
|
76
|
+
var _a, _b;
|
|
77
|
+
const configs = this.getConfigs();
|
|
78
|
+
return (_b = (_a = configs === null || configs === void 0 ? void 0 : configs.infoConfig) !== null && _a !== void 0 ? _a : configs === null || configs === void 0 ? void 0 : configs.baseConfig) !== null && _b !== void 0 ? _b : undefined;
|
|
79
|
+
}
|
|
80
|
+
static getLoadingConfig() {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
const configs = this.getConfigs();
|
|
83
|
+
return (_b = (_a = configs === null || configs === void 0 ? void 0 : configs.loadingConfig) !== null && _a !== void 0 ? _a : configs === null || configs === void 0 ? void 0 : configs.baseConfig) !== null && _b !== void 0 ? _b : undefined;
|
|
84
|
+
}
|
|
85
|
+
static success(message, options) {
|
|
86
|
+
const content = this.formatMessage(message);
|
|
87
|
+
const toastOptions = this.buildOptions(this.getSuccessConfig(), options);
|
|
88
|
+
return toast.success(content, toastOptions);
|
|
89
|
+
}
|
|
90
|
+
static error(message, options) {
|
|
91
|
+
const content = this.formatMessage(message);
|
|
92
|
+
const toastOptions = this.buildOptions(this.getErrorConfig(), options);
|
|
93
|
+
return toast.error(content, toastOptions);
|
|
94
|
+
}
|
|
95
|
+
static warning(message, options) {
|
|
96
|
+
const content = this.formatMessage(message);
|
|
97
|
+
const toastOptions = this.buildOptions(this.getWarningConfig(), options);
|
|
98
|
+
return toast.warning(content, toastOptions);
|
|
99
|
+
}
|
|
100
|
+
static info(message, options) {
|
|
101
|
+
const content = this.formatMessage(message);
|
|
102
|
+
const toastOptions = this.buildOptions(this.getInfoConfig(), options);
|
|
103
|
+
return toast.info(content, toastOptions);
|
|
104
|
+
}
|
|
105
|
+
static loading(message, options) {
|
|
106
|
+
var _a;
|
|
107
|
+
const content = this.formatMessage(message);
|
|
108
|
+
const _b = options || {}, { toastId, onClick, onClose } = _b, restOptions = __rest(_b, ["toastId", "onClick", "onClose"]);
|
|
109
|
+
const baseConfig = (_a = this.getLoadingConfig()) !== null && _a !== void 0 ? _a : FALLBACK_BASE_CONFIG;
|
|
110
|
+
return toast.loading(content, Object.assign(Object.assign(Object.assign({}, baseConfig), restOptions), { toastId,
|
|
111
|
+
onClick,
|
|
112
|
+
onClose }));
|
|
113
|
+
}
|
|
114
|
+
static update(id, options) {
|
|
115
|
+
var _a, _b;
|
|
116
|
+
const configs = this.getConfigs();
|
|
117
|
+
const typeConfig = options.type && configs
|
|
118
|
+
? {
|
|
119
|
+
success: configs.successConfig,
|
|
120
|
+
error: configs.errorConfig,
|
|
121
|
+
warning: configs.warningConfig,
|
|
122
|
+
info: configs.infoConfig,
|
|
123
|
+
}[options.type]
|
|
124
|
+
: undefined;
|
|
125
|
+
const content = options.message
|
|
126
|
+
? this.formatMessage(options.message)
|
|
127
|
+
: options.render;
|
|
128
|
+
toast.update(id, Object.assign({ render: content, type: options.type, isLoading: false, autoClose: (_b = (_a = options.autoClose) !== null && _a !== void 0 ? _a : typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.autoClose) !== null && _b !== void 0 ? _b : FALLBACK_BASE_CONFIG.autoClose }, (typeConfig !== null && typeConfig !== void 0 ? typeConfig : {})));
|
|
129
|
+
}
|
|
130
|
+
static dismiss(id) {
|
|
131
|
+
toast.dismiss(id);
|
|
132
|
+
}
|
|
133
|
+
static dismissAll() {
|
|
134
|
+
toast.dismiss();
|
|
135
|
+
}
|
|
136
|
+
static isActive(id) {
|
|
137
|
+
return toast.isActive(id);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
TemboNotify.configs = null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToastOptions } from 'react-toastify';
|
|
2
|
+
import { TemboColorPalette, TemboUIConstants } from '../../theme/index.js';
|
|
3
|
+
export declare const buildToastConfigs: (colors: TemboColorPalette, constants: TemboUIConstants) => {
|
|
4
|
+
loadingConfig: ToastOptions<unknown>;
|
|
5
|
+
infoConfig: ToastOptions<unknown>;
|
|
6
|
+
warningConfig: ToastOptions<unknown>;
|
|
7
|
+
errorConfig: ToastOptions<unknown>;
|
|
8
|
+
successConfig: ToastOptions<unknown>;
|
|
9
|
+
baseConfig: ToastOptions<unknown>;
|
|
10
|
+
colors: TemboColorPalette;
|
|
11
|
+
};
|
|
12
|
+
export type ToastConfigs = ReturnType<typeof buildToastConfigs>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, InfoCircleOutlined, LoadingOutlined, } from '@ant-design/icons';
|
|
3
|
+
export const buildToastConfigs = (colors, constants) => {
|
|
4
|
+
/**
|
|
5
|
+
* Base = WHITE background for everything unless overridden
|
|
6
|
+
*/
|
|
7
|
+
const baseConfig = {
|
|
8
|
+
position: 'top-right',
|
|
9
|
+
autoClose: 4000,
|
|
10
|
+
hideProgressBar: true,
|
|
11
|
+
closeOnClick: true,
|
|
12
|
+
pauseOnHover: true,
|
|
13
|
+
draggable: true,
|
|
14
|
+
closeButton: false,
|
|
15
|
+
style: {
|
|
16
|
+
fontFamily: constants.typography.fontFamily,
|
|
17
|
+
fontSize: 14,
|
|
18
|
+
borderRadius: 10,
|
|
19
|
+
padding: '10px 14px',
|
|
20
|
+
boxShadow: '0 12px 24px rgba(15, 23, 42, 0.12)',
|
|
21
|
+
border: 'none',
|
|
22
|
+
minHeight: 56,
|
|
23
|
+
backgroundColor: colors.surface.elevated,
|
|
24
|
+
color: colors.text.primary,
|
|
25
|
+
display: 'flex',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
gap: 8,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* SUCCESS → success colors
|
|
32
|
+
*/
|
|
33
|
+
const successConfig = Object.assign(Object.assign({}, baseConfig), { icon: (_jsx(CheckCircleOutlined, { style: { fontSize: 18, color: colors.success.main } })), style: Object.assign(Object.assign({}, baseConfig.style), { backgroundColor: colors.success.bg, color: colors.success.text }), className: 'toast-success' });
|
|
34
|
+
/**
|
|
35
|
+
* ERROR → error colors
|
|
36
|
+
*/
|
|
37
|
+
const errorConfig = Object.assign(Object.assign({}, baseConfig), { icon: (_jsx(CloseCircleOutlined, { style: { fontSize: 18, color: colors.error.main } })), style: Object.assign(Object.assign({}, baseConfig.style), { backgroundColor: colors.error.bg, color: colors.error.text }), className: 'toast-error' });
|
|
38
|
+
/**
|
|
39
|
+
* WARNING → warning colors
|
|
40
|
+
*/
|
|
41
|
+
const warningConfig = Object.assign(Object.assign({}, baseConfig), { icon: (_jsx(ExclamationCircleOutlined, { style: { fontSize: 18, color: colors.warning.main } })), style: Object.assign(Object.assign({}, baseConfig.style), { backgroundColor: colors.warning.bg, color: colors.warning.text }), className: 'toast-warning' });
|
|
42
|
+
/**
|
|
43
|
+
* INFO → *white background*, blue accents only
|
|
44
|
+
* (no colored background)
|
|
45
|
+
*/
|
|
46
|
+
const infoConfig = Object.assign(Object.assign({}, baseConfig), { icon: (_jsx(InfoCircleOutlined, { style: { fontSize: 18, color: colors.info.main } })), style: Object.assign(Object.assign({}, baseConfig.style), { backgroundColor: colors.surface.elevated, color: colors.text.primary }), className: 'toast-info' });
|
|
47
|
+
/**
|
|
48
|
+
* LOADING (unchanged)
|
|
49
|
+
*/
|
|
50
|
+
const loadingConfig = Object.assign(Object.assign({}, baseConfig), { icon: (_jsx(LoadingOutlined, { style: { fontSize: 18, color: colors.primary.main } })), style: Object.assign(Object.assign({}, baseConfig.style), { backgroundColor: colors.surface.elevated, color: colors.text.primary }), autoClose: false, closeButton: false, hideProgressBar: true, className: 'toast-loading' });
|
|
51
|
+
return {
|
|
52
|
+
loadingConfig,
|
|
53
|
+
infoConfig,
|
|
54
|
+
warningConfig,
|
|
55
|
+
errorConfig,
|
|
56
|
+
successConfig,
|
|
57
|
+
baseConfig,
|
|
58
|
+
colors,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ToastContainerProps as RTToastContainerProps } from 'react-toastify';
|
|
3
|
+
export interface TemboToastContainerProps extends Omit<RTToastContainerProps, 'closeButton' | 'hideProgressBar'> {
|
|
4
|
+
/**
|
|
5
|
+
* Show the X close button on each toast
|
|
6
|
+
* @default false
|
|
7
|
+
*/
|
|
8
|
+
showCloseButton?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Show the progress bar at the bottom of each toast
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
showProgressBar?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Toast container with Tembo styling
|
|
17
|
+
*/
|
|
18
|
+
declare const TemboToastContainer: React.FC<TemboToastContainerProps>;
|
|
19
|
+
export default TemboToastContainer;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { ToastContainer, } from 'react-toastify';
|
|
5
|
+
import { useTemboTheme } from '../../theme/index.js';
|
|
6
|
+
import { TemboNotify } from './tembo-notify.js';
|
|
7
|
+
/**
|
|
8
|
+
* Toast container with Tembo styling
|
|
9
|
+
*/
|
|
10
|
+
const TemboToastContainer = (_a) => {
|
|
11
|
+
var { showCloseButton = false, showProgressBar = false } = _a, rest = __rest(_a, ["showCloseButton", "showProgressBar"]);
|
|
12
|
+
const { colors, constants } = useTemboTheme();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
TemboNotify.init(colors, constants);
|
|
15
|
+
}, [colors, constants]);
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx(ToastContainer, Object.assign({ closeButton: showCloseButton, hideProgressBar: !showProgressBar }, rest)), _jsx("style", { children: `
|
|
17
|
+
.Toastify__toast {
|
|
18
|
+
font-family: ${constants.typography.fontFamily};
|
|
19
|
+
line-height: 1.5;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center; /* center icon + content */
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.Toastify__toast-body {
|
|
25
|
+
padding: 0;
|
|
26
|
+
margin: 0;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: flex-start;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.Toastify__toast-icon {
|
|
32
|
+
width: 18px;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
margin-inline-end: 6px; /* tighter spacing */
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.Toastify__progress-bar {
|
|
40
|
+
display: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.Toastify__close-button {
|
|
44
|
+
opacity: 0.5;
|
|
45
|
+
transition: opacity 0.2s ease;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.Toastify__close-button:hover {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Force progress bar hidden in case someone enables it unintentionally */
|
|
53
|
+
.Toastify__progress-bar {
|
|
54
|
+
display: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Smooth entrance animation */
|
|
58
|
+
@keyframes toastSlideIn {
|
|
59
|
+
from {
|
|
60
|
+
transform: translateX(110%);
|
|
61
|
+
opacity: 0;
|
|
62
|
+
}
|
|
63
|
+
to {
|
|
64
|
+
transform: translateX(0);
|
|
65
|
+
opacity: 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.Toastify__toast--top-right {
|
|
70
|
+
animation: toastSlideIn 0.3s ease-out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Optional: full-width mobile behaviour */
|
|
74
|
+
@media (max-width: 480px) {
|
|
75
|
+
.Toastify__toast-container--top-right {
|
|
76
|
+
right: 0;
|
|
77
|
+
left: 0;
|
|
78
|
+
padding: 0;
|
|
79
|
+
width: 100vw;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.Toastify__toast {
|
|
83
|
+
margin-bottom: 0;
|
|
84
|
+
border-radius: 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
` })] }));
|
|
88
|
+
};
|
|
89
|
+
export default TemboToastContainer;
|