feat(components): DialTile for sensor signal rows
This commit is contained in:
1 parent
bea019fb0f
commit
8232882977
2 files changed
+99
No files matched your search
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import TestRenderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
import { DialTile } from '../components/DialTile';
|
||||||
|
|
||||||
|
describe('DialTile', () => {
|
||||||
|
it('renders label and value', () => {
|
||||||
|
let tree: any;
|
||||||
|
TestRenderer.act(() => {
|
||||||
|
tree = TestRenderer.create(React.createElement(DialTile, { label: 'RSSI', value: '-61 dBm', testID: 'dial' }));
|
||||||
|
});
|
||||||
|
const json = JSON.stringify(tree.toJSON());
|
||||||
|
expect(json).toContain('RSSI');
|
||||||
|
expect(json).toContain('-61 dBm');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('combines label and value into accessibilityLabel', () => {
|
||||||
|
let tree: any;
|
||||||
|
TestRenderer.act(() => {
|
||||||
|
tree = TestRenderer.create(React.createElement(DialTile, { label: 'RSSI', value: '-61 dBm', testID: 'dial' }));
|
||||||
|
});
|
||||||
|
const json = JSON.stringify(tree.toJSON());
|
||||||
|
expect(json).toContain('"accessibilityLabel":"RSSI: -61 dBm"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses action color when tone=red', () => {
|
||||||
|
let tree: any;
|
||||||
|
TestRenderer.act(() => {
|
||||||
|
tree = TestRenderer.create(React.createElement(DialTile, { label: 'X', value: 'Y', tone: 'red', testID: 'dial' }));
|
||||||
|
});
|
||||||
|
const json = JSON.stringify(tree.toJSON());
|
||||||
|
expect(json).toContain('#E23B2E');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, View, type ViewStyle } from 'react-native';
|
||||||
|
import { colors, spacing, typography } from '../theme';
|
||||||
|
|
||||||
|
type Tone = 'amber' | 'green' | 'red';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
readonly label: string;
|
||||||
|
readonly value: string;
|
||||||
|
readonly tone?: Tone;
|
||||||
|
readonly testID?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function toneColor(tone: Tone | undefined): string {
|
||||||
|
if (tone === 'red') return colors.action;
|
||||||
|
if (tone === 'green') return colors.success;
|
||||||
|
return colors.warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DialTile({ label, value, tone = 'amber', testID }: Props) {
|
||||||
|
const markerStyle: ViewStyle = { backgroundColor: toneColor(tone) };
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
accessibilityLabel={`${label}: ${value}`}
|
||||||
|
style={styles.row}
|
||||||
|
testID={testID}
|
||||||
|
>
|
||||||
|
<View style={styles.markerWrap}>
|
||||||
|
<View style={[styles.marker, markerStyle]} />
|
||||||
|
</View>
|
||||||
|
<Text style={styles.value}>{value}</Text>
|
||||||
|
<Text style={styles.label}>{label}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
row: {
|
||||||
|
minHeight: 56,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderColor: colors.line,
|
||||||
|
paddingVertical: spacing.sm,
|
||||||
|
paddingHorizontal: spacing.md,
|
||||||
|
gap: spacing.md,
|
||||||
|
},
|
||||||
|
markerWrap: {
|
||||||
|
width: 4,
|
||||||
|
height: 32,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
marker: {
|
||||||
|
width: 2,
|
||||||
|
height: 32,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
...typography.detailNumeric,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
...typography.label,
|
||||||
|
color: colors.textDim,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in new issue
Block a user