diff --git a/package.json b/package.json
index ab11023..dbb4e3f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@observation.org/react-native-components",
- "version": "1.79.0",
+ "version": "1.80.0",
"main": "src/index.ts",
"exports": {
".": "./src/index.ts",
diff --git a/src/components/FilterButton.tsx b/src/components/FilterButton.tsx
new file mode 100644
index 0000000..a7a49c1
--- /dev/null
+++ b/src/components/FilterButton.tsx
@@ -0,0 +1,77 @@
+import React from 'react'
+import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
+
+import { Icon } from '@observation.org/react-native-components'
+import { rounded } from '@observation.org/react-native-components/styles'
+
+import { Theme, useStyles, useTheme } from '../theme'
+
+type FilterButtonProps = {
+ disabled?: boolean
+ activeFilters?: number
+ label: string
+ onPress?: () => void
+}
+
+const FilterButton = ({ activeFilters = 0, label, onPress }: FilterButtonProps) => {
+ const theme = useTheme()
+ const styles = useStyles(createStyles)
+
+ const backgroundColor = activeFilters > 0 ? theme.color.primary50 : theme.color.background.system.surfaceBase
+ return (
+
+
+
+
+
+ {label}
+ {activeFilters > 0 && (
+
+ {activeFilters}
+
+ )}
+
+
+ )
+}
+
+export default FilterButton
+
+const createStyles = (theme: Theme) =>
+ StyleSheet.create({
+ container: {
+ ...rounded.normal,
+ borderWidth: 2,
+ borderColor: theme.color.border.system.brand,
+ height: 32,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ title: {
+ textAlignVertical: 'center',
+ ...theme.font.small,
+ color: theme.color.text.system.brand,
+ },
+ titleContainer: {
+ marginHorizontal: theme.margin.half,
+ flexDirection: 'row',
+ },
+ iconContainerStyle: {
+ justifyContent: 'center',
+ paddingRight: theme.margin.half,
+ },
+ activeFilterContainer: {
+ ...rounded.normal,
+ marginLeft: theme.margin.half,
+ width: theme.icon.size.xl,
+ height: theme.icon.size.xl,
+ backgroundColor: theme.color.background.system.brand,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ activeFilter: {
+ textAlignVertical: 'center',
+ ...theme.font.small,
+ color: theme.color.text.system.staticWhite,
+ },
+ })
diff --git a/src/components/__tests__/FilterButton.test.tsx b/src/components/__tests__/FilterButton.test.tsx
new file mode 100644
index 0000000..9cde643
--- /dev/null
+++ b/src/components/__tests__/FilterButton.test.tsx
@@ -0,0 +1,37 @@
+import React from 'react'
+
+import { describe, expect, jest, test } from '@jest/globals'
+import { fireEvent, render } from '@testing-library/react-native'
+
+import FilterButton from '../FilterButton'
+
+describe('FilterButton', () => {
+ describe('Rendering', () => {
+ test('Default props', () => {
+ const { toJSON } = render()
+ expect(toJSON()).toMatchSnapshot()
+ })
+
+ test('Enabled', () => {
+ const { getByText, toJSON } = render()
+ expect(getByText('Filter')).toBeTruthy()
+ expect(getByText('3')).toBeTruthy()
+ expect(toJSON()).toMatchSnapshot()
+ })
+
+ test('No active filters', () => {
+ const { queryByText, toJSON } = render()
+ expect(queryByText('0')).toBeNull()
+ expect(toJSON()).toMatchSnapshot()
+ })
+ })
+
+ describe('Interaction', () => {
+ test('Calls onPress when pressed', () => {
+ const onPress = jest.fn()
+ const { getByText } = render()
+ fireEvent.press(getByText('Filter'))
+ expect(onPress).toHaveBeenCalled()
+ })
+ })
+})
diff --git a/src/components/__tests__/__snapshots__/FilterButton.test.tsx.snap b/src/components/__tests__/__snapshots__/FilterButton.test.tsx.snap
new file mode 100644
index 0000000..90bb9a0
--- /dev/null
+++ b/src/components/__tests__/__snapshots__/FilterButton.test.tsx.snap
@@ -0,0 +1,286 @@
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
+
+exports[`FilterButton Rendering Default props 1`] = `
+
+
+
+
+
+
+ Filter
+
+
+
+`;
+
+exports[`FilterButton Rendering Enabled 1`] = `
+
+
+
+
+
+
+ Filter
+
+
+
+ 3
+
+
+
+
+`;
+
+exports[`FilterButton Rendering No active filters 1`] = `
+
+
+
+
+
+
+ Filter
+
+
+
+`;
diff --git a/src/index.ts b/src/index.ts
index b605483..e64cefc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,6 +9,7 @@ import ContentImage from './components/ContentImage'
import Date from './components/Date'
import Disclose from './components/Disclose'
import DocumentLink from './components/DocumentLink'
+import FilterButton from './components/FilterButton'
import IconButton from './components/IconButton'
import IconText from './components/IconText'
import IconView from './components/IconView'
@@ -52,6 +53,7 @@ export {
Date,
Disclose,
DocumentLink,
+ FilterButton,
IconButton,
IconText,
IconView,