|
13 | 13 | import type {RNTesterModule} from '../../types/RNTesterTypes'; |
14 | 14 |
|
15 | 15 | import hotdog from '../../assets/hotdog.jpg'; |
| 16 | +import RNTesterText from '../../components/RNTesterText'; |
16 | 17 | import * as React from 'react'; |
17 | 18 | import { |
18 | 19 | DynamicColorIOS, |
@@ -257,6 +258,33 @@ const styles = StyleSheet.create({ |
257 | 258 | top: -10, |
258 | 259 | backgroundColor: 'blue', |
259 | 260 | }, |
| 261 | + hairlineBox: { |
| 262 | + width: 44, |
| 263 | + height: 44, |
| 264 | + borderWidth: StyleSheet.hairlineWidth, |
| 265 | + borderColor: 'black', |
| 266 | + backgroundColor: '#f5f5f5', |
| 267 | + }, |
| 268 | + hairlineBoxContainer: { |
| 269 | + alignItems: 'center', |
| 270 | + marginRight: 8, |
| 271 | + }, |
| 272 | + hairlineRow: { |
| 273 | + borderBottomWidth: StyleSheet.hairlineWidth, |
| 274 | + borderColor: 'black', |
| 275 | + justifyContent: 'center', |
| 276 | + paddingHorizontal: 4, |
| 277 | + }, |
| 278 | + subpixelLabel: { |
| 279 | + fontSize: 9, |
| 280 | + marginTop: 4, |
| 281 | + }, |
| 282 | + sectionTitle: { |
| 283 | + fontSize: 11, |
| 284 | + fontWeight: 'bold', |
| 285 | + marginBottom: 6, |
| 286 | + marginTop: 10, |
| 287 | + }, |
260 | 288 | }); |
261 | 289 |
|
262 | 290 | export default { |
@@ -622,5 +650,108 @@ export default { |
622 | 650 | ); |
623 | 651 | }, |
624 | 652 | }, |
| 653 | + { |
| 654 | + title: 'Hairline borders at subpixel Y offsets', |
| 655 | + name: 'hairline-subpixel-y-offsets', |
| 656 | + description: |
| 657 | + 'Ensure hairlineWidth borders render completely on all sides even when positioned at fractional/subpixel Y offsets on iOS', |
| 658 | + render: function (): React.Node { |
| 659 | + const subpixelYOffsets = [0, 0.25, 0.33, 0.5, 0.67, 0.75]; |
| 660 | + return ( |
| 661 | + <View testID="border-test-hairline-subpixel-y-offsets"> |
| 662 | + <RNTesterText style={styles.sectionTitle}> |
| 663 | + Boxes at fractional Y offsets (borderWidth = hairlineWidth): |
| 664 | + </RNTesterText> |
| 665 | + <View style={styles.wrapper}> |
| 666 | + {subpixelYOffsets.map(yOffset => ( |
| 667 | + <View key={yOffset} style={styles.hairlineBoxContainer}> |
| 668 | + <View style={[styles.hairlineBox, {top: yOffset}]} /> |
| 669 | + <RNTesterText style={styles.subpixelLabel}> |
| 670 | + {`+${yOffset}pt`} |
| 671 | + </RNTesterText> |
| 672 | + </View> |
| 673 | + ))} |
| 674 | + </View> |
| 675 | + |
| 676 | + <RNTesterText style={styles.sectionTitle}> |
| 677 | + Stacked rows with hairline bottom borders (fractional heights): |
| 678 | + </RNTesterText> |
| 679 | + <View> |
| 680 | + {subpixelYOffsets.map((fraction, index) => ( |
| 681 | + <View |
| 682 | + key={index} |
| 683 | + style={[styles.hairlineRow, {height: 24 + fraction}]}> |
| 684 | + <RNTesterText style={styles.subpixelLabel}> |
| 685 | + {`Row ${index + 1} (height: ${(24 + fraction).toFixed(2)}pt)`} |
| 686 | + </RNTesterText> |
| 687 | + </View> |
| 688 | + ))} |
| 689 | + </View> |
| 690 | + |
| 691 | + <RNTesterText style={styles.sectionTitle}> |
| 692 | + Single-side hairline borders at fractional Y offset (+0.33pt): |
| 693 | + </RNTesterText> |
| 694 | + <View style={styles.wrapper}> |
| 695 | + <View style={styles.hairlineBoxContainer}> |
| 696 | + <View |
| 697 | + style={[ |
| 698 | + styles.hairlineBox, |
| 699 | + { |
| 700 | + borderWidth: 0, |
| 701 | + borderTopWidth: StyleSheet.hairlineWidth, |
| 702 | + borderColor: 'red', |
| 703 | + top: 0.33, |
| 704 | + }, |
| 705 | + ]} |
| 706 | + /> |
| 707 | + <RNTesterText style={styles.subpixelLabel}>top</RNTesterText> |
| 708 | + </View> |
| 709 | + <View style={styles.hairlineBoxContainer}> |
| 710 | + <View |
| 711 | + style={[ |
| 712 | + styles.hairlineBox, |
| 713 | + { |
| 714 | + borderWidth: 0, |
| 715 | + borderBottomWidth: StyleSheet.hairlineWidth, |
| 716 | + borderColor: 'red', |
| 717 | + top: 0.33, |
| 718 | + }, |
| 719 | + ]} |
| 720 | + /> |
| 721 | + <RNTesterText style={styles.subpixelLabel}>bottom</RNTesterText> |
| 722 | + </View> |
| 723 | + <View style={styles.hairlineBoxContainer}> |
| 724 | + <View |
| 725 | + style={[ |
| 726 | + styles.hairlineBox, |
| 727 | + { |
| 728 | + borderWidth: 0, |
| 729 | + borderLeftWidth: StyleSheet.hairlineWidth, |
| 730 | + borderColor: 'red', |
| 731 | + top: 0.33, |
| 732 | + }, |
| 733 | + ]} |
| 734 | + /> |
| 735 | + <RNTesterText style={styles.subpixelLabel}>left</RNTesterText> |
| 736 | + </View> |
| 737 | + <View style={styles.hairlineBoxContainer}> |
| 738 | + <View |
| 739 | + style={[ |
| 740 | + styles.hairlineBox, |
| 741 | + { |
| 742 | + borderWidth: 0, |
| 743 | + borderRightWidth: StyleSheet.hairlineWidth, |
| 744 | + borderColor: 'red', |
| 745 | + top: 0.33, |
| 746 | + }, |
| 747 | + ]} |
| 748 | + /> |
| 749 | + <RNTesterText style={styles.subpixelLabel}>right</RNTesterText> |
| 750 | + </View> |
| 751 | + </View> |
| 752 | + </View> |
| 753 | + ); |
| 754 | + }, |
| 755 | + }, |
625 | 756 | ], |
626 | 757 | } as RNTesterModule; |
0 commit comments