From 9377f966896b4cc592ab7be102bfe6a0934e7c7c Mon Sep 17 00:00:00 2001 From: Barry van Veen Date: Thu, 4 Jun 2026 11:51:46 +0200 Subject: [PATCH 1/6] Add components for bottom sheet lists --- src/components/CapitalizeText.tsx | 17 + src/components/InputPanel.tsx | 93 +++ src/components/ItemSeparator.tsx | 31 + src/components/ListItem.tsx | 92 +++ src/components/SectionHeader.tsx | 35 + src/components/SingleLine.tsx | 15 + .../__tests__/CapitalizeText.test.tsx | 32 + src/components/__tests__/InputPanel.test.tsx | 80 ++ .../__tests__/ItemSeparator.test.tsx | 33 + src/components/__tests__/ListItem.test.tsx | 76 ++ .../__tests__/SectionHeader.test.tsx | 26 + src/components/__tests__/SingleLine.test.tsx | 13 + .../__snapshots__/InputPanel.test.tsx.snap | 714 ++++++++++++++++++ .../__snapshots__/ItemSeparator.test.tsx.snap | 45 ++ .../__snapshots__/ListItem.test.tsx.snap | 619 +++++++++++++++ .../__snapshots__/SectionHeader.test.tsx.snap | 67 ++ .../__snapshots__/SingleLine.test.tsx.snap | 10 + src/lib/Utils.ts | 2 + src/lib/__tests__/Utils.test.ts | 15 + 19 files changed, 2015 insertions(+) create mode 100644 src/components/CapitalizeText.tsx create mode 100644 src/components/InputPanel.tsx create mode 100644 src/components/ItemSeparator.tsx create mode 100644 src/components/ListItem.tsx create mode 100644 src/components/SectionHeader.tsx create mode 100644 src/components/SingleLine.tsx create mode 100644 src/components/__tests__/CapitalizeText.test.tsx create mode 100644 src/components/__tests__/InputPanel.test.tsx create mode 100644 src/components/__tests__/ItemSeparator.test.tsx create mode 100644 src/components/__tests__/ListItem.test.tsx create mode 100644 src/components/__tests__/SectionHeader.test.tsx create mode 100644 src/components/__tests__/SingleLine.test.tsx create mode 100644 src/components/__tests__/__snapshots__/InputPanel.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/ItemSeparator.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/ListItem.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/SectionHeader.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/SingleLine.test.tsx.snap create mode 100644 src/lib/__tests__/Utils.test.ts diff --git a/src/components/CapitalizeText.tsx b/src/components/CapitalizeText.tsx new file mode 100644 index 0000000..0df997e --- /dev/null +++ b/src/components/CapitalizeText.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { Text, TextProps } from 'react-native' + +import { capitalize } from '../lib/Utils' + +/** + * Renders the children, capitalizing the first child when this is a string + */ +const CapitalizeText = ({ children, ...props }: TextProps) => ( + + {React.Children.map(children, (child, index) => + index === 0 && typeof child === 'string' ? capitalize(child) : child, + )} + +) + +export default CapitalizeText diff --git a/src/components/InputPanel.tsx b/src/components/InputPanel.tsx new file mode 100644 index 0000000..53755db --- /dev/null +++ b/src/components/InputPanel.tsx @@ -0,0 +1,93 @@ +import React from 'react' +import { StyleProp, StyleSheet, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native' + +import { Icon } from '@observation.org/react-native-components' +import { type Theme, useStyles, useTheme } from '@observation.org/react-native-components/theme' + +import CapitalizeText from './CapitalizeText' + +type Props = { + label?: string + value?: string + onPress: () => void + containerStyle?: StyleProp + valueStyle?: StyleProp + disabled?: boolean + capitalize?: boolean + showChevron?: boolean +} + +const InputPanel = ({ + label, + value, + containerStyle, + valueStyle, + onPress, + disabled = false, + capitalize = false, + showChevron = true, +}: Props) => { + const theme = useTheme() + const styles = useStyles(createStyles) + + // todo: 48 and 36 should be input heights and we should make them dynamically themed + const paddingVertical = label + ? (48 - (styles.headerTextStyle.lineHeight! + styles.value.lineHeight!)) / 2 + : (36 - styles.value.lineHeight!) / 2 + + return ( + + + {label && ( + + {label} + + )} + {capitalize && value ? ( + + {value} + + ) : ( + + {value || ' '} + + )} + + {showChevron && ( + + + + )} + + ) +} + +// todo: dit werd geexporteerd als een observer +export default InputPanel + +const createStyles = (theme: Theme) => + StyleSheet.create({ + container: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: theme.margin.common, + }, + headerTextStyle: { + ...theme.font.extraSmall, + lineHeight: theme.font.extraSmall.fontSize, + letterSpacing: 0.3, // todo: should this be dynamic? + color: theme.color.text.system.subtler, + }, + contentContainer: { + flex: 1, + flexDirection: 'column', + }, + value: { + ...theme.font.medium, + color: theme.color.text.system.strong, + }, + icon: { + marginLeft: theme.margin.half, + }, + }) diff --git a/src/components/ItemSeparator.tsx b/src/components/ItemSeparator.tsx new file mode 100644 index 0000000..75f59d3 --- /dev/null +++ b/src/components/ItemSeparator.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native' + +import { type Theme, useStyles } from '@observation.org/react-native-components/theme' + +type Orientation = 'horizontal' | 'vertical' + +type Props = { + style?: StyleProp + orientation?: Orientation +} + +const ItemSeparator = ({ style, orientation = 'horizontal' }: Props) => { + const styles = useStyles(createStyles) + const separatorStyle = orientation === 'horizontal' ? styles.horizontalSeparator : styles.verticalSeparator + return +} + +export default ItemSeparator + +const createStyles = (theme: Theme) => + StyleSheet.create({ + horizontalSeparator: { + borderBottomWidth: 1, + borderBottomColor: theme.color.background.system.surfaceRaised, + }, + verticalSeparator: { + borderRightWidth: 1, + borderRightColor: theme.color.background.system.surfaceRaised, + }, + }) diff --git a/src/components/ListItem.tsx b/src/components/ListItem.tsx new file mode 100644 index 0000000..02c44bd --- /dev/null +++ b/src/components/ListItem.tsx @@ -0,0 +1,92 @@ +import React from 'react' +import { StyleSheet, TouchableOpacity, View } from 'react-native' + +import { Icon, IconProps } from '@observation.org/react-native-components' +import { type Theme, useStyles, useTheme } from '@observation.org/react-native-components/theme' + +import SingleLine from './SingleLine' +import Log from '../lib/Log' + +type Props = { + icon?: IconProps + label: string + subLabel?: string + extraSubLabel?: string + onPress?: () => void + selected?: boolean +} + +const ListItem = ({ icon, onPress, label, subLabel, extraSubLabel, selected = false }: Props) => { + Log.trace('ListItem', onPress) + + const theme = useTheme() + const styles = useStyles(createStyles) + + const iconMarginRight = subLabel ? theme.margin.common : theme.margin.half + const containerPaddingVertical = subLabel ? 7 : 13 + const containerBackgroundColor = selected ? theme.color.primary50 : undefined + + const renderIcon = (() => { + switch (true) { + case !!icon: + return ( + + ) + case selected: + return ( + + ) + default: + return ( + + ) + } + })() + + return ( + + + {renderIcon} + + {label} + {subLabel && ( + + {subLabel} + {extraSubLabel && {extraSubLabel}} + + )} + + + + ) +} + +export default ListItem + +const createStyles = (theme: Theme) => + StyleSheet.create({ + containerStyle: { + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: theme.margin.common, + }, + labelTextStyle: { + ...theme.font.medium, + lineHeight: theme.lineHeight.small, + color: theme.color.text.system.strong, + }, + subLabelTextStyle: { + ...theme.font.extraSmall, + color: theme.color.text.system.subtler, + }, + }) diff --git a/src/components/SectionHeader.tsx b/src/components/SectionHeader.tsx new file mode 100644 index 0000000..b9a17df --- /dev/null +++ b/src/components/SectionHeader.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native' + +import { type Theme, useStyles } from '@observation.org/react-native-components/theme' + +type Props = { + title?: string + containerStyle?: StyleProp +} + +const SectionHeader = ({ title, containerStyle }: Props) => { + const styles = useStyles(createStyles) + return ( + + {title && {title}} + + ) +} + +export default SectionHeader + +const createStyles = (theme: Theme) => + StyleSheet.create({ + header: { + paddingHorizontal: theme.margin.common, + marginTop: theme.margin.common, + }, + headerPadding: { + paddingVertical: theme.margin.quarter, + }, + contentHeaderStyle: { + ...theme.font.smallBold, + color: theme.color.text.system.subtler, + }, + }) diff --git a/src/components/SingleLine.tsx b/src/components/SingleLine.tsx new file mode 100644 index 0000000..0653058 --- /dev/null +++ b/src/components/SingleLine.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import { StyleProp, Text, TextStyle } from 'react-native' + +type Props = { + children?: React.ReactNode + style?: StyleProp +} + +const SingleLine = ({ children, style }: Props) => ( + + {children} + +) + +export default SingleLine diff --git a/src/components/__tests__/CapitalizeText.test.tsx b/src/components/__tests__/CapitalizeText.test.tsx new file mode 100644 index 0000000..c53be81 --- /dev/null +++ b/src/components/__tests__/CapitalizeText.test.tsx @@ -0,0 +1,32 @@ +import React from 'react' +import { Text } from 'react-native' + +import { describe, expect, test } from '@jest/globals' +import { render } from '@testing-library/react-native' + +import CapitalizeText from '../CapitalizeText' + +describe('CapitalizeText', () => { + test('Capitalizes the text', () => { + const { queryByText } = render(hello world) + expect(queryByText('Hello world')).toBeTruthy() + }) + + test('With multiple children, the first one being a string, the text is capitalized', () => { + const { queryByText } = render( + + hello world + , + ) + expect(queryByText('Hello world')).toBeTruthy() + }) + + test('When the first child is not a string, no text is capitalized', () => { + const { queryByText } = render( + + hello world + , + ) + expect(queryByText('hello world')).toBeTruthy() + }) +}) diff --git a/src/components/__tests__/InputPanel.test.tsx b/src/components/__tests__/InputPanel.test.tsx new file mode 100644 index 0000000..632d909 --- /dev/null +++ b/src/components/__tests__/InputPanel.test.tsx @@ -0,0 +1,80 @@ +import React from 'react' + +import { describe, expect, jest, test } from '@jest/globals' +import { fireEvent, render } from '@testing-library/react-native' + +import { color } from '../../theme/tokens/color' +import InputPanel from '../InputPanel' + +describe('InputPanel', () => { + const onPress = jest.fn() + + describe('Rendering', () => { + test('With content', () => { + const { toJSON } = render() + + expect(toJSON()).toMatchSnapshot() + }) + + test('No label', () => { + const { toJSON } = render() + + expect(toJSON()).toMatchSnapshot() + }) + + test('No value', () => { + const { toJSON } = render() + + expect(toJSON()).toMatchSnapshot() + }) + + test('Disabled', () => { + const { toJSON } = render() + + expect(toJSON()).toMatchSnapshot() + }) + + test('Capitalize value', () => { + const { toJSON, queryByText } = render( + , + ) + + expect(queryByText('Seen')).toBeTruthy() + expect(toJSON()).toMatchSnapshot() + }) + + test('Without chevron', () => { + const { toJSON } = render( + , + ) + + expect(toJSON()).toMatchSnapshot() + }) + + test('With value style', () => { + const { toJSON } = render( + , + ) + + expect(toJSON()).toMatchSnapshot() + }) + }) + + describe('Interaction', () => { + test('Click', async () => { + // GIVEN + const { getByText } = render() + + // WHEN + await fireEvent.press(getByText('Counting method')) + + // THEN + expect(onPress).toHaveBeenCalledTimes(1) + }) + }) +}) diff --git a/src/components/__tests__/ItemSeparator.test.tsx b/src/components/__tests__/ItemSeparator.test.tsx new file mode 100644 index 0000000..21773b8 --- /dev/null +++ b/src/components/__tests__/ItemSeparator.test.tsx @@ -0,0 +1,33 @@ +import React from 'react' + +import { describe, expect, test } from '@jest/globals' +import { render } from '@testing-library/react-native' + +import { margin } from '../../theme/tokens/margin' +import ItemSeparator from '../ItemSeparator' + +describe('ItemSeparator', () => { + test('Rendering default separator', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering vertical separator', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with custom style separator', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) +}) diff --git a/src/components/__tests__/ListItem.test.tsx b/src/components/__tests__/ListItem.test.tsx new file mode 100644 index 0000000..5c178a8 --- /dev/null +++ b/src/components/__tests__/ListItem.test.tsx @@ -0,0 +1,76 @@ +import React from 'react' + +import { describe, expect, jest, test } from '@jest/globals' +import { IconProps } from '@observation.org/react-native-components' +import { fireEvent, render } from '@testing-library/react-native' + +import { color } from '../../theme/tokens/color' +import ListItem from '../ListItem' + +const onPress = jest.fn() + +describe('ListItem', () => { + describe('Rendering', () => { + test('Rendering', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with radio button unselected', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with radio button selected', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with sub label', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with extra sub label', () => { + // WHEN + const { toJSON } = render( + , + ) + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('Rendering with custom icon', () => { + // WHEN + const icon: IconProps = { name: 'check', color: color.grey300, size: 20, style: 'light' } + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + }) + + test('Interaction', () => { + // GIVEN + const { getByText } = render() + + // WHEN + fireEvent.press(getByText('Read this!')) + + // THEN + expect(onPress).toHaveBeenCalled() + }) +}) diff --git a/src/components/__tests__/SectionHeader.test.tsx b/src/components/__tests__/SectionHeader.test.tsx new file mode 100644 index 0000000..2c0da49 --- /dev/null +++ b/src/components/__tests__/SectionHeader.test.tsx @@ -0,0 +1,26 @@ +import React from 'react' + +import { describe, expect, test } from '@jest/globals' +import { render } from '@testing-library/react-native' + +import SectionHeader from '../SectionHeader' + +describe('SectionHeader', () => { + describe('Rendering', () => { + test('Normal', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + + test('With container style', () => { + // WHEN + const { toJSON } = render() + + // THEN + expect(toJSON()).toMatchSnapshot() + }) + }) +}) diff --git a/src/components/__tests__/SingleLine.test.tsx b/src/components/__tests__/SingleLine.test.tsx new file mode 100644 index 0000000..7800d59 --- /dev/null +++ b/src/components/__tests__/SingleLine.test.tsx @@ -0,0 +1,13 @@ +import React from 'react' + +import { describe, expect, test } from '@jest/globals' +import { render } from '@testing-library/react-native' + +import SingleLine from '../SingleLine' + +describe('SingleLine', () => { + test('Render', () => { + const { toJSON } = render(hello world) + expect(toJSON()).toMatchSnapshot() + }) +}) diff --git a/src/components/__tests__/__snapshots__/InputPanel.test.tsx.snap b/src/components/__tests__/__snapshots__/InputPanel.test.tsx.snap new file mode 100644 index 0000000..04086f8 --- /dev/null +++ b/src/components/__tests__/__snapshots__/InputPanel.test.tsx.snap @@ -0,0 +1,714 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`InputPanel Rendering Capitalize value 1`] = ` + + + + Counting method + + + Seen + + + + + + +`; + +exports[`InputPanel Rendering Disabled 1`] = ` + + + + Counting method + + + seen + + + + + + +`; + +exports[`InputPanel Rendering No label 1`] = ` + + + + Netherlands + + + + + + +`; + +exports[`InputPanel Rendering No value 1`] = ` + + + + Counting method + + + + + + + + + +`; + +exports[`InputPanel Rendering With content 1`] = ` + + + + Counting method + + + seen + + + + + + +`; + +exports[`InputPanel Rendering With value style 1`] = ` + + + + Counting method + + + seen + + + + + + +`; + +exports[`InputPanel Rendering Without chevron 1`] = ` + + + + Counting method + + + seen + + + +`; diff --git a/src/components/__tests__/__snapshots__/ItemSeparator.test.tsx.snap b/src/components/__tests__/__snapshots__/ItemSeparator.test.tsx.snap new file mode 100644 index 0000000..e74a4e1 --- /dev/null +++ b/src/components/__tests__/__snapshots__/ItemSeparator.test.tsx.snap @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`ItemSeparator Rendering default separator 1`] = ` + +`; + +exports[`ItemSeparator Rendering vertical separator 1`] = ` + +`; + +exports[`ItemSeparator Rendering with custom style separator 1`] = ` + +`; diff --git a/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap b/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap new file mode 100644 index 0000000..5a13f98 --- /dev/null +++ b/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap @@ -0,0 +1,619 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`ListItem Rendering Rendering 1`] = ` + + + + + + + + Read this! + + + + +`; + +exports[`ListItem Rendering Rendering with custom icon 1`] = ` + + + + + + + + Read this! + + + + +`; + +exports[`ListItem Rendering Rendering with extra sub label 1`] = ` + + + + + + + + Read this! + + + + Really! + + + Or not + + + + + +`; + +exports[`ListItem Rendering Rendering with radio button selected 1`] = ` + + + + + + + + Read this! + + + + +`; + +exports[`ListItem Rendering Rendering with radio button unselected 1`] = ` + + + + + + + + Read this! + + + + +`; + +exports[`ListItem Rendering Rendering with sub label 1`] = ` + + + + + + + + Read this! + + + + Really! + + + + + +`; diff --git a/src/components/__tests__/__snapshots__/SectionHeader.test.tsx.snap b/src/components/__tests__/__snapshots__/SectionHeader.test.tsx.snap new file mode 100644 index 0000000..74df60d --- /dev/null +++ b/src/components/__tests__/__snapshots__/SectionHeader.test.tsx.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SectionHeader Rendering Normal 1`] = ` + + + Header title + + +`; + +exports[`SectionHeader Rendering With container style 1`] = ` + + + Header title + + +`; diff --git a/src/components/__tests__/__snapshots__/SingleLine.test.tsx.snap b/src/components/__tests__/__snapshots__/SingleLine.test.tsx.snap new file mode 100644 index 0000000..cdb8d3e --- /dev/null +++ b/src/components/__tests__/__snapshots__/SingleLine.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SingleLine Render 1`] = ` + + hello world + +`; diff --git a/src/lib/Utils.ts b/src/lib/Utils.ts index f42b223..7f6a6a2 100644 --- a/src/lib/Utils.ts +++ b/src/lib/Utils.ts @@ -21,3 +21,5 @@ export const deepMerge = (target: T, source: Partial): T => { } return target } + +export const capitalize = (input: string) => input.charAt(0).toUpperCase() + input.slice(1) diff --git a/src/lib/__tests__/Utils.test.ts b/src/lib/__tests__/Utils.test.ts new file mode 100644 index 0000000..514f06e --- /dev/null +++ b/src/lib/__tests__/Utils.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, test } from '@jest/globals' + +import { capitalize } from '../Utils' + +describe('Utils', () => { + test('capitalize', () => { + expect(capitalize('')).toBe('') + expect(capitalize('a')).toBe('A') + expect(capitalize('A')).toBe('A') + expect(capitalize('abc')).toBe('Abc') + expect(capitalize('ABC')).toBe('ABC') + expect(capitalize('aBC')).toBe('ABC') + expect(capitalize('ábc')).toBe('Ábc') + }) +}) From f293db11a09e129530ac66407609dcce4b8354aa Mon Sep 17 00:00:00 2001 From: Barry van Veen Date: Thu, 4 Jun 2026 11:52:22 +0200 Subject: [PATCH 2/6] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de9d87b..ab11023 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@observation.org/react-native-components", - "version": "1.78.0", + "version": "1.79.0", "main": "src/index.ts", "exports": { ".": "./src/index.ts", From 977f4c607e7864129058c2fbdce8097b7d10d4f2 Mon Sep 17 00:00:00 2001 From: Barry van Veen Date: Thu, 4 Jun 2026 12:46:42 +0200 Subject: [PATCH 3/6] Update exports --- src/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/index.ts b/src/index.ts index b6de246..b605483 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import Accordion from './components/Accordion' import BackButton from './components/BackButton' import BackgroundImage from './components/BackgroundImage' import BottomSheet from './components/BottomSheet' +import CapitalizeText from './components/CapitalizeText' import Checkbox from './components/Checkbox' import Chip from './components/Chip' import ContentImage from './components/ContentImage' @@ -12,8 +13,11 @@ import IconButton from './components/IconButton' import IconText from './components/IconText' import IconView from './components/IconView' import InputField from './components/InputField' +import InputPanel from './components/InputPanel' +import ItemSeparator from './components/ItemSeparator' import LargeButton, { LargeButtonProps } from './components/LargeButton' import Lightbox from './components/Lightbox' +import ListItem from './components/ListItem' import Location from './components/Location' import Message from './components/Message' import MoreInfo from './components/MoreInfo' @@ -23,6 +27,8 @@ import PageIndicator from './components/PageIndicator' import Panel from './components/Panel' import Popup from './components/Popup' import ProgressBarList from './components/ProgressBarList' +import SectionHeader from './components/SectionHeader' +import SingleLine from './components/SingleLine' import TextLink from './components/TextLink' import Tooltip, { TooltipProps } from './components/Tooltip' import WebLink from './components/WebLink' @@ -39,6 +45,7 @@ export { BackButton, BackgroundImage, BottomSheet, + CapitalizeText, Checkbox, Chip, ContentImage, @@ -51,8 +58,11 @@ export { Icons, BrandIcons, InputField, + InputPanel, + ItemSeparator, LargeButton, Lightbox, + ListItem, Location, Message, MoreInfo, @@ -63,6 +73,8 @@ export { Popup, ProgressBar, ProgressBarList, + SectionHeader, + SingleLine, TextLink, ThemeProvider, Tooltip, From 3381f91a387fd1de61c40a0123375f04ab262d97 Mon Sep 17 00:00:00 2001 From: Barry van Veen Date: Tue, 9 Jun 2026 13:04:21 +0200 Subject: [PATCH 4/6] Review comments --- src/components/InputPanel.tsx | 8 +- src/components/ItemSeparator.tsx | 2 +- src/components/ListItem.tsx | 5 +- src/components/SectionHeader.tsx | 2 +- src/components/__tests__/ListItem.test.tsx | 8 -- .../__snapshots__/ListItem.test.tsx.snap | 92 ------------------- 6 files changed, 6 insertions(+), 111 deletions(-) diff --git a/src/components/InputPanel.tsx b/src/components/InputPanel.tsx index 53755db..8ef9bf8 100644 --- a/src/components/InputPanel.tsx +++ b/src/components/InputPanel.tsx @@ -1,10 +1,9 @@ import React from 'react' import { StyleProp, StyleSheet, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native' -import { Icon } from '@observation.org/react-native-components' -import { type Theme, useStyles, useTheme } from '@observation.org/react-native-components/theme' - import CapitalizeText from './CapitalizeText' +import { Theme, useStyles, useTheme } from '../theme' +import { Icon } from './Icon' type Props = { label?: string @@ -62,7 +61,6 @@ const InputPanel = ({ ) } -// todo: dit werd geexporteerd als een observer export default InputPanel const createStyles = (theme: Theme) => @@ -76,7 +74,7 @@ const createStyles = (theme: Theme) => headerTextStyle: { ...theme.font.extraSmall, lineHeight: theme.font.extraSmall.fontSize, - letterSpacing: 0.3, // todo: should this be dynamic? + letterSpacing: 0.03 * theme.font.extraSmall.fontSize, color: theme.color.text.system.subtler, }, contentContainer: { diff --git a/src/components/ItemSeparator.tsx b/src/components/ItemSeparator.tsx index 75f59d3..c739f95 100644 --- a/src/components/ItemSeparator.tsx +++ b/src/components/ItemSeparator.tsx @@ -1,7 +1,7 @@ import React from 'react' import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native' -import { type Theme, useStyles } from '@observation.org/react-native-components/theme' +import { Theme, useStyles } from '../theme' type Orientation = 'horizontal' | 'vertical' diff --git a/src/components/ListItem.tsx b/src/components/ListItem.tsx index 02c44bd..08054d5 100644 --- a/src/components/ListItem.tsx +++ b/src/components/ListItem.tsx @@ -2,10 +2,9 @@ import React from 'react' import { StyleSheet, TouchableOpacity, View } from 'react-native' import { Icon, IconProps } from '@observation.org/react-native-components' -import { type Theme, useStyles, useTheme } from '@observation.org/react-native-components/theme' import SingleLine from './SingleLine' -import Log from '../lib/Log' +import { Theme, useStyles, useTheme } from '../theme' type Props = { icon?: IconProps @@ -17,8 +16,6 @@ type Props = { } const ListItem = ({ icon, onPress, label, subLabel, extraSubLabel, selected = false }: Props) => { - Log.trace('ListItem', onPress) - const theme = useTheme() const styles = useStyles(createStyles) diff --git a/src/components/SectionHeader.tsx b/src/components/SectionHeader.tsx index b9a17df..f944f7a 100644 --- a/src/components/SectionHeader.tsx +++ b/src/components/SectionHeader.tsx @@ -1,7 +1,7 @@ import React from 'react' import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native' -import { type Theme, useStyles } from '@observation.org/react-native-components/theme' +import { Theme, useStyles } from '../theme' type Props = { title?: string diff --git a/src/components/__tests__/ListItem.test.tsx b/src/components/__tests__/ListItem.test.tsx index 5c178a8..0ccf6f1 100644 --- a/src/components/__tests__/ListItem.test.tsx +++ b/src/components/__tests__/ListItem.test.tsx @@ -11,14 +11,6 @@ const onPress = jest.fn() describe('ListItem', () => { describe('Rendering', () => { - test('Rendering', () => { - // WHEN - const { toJSON } = render() - - // THEN - expect(toJSON()).toMatchSnapshot() - }) - test('Rendering with radio button unselected', () => { // WHEN const { toJSON } = render() diff --git a/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap b/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap index 5a13f98..2ddf162 100644 --- a/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/ListItem.test.tsx.snap @@ -1,97 +1,5 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`ListItem Rendering Rendering 1`] = ` - - - - - - - - Read this! - - - - -`; - exports[`ListItem Rendering Rendering with custom icon 1`] = ` Date: Wed, 10 Jun 2026 12:26:40 +0200 Subject: [PATCH 5/6] Fix more review comments --- src/components/ListItem.tsx | 3 +-- src/components/__tests__/ListItem.test.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ListItem.tsx b/src/components/ListItem.tsx index 08054d5..057d8fb 100644 --- a/src/components/ListItem.tsx +++ b/src/components/ListItem.tsx @@ -1,10 +1,9 @@ import React from 'react' import { StyleSheet, TouchableOpacity, View } from 'react-native' -import { Icon, IconProps } from '@observation.org/react-native-components' - import SingleLine from './SingleLine' import { Theme, useStyles, useTheme } from '../theme' +import { Icon, IconProps } from './Icon' type Props = { icon?: IconProps diff --git a/src/components/__tests__/ListItem.test.tsx b/src/components/__tests__/ListItem.test.tsx index 0ccf6f1..a6a66ff 100644 --- a/src/components/__tests__/ListItem.test.tsx +++ b/src/components/__tests__/ListItem.test.tsx @@ -1,10 +1,10 @@ import React from 'react' import { describe, expect, jest, test } from '@jest/globals' -import { IconProps } from '@observation.org/react-native-components' import { fireEvent, render } from '@testing-library/react-native' import { color } from '../../theme/tokens/color' +import { IconProps } from '../Icon' import ListItem from '../ListItem' const onPress = jest.fn() From 854864532a9052b5002b885f4478f9fcf27d1c83 Mon Sep 17 00:00:00 2001 From: Barry van Veen Date: Wed, 10 Jun 2026 13:19:19 +0200 Subject: [PATCH 6/6] Fix todo --- src/components/InputPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/InputPanel.tsx b/src/components/InputPanel.tsx index 8ef9bf8..f458bab 100644 --- a/src/components/InputPanel.tsx +++ b/src/components/InputPanel.tsx @@ -29,7 +29,7 @@ const InputPanel = ({ const theme = useTheme() const styles = useStyles(createStyles) - // todo: 48 and 36 should be input heights and we should make them dynamically themed + // TODO: 48 and 36 should be input heights and we should make them dynamically themed const paddingVertical = label ? (48 - (styles.headerTextStyle.lineHeight! + styles.value.lineHeight!)) / 2 : (36 - styles.value.lineHeight!) / 2