@mgcrea/react-native-tailwind 0.12.1 → 0.14.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 +45 -2031
- package/dist/babel/index.cjs +1726 -1094
- package/dist/babel/plugin/componentScope.d.ts +26 -0
- package/dist/babel/plugin/componentScope.ts +87 -0
- package/dist/babel/plugin/state.d.ts +123 -0
- package/dist/babel/plugin/state.ts +185 -0
- package/dist/babel/plugin/visitors/className.d.ts +11 -0
- package/{src/babel/plugin.test.ts → dist/babel/plugin/visitors/className.test.ts} +285 -572
- package/dist/babel/plugin/visitors/className.ts +652 -0
- package/dist/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
- package/dist/babel/plugin/visitors/imports.d.ts +11 -0
- package/dist/babel/plugin/visitors/imports.test.ts +88 -0
- package/dist/babel/plugin/visitors/imports.ts +116 -0
- package/dist/babel/plugin/visitors/program.d.ts +15 -0
- package/dist/babel/plugin/visitors/program.test.ts +325 -0
- package/dist/babel/plugin/visitors/program.ts +116 -0
- package/dist/babel/plugin/visitors/tw.d.ts +16 -0
- package/dist/babel/plugin/visitors/tw.test.ts +771 -0
- package/dist/babel/plugin/visitors/tw.ts +148 -0
- package/dist/babel/plugin.d.ts +3 -96
- package/dist/babel/plugin.test.ts +470 -0
- package/dist/babel/plugin.ts +28 -963
- package/dist/babel/utils/colorSchemeModifierProcessing.ts +11 -0
- package/dist/babel/utils/componentSupport.test.ts +20 -7
- package/dist/babel/utils/componentSupport.ts +2 -0
- package/dist/babel/utils/directionalModifierProcessing.d.ts +34 -0
- package/dist/babel/utils/directionalModifierProcessing.ts +99 -0
- package/dist/babel/utils/modifierProcessing.ts +21 -0
- package/dist/babel/utils/platformModifierProcessing.ts +11 -0
- package/dist/babel/utils/styleInjection.d.ts +31 -0
- package/dist/babel/utils/styleInjection.ts +253 -7
- package/dist/babel/utils/twProcessing.d.ts +2 -0
- package/dist/babel/utils/twProcessing.ts +103 -3
- package/dist/babel/utils/windowDimensionsProcessing.d.ts +56 -0
- package/dist/babel/utils/windowDimensionsProcessing.ts +121 -0
- package/dist/components/TouchableOpacity.d.ts +35 -0
- package/dist/components/TouchableOpacity.js +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +1 -0
- package/dist/config/markers.d.ts +5 -0
- package/dist/config/markers.js +1 -0
- package/dist/index.d.ts +2 -5
- package/dist/index.js +1 -1
- package/dist/parser/borders.d.ts +3 -1
- package/dist/parser/borders.js +1 -1
- package/dist/parser/borders.test.js +1 -1
- package/dist/parser/colors.js +1 -1
- package/dist/parser/colors.test.js +1 -1
- package/dist/parser/index.d.ts +2 -2
- package/dist/parser/index.js +1 -1
- package/dist/parser/layout.js +1 -1
- package/dist/parser/layout.test.js +1 -1
- package/dist/parser/modifiers.d.ts +32 -2
- package/dist/parser/modifiers.js +1 -1
- package/dist/parser/modifiers.test.js +1 -1
- package/dist/parser/sizing.js +1 -1
- package/dist/parser/spacing.d.ts +1 -1
- package/dist/parser/spacing.js +1 -1
- package/dist/parser/spacing.test.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.js +1 -1
- package/dist/runtime.js.map +4 -4
- package/package.json +6 -6
- package/src/babel/plugin/componentScope.ts +87 -0
- package/src/babel/plugin/state.ts +185 -0
- package/src/babel/plugin/visitors/className.test.ts +1625 -0
- package/src/babel/plugin/visitors/className.ts +652 -0
- package/src/babel/plugin/visitors/className.windowDimensions.test.ts +406 -0
- package/src/babel/plugin/visitors/imports.test.ts +88 -0
- package/src/babel/plugin/visitors/imports.ts +116 -0
- package/src/babel/plugin/visitors/program.test.ts +325 -0
- package/src/babel/plugin/visitors/program.ts +116 -0
- package/src/babel/plugin/visitors/tw.test.ts +771 -0
- package/src/babel/plugin/visitors/tw.ts +148 -0
- package/src/babel/plugin.ts +28 -963
- package/src/babel/utils/colorSchemeModifierProcessing.ts +11 -0
- package/src/babel/utils/componentSupport.test.ts +20 -7
- package/src/babel/utils/componentSupport.ts +2 -0
- package/src/babel/utils/directionalModifierProcessing.ts +99 -0
- package/src/babel/utils/modifierProcessing.ts +21 -0
- package/src/babel/utils/platformModifierProcessing.ts +11 -0
- package/src/babel/utils/styleInjection.ts +253 -7
- package/src/babel/utils/twProcessing.ts +103 -3
- package/src/babel/utils/windowDimensionsProcessing.ts +121 -0
- package/src/components/TouchableOpacity.tsx +71 -0
- package/src/components/index.ts +3 -0
- package/src/config/markers.ts +5 -0
- package/src/index.ts +4 -5
- package/src/parser/borders.test.ts +162 -0
- package/src/parser/borders.ts +67 -9
- package/src/parser/colors.test.ts +249 -0
- package/src/parser/colors.ts +38 -0
- package/src/parser/index.ts +4 -2
- package/src/parser/layout.test.ts +74 -0
- package/src/parser/layout.ts +94 -0
- package/src/parser/modifiers.test.ts +206 -0
- package/src/parser/modifiers.ts +62 -3
- package/src/parser/sizing.ts +11 -0
- package/src/parser/spacing.test.ts +66 -0
- package/src/parser/spacing.ts +15 -5
- package/src/parser/typography.test.ts +8 -0
- package/src/parser/typography.ts +4 -0
|
@@ -391,3 +391,252 @@ describe("parseColor - opacity modifiers", () => {
|
|
|
391
391
|
});
|
|
392
392
|
});
|
|
393
393
|
});
|
|
394
|
+
|
|
395
|
+
describe("parseColor - directional border colors", () => {
|
|
396
|
+
it("should parse directional border colors with preset values", () => {
|
|
397
|
+
expect(parseColor("border-t-red-500")).toEqual({ borderTopColor: COLORS["red-500"] });
|
|
398
|
+
expect(parseColor("border-r-blue-500")).toEqual({ borderRightColor: COLORS["blue-500"] });
|
|
399
|
+
expect(parseColor("border-b-green-500")).toEqual({ borderBottomColor: COLORS["green-500"] });
|
|
400
|
+
expect(parseColor("border-l-yellow-500")).toEqual({ borderLeftColor: COLORS["yellow-500"] });
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("should parse directional border colors with basic values", () => {
|
|
404
|
+
expect(parseColor("border-t-white")).toEqual({ borderTopColor: "#FFFFFF" });
|
|
405
|
+
expect(parseColor("border-r-black")).toEqual({ borderRightColor: "#000000" });
|
|
406
|
+
expect(parseColor("border-b-transparent")).toEqual({ borderBottomColor: "transparent" });
|
|
407
|
+
expect(parseColor("border-l-white")).toEqual({ borderLeftColor: "#FFFFFF" });
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it("should parse directional border colors with arbitrary 6-digit hex values", () => {
|
|
411
|
+
expect(parseColor("border-t-[#ff0000]")).toEqual({ borderTopColor: "#ff0000" });
|
|
412
|
+
expect(parseColor("border-r-[#3B82F6]")).toEqual({ borderRightColor: "#3B82F6" });
|
|
413
|
+
expect(parseColor("border-b-[#00ff00]")).toEqual({ borderBottomColor: "#00ff00" });
|
|
414
|
+
expect(parseColor("border-l-[#cccccc]")).toEqual({ borderLeftColor: "#cccccc" });
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("should parse directional border colors with arbitrary 3-digit hex values", () => {
|
|
418
|
+
expect(parseColor("border-t-[#f00]")).toEqual({ borderTopColor: "#ff0000" });
|
|
419
|
+
expect(parseColor("border-r-[#abc]")).toEqual({ borderRightColor: "#aabbcc" });
|
|
420
|
+
expect(parseColor("border-b-[#123]")).toEqual({ borderBottomColor: "#112233" });
|
|
421
|
+
expect(parseColor("border-l-[#999]")).toEqual({ borderLeftColor: "#999999" });
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("should parse directional border colors with arbitrary 8-digit hex values (with alpha)", () => {
|
|
425
|
+
expect(parseColor("border-t-[#ff0000aa]")).toEqual({ borderTopColor: "#ff0000aa" });
|
|
426
|
+
expect(parseColor("border-r-[#0000FF50]")).toEqual({ borderRightColor: "#0000FF50" });
|
|
427
|
+
expect(parseColor("border-b-[#00FF0080]")).toEqual({ borderBottomColor: "#00FF0080" });
|
|
428
|
+
expect(parseColor("border-l-[#FFFFFF00]")).toEqual({ borderLeftColor: "#FFFFFF00" });
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("should parse directional border colors with opacity modifiers", () => {
|
|
432
|
+
expect(parseColor("border-t-red-500/50")).toEqual({
|
|
433
|
+
borderTopColor: applyOpacity(COLORS["red-500"], 50),
|
|
434
|
+
});
|
|
435
|
+
expect(parseColor("border-r-blue-500/80")).toEqual({
|
|
436
|
+
borderRightColor: applyOpacity(COLORS["blue-500"], 80),
|
|
437
|
+
});
|
|
438
|
+
expect(parseColor("border-b-green-500/30")).toEqual({
|
|
439
|
+
borderBottomColor: applyOpacity(COLORS["green-500"], 30),
|
|
440
|
+
});
|
|
441
|
+
expect(parseColor("border-l-black/25")).toEqual({
|
|
442
|
+
borderLeftColor: applyOpacity(COLORS.black, 25),
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("should parse directional border colors with arbitrary hex and opacity", () => {
|
|
447
|
+
expect(parseColor("border-t-[#ff0000]/50")).toEqual({ borderTopColor: "#FF000080" });
|
|
448
|
+
expect(parseColor("border-r-[#3B82F6]/80")).toEqual({ borderRightColor: "#3B82F6CC" });
|
|
449
|
+
expect(parseColor("border-b-[#abc]/60")).toEqual({ borderBottomColor: "#AABBCC99" });
|
|
450
|
+
expect(parseColor("border-l-[#000]/100")).toEqual({ borderLeftColor: "#000000FF" });
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("should parse directional border colors with custom colors", () => {
|
|
454
|
+
const customColors = {
|
|
455
|
+
"brand-primary": "#FF6B6B",
|
|
456
|
+
"brand-secondary": "#4ECDC4",
|
|
457
|
+
accent: "#FFE66D",
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
expect(parseColor("border-t-brand-primary", customColors)).toEqual({
|
|
461
|
+
borderTopColor: "#FF6B6B",
|
|
462
|
+
});
|
|
463
|
+
expect(parseColor("border-r-brand-secondary", customColors)).toEqual({
|
|
464
|
+
borderRightColor: "#4ECDC4",
|
|
465
|
+
});
|
|
466
|
+
expect(parseColor("border-b-accent", customColors)).toEqual({ borderBottomColor: "#FFE66D" });
|
|
467
|
+
expect(parseColor("border-l-brand-primary", customColors)).toEqual({
|
|
468
|
+
borderLeftColor: "#FF6B6B",
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it("should parse directional border colors with custom colors and opacity", () => {
|
|
473
|
+
const customColors = { "brand-primary": "#FF6B6B" };
|
|
474
|
+
expect(parseColor("border-t-brand-primary/50", customColors)).toEqual({
|
|
475
|
+
borderTopColor: "#FF6B6B80",
|
|
476
|
+
});
|
|
477
|
+
expect(parseColor("border-l-brand-primary/75", customColors)).toEqual({
|
|
478
|
+
borderLeftColor: "#FF6B6BBF",
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it("should not match border width classes", () => {
|
|
483
|
+
// These should be handled by parseBorder
|
|
484
|
+
expect(parseColor("border-t-2")).toBeNull();
|
|
485
|
+
expect(parseColor("border-r-4")).toBeNull();
|
|
486
|
+
expect(parseColor("border-b-8")).toBeNull();
|
|
487
|
+
expect(parseColor("border-l-0")).toBeNull();
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
it("should not match border width arbitrary values", () => {
|
|
491
|
+
// These should be handled by parseBorder
|
|
492
|
+
expect(parseColor("border-t-[3px]")).toBeNull();
|
|
493
|
+
expect(parseColor("border-r-[8px]")).toBeNull();
|
|
494
|
+
expect(parseColor("border-b-[5]")).toBeNull();
|
|
495
|
+
expect(parseColor("border-l-[10px]")).toBeNull();
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it("should return null for invalid directional border color values", () => {
|
|
499
|
+
expect(parseColor("border-t-invalid")).toBeNull();
|
|
500
|
+
expect(parseColor("border-r-notacolor")).toBeNull();
|
|
501
|
+
expect(parseColor("border-b-xyz")).toBeNull();
|
|
502
|
+
expect(parseColor("border-l-wrongcolor")).toBeNull();
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it("should handle all directions with same color", () => {
|
|
506
|
+
const color = COLORS["blue-500"];
|
|
507
|
+
expect(parseColor("border-t-blue-500")).toEqual({ borderTopColor: color });
|
|
508
|
+
expect(parseColor("border-r-blue-500")).toEqual({ borderRightColor: color });
|
|
509
|
+
expect(parseColor("border-b-blue-500")).toEqual({ borderBottomColor: color });
|
|
510
|
+
expect(parseColor("border-l-blue-500")).toEqual({ borderLeftColor: color });
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it("should handle all color families for directional borders", () => {
|
|
514
|
+
const families = ["gray", "red", "blue", "green", "yellow", "purple", "pink", "orange", "indigo"];
|
|
515
|
+
families.forEach((family) => {
|
|
516
|
+
expect(parseColor(`border-t-${family}-500`)).toBeTruthy();
|
|
517
|
+
expect(parseColor(`border-r-${family}-500`)).toBeTruthy();
|
|
518
|
+
expect(parseColor(`border-b-${family}-500`)).toBeTruthy();
|
|
519
|
+
expect(parseColor(`border-l-${family}-500`)).toBeTruthy();
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it("should handle directional borders with all opacity levels", () => {
|
|
524
|
+
expect(parseColor("border-t-black/0")).toEqual({ borderTopColor: "#00000000" });
|
|
525
|
+
expect(parseColor("border-t-black/25")).toEqual({ borderTopColor: "#00000040" });
|
|
526
|
+
expect(parseColor("border-t-black/50")).toEqual({ borderTopColor: "#00000080" });
|
|
527
|
+
expect(parseColor("border-t-black/75")).toEqual({ borderTopColor: "#000000BF" });
|
|
528
|
+
expect(parseColor("border-t-black/100")).toEqual({ borderTopColor: "#000000FF" });
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
describe("parseColor - border-x and border-y colors", () => {
|
|
533
|
+
it("should parse border-x colors (horizontal: left + right)", () => {
|
|
534
|
+
expect(parseColor("border-x-red-500")).toEqual({
|
|
535
|
+
borderLeftColor: COLORS["red-500"],
|
|
536
|
+
borderRightColor: COLORS["red-500"],
|
|
537
|
+
});
|
|
538
|
+
expect(parseColor("border-x-blue-500")).toEqual({
|
|
539
|
+
borderLeftColor: COLORS["blue-500"],
|
|
540
|
+
borderRightColor: COLORS["blue-500"],
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
it("should parse border-y colors (vertical: top + bottom)", () => {
|
|
545
|
+
expect(parseColor("border-y-green-500")).toEqual({
|
|
546
|
+
borderTopColor: COLORS["green-500"],
|
|
547
|
+
borderBottomColor: COLORS["green-500"],
|
|
548
|
+
});
|
|
549
|
+
expect(parseColor("border-y-yellow-500")).toEqual({
|
|
550
|
+
borderTopColor: COLORS["yellow-500"],
|
|
551
|
+
borderBottomColor: COLORS["yellow-500"],
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it("should parse border-x with basic colors", () => {
|
|
556
|
+
expect(parseColor("border-x-white")).toEqual({
|
|
557
|
+
borderLeftColor: "#FFFFFF",
|
|
558
|
+
borderRightColor: "#FFFFFF",
|
|
559
|
+
});
|
|
560
|
+
expect(parseColor("border-x-black")).toEqual({
|
|
561
|
+
borderLeftColor: "#000000",
|
|
562
|
+
borderRightColor: "#000000",
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it("should parse border-y with basic colors", () => {
|
|
567
|
+
expect(parseColor("border-y-white")).toEqual({
|
|
568
|
+
borderTopColor: "#FFFFFF",
|
|
569
|
+
borderBottomColor: "#FFFFFF",
|
|
570
|
+
});
|
|
571
|
+
expect(parseColor("border-y-transparent")).toEqual({
|
|
572
|
+
borderTopColor: "transparent",
|
|
573
|
+
borderBottomColor: "transparent",
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
it("should parse border-x with opacity", () => {
|
|
578
|
+
expect(parseColor("border-x-red-500/50")).toEqual({
|
|
579
|
+
borderLeftColor: applyOpacity(COLORS["red-500"], 50),
|
|
580
|
+
borderRightColor: applyOpacity(COLORS["red-500"], 50),
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it("should parse border-y with opacity", () => {
|
|
585
|
+
expect(parseColor("border-y-blue-500/80")).toEqual({
|
|
586
|
+
borderTopColor: applyOpacity(COLORS["blue-500"], 80),
|
|
587
|
+
borderBottomColor: applyOpacity(COLORS["blue-500"], 80),
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
it("should parse border-x with arbitrary hex colors", () => {
|
|
592
|
+
expect(parseColor("border-x-[#ff0000]")).toEqual({
|
|
593
|
+
borderLeftColor: "#ff0000",
|
|
594
|
+
borderRightColor: "#ff0000",
|
|
595
|
+
});
|
|
596
|
+
expect(parseColor("border-x-[#abc]")).toEqual({
|
|
597
|
+
borderLeftColor: "#aabbcc",
|
|
598
|
+
borderRightColor: "#aabbcc",
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it("should parse border-y with arbitrary hex colors", () => {
|
|
603
|
+
expect(parseColor("border-y-[#00ff00]")).toEqual({
|
|
604
|
+
borderTopColor: "#00ff00",
|
|
605
|
+
borderBottomColor: "#00ff00",
|
|
606
|
+
});
|
|
607
|
+
expect(parseColor("border-y-[#123]")).toEqual({
|
|
608
|
+
borderTopColor: "#112233",
|
|
609
|
+
borderBottomColor: "#112233",
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it("should parse border-x with custom colors", () => {
|
|
614
|
+
const customColors = { "brand-primary": "#FF6B6B" };
|
|
615
|
+
expect(parseColor("border-x-brand-primary", customColors)).toEqual({
|
|
616
|
+
borderLeftColor: "#FF6B6B",
|
|
617
|
+
borderRightColor: "#FF6B6B",
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("should parse border-y with custom colors", () => {
|
|
622
|
+
const customColors = { accent: "#FFE66D" };
|
|
623
|
+
expect(parseColor("border-y-accent", customColors)).toEqual({
|
|
624
|
+
borderTopColor: "#FFE66D",
|
|
625
|
+
borderBottomColor: "#FFE66D",
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("should not match border-x/border-y width classes", () => {
|
|
630
|
+
expect(parseColor("border-x-2")).toBeNull();
|
|
631
|
+
expect(parseColor("border-y-4")).toBeNull();
|
|
632
|
+
expect(parseColor("border-x-0")).toBeNull();
|
|
633
|
+
expect(parseColor("border-y-8")).toBeNull();
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
it("should not match border-x/border-y arbitrary width values", () => {
|
|
637
|
+
expect(parseColor("border-x-[3px]")).toBeNull();
|
|
638
|
+
expect(parseColor("border-y-[5px]")).toBeNull();
|
|
639
|
+
expect(parseColor("border-x-[10]")).toBeNull();
|
|
640
|
+
expect(parseColor("border-y-[8px]")).toBeNull();
|
|
641
|
+
});
|
|
642
|
+
});
|
package/src/parser/colors.ts
CHANGED
|
@@ -178,5 +178,43 @@ export function parseColor(cls: string, customColors?: Record<string, string>):
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
// Directional border colors: border-t-red-500, border-l-blue-500/50, border-r-[#ff0000]
|
|
182
|
+
const dirBorderMatch = cls.match(/^border-([trblxy])-(.+)$/);
|
|
183
|
+
if (dirBorderMatch) {
|
|
184
|
+
const dir = dirBorderMatch[1];
|
|
185
|
+
const colorKey = dirBorderMatch[2];
|
|
186
|
+
|
|
187
|
+
// Skip arbitrary values that don't look like colors (e.g., border-t-[3px] is width)
|
|
188
|
+
if (colorKey.startsWith("[") && !colorKey.startsWith("[#")) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const color = parseColorWithOpacity(colorKey);
|
|
193
|
+
if (color) {
|
|
194
|
+
// Map direction to React Native property/properties
|
|
195
|
+
// x and y apply to multiple sides (RN doesn't have borderHorizontalColor/borderVerticalColor)
|
|
196
|
+
if (dir === "x") {
|
|
197
|
+
return {
|
|
198
|
+
borderLeftColor: color,
|
|
199
|
+
borderRightColor: color,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (dir === "y") {
|
|
203
|
+
return {
|
|
204
|
+
borderTopColor: color,
|
|
205
|
+
borderBottomColor: color,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const propMap: Record<string, string> = {
|
|
210
|
+
t: "borderTopColor",
|
|
211
|
+
r: "borderRightColor",
|
|
212
|
+
b: "borderBottomColor",
|
|
213
|
+
l: "borderLeftColor",
|
|
214
|
+
};
|
|
215
|
+
return { [propMap[dir]]: color };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
181
219
|
return null;
|
|
182
220
|
}
|
package/src/parser/index.ts
CHANGED
|
@@ -50,10 +50,10 @@ export function parseClassName(className: string, customTheme?: CustomTheme): St
|
|
|
50
50
|
export function parseClass(cls: string, customTheme?: CustomTheme): StyleObject {
|
|
51
51
|
// Try each parser in order
|
|
52
52
|
// Note: parseBorder must come before parseColor to avoid border-[3px] being parsed as a color
|
|
53
|
-
// parseColor and parseTypography get custom theme
|
|
53
|
+
// parseBorder, parseColor and parseTypography get custom theme
|
|
54
54
|
const parsers: Array<(cls: string) => StyleObject | null> = [
|
|
55
55
|
parseSpacing,
|
|
56
|
-
parseBorder,
|
|
56
|
+
(cls: string) => parseBorder(cls, customTheme?.colors),
|
|
57
57
|
(cls: string) => parseColor(cls, customTheme?.colors),
|
|
58
58
|
parseLayout,
|
|
59
59
|
(cls: string) => parseTypography(cls, customTheme?.fontFamily, customTheme?.fontSize),
|
|
@@ -97,6 +97,7 @@ export {
|
|
|
97
97
|
hasModifier,
|
|
98
98
|
isColorClass,
|
|
99
99
|
isColorSchemeModifier,
|
|
100
|
+
isDirectionalModifier,
|
|
100
101
|
isPlatformModifier,
|
|
101
102
|
isSchemeModifier,
|
|
102
103
|
isStateModifier,
|
|
@@ -105,6 +106,7 @@ export {
|
|
|
105
106
|
} from "./modifiers";
|
|
106
107
|
export type {
|
|
107
108
|
ColorSchemeModifierType,
|
|
109
|
+
DirectionalModifierType,
|
|
108
110
|
ModifierType,
|
|
109
111
|
ParsedModifier,
|
|
110
112
|
PlatformModifierType,
|
|
@@ -645,3 +645,77 @@ describe("parseLayout - specific property coverage", () => {
|
|
|
645
645
|
expect(insetY).not.toHaveProperty("right");
|
|
646
646
|
});
|
|
647
647
|
});
|
|
648
|
+
|
|
649
|
+
describe("parseLayout - logical positioning (RTL-aware)", () => {
|
|
650
|
+
it("should parse start positioning with preset values", () => {
|
|
651
|
+
expect(parseLayout("start-0")).toEqual({ start: 0 });
|
|
652
|
+
expect(parseLayout("start-4")).toEqual({ start: 16 });
|
|
653
|
+
expect(parseLayout("start-8")).toEqual({ start: 32 });
|
|
654
|
+
expect(parseLayout("start-0.5")).toEqual({ start: 2 });
|
|
655
|
+
expect(parseLayout("start-2.5")).toEqual({ start: 10 });
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
it("should parse end positioning with preset values", () => {
|
|
659
|
+
expect(parseLayout("end-0")).toEqual({ end: 0 });
|
|
660
|
+
expect(parseLayout("end-4")).toEqual({ end: 16 });
|
|
661
|
+
expect(parseLayout("end-8")).toEqual({ end: 32 });
|
|
662
|
+
expect(parseLayout("end-0.5")).toEqual({ end: 2 });
|
|
663
|
+
expect(parseLayout("end-2.5")).toEqual({ end: 10 });
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
it("should parse start/end with arbitrary pixel values", () => {
|
|
667
|
+
expect(parseLayout("start-[10px]")).toEqual({ start: 10 });
|
|
668
|
+
expect(parseLayout("start-[50]")).toEqual({ start: 50 });
|
|
669
|
+
expect(parseLayout("end-[10px]")).toEqual({ end: 10 });
|
|
670
|
+
expect(parseLayout("end-[50]")).toEqual({ end: 50 });
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("should parse start/end with arbitrary percentage values", () => {
|
|
674
|
+
expect(parseLayout("start-[10%]")).toEqual({ start: "10%" });
|
|
675
|
+
expect(parseLayout("start-[50%]")).toEqual({ start: "50%" });
|
|
676
|
+
expect(parseLayout("end-[10%]")).toEqual({ end: "10%" });
|
|
677
|
+
expect(parseLayout("end-[50%]")).toEqual({ end: "50%" });
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
it("should parse negative start/end with preset values", () => {
|
|
681
|
+
expect(parseLayout("-start-4")).toEqual({ start: -16 });
|
|
682
|
+
expect(parseLayout("-start-8")).toEqual({ start: -32 });
|
|
683
|
+
expect(parseLayout("-end-4")).toEqual({ end: -16 });
|
|
684
|
+
expect(parseLayout("-end-8")).toEqual({ end: -32 });
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it("should parse negative start/end with arbitrary values", () => {
|
|
688
|
+
expect(parseLayout("-start-[10px]")).toEqual({ start: -10 });
|
|
689
|
+
expect(parseLayout("-start-[50]")).toEqual({ start: -50 });
|
|
690
|
+
expect(parseLayout("-end-[10px]")).toEqual({ end: -10 });
|
|
691
|
+
expect(parseLayout("-end-[50]")).toEqual({ end: -50 });
|
|
692
|
+
expect(parseLayout("-start-[10%]")).toEqual({ start: "-10%" });
|
|
693
|
+
expect(parseLayout("-end-[25%]")).toEqual({ end: "-25%" });
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it("should handle auto value for start/end", () => {
|
|
697
|
+
expect(parseLayout("start-auto")).toEqual({});
|
|
698
|
+
expect(parseLayout("end-auto")).toEqual({});
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
describe("parseLayout - logical inset (RTL-aware)", () => {
|
|
703
|
+
it("should parse inset-s (start) with preset values", () => {
|
|
704
|
+
expect(parseLayout("inset-s-0")).toEqual({ start: 0 });
|
|
705
|
+
expect(parseLayout("inset-s-4")).toEqual({ start: 16 });
|
|
706
|
+
expect(parseLayout("inset-s-8")).toEqual({ start: 32 });
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
it("should parse inset-e (end) with preset values", () => {
|
|
710
|
+
expect(parseLayout("inset-e-0")).toEqual({ end: 0 });
|
|
711
|
+
expect(parseLayout("inset-e-4")).toEqual({ end: 16 });
|
|
712
|
+
expect(parseLayout("inset-e-8")).toEqual({ end: 32 });
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
it("should parse inset-s/inset-e with arbitrary values", () => {
|
|
716
|
+
expect(parseLayout("inset-s-[10px]")).toEqual({ start: 10 });
|
|
717
|
+
expect(parseLayout("inset-s-[20%]")).toEqual({ start: "20%" });
|
|
718
|
+
expect(parseLayout("inset-e-[10px]")).toEqual({ end: 10 });
|
|
719
|
+
expect(parseLayout("inset-e-[20%]")).toEqual({ end: "20%" });
|
|
720
|
+
});
|
|
721
|
+
});
|
package/src/parser/layout.ts
CHANGED
|
@@ -339,6 +339,68 @@ export function parseLayout(cls: string): StyleObject | null {
|
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
// Start positioning (RTL-aware): start-0, start-4, start-[10px], -start-4, etc.
|
|
343
|
+
const startMatch = cls.match(/^(-?)start-(.+)$/);
|
|
344
|
+
if (startMatch) {
|
|
345
|
+
const [, negPrefix, startKey] = startMatch;
|
|
346
|
+
const isNegative = negPrefix === "-";
|
|
347
|
+
|
|
348
|
+
// Auto value - return empty object (no-op, removes the property)
|
|
349
|
+
if (startKey === "auto") {
|
|
350
|
+
return {};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Arbitrary values: start-[123px], start-[50%], -start-[10px]
|
|
354
|
+
const arbitraryStart = parseArbitraryInset(startKey);
|
|
355
|
+
if (arbitraryStart !== null) {
|
|
356
|
+
if (typeof arbitraryStart === "number") {
|
|
357
|
+
return { start: isNegative ? -arbitraryStart : arbitraryStart };
|
|
358
|
+
}
|
|
359
|
+
// Percentage values with negative prefix
|
|
360
|
+
if (isNegative && arbitraryStart.endsWith("%")) {
|
|
361
|
+
const numValue = parseFloat(arbitraryStart);
|
|
362
|
+
return { start: `${-numValue}%` };
|
|
363
|
+
}
|
|
364
|
+
return { start: arbitraryStart };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const startValue = INSET_SCALE[startKey];
|
|
368
|
+
if (startValue !== undefined) {
|
|
369
|
+
return { start: isNegative ? -startValue : startValue };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// End positioning (RTL-aware): end-0, end-4, end-[10px], -end-4, etc.
|
|
374
|
+
const endMatch = cls.match(/^(-?)end-(.+)$/);
|
|
375
|
+
if (endMatch) {
|
|
376
|
+
const [, negPrefix, endKey] = endMatch;
|
|
377
|
+
const isNegative = negPrefix === "-";
|
|
378
|
+
|
|
379
|
+
// Auto value - return empty object (no-op, removes the property)
|
|
380
|
+
if (endKey === "auto") {
|
|
381
|
+
return {};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Arbitrary values: end-[123px], end-[50%], -end-[10px]
|
|
385
|
+
const arbitraryEnd = parseArbitraryInset(endKey);
|
|
386
|
+
if (arbitraryEnd !== null) {
|
|
387
|
+
if (typeof arbitraryEnd === "number") {
|
|
388
|
+
return { end: isNegative ? -arbitraryEnd : arbitraryEnd };
|
|
389
|
+
}
|
|
390
|
+
// Percentage values with negative prefix
|
|
391
|
+
if (isNegative && arbitraryEnd.endsWith("%")) {
|
|
392
|
+
const numValue = parseFloat(arbitraryEnd);
|
|
393
|
+
return { end: `${-numValue}%` };
|
|
394
|
+
}
|
|
395
|
+
return { end: arbitraryEnd };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const endValue = INSET_SCALE[endKey];
|
|
399
|
+
if (endValue !== undefined) {
|
|
400
|
+
return { end: isNegative ? -endValue : endValue };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
342
404
|
// Inset X (left and right): inset-x-0, inset-x-4, inset-x-[10px], etc.
|
|
343
405
|
if (cls.startsWith("inset-x-")) {
|
|
344
406
|
const insetKey = cls.substring(8);
|
|
@@ -371,6 +433,38 @@ export function parseLayout(cls: string): StyleObject | null {
|
|
|
371
433
|
}
|
|
372
434
|
}
|
|
373
435
|
|
|
436
|
+
// Inset S (start, RTL-aware): inset-s-0, inset-s-4, inset-s-[10px], etc.
|
|
437
|
+
if (cls.startsWith("inset-s-")) {
|
|
438
|
+
const insetKey = cls.substring(8);
|
|
439
|
+
|
|
440
|
+
// Arbitrary values: inset-s-[123px], inset-s-[50%]
|
|
441
|
+
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
442
|
+
if (arbitraryInset !== null) {
|
|
443
|
+
return { start: arbitraryInset };
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const insetValue = INSET_SCALE[insetKey];
|
|
447
|
+
if (insetValue !== undefined) {
|
|
448
|
+
return { start: insetValue };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Inset E (end, RTL-aware): inset-e-0, inset-e-4, inset-e-[10px], etc.
|
|
453
|
+
if (cls.startsWith("inset-e-")) {
|
|
454
|
+
const insetKey = cls.substring(8);
|
|
455
|
+
|
|
456
|
+
// Arbitrary values: inset-e-[123px], inset-e-[50%]
|
|
457
|
+
const arbitraryInset = parseArbitraryInset(insetKey);
|
|
458
|
+
if (arbitraryInset !== null) {
|
|
459
|
+
return { end: arbitraryInset };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const insetValue = INSET_SCALE[insetKey];
|
|
463
|
+
if (insetValue !== undefined) {
|
|
464
|
+
return { end: insetValue };
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
374
468
|
// Inset (all sides): inset-0, inset-4, inset-[10px], etc.
|
|
375
469
|
if (cls.startsWith("inset-")) {
|
|
376
470
|
const insetKey = cls.substring(6);
|