nestable-tailwind-variants 0.1.4 → 0.2.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.
@@ -0,0 +1,6 @@
1
+ import { extendTailwindMerge } from 'tailwind-merge';
2
+ import type { TwMergeConfig } from './types.js';
3
+ type TwMergeFn = ReturnType<typeof extendTailwindMerge>;
4
+ export declare function getCachedTwMerge(config: TwMergeConfig): TwMergeFn;
5
+ export {};
6
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAIxD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAOjE"}
package/dist/cache.js ADDED
@@ -0,0 +1,11 @@
1
+ import { extendTailwindMerge } from 'tailwind-merge';
2
+ const cache = new Map();
3
+ export function getCachedTwMerge(config) {
4
+ let cached = cache.get(config);
5
+ if (!cached) {
6
+ cached = extendTailwindMerge(config);
7
+ cache.set(config, cached);
8
+ }
9
+ return cached;
10
+ }
11
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAKrD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;AAElD,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { composeNtv, createComposeNtv } from './composeNtv.js';
2
- export { createNTV, ntv } from './ntv.js';
3
- export type { NTVConfig, TWMergeConfig } from './types.js';
1
+ export { createMergeNtv, mergeNtv, mergeNtvWithOptions } from './merge.js';
2
+ export { createNtv, ntv } from './ntv.js';
3
+ export type { ClassProp, ClassValue, MergeStyleFunctionProps, NtvOptions, NtvProps, NtvScheme, SchemeFor, StyleFunction, TwMergeConfig, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EACV,SAAS,EACT,UAAU,EACV,uBAAuB,EACvB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { composeNtv, createComposeNtv } from './composeNtv.js';
2
- export { createNTV, ntv } from './ntv.js';
1
+ export { createMergeNtv, mergeNtv, mergeNtvWithOptions } from './merge.js';
2
+ export { createNtv, ntv } from './ntv.js';
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { MergeStyleFunctionProps, NtvOptions, StyleFunction } from './types.js';
2
+ /**
3
+ * Create a merged style function with custom options (curried version).
4
+ *
5
+ * @param styleFns - Style functions to merge
6
+ * @returns A function that accepts options and returns a merged style function
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const styles = mergeNtvWithOptions(baseStyles, overrideStyles)({ twMerge: false });
11
+ * styles({ variant: 'primary' });
12
+ * ```
13
+ */
14
+ export declare function mergeNtvWithOptions<T extends readonly StyleFunction<any>[]>(...styleFns: T): (options?: NtvOptions) => StyleFunction<MergeStyleFunctionProps<T>>;
15
+ /**
16
+ * Merge multiple style functions into a single style function.
17
+ * Later functions take precedence over earlier ones (via tailwind-merge).
18
+ *
19
+ * @param styleFns - Style functions to merge
20
+ * @returns A merged style function that accepts combined props from all input functions
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const colorStyles = ntv<{ color: 'red' | 'blue' }>({
25
+ * color: { red: 'text-red', blue: 'text-blue' },
26
+ * });
27
+ *
28
+ * const sizeStyles = ntv<{ size: 'sm' | 'lg' }>({
29
+ * size: { sm: 'text-sm', lg: 'text-lg' },
30
+ * });
31
+ *
32
+ * const styles = mergeNtv(colorStyles, sizeStyles);
33
+ * styles({ color: 'red', size: 'lg' }); // 'text-red text-lg'
34
+ * ```
35
+ */
36
+ export declare function mergeNtv<T extends readonly StyleFunction<any>[]>(...styleFns: T): StyleFunction<MergeStyleFunctionProps<T>>;
37
+ /**
38
+ * Create a pre-configured mergeNtv function with fixed options.
39
+ *
40
+ * @param defaultOptions - Default options to apply to all mergeNtv calls
41
+ * @returns A pre-configured mergeNtv function
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const myMergeNtv = createMergeNtv({
46
+ * twMergeConfig: {
47
+ * extend: {
48
+ * classGroups: {
49
+ * 'font-size': [{ text: ['huge', 'tiny'] }],
50
+ * },
51
+ * },
52
+ * },
53
+ * });
54
+ *
55
+ * const styles = myMergeNtv(baseStyles, overrideStyles);
56
+ * ```
57
+ */
58
+ export declare function createMergeNtv(defaultOptions: NtvOptions): <T extends readonly StyleFunction<any>[]>(...styleFns: T) => StyleFunction<MergeStyleFunctionProps<[...T]>>;
59
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,uBAAuB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhG;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EACzE,GAAG,QAAQ,EAAE,CAAC,GACb,CAAC,OAAO,CAAC,EAAE,UAAU,KAAK,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAoBrE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EAC9D,GAAG,QAAQ,EAAE,CAAC,GACb,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAE3C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,UAAU,IACpB,CAAC,SAAS,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,UAAU,CAAC,oDAG3F"}
package/dist/merge.js ADDED
@@ -0,0 +1,78 @@
1
+ import { twJoin, twMerge } from 'tailwind-merge';
2
+ import { getCachedTwMerge } from './cache.js';
3
+ /**
4
+ * Create a merged style function with custom options (curried version).
5
+ *
6
+ * @param styleFns - Style functions to merge
7
+ * @returns A function that accepts options and returns a merged style function
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const styles = mergeNtvWithOptions(baseStyles, overrideStyles)({ twMerge: false });
12
+ * styles({ variant: 'primary' });
13
+ * ```
14
+ */
15
+ export function mergeNtvWithOptions(...styleFns) {
16
+ return function createMergedStyleFn({ twMerge: usesTwMerge = true, twMergeConfig, } = {}) {
17
+ const mergeFn = usesTwMerge
18
+ ? twMergeConfig
19
+ ? getCachedTwMerge(twMergeConfig)
20
+ : twMerge
21
+ : twJoin;
22
+ return function mergedStyleFn({ class: slotClass, className: slotClassName, ...props } = {}) {
23
+ const styleResults = styleFns.map((fn) => fn(props));
24
+ return mergeFn(...styleResults, slotClass, slotClassName);
25
+ };
26
+ };
27
+ }
28
+ /**
29
+ * Merge multiple style functions into a single style function.
30
+ * Later functions take precedence over earlier ones (via tailwind-merge).
31
+ *
32
+ * @param styleFns - Style functions to merge
33
+ * @returns A merged style function that accepts combined props from all input functions
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const colorStyles = ntv<{ color: 'red' | 'blue' }>({
38
+ * color: { red: 'text-red', blue: 'text-blue' },
39
+ * });
40
+ *
41
+ * const sizeStyles = ntv<{ size: 'sm' | 'lg' }>({
42
+ * size: { sm: 'text-sm', lg: 'text-lg' },
43
+ * });
44
+ *
45
+ * const styles = mergeNtv(colorStyles, sizeStyles);
46
+ * styles({ color: 'red', size: 'lg' }); // 'text-red text-lg'
47
+ * ```
48
+ */
49
+ export function mergeNtv(...styleFns) {
50
+ return mergeNtvWithOptions(...styleFns)();
51
+ }
52
+ /**
53
+ * Create a pre-configured mergeNtv function with fixed options.
54
+ *
55
+ * @param defaultOptions - Default options to apply to all mergeNtv calls
56
+ * @returns A pre-configured mergeNtv function
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const myMergeNtv = createMergeNtv({
61
+ * twMergeConfig: {
62
+ * extend: {
63
+ * classGroups: {
64
+ * 'font-size': [{ text: ['huge', 'tiny'] }],
65
+ * },
66
+ * },
67
+ * },
68
+ * });
69
+ *
70
+ * const styles = myMergeNtv(baseStyles, overrideStyles);
71
+ * ```
72
+ */
73
+ export function createMergeNtv(defaultOptions) {
74
+ return function configuredMergeNtv(...styleFns) {
75
+ return mergeNtvWithOptions(...styleFns)(defaultOptions);
76
+ };
77
+ }
78
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAG,QAAW;IAEd,OAAO,SAAS,mBAAmB,CAAC,EAClC,OAAO,EAAE,WAAW,GAAG,IAAI,EAC3B,aAAa,MACC,EAAE;QAChB,MAAM,OAAO,GAAG,WAAW;YACzB,CAAC,CAAC,aAAa;gBACb,CAAC,CAAC,gBAAgB,CAAC,aAAa,CAAC;gBACjC,CAAC,CAAC,OAAO;YACX,CAAC,CAAC,MAAM,CAAC;QAEX,OAAO,SAAS,aAAa,CAAC,EAC5B,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,aAAa,EACxB,GAAG,KAAK,KAC+B,EAAE;YACzC,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,OAAO,OAAO,CAAC,GAAG,YAAY,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QAC5D,CAA8C,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,QAAQ,CACtB,GAAG,QAAW;IAEd,OAAO,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,cAAc,CAAC,cAA0B;IACvD,OAAO,SAAS,kBAAkB,CAA0C,GAAG,QAAW;QACxF,OAAO,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC;IAC1D,CAAC,CAAC;AACJ,CAAC"}
package/dist/ntv.d.ts CHANGED
@@ -1,61 +1,59 @@
1
- import type { NTVConfig, StyleFunction } from './types.js';
2
- type BooleanConditionKey = `is${Capitalize<string>}` | `allows${Capitalize<string>}`;
3
- type ExtractBooleanKeys<Props> = {
4
- [K in keyof Props]: K extends BooleanConditionKey ? K : never;
5
- }[keyof Props];
6
- type ExtractVariantKeys<Props> = Exclude<keyof Props, ExtractBooleanKeys<Props>>;
7
- type NestedStyleValue<Props> = string | StyleDefinition<Props>;
8
- type StyleDefinition<Props> = {
9
- default?: string;
10
- } & {
11
- [K in ExtractBooleanKeys<Props>]?: NestedStyleValue<Props>;
12
- } & {
13
- [K in ExtractVariantKeys<Props>]?: {
14
- [V in Extract<Props[K], string>]?: NestedStyleValue<Props>;
15
- };
16
- };
1
+ import type { NtvOptions, NtvProps, NtvScheme, SchemeFor, StyleFunction } from './types.js';
17
2
  /**
18
- * Creates a customized `ntv` function with the specified options.
3
+ * Create a nestable tailwind variants style function.
4
+ *
5
+ * @param scheme - The scheme object defining variants and conditions
6
+ * @param options - Optional settings for tailwind-merge behavior
7
+ * @returns A style function that accepts props and returns merged class names
19
8
  *
20
9
  * @example
21
10
  * ```ts
22
- * // Disable tailwind-merge
23
- * const ntvNoMerge = createNTV({ twMerge: false });
11
+ * type ButtonProps = { variant: 'primary' | 'secondary'; isDisabled: boolean };
24
12
  *
25
- * // With custom tailwind-merge config
26
- * const customNTV = createNTV({
27
- * twMergeConfig: {
28
- * extend: {
29
- * theme: {
30
- * shadow: ['100', '200', '300'],
31
- * },
32
- * },
13
+ * const button = ntv<ButtonProps>({
14
+ * $base: 'px-4 py-2 rounded',
15
+ * variant: {
16
+ * primary: 'bg-blue-500 text-white',
17
+ * secondary: 'bg-gray-200 text-gray-800',
33
18
  * },
19
+ * isDisabled: 'opacity-50 cursor-not-allowed',
34
20
  * });
21
+ *
22
+ * button({ variant: 'primary' }); // 'px-4 py-2 rounded bg-blue-500 text-white'
23
+ * button({ variant: 'primary', isDisabled: true }); // 'px-4 py-2 rounded bg-blue-500 text-white opacity-50 cursor-not-allowed'
35
24
  * ```
36
25
  */
37
- export declare function createNTV(options?: NTVConfig): <Props extends Record<string, any>>(style: StyleDefinition<Props>) => StyleFunction<Props>;
26
+ export declare function ntv<TProps extends NtvProps>(scheme: SchemeFor<TProps>, options?: NtvOptions): StyleFunction<TProps>;
27
+ export declare function ntv(scheme: NtvScheme, options?: NtvOptions): StyleFunction<any>;
38
28
  /**
39
- * Creates a style function from a nested style definition.
29
+ * Create a pre-configured ntv function with fixed options.
30
+ *
31
+ * @param defaultOptions - Default options to apply to all ntv calls
32
+ * @returns A pre-configured ntv function
40
33
  *
41
34
  * @example
42
35
  * ```ts
43
- * const button = ntv<{ variant?: 'primary' | 'secondary'; isDisabled?: boolean }>({
44
- * default: 'px-4 py-2 rounded',
45
- * variant: {
46
- * primary: 'bg-blue-500 text-white',
47
- * secondary: 'bg-gray-200 text-gray-800',
36
+ * const myNtv = createNtv({
37
+ * twMergeConfig: {
38
+ * extend: {
39
+ * classGroups: {
40
+ * 'font-size': [{ text: ['huge', 'tiny'] }],
41
+ * },
42
+ * },
48
43
  * },
49
- * isDisabled: 'opacity-50 cursor-not-allowed',
50
44
  * });
51
45
  *
52
- * button({ variant: 'primary' });
53
- * // => 'px-4 py-2 rounded bg-blue-500 text-white'
54
- *
55
- * button({ variant: 'primary', isDisabled: true });
56
- * // => 'px-4 py-2 rounded bg-blue-500 text-white opacity-50 cursor-not-allowed'
46
+ * const button = myNtv({
47
+ * $base: 'text-huge',
48
+ * variant: {
49
+ * primary: 'bg-blue-500',
50
+ * secondary: 'bg-gray-200',
51
+ * },
52
+ * });
57
53
  * ```
58
54
  */
59
- export declare const ntv: <Props extends Record<string, any>>(style: StyleDefinition<Props>) => StyleFunction<Props>;
60
- export {};
55
+ export declare function createNtv(defaultOptions: NtvOptions): {
56
+ <TProps extends NtvProps>(scheme: SchemeFor<TProps>): StyleFunction<TProps>;
57
+ (scheme: NtvScheme): StyleFunction<any>;
58
+ };
61
59
  //# sourceMappingURL=ntv.d.ts.map
package/dist/ntv.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ntv.d.ts","sourceRoot":"","sources":["../src/ntv.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3D,KAAK,mBAAmB,GAAG,KAAK,UAAU,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AAErF,KAAK,kBAAkB,CAAC,KAAK,IAAI;KAC9B,CAAC,IAAI,MAAM,KAAK,GAAG,CAAC,SAAS,mBAAmB,GAAG,CAAC,GAAG,KAAK;CAC9D,CAAC,MAAM,KAAK,CAAC,CAAC;AAEf,KAAK,kBAAkB,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;AAEjF,KAAK,gBAAgB,CAAC,KAAK,IAAI,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;AAE/D,KAAK,eAAe,CAAC,KAAK,IAAI;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG;KACD,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC;CAC3D,GAAG;KACD,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SAChC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC;KAC3D;CACF,CAAC;AAgFF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,SAAc,IAS3B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACnD,OAAO,eAAe,CAAC,KAAK,CAAC,KAC5B,aAAa,CAAC,KAAK,CAAC,CAaxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,GAAG,GAtCM,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,SAC5C,eAAe,CAAC,KAAK,CAAC,KAC5B,aAAa,CAAC,KAAK,CAoCM,CAAC"}
1
+ {"version":3,"file":"ntv.d.ts","sourceRoot":"","sources":["../src/ntv.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EACT,aAAa,EACd,MAAM,YAAY,CAAC;AAiCpB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,GAAG,CAAC,MAAM,SAAS,QAAQ,EACzC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EACzB,OAAO,CAAC,EAAE,UAAU,GACnB,aAAa,CAAC,MAAM,CAAC,CAAC;AACzB,wBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;AAwBjF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,cAAc,EAAE,UAAU,GAAG;IACrD,CAAC,MAAM,SAAS,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;CACzC,CAIA"}
package/dist/ntv.js CHANGED
@@ -1,123 +1,70 @@
1
- import { extendTailwindMerge, twMerge } from 'tailwind-merge';
2
- import { joinClasses } from './utils.js';
3
- function isStyleDefinition(value) {
4
- return typeof value === 'object' && value !== null && !Array.isArray(value);
5
- }
6
- function evaluateDefinition(definition, context) {
7
- if (typeof definition === 'string') {
8
- context.classes.push(definition);
9
- return;
10
- }
11
- if (!isStyleDefinition(definition)) {
12
- return;
1
+ import { twJoin, twMerge } from 'tailwind-merge';
2
+ import { getCachedTwMerge } from './cache.js';
3
+ import { resolveConditions } from './resolver.js';
4
+ import { isPlainObject } from './utils.js';
5
+ function validateScheme(scheme) {
6
+ if ('class' in scheme) {
7
+ throw new Error('The "class" property is not allowed in ntv scheme. Use "$base" instead.');
13
8
  }
14
- const entries = Object.entries(definition);
15
- let defaultValue = undefined;
16
- const conditions = [];
17
- for (const [key, value] of entries) {
18
- if (key === 'default') {
19
- defaultValue = value;
20
- }
21
- else {
22
- conditions.push([key, value]);
23
- }
9
+ if ('className' in scheme) {
10
+ throw new Error('The "className" property is not allowed in ntv scheme. Use "$base" instead.');
24
11
  }
25
- const allConditionKeys = conditions.map(([key]) => key);
26
- const subSkipConditions = new Set([...context.skipConditions, ...allConditionKeys]);
27
- if (defaultValue !== undefined) {
28
- evaluateDefinition(defaultValue, {
29
- ...context,
30
- skipConditions: subSkipConditions,
31
- });
32
- }
33
- for (const [key, value] of conditions) {
34
- if (context.skipConditions.has(key)) {
35
- continue;
36
- }
37
- subSkipConditions.delete(key);
38
- const propValue = context.props[key];
39
- if (/^(is|allows)[A-Z]/.test(key) && propValue) {
40
- const nestedSkipConditions = new Set([...subSkipConditions, key]);
41
- evaluateDefinition(value, {
42
- props: context.props,
43
- skipConditions: nestedSkipConditions,
44
- classes: context.classes,
45
- });
12
+ validateNoNestedSpecialKeys(scheme, false);
13
+ }
14
+ function validateNoNestedSpecialKeys(obj, isNested) {
15
+ for (const [key, value] of Object.entries(obj)) {
16
+ // Check if this is a top-level-only key in a nested context
17
+ if (isNested && key === '$base') {
18
+ throw new Error(`The "${key}" property is only allowed at the top level of ntv scheme. It cannot be nested inside variants or conditions.`);
46
19
  }
47
- else if (key !== 'default' && propValue !== undefined) {
48
- if (isStyleDefinition(value)) {
49
- const variantValue = value[propValue];
50
- if (variantValue !== undefined) {
51
- const nestedSkipConditions = new Set([...subSkipConditions, key]);
52
- evaluateDefinition(variantValue, {
53
- props: context.props,
54
- skipConditions: nestedSkipConditions,
55
- classes: context.classes,
56
- });
57
- }
58
- }
20
+ // Recursively validate nested objects
21
+ if (isPlainObject(value)) {
22
+ validateNoNestedSpecialKeys(value, true);
59
23
  }
60
24
  }
61
25
  }
26
+ export function ntv(scheme, { twMerge: usesTwMerge = true, twMergeConfig } = {}) {
27
+ validateScheme(scheme);
28
+ const { $base, ...conditions } = scheme;
29
+ const mergeFn = usesTwMerge
30
+ ? twMergeConfig
31
+ ? getCachedTwMerge(twMergeConfig)
32
+ : twMerge
33
+ : twJoin;
34
+ return function styleFn({ class: slotClass, className: slotClassName, ...props } = {}) {
35
+ return mergeFn($base, ...resolveConditions(conditions, props), slotClass, slotClassName);
36
+ };
37
+ }
62
38
  /**
63
- * Creates a customized `ntv` function with the specified options.
39
+ * Create a pre-configured ntv function with fixed options.
40
+ *
41
+ * @param defaultOptions - Default options to apply to all ntv calls
42
+ * @returns A pre-configured ntv function
64
43
  *
65
44
  * @example
66
45
  * ```ts
67
- * // Disable tailwind-merge
68
- * const ntvNoMerge = createNTV({ twMerge: false });
69
- *
70
- * // With custom tailwind-merge config
71
- * const customNTV = createNTV({
46
+ * const myNtv = createNtv({
72
47
  * twMergeConfig: {
73
48
  * extend: {
74
- * theme: {
75
- * shadow: ['100', '200', '300'],
49
+ * classGroups: {
50
+ * 'font-size': [{ text: ['huge', 'tiny'] }],
76
51
  * },
77
52
  * },
78
53
  * },
79
54
  * });
80
- * ```
81
- */
82
- export function createNTV(options = {}) {
83
- const { twMerge: useTwMerge = true, twMergeConfig } = options;
84
- const mergeClasses = useTwMerge
85
- ? twMergeConfig
86
- ? extendTailwindMerge(twMergeConfig)
87
- : twMerge
88
- : joinClasses;
89
- return function ntv(style) {
90
- return (props) => {
91
- const context = {
92
- props,
93
- skipConditions: new Set(),
94
- classes: [],
95
- };
96
- evaluateDefinition(style, context);
97
- return mergeClasses(...context.classes);
98
- };
99
- };
100
- }
101
- /**
102
- * Creates a style function from a nested style definition.
103
55
  *
104
- * @example
105
- * ```ts
106
- * const button = ntv<{ variant?: 'primary' | 'secondary'; isDisabled?: boolean }>({
107
- * default: 'px-4 py-2 rounded',
56
+ * const button = myNtv({
57
+ * $base: 'text-huge',
108
58
  * variant: {
109
- * primary: 'bg-blue-500 text-white',
110
- * secondary: 'bg-gray-200 text-gray-800',
59
+ * primary: 'bg-blue-500',
60
+ * secondary: 'bg-gray-200',
111
61
  * },
112
- * isDisabled: 'opacity-50 cursor-not-allowed',
113
62
  * });
114
- *
115
- * button({ variant: 'primary' });
116
- * // => 'px-4 py-2 rounded bg-blue-500 text-white'
117
- *
118
- * button({ variant: 'primary', isDisabled: true });
119
- * // => 'px-4 py-2 rounded bg-blue-500 text-white opacity-50 cursor-not-allowed'
120
63
  * ```
121
64
  */
122
- export const ntv = createNTV();
65
+ export function createNtv(defaultOptions) {
66
+ return function configuredNtv(scheme) {
67
+ return ntv(scheme, defaultOptions);
68
+ };
69
+ }
123
70
  //# sourceMappingURL=ntv.js.map
package/dist/ntv.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ntv.js","sourceRoot":"","sources":["../src/ntv.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ntv.js","sourceRoot":"","sources":["../src/ntv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AASjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,cAAc,CAAC,MAAiB;IACvC,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,WAAW,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IAED,2BAA2B,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,2BAA2B,CAAC,GAA4B,EAAE,QAAiB;IAClF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,4DAA4D;QAC5D,IAAI,QAAQ,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,QAAQ,GAAG,+GAA+G,CAC3H,CAAC;QACJ,CAAC;QAED,sCAAsC;QACtC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,2BAA2B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;AACH,CAAC;AA+BD,MAAM,UAAU,GAAG,CACjB,MAAiB,EACjB,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,aAAa,KAAiB,EAAE;IAE/D,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,GAAG,MAAM,CAAC;IAExC,MAAM,OAAO,GAAG,WAAW;QACzB,CAAC,CAAC,aAAa;YACb,CAAC,CAAC,gBAAgB,CAAC,aAAa,CAAC;YACjC,CAAC,CAAC,OAAO;QACX,CAAC,CAAC,MAAM,CAAC;IAEX,OAAO,SAAS,OAAO,CAAC,EACtB,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,aAAa,EACxB,GAAG,KAAK,KAC+B,EAAE;QACzC,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;IAC3F,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,SAAS,CAAC,cAA0B;IAIlD,OAAO,SAAS,aAAa,CAAC,MAAiB;QAC7C,OAAO,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ClassValue } from './types.js';
2
+ /**
3
+ * Resolves conditions from scheme based on provided props to generate class values.
4
+ *
5
+ * $default behavior:
6
+ * - If no conditions match at a level, that level's $default is applied
7
+ * - If a variant matches, only the nested evaluation result is used
8
+ * - When no conditions match, $defaults accumulate from each unmatched level
9
+ */
10
+ export declare function resolveConditions({ $default, ...conditions }: Record<string, unknown>, props: Record<string, unknown>): ClassValue[];
11
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,UAAU,EAAE,CA8Cd"}
@@ -0,0 +1,50 @@
1
+ import { isPlainObject } from './utils.js';
2
+ /**
3
+ * Resolves conditions from scheme based on provided props to generate class values.
4
+ *
5
+ * $default behavior:
6
+ * - If no conditions match at a level, that level's $default is applied
7
+ * - If a variant matches, only the nested evaluation result is used
8
+ * - When no conditions match, $defaults accumulate from each unmatched level
9
+ */
10
+ export function resolveConditions({ $default, ...conditions }, props) {
11
+ const classes = [];
12
+ let hasMatchedCondition = false;
13
+ function addClasses(value) {
14
+ if (isPlainObject(value)) {
15
+ classes.push(...resolveConditions(value, props));
16
+ }
17
+ else {
18
+ classes.push(value);
19
+ }
20
+ }
21
+ for (const [key, value] of Object.entries(conditions)) {
22
+ const propValue = props[key];
23
+ if (propValue === '$default') {
24
+ throw new Error(`The value "$default" cannot be passed as a runtime value for "${key}". "$default" is a reserved keyword.`);
25
+ }
26
+ // Boolean conditions (isXxx or allowsXxx)
27
+ if (/^is[A-Z]/.test(key) || /^allows[A-Z]/.test(key)) {
28
+ if (propValue) {
29
+ hasMatchedCondition = true;
30
+ addClasses(value);
31
+ }
32
+ continue;
33
+ }
34
+ // Variant conditions (nested objects)
35
+ if (isPlainObject(value)) {
36
+ if (typeof propValue === 'string' && propValue in value) {
37
+ hasMatchedCondition = true;
38
+ addClasses(value[propValue]);
39
+ }
40
+ else {
41
+ classes.push(value['$default']);
42
+ }
43
+ }
44
+ }
45
+ if (!hasMatchedCondition) {
46
+ classes.unshift($default);
47
+ }
48
+ return classes;
49
+ }
50
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,EAAE,QAAQ,EAAE,GAAG,UAAU,EAA2B,EACpD,KAA8B;IAE9B,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAEhC,SAAS,UAAU,CAAC,KAAc;QAChC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,KAAmB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAE7B,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,iEAAiE,GAAG,sCAAsC,CAC3G,CAAC;QACJ,CAAC;QAED,0CAA0C;QAC1C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,IAAI,SAAS,EAAE,CAAC;gBACd,mBAAmB,GAAG,IAAI,CAAC;gBAC3B,UAAU,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;YACD,SAAS;QACX,CAAC;QAED,sCAAsC;QACtC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;gBACxD,mBAAmB,GAAG,IAAI,CAAC;gBAC3B,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAe,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,CAAC,OAAO,CAAC,QAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}