@mgcrea/react-native-tailwind 0.7.0 → 0.8.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.
- package/README.md +2 -1
- package/dist/babel/index.cjs +333 -195
- package/dist/babel/index.d.ts +4 -40
- package/dist/babel/index.test.ts +214 -1
- package/dist/babel/index.ts +4 -1169
- package/dist/babel/plugin.d.ts +42 -0
- package/{src/babel/index.test.ts → dist/babel/plugin.test.ts} +216 -2
- package/dist/babel/plugin.ts +491 -0
- package/dist/babel/utils/attributeMatchers.d.ts +23 -0
- package/dist/babel/utils/attributeMatchers.ts +71 -0
- package/dist/babel/utils/componentSupport.d.ts +18 -0
- package/dist/babel/utils/componentSupport.ts +68 -0
- package/dist/babel/utils/dynamicProcessing.d.ts +32 -0
- package/dist/babel/utils/dynamicProcessing.ts +223 -0
- package/dist/babel/utils/modifierProcessing.d.ts +26 -0
- package/dist/babel/utils/modifierProcessing.ts +118 -0
- package/dist/babel/utils/styleInjection.d.ts +15 -0
- package/dist/babel/utils/styleInjection.ts +80 -0
- package/dist/babel/utils/styleTransforms.d.ts +39 -0
- package/dist/babel/utils/styleTransforms.test.ts +349 -0
- package/dist/babel/utils/styleTransforms.ts +258 -0
- package/dist/babel/utils/twProcessing.d.ts +28 -0
- package/dist/babel/utils/twProcessing.ts +124 -0
- package/dist/components/TextInput.d.ts +171 -14
- package/dist/config/tailwind.d.ts +302 -0
- package/dist/config/tailwind.js +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/dist/parser/colors.js +1 -1
- package/dist/parser/index.d.ts +1 -0
- package/dist/parser/index.js +1 -1
- package/dist/parser/modifiers.d.ts +2 -2
- package/dist/parser/modifiers.js +1 -1
- package/dist/parser/placeholder.d.ts +36 -0
- package/dist/parser/placeholder.js +1 -0
- package/dist/parser/placeholder.test.js +1 -0
- package/dist/parser/typography.d.ts +1 -0
- package/dist/parser/typography.js +1 -1
- package/dist/parser/typography.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +4 -4
- package/dist/runtime.d.ts +1 -14
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +4 -4
- package/dist/stubs/tw.d.ts +1 -14
- package/dist/types/core.d.ts +40 -0
- package/dist/types/core.js +0 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/types/runtime.d.ts +15 -0
- package/dist/types/runtime.js +1 -0
- package/dist/types/util.d.ts +3 -0
- package/dist/types/util.js +0 -0
- package/package.json +1 -1
- package/src/babel/index.ts +4 -1169
- package/src/babel/plugin.test.ts +482 -0
- package/src/babel/plugin.ts +491 -0
- package/src/babel/utils/attributeMatchers.ts +71 -0
- package/src/babel/utils/componentSupport.ts +68 -0
- package/src/babel/utils/dynamicProcessing.ts +223 -0
- package/src/babel/utils/modifierProcessing.ts +118 -0
- package/src/babel/utils/styleInjection.ts +80 -0
- package/src/babel/utils/styleTransforms.test.ts +349 -0
- package/src/babel/utils/styleTransforms.ts +258 -0
- package/src/babel/utils/twProcessing.ts +124 -0
- package/src/components/TextInput.tsx +17 -14
- package/src/config/{palettes.ts → tailwind.ts} +2 -2
- package/src/index.ts +6 -3
- package/src/parser/colors.ts +2 -2
- package/src/parser/index.ts +1 -0
- package/src/parser/modifiers.ts +10 -4
- package/src/parser/placeholder.test.ts +105 -0
- package/src/parser/placeholder.ts +78 -0
- package/src/parser/typography.test.ts +11 -0
- package/src/parser/typography.ts +20 -2
- package/src/runtime.ts +1 -16
- package/src/stubs/tw.ts +1 -16
- package/src/{types.ts → types/core.ts} +0 -4
- package/src/types/index.ts +2 -0
- package/src/types/runtime.ts +17 -0
- package/src/types/util.ts +1 -0
package/dist/babel/index.d.ts
CHANGED
|
@@ -1,42 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Main entry point for the Babel plugin
|
|
3
|
+
* Re-exports the plugin from plugin.ts
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { StyleObject } from "src/types.js";
|
|
8
|
-
/**
|
|
9
|
-
* Plugin options
|
|
10
|
-
*/
|
|
11
|
-
export type PluginOptions = {
|
|
12
|
-
/**
|
|
13
|
-
* List of JSX attribute names to transform (in addition to or instead of 'className')
|
|
14
|
-
* Supports exact matches and glob patterns:
|
|
15
|
-
* - Exact: 'className', 'containerClassName'
|
|
16
|
-
* - Glob: '*ClassName' (matches any attribute ending in 'ClassName')
|
|
17
|
-
*
|
|
18
|
-
* @default ['className', 'contentContainerClassName', 'columnWrapperClassName', 'ListHeaderComponentClassName', 'ListFooterComponentClassName']
|
|
19
|
-
*/
|
|
20
|
-
attributes?: string[];
|
|
21
|
-
/**
|
|
22
|
-
* Custom identifier name for the generated StyleSheet constant
|
|
23
|
-
*
|
|
24
|
-
* @default '_twStyles'
|
|
25
|
-
*/
|
|
26
|
-
stylesIdentifier?: string;
|
|
27
|
-
};
|
|
28
|
-
type PluginState = PluginPass & {
|
|
29
|
-
styleRegistry: Map<string, StyleObject>;
|
|
30
|
-
hasClassNames: boolean;
|
|
31
|
-
hasStyleSheetImport: boolean;
|
|
32
|
-
customColors: Record<string, string>;
|
|
33
|
-
supportedAttributes: Set<string>;
|
|
34
|
-
attributePatterns: RegExp[];
|
|
35
|
-
stylesIdentifier: string;
|
|
36
|
-
twImportNames: Set<string>;
|
|
37
|
-
hasTwImport: boolean;
|
|
38
|
-
};
|
|
39
|
-
export default function reactNativeTailwindBabelPlugin({ types: t }: {
|
|
40
|
-
types: typeof BabelTypes;
|
|
41
|
-
}, options?: PluginOptions): PluginObj<PluginState>;
|
|
42
|
-
export {};
|
|
5
|
+
export { default } from "./plugin.js";
|
|
6
|
+
export type { PluginOptions } from "./plugin.js";
|
package/dist/babel/index.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { transformSync } from "@babel/core";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
import babelPlugin, { type PluginOptions } from "./index.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -265,4 +265,217 @@ describe("Babel plugin - className transformation (existing behavior)", () => {
|
|
|
265
265
|
expect(output).toContain("_bg_red_500");
|
|
266
266
|
expect(output).toContain("_m_4_p_2");
|
|
267
267
|
});
|
|
268
|
+
|
|
269
|
+
it("should merge className with function-based style prop", () => {
|
|
270
|
+
const input = `
|
|
271
|
+
import { TextInput } from 'react-native';
|
|
272
|
+
export function Component() {
|
|
273
|
+
return (
|
|
274
|
+
<TextInput
|
|
275
|
+
className="border border-gray-300 bg-gray-100"
|
|
276
|
+
style={({ focused, disabled }) => [
|
|
277
|
+
baseStyles,
|
|
278
|
+
focused && focusedStyles,
|
|
279
|
+
]}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
const output = transform(input, undefined, true); // Enable JSX
|
|
286
|
+
|
|
287
|
+
// Should have StyleSheet with className styles
|
|
288
|
+
expect(output).toContain("StyleSheet.create");
|
|
289
|
+
// Style keys are sorted alphabetically: bg-gray-100 comes before border
|
|
290
|
+
expect(output).toContain("_bg_gray_100_border_border_gray_300");
|
|
291
|
+
|
|
292
|
+
// Should create a wrapper function that merges both
|
|
293
|
+
// The wrapper should call the original function and merge results
|
|
294
|
+
expect(output).toContain("_state");
|
|
295
|
+
expect(output).toContain("_twStyles._bg_gray_100_border_border_gray_300");
|
|
296
|
+
|
|
297
|
+
// Should not have className in output
|
|
298
|
+
expect(output).not.toContain("className");
|
|
299
|
+
|
|
300
|
+
// Should have a function that accepts state and returns an array
|
|
301
|
+
expect(output).toMatch(/_state\s*=>/);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should merge dynamic className with function-based style prop", () => {
|
|
305
|
+
const input = `
|
|
306
|
+
import { TextInput } from 'react-native';
|
|
307
|
+
export function Component({ isError }) {
|
|
308
|
+
return (
|
|
309
|
+
<TextInput
|
|
310
|
+
className={\`border \${isError ? 'border-red-500' : 'border-gray-300'}\`}
|
|
311
|
+
style={({ focused }) => [
|
|
312
|
+
baseStyles,
|
|
313
|
+
focused && focusedStyles,
|
|
314
|
+
]}
|
|
315
|
+
/>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
`;
|
|
319
|
+
|
|
320
|
+
const output = transform(input, undefined, true); // Enable JSX
|
|
321
|
+
|
|
322
|
+
// Should have StyleSheet with both className styles
|
|
323
|
+
expect(output).toContain("StyleSheet.create");
|
|
324
|
+
expect(output).toContain("_border");
|
|
325
|
+
expect(output).toContain("_border_red_500");
|
|
326
|
+
expect(output).toContain("_border_gray_300");
|
|
327
|
+
|
|
328
|
+
// Should create a wrapper function that merges dynamic styles with function result
|
|
329
|
+
expect(output).toContain("_state");
|
|
330
|
+
|
|
331
|
+
// Should not have className in output
|
|
332
|
+
expect(output).not.toContain("className");
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe("Babel plugin - placeholder: modifier transformation", () => {
|
|
337
|
+
it("should transform placeholder:text-{color} to placeholderTextColor prop", () => {
|
|
338
|
+
const input = `
|
|
339
|
+
import { TextInput } from 'react-native';
|
|
340
|
+
export function Component() {
|
|
341
|
+
return (
|
|
342
|
+
<TextInput
|
|
343
|
+
className="border-2 placeholder:text-gray-400"
|
|
344
|
+
placeholder="Email"
|
|
345
|
+
/>
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
`;
|
|
349
|
+
|
|
350
|
+
const output = transform(input, undefined, true);
|
|
351
|
+
|
|
352
|
+
// Should have placeholderTextColor prop with correct hex value (from custom palette)
|
|
353
|
+
expect(output).toContain('placeholderTextColor: "#99a1af"');
|
|
354
|
+
|
|
355
|
+
// Should still have style for border-2
|
|
356
|
+
expect(output).toContain("StyleSheet.create");
|
|
357
|
+
expect(output).toContain("_border_2");
|
|
358
|
+
|
|
359
|
+
// Should not have className in output
|
|
360
|
+
expect(output).not.toContain("className");
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("should support placeholder colors with opacity", () => {
|
|
364
|
+
const input = `
|
|
365
|
+
import { TextInput } from 'react-native';
|
|
366
|
+
export function Component() {
|
|
367
|
+
return <TextInput className="placeholder:text-red-500/50" />;
|
|
368
|
+
}
|
|
369
|
+
`;
|
|
370
|
+
|
|
371
|
+
const output = transform(input, undefined, true);
|
|
372
|
+
|
|
373
|
+
// Should have 8-digit hex with alpha channel (custom palette red-500, uppercased)
|
|
374
|
+
expect(output).toContain('placeholderTextColor: "#FB2C3680"');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should support arbitrary placeholder colors", () => {
|
|
378
|
+
const input = `
|
|
379
|
+
import { TextInput } from 'react-native';
|
|
380
|
+
export function Component() {
|
|
381
|
+
return <TextInput className="placeholder:text-[#ff0000]" />;
|
|
382
|
+
}
|
|
383
|
+
`;
|
|
384
|
+
|
|
385
|
+
const output = transform(input, undefined, true);
|
|
386
|
+
|
|
387
|
+
expect(output).toContain('placeholderTextColor: "#ff0000"');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("should combine placeholder: with other modifiers", () => {
|
|
391
|
+
const input = `
|
|
392
|
+
import { TextInput } from 'react-native';
|
|
393
|
+
export function Component() {
|
|
394
|
+
return (
|
|
395
|
+
<TextInput
|
|
396
|
+
className="border-2 focus:border-blue-500 placeholder:text-gray-400"
|
|
397
|
+
placeholder="Email"
|
|
398
|
+
/>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
`;
|
|
402
|
+
|
|
403
|
+
const output = transform(input, undefined, true);
|
|
404
|
+
|
|
405
|
+
// Should have placeholderTextColor prop (custom palette gray-400)
|
|
406
|
+
expect(output).toContain('placeholderTextColor: "#99a1af"');
|
|
407
|
+
|
|
408
|
+
// Should have focus: modifier handling (style function)
|
|
409
|
+
expect(output).toContain("focused");
|
|
410
|
+
expect(output).toMatch(/style[\s\S]*=>/); // Style function
|
|
411
|
+
|
|
412
|
+
// Should not have className
|
|
413
|
+
expect(output).not.toContain("className");
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("should handle multiple placeholder: classes (last wins)", () => {
|
|
417
|
+
const input = `
|
|
418
|
+
import { TextInput } from 'react-native';
|
|
419
|
+
export function Component() {
|
|
420
|
+
return (
|
|
421
|
+
<TextInput className="placeholder:text-red-500 placeholder:text-blue-500" />
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
`;
|
|
425
|
+
|
|
426
|
+
const output = transform(input, undefined, true);
|
|
427
|
+
|
|
428
|
+
// Blue should win (last color, custom palette blue-500)
|
|
429
|
+
expect(output).toContain('placeholderTextColor: "#2b7fff"');
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it("should ignore non-text utilities in placeholder: modifier", () => {
|
|
433
|
+
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
434
|
+
|
|
435
|
+
const input = `
|
|
436
|
+
import { TextInput } from 'react-native';
|
|
437
|
+
export function Component() {
|
|
438
|
+
return (
|
|
439
|
+
<TextInput className="placeholder:font-bold placeholder:text-gray-400" />
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
`;
|
|
443
|
+
|
|
444
|
+
const output = transform(input, undefined, true);
|
|
445
|
+
|
|
446
|
+
// Should still have the valid text color (custom palette gray-400)
|
|
447
|
+
expect(output).toContain('placeholderTextColor: "#99a1af"');
|
|
448
|
+
|
|
449
|
+
// Should not have font-bold anywhere
|
|
450
|
+
expect(output).not.toContain("fontWeight");
|
|
451
|
+
|
|
452
|
+
consoleSpy.mockRestore();
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it("should work with custom colors", () => {
|
|
456
|
+
// Note: This test would require setting up a tailwind.config file
|
|
457
|
+
// For now, we'll skip custom color testing in Babel tests
|
|
458
|
+
// Custom colors are tested in the parser tests
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it("should not transform placeholder: on non-TextInput elements", () => {
|
|
462
|
+
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
463
|
+
|
|
464
|
+
const input = `
|
|
465
|
+
import { View } from 'react-native';
|
|
466
|
+
export function Component() {
|
|
467
|
+
return <View className="placeholder:text-gray-400" />;
|
|
468
|
+
}
|
|
469
|
+
`;
|
|
470
|
+
|
|
471
|
+
const output = transform(input, undefined, true);
|
|
472
|
+
|
|
473
|
+
// Should not have placeholderTextColor prop (View doesn't support it)
|
|
474
|
+
expect(output).not.toContain("placeholderTextColor");
|
|
475
|
+
|
|
476
|
+
// Should warn about unsupported modifier
|
|
477
|
+
// (The warning happens because View doesn't support any modifiers)
|
|
478
|
+
|
|
479
|
+
consoleSpy.mockRestore();
|
|
480
|
+
});
|
|
268
481
|
});
|