nestable-tailwind-variants 0.1.4 → 0.2.0

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,7 @@
1
+ import { extendTailwindMerge } from 'tailwind-merge';
2
+ import type { NtvOptions } from './types.js';
3
+ type TwMergeConfig = NonNullable<NtvOptions['twMergeConfig']>;
4
+ type TwMergeFn = ReturnType<typeof extendTailwindMerge>;
5
+ export declare function getCachedTwMerge(config: TwMergeConfig): TwMergeFn;
6
+ export {};
7
+ //# 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,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,KAAK,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;AAC9D,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;AAMrD,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, NtvOptions, 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,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,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;AAoCpB;;;;;;;;;;;;;;;;;;;;;;;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,72 @@
1
- import { extendTailwindMerge, twMerge } from 'tailwind-merge';
2
- import { joinClasses } from './utils.js';
3
- function isStyleDefinition(value) {
1
+ import { twJoin, twMerge } from 'tailwind-merge';
2
+ import { getCachedTwMerge } from './cache.js';
3
+ import { resolveConditions } from './resolver.js';
4
+ function isPlainObject(value) {
4
5
  return typeof value === 'object' && value !== null && !Array.isArray(value);
5
6
  }
6
- function evaluateDefinition(definition, context) {
7
- if (typeof definition === 'string') {
8
- context.classes.push(definition);
9
- return;
7
+ function validateScheme(scheme) {
8
+ if ('class' in scheme) {
9
+ throw new Error('The "class" property is not allowed in ntv scheme. Use "$base" instead.');
10
10
  }
11
- if (!isStyleDefinition(definition)) {
12
- return;
11
+ if ('className' in scheme) {
12
+ throw new Error('The "className" property is not allowed in ntv scheme. Use "$base" instead.');
13
13
  }
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
- }
24
- }
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
- });
14
+ validateNoNestedSpecialKeys(scheme, false);
15
+ }
16
+ function validateNoNestedSpecialKeys(obj, isNested) {
17
+ for (const [key, value] of Object.entries(obj)) {
18
+ // Check if this is a top-level-only key in a nested context
19
+ if (isNested && key === '$base') {
20
+ 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
21
  }
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
- }
22
+ // Recursively validate nested objects
23
+ if (isPlainObject(value)) {
24
+ validateNoNestedSpecialKeys(value, true);
59
25
  }
60
26
  }
61
27
  }
28
+ export function ntv(scheme, { twMerge: usesTwMerge = true, twMergeConfig } = {}) {
29
+ validateScheme(scheme);
30
+ const { $base, ...conditions } = scheme;
31
+ const mergeFn = usesTwMerge
32
+ ? twMergeConfig
33
+ ? getCachedTwMerge(twMergeConfig)
34
+ : twMerge
35
+ : twJoin;
36
+ return function styleFn({ class: slotClass, className: slotClassName, ...props } = {}) {
37
+ return mergeFn($base, ...resolveConditions(conditions, props), slotClass, slotClassName);
38
+ };
39
+ }
62
40
  /**
63
- * Creates a customized `ntv` function with the specified options.
41
+ * Create a pre-configured ntv function with fixed options.
42
+ *
43
+ * @param defaultOptions - Default options to apply to all ntv calls
44
+ * @returns A pre-configured ntv function
64
45
  *
65
46
  * @example
66
47
  * ```ts
67
- * // Disable tailwind-merge
68
- * const ntvNoMerge = createNTV({ twMerge: false });
69
- *
70
- * // With custom tailwind-merge config
71
- * const customNTV = createNTV({
48
+ * const myNtv = createNtv({
72
49
  * twMergeConfig: {
73
50
  * extend: {
74
- * theme: {
75
- * shadow: ['100', '200', '300'],
51
+ * classGroups: {
52
+ * 'font-size': [{ text: ['huge', 'tiny'] }],
76
53
  * },
77
54
  * },
78
55
  * },
79
56
  * });
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
57
  *
104
- * @example
105
- * ```ts
106
- * const button = ntv<{ variant?: 'primary' | 'secondary'; isDisabled?: boolean }>({
107
- * default: 'px-4 py-2 rounded',
58
+ * const button = myNtv({
59
+ * $base: 'text-huge',
108
60
  * variant: {
109
- * primary: 'bg-blue-500 text-white',
110
- * secondary: 'bg-gray-200 text-gray-800',
61
+ * primary: 'bg-blue-500',
62
+ * secondary: 'bg-gray-200',
111
63
  * },
112
- * isDisabled: 'opacity-50 cursor-not-allowed',
113
64
  * });
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
65
  * ```
121
66
  */
122
- export const ntv = createNTV();
67
+ export function createNtv(defaultOptions) {
68
+ return function configuredNtv(scheme) {
69
+ return ntv(scheme, defaultOptions);
70
+ };
71
+ }
123
72
  //# 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;AAElD,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,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;AAM7C;;;;;;;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,52 @@
1
+ function isObject(value) {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ }
4
+ /**
5
+ * Resolves conditions from scheme based on provided props to generate class values.
6
+ *
7
+ * $default behavior:
8
+ * - If no conditions match at a level, that level's $default is applied
9
+ * - If a variant matches, only the nested evaluation result is used
10
+ * - When no conditions match, $defaults accumulate from each unmatched level
11
+ */
12
+ export function resolveConditions({ $default, ...conditions }, props) {
13
+ const classes = [];
14
+ let hasMatchedCondition = false;
15
+ function addClasses(value) {
16
+ if (isObject(value)) {
17
+ classes.push(...resolveConditions(value, props));
18
+ }
19
+ else {
20
+ classes.push(value);
21
+ }
22
+ }
23
+ for (const [key, value] of Object.entries(conditions)) {
24
+ const propValue = props[key];
25
+ if (propValue === '$default') {
26
+ throw new Error(`The value "$default" cannot be passed as a runtime value for "${key}". "$default" is a reserved keyword.`);
27
+ }
28
+ // Boolean conditions (isXxx or allowsXxx)
29
+ if (/^is[A-Z]/.test(key) || /^allows[A-Z]/.test(key)) {
30
+ if (propValue) {
31
+ hasMatchedCondition = true;
32
+ addClasses(value);
33
+ }
34
+ continue;
35
+ }
36
+ // Variant conditions (nested objects)
37
+ if (isObject(value)) {
38
+ if (typeof propValue === 'string' && propValue in value) {
39
+ hasMatchedCondition = true;
40
+ addClasses(value[propValue]);
41
+ }
42
+ else {
43
+ classes.push(value['$default']);
44
+ }
45
+ }
46
+ }
47
+ if (!hasMatchedCondition) {
48
+ classes.unshift($default);
49
+ }
50
+ return classes;
51
+ }
52
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAEA,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;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,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,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,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,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"}