@ledgerhq/lumen-utils-shared 0.0.11
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 +32 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/create-safe-context/create-safe-context.d.ts +9 -0
- package/dist/lib/create-safe-context/create-safe-context.d.ts.map +1 -0
- package/dist/lib/create-safe-context/index.d.ts +2 -0
- package/dist/lib/create-safe-context/index.d.ts.map +1 -0
- package/dist/lib/get-object-path/get-object-path.d.ts +18 -0
- package/dist/lib/get-object-path/get-object-path.d.ts.map +1 -0
- package/dist/lib/get-object-path/index.d.ts +2 -0
- package/dist/lib/get-object-path/index.d.ts.map +1 -0
- package/dist/lib/input-formatter/font-size-formatter.d.ts +6 -0
- package/dist/lib/input-formatter/font-size-formatter.d.ts.map +1 -0
- package/dist/lib/input-formatter/format-thousands.d.ts +18 -0
- package/dist/lib/input-formatter/format-thousands.d.ts.map +1 -0
- package/dist/lib/input-formatter/index.d.ts +4 -0
- package/dist/lib/input-formatter/index.d.ts.map +1 -0
- package/dist/lib/input-formatter/text-formatter.d.ts +31 -0
- package/dist/lib/input-formatter/text-formatter.d.ts.map +1 -0
- package/dist/lib/is-text-children/index.d.ts +2 -0
- package/dist/lib/is-text-children/index.d.ts.map +1 -0
- package/dist/lib/is-text-children/is-text-children.d.ts +3 -0
- package/dist/lib/is-text-children/is-text-children.d.ts.map +1 -0
- package/dist/lib/string-utils/index.d.ts +2 -0
- package/dist/lib/string-utils/index.d.ts.map +1 -0
- package/dist/lib/string-utils/string-utils.d.ts +6 -0
- package/dist/lib/string-utils/string-utils.d.ts.map +1 -0
- package/dist/lib/use-merge-ref/index.d.ts +2 -0
- package/dist/lib/use-merge-ref/index.d.ts.map +1 -0
- package/dist/lib/use-merge-ref/use-merge-ref.d.ts +8 -0
- package/dist/lib/use-merge-ref/use-merge-ref.d.ts.map +1 -0
- package/eslint.config.mjs +22 -0
- package/package.json +28 -0
- package/project.json +7 -0
- package/src/index.ts +7 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/create-safe-context/create-safe-context.test.tsx +69 -0
- package/src/lib/create-safe-context/create-safe-context.tsx +46 -0
- package/src/lib/create-safe-context/index.ts +1 -0
- package/src/lib/get-object-path/get-object-path.test.ts +72 -0
- package/src/lib/get-object-path/get-object-path.ts +31 -0
- package/src/lib/get-object-path/index.ts +1 -0
- package/src/lib/input-formatter/font-size-formatter.ts +16 -0
- package/src/lib/input-formatter/format-thousands.test.ts +36 -0
- package/src/lib/input-formatter/format-thousands.ts +34 -0
- package/src/lib/input-formatter/index.ts +3 -0
- package/src/lib/input-formatter/text-formatter.test.ts +503 -0
- package/src/lib/input-formatter/text-formatter.ts +95 -0
- package/src/lib/is-text-children/index.ts +1 -0
- package/src/lib/is-text-children/is-text-children.test.ts +33 -0
- package/src/lib/is-text-children/is-text-children.ts +9 -0
- package/src/lib/string-utils/index.ts +1 -0
- package/src/lib/string-utils/string-utils.test.ts +85 -0
- package/src/lib/string-utils/string-utils.ts +11 -0
- package/src/lib/use-merge-ref/index.ts +1 -0
- package/src/lib/use-merge-ref/use-merge-ref.ts +41 -0
- package/tsconfig.json +13 -0
- package/tsconfig.lib.json +29 -0
- package/tsconfig.spec.json +37 -0
- package/vite.config.ts +40 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { formatThousands } from './format-thousands';
|
|
2
|
+
|
|
3
|
+
export type TextFormatterOptions = {
|
|
4
|
+
/** Whether to allow decimal values */
|
|
5
|
+
allowDecimals?: boolean;
|
|
6
|
+
/** Whether to format with space-separated thousands */
|
|
7
|
+
thousandsSeparator?: boolean;
|
|
8
|
+
/** Maximum length for integer part (before decimal) */
|
|
9
|
+
maxIntegerLength?: number;
|
|
10
|
+
/** Maximum length for decimal part (after decimal) */
|
|
11
|
+
maxDecimalLength?: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Formats and validates numeric input text for amount inputs.
|
|
16
|
+
* Handles decimal formatting, leading zeros, and prevents multiple decimal points.
|
|
17
|
+
* Can optionally format with space-separated thousands.
|
|
18
|
+
* @returns Formatted and cleaned numeric string
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* textFormatter('01') // '1'
|
|
22
|
+
* textFormatter('.5') // '0.5'
|
|
23
|
+
* textFormatter('1.2.3') // '1.23'
|
|
24
|
+
* textFormatter('1,5') // '1.5'
|
|
25
|
+
* textFormatter('abc123') // '123'
|
|
26
|
+
* textFormatter('1000000', { thousandsSeparator: true }) // '1 000 000'
|
|
27
|
+
* textFormatter('1234.5678', { thousandsSeparator: true }) // '1 234.5678'
|
|
28
|
+
* textFormatter('123456789012', { maxIntegerLength: 9 }) // '123456789'
|
|
29
|
+
* textFormatter('123.123456', { maxDecimalLength: 2 }) // '123.12'
|
|
30
|
+
*/
|
|
31
|
+
export function textFormatter(
|
|
32
|
+
/** The input value to format */
|
|
33
|
+
value: string,
|
|
34
|
+
options: TextFormatterOptions = {},
|
|
35
|
+
): string {
|
|
36
|
+
const {
|
|
37
|
+
allowDecimals = true,
|
|
38
|
+
thousandsSeparator = true,
|
|
39
|
+
maxIntegerLength = 9,
|
|
40
|
+
maxDecimalLength = 9,
|
|
41
|
+
} = options;
|
|
42
|
+
// Normalize input: convert comma to dot, remove non-digit/non-dot characters
|
|
43
|
+
const normalizedValue = value.replace(',', '.').replace(/[^\d.]/g, '');
|
|
44
|
+
let cleaned = normalizedValue;
|
|
45
|
+
|
|
46
|
+
// Remove leading zeros (except when followed by dot)
|
|
47
|
+
cleaned = cleaned.replace(/^0+(?=\d)/, '');
|
|
48
|
+
|
|
49
|
+
if (!allowDecimals) {
|
|
50
|
+
// Integer-only: remove any non-digit and apply max length
|
|
51
|
+
cleaned = cleaned.replace(/\D/g, '');
|
|
52
|
+
if (maxIntegerLength > 0 && cleaned.length > maxIntegerLength) {
|
|
53
|
+
cleaned = cleaned.slice(0, maxIntegerLength);
|
|
54
|
+
}
|
|
55
|
+
return thousandsSeparator ? formatThousands(cleaned) : cleaned;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Handle single dot input as "0."
|
|
59
|
+
if (cleaned === '.') {
|
|
60
|
+
cleaned = '0.';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const firstDot = cleaned.indexOf('.');
|
|
64
|
+
if (firstDot !== -1) {
|
|
65
|
+
// Split integer and decimal parts
|
|
66
|
+
let integerPart = cleaned.slice(0, firstDot);
|
|
67
|
+
let decimalPart = cleaned.slice(firstDot + 1).replace(/\./g, '');
|
|
68
|
+
|
|
69
|
+
// Apply length limits
|
|
70
|
+
if (maxIntegerLength > 0 && integerPart.length > maxIntegerLength) {
|
|
71
|
+
integerPart = integerPart.slice(0, maxIntegerLength);
|
|
72
|
+
}
|
|
73
|
+
decimalPart = decimalPart.slice(0, maxDecimalLength);
|
|
74
|
+
|
|
75
|
+
// Ensure integer part is not empty
|
|
76
|
+
if (integerPart === '') integerPart = '0';
|
|
77
|
+
|
|
78
|
+
// Preserve trailing dot if user is typing
|
|
79
|
+
const hasTrailingDot =
|
|
80
|
+
normalizedValue.endsWith('.') || cleaned.endsWith('.');
|
|
81
|
+
cleaned =
|
|
82
|
+
decimalPart.length > 0
|
|
83
|
+
? `${integerPart}.${decimalPart}`
|
|
84
|
+
: hasTrailingDot
|
|
85
|
+
? `${integerPart}.`
|
|
86
|
+
: integerPart;
|
|
87
|
+
} else {
|
|
88
|
+
// No decimal point, just apply integer length limit
|
|
89
|
+
if (maxIntegerLength > 0 && cleaned.length > maxIntegerLength) {
|
|
90
|
+
cleaned = cleaned.slice(0, maxIntegerLength);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return thousandsSeparator ? formatThousands(cleaned) : cleaned;
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './is-text-children';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { isTextChildren } from './is-text-children';
|
|
4
|
+
|
|
5
|
+
describe('isAllowedTextChildren', () => {
|
|
6
|
+
type Case = { name: string; input: unknown; expected: boolean };
|
|
7
|
+
|
|
8
|
+
const cases: Case[] = [
|
|
9
|
+
{ name: 'string', input: 'hello', expected: true },
|
|
10
|
+
{ name: 'empty string', input: '', expected: true },
|
|
11
|
+
{ name: 'number', input: 42, expected: true },
|
|
12
|
+
{ name: 'zero', input: 0, expected: true },
|
|
13
|
+
{ name: 'NaN', input: Number.NaN, expected: true },
|
|
14
|
+
{ name: 'array of strings', input: ['a', 'b'], expected: true },
|
|
15
|
+
{
|
|
16
|
+
name: 'React element',
|
|
17
|
+
input: React.createElement('View', null),
|
|
18
|
+
expected: false,
|
|
19
|
+
},
|
|
20
|
+
{ name: 'null', input: null, expected: false },
|
|
21
|
+
{ name: 'undefined', input: undefined, expected: false },
|
|
22
|
+
{ name: 'array of object and string', input: [{}, 'b'], expected: false },
|
|
23
|
+
{ name: 'boolean true', input: true, expected: false },
|
|
24
|
+
{ name: 'boolean false', input: false, expected: false },
|
|
25
|
+
{ name: 'object', input: { a: 1 }, expected: false },
|
|
26
|
+
{ name: 'function', input: () => 'x', expected: false },
|
|
27
|
+
{ name: 'symbol', input: Symbol('s'), expected: false },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
it.each(cases)('$name', ({ input, expected }) => {
|
|
31
|
+
expect(isTextChildren(input as ReactNode)).toBe(expected);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
const isStringOrNumber = (element: ReactNode) =>
|
|
4
|
+
typeof element === 'string' || typeof element === 'number';
|
|
5
|
+
|
|
6
|
+
export const isTextChildren = (element: ReactNode) => {
|
|
7
|
+
const isArray = Array.isArray(element);
|
|
8
|
+
return isArray ? element.every(isStringOrNumber) : isStringOrNumber(element);
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './string-utils';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { toPascalCase } from './string-utils.js';
|
|
3
|
+
|
|
4
|
+
describe('toPascalCase', () => {
|
|
5
|
+
it('should convert kebab-case to PascalCase', () => {
|
|
6
|
+
expect(toPascalCase('arrow-up')).toBe('ArrowUp');
|
|
7
|
+
expect(toPascalCase('chevron-down')).toBe('ChevronDown');
|
|
8
|
+
expect(toPascalCase('external-link')).toBe('ExternalLink');
|
|
9
|
+
expect(toPascalCase('settings-alt-2')).toBe('SettingsAlt2');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should convert snake_case to PascalCase', () => {
|
|
13
|
+
expect(toPascalCase('arrow_up')).toBe('ArrowUp');
|
|
14
|
+
expect(toPascalCase('chevron_down')).toBe('ChevronDown');
|
|
15
|
+
expect(toPascalCase('external_link')).toBe('ExternalLink');
|
|
16
|
+
expect(toPascalCase('settings_alt_2')).toBe('SettingsAlt2');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should convert space-separated words to PascalCase', () => {
|
|
20
|
+
expect(toPascalCase('arrow up')).toBe('ArrowUp');
|
|
21
|
+
expect(toPascalCase('chevron down')).toBe('ChevronDown');
|
|
22
|
+
expect(toPascalCase('external link')).toBe('ExternalLink');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should handle mixed separators', () => {
|
|
26
|
+
expect(toPascalCase('arrow-up_down')).toBe('ArrowUpDown');
|
|
27
|
+
expect(toPascalCase('external_link-icon')).toBe('ExternalLinkIcon');
|
|
28
|
+
expect(toPascalCase('settings alt-2_variant')).toBe('SettingsAlt2Variant');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should handle single words', () => {
|
|
32
|
+
expect(toPascalCase('arrow')).toBe('Arrow');
|
|
33
|
+
expect(toPascalCase('icon')).toBe('Icon');
|
|
34
|
+
expect(toPascalCase('button')).toBe('Button');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle already PascalCase strings', () => {
|
|
38
|
+
expect(toPascalCase('ArrowUp')).toBe('Arrowup');
|
|
39
|
+
expect(toPascalCase('ExternalLink')).toBe('Externallink');
|
|
40
|
+
// Note: This behavior converts already PascalCase to lowercase except first letter
|
|
41
|
+
// because it treats the whole string as one word without separators
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle empty string', () => {
|
|
45
|
+
expect(toPascalCase('')).toBe('');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle strings with numbers', () => {
|
|
49
|
+
expect(toPascalCase('icon-24')).toBe('Icon24');
|
|
50
|
+
expect(toPascalCase('chart_1')).toBe('Chart1');
|
|
51
|
+
expect(toPascalCase('version 2')).toBe('Version2');
|
|
52
|
+
expect(toPascalCase('api-v1-endpoint')).toBe('ApiV1Endpoint');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle multiple consecutive separators', () => {
|
|
56
|
+
expect(toPascalCase('arrow--up')).toBe('ArrowUp');
|
|
57
|
+
expect(toPascalCase('external__link')).toBe('ExternalLink');
|
|
58
|
+
expect(toPascalCase('icon button')).toBe('IconButton');
|
|
59
|
+
expect(toPascalCase('mixed-_-separators')).toBe('MixedSeparators');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle separators at the beginning and end', () => {
|
|
63
|
+
expect(toPascalCase('-arrow-up')).toBe('ArrowUp');
|
|
64
|
+
expect(toPascalCase('_external-link_')).toBe('ExternalLink');
|
|
65
|
+
expect(toPascalCase(' icon button ')).toBe('IconButton');
|
|
66
|
+
expect(toPascalCase('--start-end--')).toBe('StartEnd');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should handle strings with special characters mixed with separators', () => {
|
|
70
|
+
expect(toPascalCase('icon-24px')).toBe('Icon24px');
|
|
71
|
+
expect(toPascalCase('api_v2.0')).toBe('ApiV2.0');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should handle case variations in input', () => {
|
|
75
|
+
expect(toPascalCase('ARROW-UP')).toBe('ArrowUp');
|
|
76
|
+
expect(toPascalCase('ExTerNaL-LiNk')).toBe('ExternalLink');
|
|
77
|
+
expect(toPascalCase('mixed_CASE_string')).toBe('MixedCaseString');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should handle single character segments', () => {
|
|
81
|
+
expect(toPascalCase('a-b-c')).toBe('ABC');
|
|
82
|
+
expect(toPascalCase('x_y_z')).toBe('XYZ');
|
|
83
|
+
expect(toPascalCase('i o s')).toBe('IOS');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transforms a kebab-case or snake_case string into a PascalCase string.
|
|
3
|
+
* e.g., 'arrow-up' -> 'ArrowUp'
|
|
4
|
+
*/
|
|
5
|
+
export function toPascalCase(str: string): string {
|
|
6
|
+
if (!str) return '';
|
|
7
|
+
return str
|
|
8
|
+
.split(/[-_ ]+/)
|
|
9
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
10
|
+
.join('');
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './use-merge-ref';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Ref, useMemo, type RefCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
type PossibleRef<T> = Ref<T> | undefined;
|
|
4
|
+
type RefCleanup = void | (() => void);
|
|
5
|
+
|
|
6
|
+
export function assignRef<T>(ref: PossibleRef<T>, value: T | null): RefCleanup {
|
|
7
|
+
if (typeof ref === 'function') {
|
|
8
|
+
return ref(value);
|
|
9
|
+
} else if (typeof ref === 'object' && ref !== null && 'current' in ref) {
|
|
10
|
+
(ref as { current: T | null }).current = value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function mergeRefs<T>(...refs: PossibleRef<T>[]): RefCallback<T> {
|
|
15
|
+
const cleanupMap = new Map<PossibleRef<T>, () => void>();
|
|
16
|
+
|
|
17
|
+
return (node: T | null) => {
|
|
18
|
+
if (node === null) {
|
|
19
|
+
refs.forEach((ref) => {
|
|
20
|
+
const cleanup = cleanupMap.get(ref);
|
|
21
|
+
if (typeof cleanup === 'function') {
|
|
22
|
+
cleanup();
|
|
23
|
+
}
|
|
24
|
+
assignRef(ref, null);
|
|
25
|
+
});
|
|
26
|
+
cleanupMap.clear();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
refs.forEach((ref) => {
|
|
31
|
+
const cleanup = assignRef(ref, node);
|
|
32
|
+
if (typeof cleanup === 'function') {
|
|
33
|
+
cleanupMap.set(ref, cleanup);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function useMergedRef<T>(...refs: PossibleRef<T>[]): RefCallback<T> {
|
|
40
|
+
return useMemo(() => mergeRefs<T>(...refs), refs);
|
|
41
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
8
|
+
"emitDeclarationOnly": false,
|
|
9
|
+
"jsx": "react-jsx",
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"types": ["node"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
14
|
+
"references": [],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"vite.config.ts",
|
|
17
|
+
"vite.config.mts",
|
|
18
|
+
"vitest.config.ts",
|
|
19
|
+
"vitest.config.mts",
|
|
20
|
+
"src/**/*.test.ts",
|
|
21
|
+
"src/**/*.spec.ts",
|
|
22
|
+
"src/**/*.test.tsx",
|
|
23
|
+
"src/**/*.spec.tsx",
|
|
24
|
+
"src/**/*.test.js",
|
|
25
|
+
"src/**/*.spec.js",
|
|
26
|
+
"src/**/*.test.jsx",
|
|
27
|
+
"src/**/*.spec.jsx"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./out-tsc/vitest",
|
|
5
|
+
"types": [
|
|
6
|
+
"vitest/globals",
|
|
7
|
+
"vitest/importMeta",
|
|
8
|
+
"vite/client",
|
|
9
|
+
"node",
|
|
10
|
+
"vitest"
|
|
11
|
+
],
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"module": "esnext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"forceConsistentCasingInFileNames": true
|
|
16
|
+
},
|
|
17
|
+
"include": [
|
|
18
|
+
"vite.config.ts",
|
|
19
|
+
"vite.config.mts",
|
|
20
|
+
"vitest.config.ts",
|
|
21
|
+
"vitest.config.mts",
|
|
22
|
+
"src/**/*.test.ts",
|
|
23
|
+
"src/**/*.spec.ts",
|
|
24
|
+
"src/**/*.test.tsx",
|
|
25
|
+
"src/**/*.spec.tsx",
|
|
26
|
+
"src/**/*.test.js",
|
|
27
|
+
"src/**/*.spec.js",
|
|
28
|
+
"src/**/*.test.jsx",
|
|
29
|
+
"src/**/*.spec.jsx",
|
|
30
|
+
"src/**/*.d.ts"
|
|
31
|
+
],
|
|
32
|
+
"references": [
|
|
33
|
+
{
|
|
34
|
+
"path": "./tsconfig.lib.json"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
import type { LibraryFormats } from 'vite';
|
|
5
|
+
import dts from 'vite-plugin-dts';
|
|
6
|
+
|
|
7
|
+
export default defineConfig(() => ({
|
|
8
|
+
root: __dirname,
|
|
9
|
+
cacheDir: '../../node_modules/.vite/libs/utils-shared',
|
|
10
|
+
plugins: [
|
|
11
|
+
react(),
|
|
12
|
+
dts({
|
|
13
|
+
entryRoot: 'src',
|
|
14
|
+
tsconfigPath: join(__dirname, 'tsconfig.lib.json'),
|
|
15
|
+
}),
|
|
16
|
+
],
|
|
17
|
+
build: {
|
|
18
|
+
lib: {
|
|
19
|
+
entry: join(__dirname, 'src/index.ts'),
|
|
20
|
+
name: 'utils-shared',
|
|
21
|
+
fileName: 'index',
|
|
22
|
+
formats: ['es' as LibraryFormats],
|
|
23
|
+
},
|
|
24
|
+
rollupOptions: {
|
|
25
|
+
external: ['clsx', 'tailwind-merge', 'react', 'react/jsx-runtime'],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
test: {
|
|
29
|
+
watch: false,
|
|
30
|
+
globals: true,
|
|
31
|
+
silent: true,
|
|
32
|
+
environment: 'jsdom',
|
|
33
|
+
include: ['src/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
34
|
+
reporters: ['default'],
|
|
35
|
+
coverage: {
|
|
36
|
+
reportsDirectory: './test-output/vitest/coverage',
|
|
37
|
+
provider: 'v8' as const,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
}));
|