@utilitywarehouse/hearth-react-native 0.27.3 → 0.28.0-testid-fix-1
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/.turbo/turbo-build.log +5 -4
- package/.turbo/turbo-lint.log +70 -69
- package/CHANGELOG.md +110 -0
- package/build/components/Combobox/Combobox.context.d.ts +13 -0
- package/build/components/Combobox/Combobox.context.js +9 -0
- package/build/components/Combobox/Combobox.d.ts +6 -0
- package/build/components/Combobox/Combobox.js +246 -0
- package/build/components/Combobox/Combobox.props.d.ts +180 -0
- package/build/components/Combobox/Combobox.props.js +1 -0
- package/build/components/Combobox/ComboboxOption.d.ts +6 -0
- package/build/components/Combobox/ComboboxOption.js +56 -0
- package/build/components/Combobox/index.d.ts +4 -0
- package/build/components/Combobox/index.js +3 -0
- package/build/components/DatePicker/TimePicker.d.ts +3 -0
- package/build/components/DatePicker/TimePicker.js +84 -0
- package/build/components/DatePicker/time-picker/animated-math.d.ts +4 -0
- package/build/components/DatePicker/time-picker/animated-math.js +19 -0
- package/build/components/DatePicker/time-picker/period-native.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-native.js +17 -0
- package/build/components/DatePicker/time-picker/period-picker.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-picker.js +10 -0
- package/build/components/DatePicker/time-picker/period-web.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-web.js +21 -0
- package/build/components/DatePicker/time-picker/wheel-native.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel-native.js +19 -0
- package/build/components/DatePicker/time-picker/wheel-picker/index.d.ts +2 -0
- package/build/components/DatePicker/time-picker/wheel-picker/index.js +2 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.d.ts +16 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.js +97 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.d.ts +21 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.js +88 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.d.ts +23 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.js +21 -0
- package/build/components/DatePicker/time-picker/wheel-web.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel-web.js +146 -0
- package/build/components/DatePicker/time-picker/wheel.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel.js +10 -0
- package/build/components/Modal/Modal.js +26 -42
- package/build/components/Modal/Modal.web.js +3 -3
- package/build/components/Pagination/Pagination.d.ts +6 -0
- package/build/components/Pagination/Pagination.js +125 -0
- package/build/components/Pagination/Pagination.props.d.ts +26 -0
- package/build/components/Pagination/Pagination.props.js +1 -0
- package/build/components/Pagination/Pagination.utils.d.ts +2 -0
- package/build/components/Pagination/Pagination.utils.js +20 -0
- package/build/components/Pagination/Pagination.utils.test.d.ts +1 -0
- package/build/components/Pagination/Pagination.utils.test.js +16 -0
- package/build/components/Pagination/index.d.ts +2 -0
- package/build/components/Pagination/index.js +1 -0
- package/build/components/SafeAreaView/SafeAreaView.d.ts +5 -0
- package/build/components/SafeAreaView/SafeAreaView.js +117 -0
- package/build/components/SafeAreaView/SafeAreaView.props.d.ts +17 -0
- package/build/components/SafeAreaView/SafeAreaView.props.js +1 -0
- package/build/components/SafeAreaView/index.d.ts +2 -0
- package/build/components/SafeAreaView/index.js +1 -0
- package/build/components/Select/Select.d.ts +1 -1
- package/build/components/Select/Select.js +6 -5
- package/build/components/Select/Select.props.d.ts +4 -0
- package/build/components/Select/SelectOption.d.ts +1 -1
- package/build/components/Select/SelectOption.js +2 -2
- package/build/components/Table/Table.context.d.ts +12 -0
- package/build/components/Table/Table.context.js +9 -0
- package/build/components/Table/Table.d.ts +6 -0
- package/build/components/Table/Table.js +71 -0
- package/build/components/Table/Table.props.d.ts +56 -0
- package/build/components/Table/Table.props.js +1 -0
- package/build/components/Table/Table.utils.d.ts +5 -0
- package/build/components/Table/Table.utils.js +48 -0
- package/build/components/Table/Table.utils.test.d.ts +1 -0
- package/build/components/Table/Table.utils.test.js +71 -0
- package/build/components/Table/TableBody.d.ts +6 -0
- package/build/components/Table/TableBody.js +16 -0
- package/build/components/Table/TableCell.d.ts +10 -0
- package/build/components/Table/TableCell.js +44 -0
- package/build/components/Table/TableHeader.d.ts +6 -0
- package/build/components/Table/TableHeader.js +24 -0
- package/build/components/Table/TableHeaderCell.d.ts +10 -0
- package/build/components/Table/TableHeaderCell.js +97 -0
- package/build/components/Table/TablePagination.d.ts +6 -0
- package/build/components/Table/TablePagination.js +7 -0
- package/build/components/Table/TableRow.d.ts +8 -0
- package/build/components/Table/TableRow.js +25 -0
- package/build/components/Table/index.d.ts +8 -0
- package/build/components/Table/index.js +7 -0
- package/build/components/Timeline/Timeline.d.ts +6 -0
- package/build/components/Timeline/Timeline.js +34 -0
- package/build/components/Timeline/Timeline.props.d.ts +47 -0
- package/build/components/Timeline/Timeline.props.js +1 -0
- package/build/components/Timeline/TimelineItem.d.ts +6 -0
- package/build/components/Timeline/TimelineItem.js +235 -0
- package/build/components/Timeline/index.d.ts +3 -0
- package/build/components/Timeline/index.js +2 -0
- package/build/components/VerificationInput/VerificationInput.js +3 -3
- package/build/components/index.d.ts +5 -0
- package/build/components/index.js +5 -0
- package/build/tokens/components/dark/timeline.d.ts +2 -2
- package/build/tokens/components/dark/timeline.js +2 -2
- package/docs/components/AllComponents.web.tsx +106 -23
- package/docs/llm-docs/unistyles-llms-full.txt +1132 -534
- package/docs/llm-docs/unistyles-llms-small.txt +37 -37
- package/package.json +4 -4
- package/src/components/Combobox/Combobox.context.ts +26 -0
- package/src/components/Combobox/Combobox.docs.mdx +277 -0
- package/src/components/Combobox/Combobox.figma.tsx +60 -0
- package/src/components/Combobox/Combobox.props.ts +187 -0
- package/src/components/Combobox/Combobox.stories.tsx +233 -0
- package/src/components/Combobox/Combobox.tsx +446 -0
- package/src/components/Combobox/ComboboxOption.tsx +100 -0
- package/src/components/Combobox/index.ts +9 -0
- package/src/components/Modal/Modal.tsx +52 -74
- package/src/components/Modal/Modal.web.tsx +3 -3
- package/src/components/Pagination/Pagination.docs.mdx +99 -0
- package/src/components/Pagination/Pagination.figma.tsx +20 -0
- package/src/components/Pagination/Pagination.props.ts +28 -0
- package/src/components/Pagination/Pagination.stories.tsx +88 -0
- package/src/components/Pagination/Pagination.tsx +248 -0
- package/src/components/Pagination/Pagination.utils.test.ts +20 -0
- package/src/components/Pagination/Pagination.utils.ts +37 -0
- package/src/components/Pagination/index.ts +2 -0
- package/src/components/SafeAreaView/SafeAreaView.props.ts +20 -0
- package/src/components/SafeAreaView/SafeAreaView.tsx +173 -0
- package/src/components/SafeAreaView/index.ts +2 -0
- package/src/components/Select/Select.props.ts +4 -0
- package/src/components/Select/Select.tsx +35 -28
- package/src/components/Select/SelectOption.tsx +2 -0
- package/src/components/Table/Table.context.tsx +23 -0
- package/src/components/Table/Table.docs.mdx +239 -0
- package/src/components/Table/Table.figma.tsx +65 -0
- package/src/components/Table/Table.props.ts +65 -0
- package/src/components/Table/Table.stories.tsx +399 -0
- package/src/components/Table/Table.tsx +127 -0
- package/src/components/Table/Table.utils.test.ts +82 -0
- package/src/components/Table/Table.utils.ts +72 -0
- package/src/components/Table/TableBody.tsx +25 -0
- package/src/components/Table/TableCell.tsx +67 -0
- package/src/components/Table/TableHeader.tsx +41 -0
- package/src/components/Table/TableHeaderCell.tsx +136 -0
- package/src/components/Table/TablePagination.tsx +10 -0
- package/src/components/Table/TableRow.tsx +42 -0
- package/src/components/Table/index.ts +16 -0
- package/src/components/Timeline/Timeline.docs.mdx +177 -0
- package/src/components/Timeline/Timeline.figma.tsx +89 -0
- package/src/components/Timeline/Timeline.props.ts +51 -0
- package/src/components/Timeline/Timeline.stories.tsx +102 -0
- package/src/components/Timeline/Timeline.tsx +48 -0
- package/src/components/Timeline/TimelineItem.tsx +293 -0
- package/src/components/Timeline/index.ts +9 -0
- package/src/components/VerificationInput/VerificationInput.tsx +3 -0
- package/src/components/index.ts +5 -0
- package/src/tokens/components/dark/timeline.ts +2 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @utilitywarehouse/hearth-react-native@0.28.0-testid-fix-1 build /Users/filmondaniels/Projects/Work/hearth/packages/react-native
|
|
4
|
+
> tsc
|
|
5
|
+
|
package/.turbo/turbo-lint.log
CHANGED
|
@@ -1,69 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
no-
|
|
68
|
-
no-
|
|
69
|
-
@typescript-eslint/triple-slash-reference |
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @utilitywarehouse/hearth-react-native@0.27.2 lint /Users/filmondaniels/Projects/Work/hearth/packages/react-native
|
|
4
|
+
> TIMING=1 eslint .
|
|
5
|
+
|
|
6
|
+
[0m[0m
|
|
7
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Carousel/Carousel.context.tsx[24m[0m
|
|
8
|
+
[0m [2m6:14[22m [33mwarning[39m Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components [2mreact-refresh/only-export-components[22m[0m
|
|
9
|
+
[0m[0m
|
|
10
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Carousel/Carousel.tsx[24m[0m
|
|
11
|
+
[0m [2m146:6[22m [33mwarning[39m React Hook useMemo has a missing dependency: 'hasCarouselControlsInTree'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
12
|
+
[0m[0m
|
|
13
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/DatePicker/DatePicker.tsx[24m[0m
|
|
14
|
+
[0m [2m109:6[22m [33mwarning[39m React Hook useCallback has an unnecessary dependency: 'modalRef.current'. Either exclude it or remove the dependency array. Mutable values like 'modalRef.current' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m
|
|
15
|
+
[0m [2m259:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'initialState'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
16
|
+
[0m [2m346:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'onChange'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
17
|
+
[0m [2m468:5[22m [33mwarning[39m React Hook useCallback has a missing dependency: 'onChange'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
18
|
+
[0m [2m536:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'onSelectMonth'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
19
|
+
[0m [2m542:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'onSelectYear'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
20
|
+
[0m[0m
|
|
21
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/DatePicker/DatePickerDay.tsx[24m[0m
|
|
22
|
+
[0m [2m76:6[22m [33mwarning[39m React Hook useMemo has an unnecessary dependency: 'styles.rangeRoot'. Either exclude it or remove the dependency array. Outer scope values like 'styles.rangeRoot' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m
|
|
23
|
+
[0m [2m84:6[22m [33mwarning[39m React Hook useMemo has a missing dependency: 'isSelected'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
24
|
+
[0m[0m
|
|
25
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/DatePicker/DatePickerDays.tsx[24m[0m
|
|
26
|
+
[0m [2m179:6[22m [33mwarning[39m React Hook useMemo has unnecessary dependencies: 'month' and 'year'. Either exclude them or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
27
|
+
[0m[0m
|
|
28
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/DatePicker/DatePickerYears.tsx[24m[0m
|
|
29
|
+
[0m [2m52:6[22m [33mwarning[39m React Hook useCallback has a missing dependency: 'containerHeight'. Either include it or remove the dependency array. Outer scope values like 'styles' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m
|
|
30
|
+
[0m[0m
|
|
31
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Input/Input.tsx[24m[0m
|
|
32
|
+
[0m [2m78:8[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
33
|
+
[0m[0m
|
|
34
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Modal/Modal.tsx[24m[0m
|
|
35
|
+
[0m [2m93:6[22m [33mwarning[39m React Hook useCallback has an unnecessary dependency: 'Platform.OS'. Either exclude it or remove the dependency array. Outer scope values like 'Platform.OS' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m
|
|
36
|
+
[0m [2m330:5[22m [33mwarning[39m React Hook useCallback has a missing dependency: 'footer'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
37
|
+
[0m[0m
|
|
38
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Modal/Modal.web.tsx[24m[0m
|
|
39
|
+
[0m [2m66:6[22m [33mwarning[39m React Hook useCallback has an unnecessary dependency: 'Platform.OS'. Either exclude it or remove the dependency array. Outer scope values like 'Platform.OS' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m
|
|
40
|
+
[0m[0m
|
|
41
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/PillGroup/PillGroup.tsx[24m[0m
|
|
42
|
+
[0m [2m17:9[22m [33mwarning[39m The 'normalizedValue' conditional could make the dependencies of useMemo Hook (at line 33) change on every render. Move it inside the useMemo callback. Alternatively, wrap the initialization of 'normalizedValue' in its own useMemo() Hook [2mreact-hooks/exhaustive-deps[22m[0m
|
|
43
|
+
[0m[0m
|
|
44
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Tabs/Tabs.tsx[24m[0m
|
|
45
|
+
[0m [2m53:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'tabValues'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
46
|
+
[0m [2m53:7[22m [33mwarning[39m React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked [2mreact-hooks/exhaustive-deps[22m[0m
|
|
47
|
+
[0m [2m104:5[22m [33mwarning[39m React Hook useMemo has an unnecessary dependency: 'tabValues'. Either exclude it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
48
|
+
[0m [2m127:62[22m [33mwarning[39m React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked [2mreact-hooks/exhaustive-deps[22m[0m
|
|
49
|
+
[0m[0m
|
|
50
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Textarea/Textarea.tsx[24m[0m
|
|
51
|
+
[0m [2m45:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m
|
|
52
|
+
[0m[0m
|
|
53
|
+
[0m[4m/Users/filmondaniels/Projects/Work/hearth/packages/react-native/src/components/Toast/Toast.context.tsx[24m[0m
|
|
54
|
+
[0m [2m14:14[22m [33mwarning[39m Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components [2mreact-refresh/only-export-components[22m[0m
|
|
55
|
+
[0m [2m106:14[22m [33mwarning[39m Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components [2mreact-refresh/only-export-components[22m[0m
|
|
56
|
+
[0m[0m
|
|
57
|
+
[0m[33m[1m✖ 24 problems (0 errors, 24 warnings)[22m[39m[0m
|
|
58
|
+
[0m[33m[1m[22m[39m[0m
|
|
59
|
+
Rule | Time (ms) | Relative
|
|
60
|
+
:-----------------------------------------|----------:|--------:
|
|
61
|
+
@typescript-eslint/no-unused-vars | 436.390 | 62.5%
|
|
62
|
+
react-hooks/exhaustive-deps | 28.433 | 4.1%
|
|
63
|
+
no-global-assign | 25.595 | 3.7%
|
|
64
|
+
react-hooks/rules-of-hooks | 20.152 | 2.9%
|
|
65
|
+
@typescript-eslint/ban-ts-comment | 17.023 | 2.4%
|
|
66
|
+
no-misleading-character-class | 12.606 | 1.8%
|
|
67
|
+
@typescript-eslint/no-unused-expressions | 9.189 | 1.3%
|
|
68
|
+
no-unexpected-multiline | 8.943 | 1.3%
|
|
69
|
+
@typescript-eslint/triple-slash-reference | 8.378 | 1.2%
|
|
70
|
+
no-loss-of-precision | 8.049 | 1.2%
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,115 @@
|
|
|
1
1
|
# @utilitywarehouse/hearth-react-native
|
|
2
2
|
|
|
3
|
+
## 0.28.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1014](https://github.com/utilitywarehouse/hearth/pull/1014) [`c10ff82`](https://github.com/utilitywarehouse/hearth/commit/c10ff82243265217acd95f687d48d803b3c7a4bd) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `Combobox` and `SafeAreaView` to the React Native library
|
|
8
|
+
|
|
9
|
+
The React Native package now includes a `Combobox` component for searchable selection in a bottom sheet, plus a `SafeAreaView` primitive that applies Unistyles runtime insets only when a view actually overlaps a screen edge. `Combobox` supports the built-in options API for fixed lists, controlled search values for dynamic results, and custom bottom sheet content for cases where you need to bring your own `BottomSheetFlatList` or bespoke option layout. `Modal` now uses `SafeAreaView` in its full-screen navigation modal path so content like search inputs no longer sits behind the dynamic island on iOS.
|
|
10
|
+
|
|
11
|
+
**Components affected**:
|
|
12
|
+
- `Combobox`
|
|
13
|
+
- `ComboboxOption`
|
|
14
|
+
- `SafeAreaView`
|
|
15
|
+
- `Modal`
|
|
16
|
+
|
|
17
|
+
**Developer changes**:
|
|
18
|
+
|
|
19
|
+
Import the new components from `@utilitywarehouse/hearth-react-native` and choose the API that fits your layout. Use `options` for straightforward searchable lists, render custom sheet content when you need virtualised or dynamic results, and wrap full-screen content in `SafeAreaView` when it should only pick up edge insets if it actually touches that edge.
|
|
20
|
+
|
|
21
|
+
- [`8e37595`](https://github.com/utilitywarehouse/hearth/commit/8e375958559357ce5c1703505fa7438887d9e18e) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `Pagination` component
|
|
22
|
+
|
|
23
|
+
The package now includes a `Pagination` component for moving between pages of content. It supports numbered pagination, a condensed layout for smaller spaces, optional skip buttons for jumping to the first and last page, and controlled page state so it can be wired into lists, tables, or other paged views.
|
|
24
|
+
|
|
25
|
+
**Components affected**:
|
|
26
|
+
- `Pagination`
|
|
27
|
+
|
|
28
|
+
**Developer changes**:
|
|
29
|
+
|
|
30
|
+
Import `Pagination` from `@utilitywarehouse/hearth-react-native` and control the current page in your screen or feature state.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { useState } from 'react';
|
|
34
|
+
import { Pagination } from '@utilitywarehouse/hearth-react-native';
|
|
35
|
+
|
|
36
|
+
const MyComponent = () => {
|
|
37
|
+
const [page, setPage] = useState(1);
|
|
38
|
+
|
|
39
|
+
return <Pagination currentPage={page} onPageChange={setPage} totalPages={10} />;
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- [`8e37595`](https://github.com/utilitywarehouse/hearth/commit/8e375958559357ce5c1703505fa7438887d9e18e) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `Table` component
|
|
44
|
+
|
|
45
|
+
The package now includes a composable `Table` API for presenting structured data with headers, rows, cells, optional card-style containers, horizontal scrolling for narrow viewports, configurable column widths, and pagination support through `TablePagination`. Header cells support trailing actions such as sort controls, and the API is split into smaller building blocks so layouts can be assembled to fit different datasets.
|
|
46
|
+
|
|
47
|
+
**Components affected**:
|
|
48
|
+
- `Table`
|
|
49
|
+
- `TableHeader`
|
|
50
|
+
- `TableHeaderCell`
|
|
51
|
+
- `TableBody`
|
|
52
|
+
- `TableRow`
|
|
53
|
+
- `TableCell`
|
|
54
|
+
- `TablePagination`
|
|
55
|
+
|
|
56
|
+
**Developer changes**:
|
|
57
|
+
|
|
58
|
+
Import the table primitives from `@utilitywarehouse/hearth-react-native` and compose them to match your data shape. Add `columnWidths` when you need fixed or weighted columns, and pass `pagination` when rows should be paged.
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import {
|
|
62
|
+
Table,
|
|
63
|
+
TableBody,
|
|
64
|
+
TableCell,
|
|
65
|
+
TableHeader,
|
|
66
|
+
TableHeaderCell,
|
|
67
|
+
TableRow,
|
|
68
|
+
} from '@utilitywarehouse/hearth-react-native';
|
|
69
|
+
|
|
70
|
+
const MyComponent = () => (
|
|
71
|
+
<Table columnWidths={[180, '2fr', '1fr']} container="subtle">
|
|
72
|
+
<TableHeader color="purple">
|
|
73
|
+
<TableHeaderCell>Name</TableHeaderCell>
|
|
74
|
+
<TableHeaderCell>Email</TableHeaderCell>
|
|
75
|
+
<TableHeaderCell>Status</TableHeaderCell>
|
|
76
|
+
</TableHeader>
|
|
77
|
+
<TableBody>
|
|
78
|
+
<TableRow>
|
|
79
|
+
<TableHeaderCell row>Alex Morgan</TableHeaderCell>
|
|
80
|
+
<TableCell>alex@example.com</TableCell>
|
|
81
|
+
<TableCell>Active</TableCell>
|
|
82
|
+
</TableRow>
|
|
83
|
+
</TableBody>
|
|
84
|
+
</Table>
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- [#1016](https://github.com/utilitywarehouse/hearth/pull/1016) [`33baa9e`](https://github.com/utilitywarehouse/hearth/commit/33baa9e8edb091bbd1d17c9a3838352a7f1b87ea) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Adds `Timeline` and `TimelineItem`
|
|
89
|
+
|
|
90
|
+
The package now includes `Timeline` and `TimelineItem` components for showing a sequence of static stops or progress steps. The new API supports labelled items, optional helper text, progress states for complete or active steps, and custom content within an item when you need to show extra context or actions.
|
|
91
|
+
|
|
92
|
+
**Components affected**:
|
|
93
|
+
- `Timeline`
|
|
94
|
+
- `TimelineItem`
|
|
95
|
+
|
|
96
|
+
**Developer changes**:
|
|
97
|
+
|
|
98
|
+
Import `Timeline` and `TimelineItem` from `@utilitywarehouse/hearth-react-native`. Use `variant="static"` for simple ordered events, or `variant="progress"` with item `state` values to communicate step progress.
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { Timeline, TimelineItem } from '@utilitywarehouse/hearth-react-native';
|
|
102
|
+
|
|
103
|
+
const MyComponent = () => (
|
|
104
|
+
<Timeline variant="progress">
|
|
105
|
+
<TimelineItem label="Ordered" helperText="We have received your order" state="complete" />
|
|
106
|
+
<TimelineItem label="Packed" helperText="Your items are ready" state="complete" />
|
|
107
|
+
<TimelineItem label="Out for delivery" helperText="Arriving today" state="active" />
|
|
108
|
+
<TimelineItem label="Delivered" helperText="Pending" state="incomplete" />
|
|
109
|
+
</Timeline>
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
3
113
|
## 0.27.3
|
|
4
114
|
|
|
5
115
|
### Patch Changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ComboboxSelection {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ComboboxContextValue {
|
|
6
|
+
close: () => void;
|
|
7
|
+
search: string;
|
|
8
|
+
selectedValue?: string | null;
|
|
9
|
+
selectOption: (option: ComboboxSelection) => void;
|
|
10
|
+
setSearch: (value: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const ComboboxContext: import("react").Context<ComboboxContextValue | undefined>;
|
|
13
|
+
export declare const useComboboxContext: () => ComboboxContextValue;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const ComboboxContext = createContext(undefined);
|
|
3
|
+
export const useComboboxContext = () => {
|
|
4
|
+
const context = useContext(ComboboxContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error('useComboboxContext must be used within a Combobox');
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import ComboboxProps from './Combobox.props';
|
|
2
|
+
declare const Combobox: {
|
|
3
|
+
({ options, value, onValueChange, inputValue, onInputValueChange, label, labelVariant, placeholder, searchPlaceholder, disabled, validationStatus, helperText, helperIcon, invalidText, validText, required, children, bottomSheetProps, menuHeading, noOptionsFoundText, listProps, loading, readonly, getValueLabel, filterOption, ...rest }: ComboboxProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
displayName: string;
|
|
5
|
+
};
|
|
6
|
+
export default Combobox;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CloseSmallIcon, SearchMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
3
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { Pressable, View } from 'react-native';
|
|
5
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
6
|
+
import { useTheme } from '../../hooks';
|
|
7
|
+
import { BodyText } from '../BodyText';
|
|
8
|
+
import { BottomSheetFlatList, BottomSheetModal, BottomSheetView } from '../BottomSheet';
|
|
9
|
+
import { DetailText } from '../DetailText';
|
|
10
|
+
import { FormField, useFormFieldContext } from '../FormField';
|
|
11
|
+
import { Icon } from '../Icon';
|
|
12
|
+
import { Input } from '../Input';
|
|
13
|
+
import { Spinner } from '../Spinner';
|
|
14
|
+
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
15
|
+
import { ComboboxContext } from './Combobox.context';
|
|
16
|
+
import { SafeAreaView } from '../SafeAreaView';
|
|
17
|
+
import ComboboxOption from './ComboboxOption';
|
|
18
|
+
const DEFAULT_SNAP_POINTS = ['25%', '40%', '80%'];
|
|
19
|
+
const Combobox = ({ options = [], value, onValueChange, inputValue, onInputValueChange, label, labelVariant = 'body', placeholder = 'Search', searchPlaceholder = 'Search', disabled = false, validationStatus = 'initial', helperText, helperIcon, invalidText, validText, required = true, children, bottomSheetProps, menuHeading, noOptionsFoundText = 'No options found', listProps, loading = false, readonly = false, getValueLabel, filterOption, ...rest }) => {
|
|
20
|
+
const formFieldContext = useFormFieldContext();
|
|
21
|
+
const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
|
|
22
|
+
const isRequired = formFieldContext?.required ?? required;
|
|
23
|
+
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
24
|
+
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
25
|
+
const { color } = useTheme();
|
|
26
|
+
const bottomSheetModalRef = useRef(null);
|
|
27
|
+
const searchInputRef = useRef(null);
|
|
28
|
+
const focusTimeoutRef = useRef(null);
|
|
29
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
30
|
+
const [selectedChildLabel, setSelectedChildLabel] = useState(undefined);
|
|
31
|
+
const [uncontrolledInputValue, setUncontrolledInputValue] = useState('');
|
|
32
|
+
const isInputControlled = inputValue !== undefined;
|
|
33
|
+
const selectedOption = options.find(option => option.value === value);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (typeof children === 'function' || !children || selectedOption || !value || getValueLabel) {
|
|
36
|
+
setSelectedChildLabel(undefined);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let nextLabel;
|
|
40
|
+
React.Children.forEach(children, child => {
|
|
41
|
+
if (!React.isValidElement(child) || nextLabel) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (child.props.value === value) {
|
|
45
|
+
nextLabel = child.props.label;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
setSelectedChildLabel(nextLabel);
|
|
49
|
+
}, [children, getValueLabel, selectedOption, value]);
|
|
50
|
+
const selectedLabel = useMemo(() => {
|
|
51
|
+
return getValueLabel?.(value) || selectedOption?.label || selectedChildLabel || '';
|
|
52
|
+
}, [getValueLabel, selectedChildLabel, selectedOption?.label, value]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (isInputControlled) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
setUncontrolledInputValue(selectedLabel);
|
|
58
|
+
}, [isInputControlled, selectedLabel]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
return () => {
|
|
61
|
+
if (focusTimeoutRef.current) {
|
|
62
|
+
clearTimeout(focusTimeoutRef.current);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}, []);
|
|
66
|
+
const search = isInputControlled ? (inputValue ?? '') : uncontrolledInputValue;
|
|
67
|
+
const accessibilityLabel = useMemo(() => {
|
|
68
|
+
if (!label) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return isRequired ? `${label}, required` : label;
|
|
72
|
+
}, [isRequired, label]);
|
|
73
|
+
const accessibilityHint = useMemo(() => {
|
|
74
|
+
const hints = [];
|
|
75
|
+
if (helperText) {
|
|
76
|
+
hints.push(helperText);
|
|
77
|
+
}
|
|
78
|
+
if (validationStatusFromContext === 'invalid' && invalidText) {
|
|
79
|
+
hints.push(invalidText);
|
|
80
|
+
}
|
|
81
|
+
if (validationStatusFromContext === 'valid' && validText) {
|
|
82
|
+
hints.push(validText);
|
|
83
|
+
}
|
|
84
|
+
return hints.length > 0 ? hints.join(', ') : undefined;
|
|
85
|
+
}, [helperText, invalidText, validText, validationStatusFromContext]);
|
|
86
|
+
styles.useVariants({
|
|
87
|
+
disabled: isDisabled,
|
|
88
|
+
hasValue: search.length > 0,
|
|
89
|
+
readonly: isReadonly,
|
|
90
|
+
validationStatus: validationStatusFromContext,
|
|
91
|
+
});
|
|
92
|
+
const setSearch = useCallback((nextValue) => {
|
|
93
|
+
if (!isInputControlled) {
|
|
94
|
+
setUncontrolledInputValue(nextValue);
|
|
95
|
+
}
|
|
96
|
+
onInputValueChange?.(nextValue);
|
|
97
|
+
}, [isInputControlled, onInputValueChange]);
|
|
98
|
+
const handleClose = useCallback((index) => {
|
|
99
|
+
if (index === -1) {
|
|
100
|
+
setIsOpen(false);
|
|
101
|
+
setSearch('');
|
|
102
|
+
}
|
|
103
|
+
}, [setSearch]);
|
|
104
|
+
const focusSearchInput = useCallback(() => {
|
|
105
|
+
if (focusTimeoutRef.current) {
|
|
106
|
+
clearTimeout(focusTimeoutRef.current);
|
|
107
|
+
}
|
|
108
|
+
focusTimeoutRef.current = setTimeout(() => {
|
|
109
|
+
searchInputRef.current?.focus();
|
|
110
|
+
}, 300);
|
|
111
|
+
}, []);
|
|
112
|
+
const openBottomSheet = useCallback(() => {
|
|
113
|
+
if (isDisabled || isReadonly) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
bottomSheetModalRef.current?.present();
|
|
117
|
+
setIsOpen(true);
|
|
118
|
+
focusSearchInput();
|
|
119
|
+
}, [focusSearchInput, isDisabled, isReadonly]);
|
|
120
|
+
const closeBottomSheet = useCallback(() => {
|
|
121
|
+
bottomSheetModalRef.current?.dismiss();
|
|
122
|
+
setIsOpen(false);
|
|
123
|
+
}, []);
|
|
124
|
+
const selectOption = useCallback(({ label: optionLabel, value: optionValue }) => {
|
|
125
|
+
setSearch(optionLabel);
|
|
126
|
+
onValueChange?.(optionValue);
|
|
127
|
+
closeBottomSheet();
|
|
128
|
+
}, [closeBottomSheet, onValueChange, setSearch]);
|
|
129
|
+
const handleClear = useCallback(() => {
|
|
130
|
+
setSearch('');
|
|
131
|
+
onValueChange?.(null);
|
|
132
|
+
}, [onValueChange, setSearch]);
|
|
133
|
+
const handleClearPress = useCallback((event) => {
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
handleClear();
|
|
136
|
+
}, [handleClear]);
|
|
137
|
+
const defaultFilterOption = useCallback((option, query) => {
|
|
138
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
139
|
+
if (!normalizedQuery) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const haystack = [option.label, ...(option.keywords ?? [])].map(term => term.toLowerCase());
|
|
143
|
+
return haystack.some(term => term.includes(normalizedQuery));
|
|
144
|
+
}, []);
|
|
145
|
+
const filteredOptions = useMemo(() => {
|
|
146
|
+
const optionFilter = filterOption ?? defaultFilterOption;
|
|
147
|
+
return options.filter(option => optionFilter(option, search));
|
|
148
|
+
}, [defaultFilterOption, filterOption, options, search]);
|
|
149
|
+
const renderSelectOption = useCallback(({ item }) => (_jsx(ComboboxOption, { label: item.label, value: item.value, disabled: item.disabled, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon })), []);
|
|
150
|
+
const renderEmptyComponent = useCallback(() => (_jsx(BottomSheetView, { style: styles.emptyContainer, children: _jsx(DetailText, { children: noOptionsFoundText }) })), [noOptionsFoundText]);
|
|
151
|
+
const renderContentProps = useMemo(() => ({
|
|
152
|
+
close: closeBottomSheet,
|
|
153
|
+
search,
|
|
154
|
+
selectedValue: value,
|
|
155
|
+
selectOption,
|
|
156
|
+
setSearch,
|
|
157
|
+
}), [closeBottomSheet, search, selectOption, setSearch, value]);
|
|
158
|
+
const customContent = typeof children === 'function' ? children(renderContentProps) : children;
|
|
159
|
+
return (_jsxs(View, { ...rest, style: [styles.container, rest.style], children: [_jsx(FormField, { label: label, labelVariant: labelVariant, helperText: helperText, helperIcon: helperIcon, validationStatus: validationStatusFromContext, required: isRequired, disabled: isDisabled, readonly: isReadonly, invalidText: invalidText, validText: validText, accessibilityHandledByChildren: true, children: _jsxs(Pressable, { onPress: openBottomSheet, disabled: isDisabled || isReadonly, accessibilityRole: "button", accessibilityLabel: accessibilityLabel, accessibilityHint: accessibilityHint, accessibilityState: { expanded: isOpen, disabled: isDisabled || isReadonly }, style: ({ pressed }) => [styles.trigger, (pressed || isOpen) && styles.triggerFocused], children: [_jsx(View, { style: styles.leadingIconContainer, children: _jsx(Icon, { as: SearchMediumIcon, style: styles.icon }) }), _jsx(View, { style: styles.valueContainer, children: _jsx(BodyText, { numberOfLines: 1, style: styles.valueText, children: search || placeholder }) }), loading && _jsx(Spinner, { size: "xs", color: color.icon.primary }), !!search && (_jsx(UnstyledIconButton, { accessibilityLabel: "Clear search", onPress: handleClearPress, icon: CloseSmallIcon }))] }) }), _jsx(BottomSheetModal, { ref: bottomSheetModalRef, snapPoints: DEFAULT_SNAP_POINTS, onChange: handleClose, enableDynamicSizing: false, ...bottomSheetProps, children: _jsxs(ComboboxContext.Provider, { value: {
|
|
160
|
+
close: closeBottomSheet,
|
|
161
|
+
search,
|
|
162
|
+
selectedValue: value,
|
|
163
|
+
selectOption,
|
|
164
|
+
setSearch,
|
|
165
|
+
}, children: [_jsxs(SafeAreaView, { edges: ['top'], children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), _jsx(View, { style: styles.searchContainer, children: _jsx(Input, { ref: searchInputRef, placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search", clearable: true, onClear: handleClear, loading: loading }) })] }), customContent || (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, ...listProps }))] }) })] }));
|
|
166
|
+
};
|
|
167
|
+
const styles = StyleSheet.create(theme => ({
|
|
168
|
+
container: {
|
|
169
|
+
gap: theme.components.select.gap,
|
|
170
|
+
},
|
|
171
|
+
trigger: {
|
|
172
|
+
flexDirection: 'row',
|
|
173
|
+
alignItems: 'center',
|
|
174
|
+
minHeight: theme.components.input.height,
|
|
175
|
+
backgroundColor: theme.color.surface.neutral.strong,
|
|
176
|
+
borderWidth: theme.components.input.borderWidth,
|
|
177
|
+
borderColor: theme.color.border.strong,
|
|
178
|
+
borderRadius: theme.components.input.borderRadius,
|
|
179
|
+
paddingHorizontal: theme.components.input.paddingHorizontal,
|
|
180
|
+
gap: theme.components.input.gap,
|
|
181
|
+
outlineStyle: 'solid',
|
|
182
|
+
outlineWidth: theme.components.input.borderWidth,
|
|
183
|
+
outlineColor: theme.color.border.strong,
|
|
184
|
+
variants: {
|
|
185
|
+
disabled: {
|
|
186
|
+
true: {
|
|
187
|
+
opacity: theme.opacity.disabled,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
readonly: {
|
|
191
|
+
true: {
|
|
192
|
+
borderColor: theme.color.border.subtle,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
validationStatus: {
|
|
196
|
+
initial: {},
|
|
197
|
+
valid: {
|
|
198
|
+
borderColor: theme.color.feedback.positive.border,
|
|
199
|
+
outlineColor: theme.color.feedback.positive.border,
|
|
200
|
+
},
|
|
201
|
+
invalid: {
|
|
202
|
+
borderColor: theme.color.feedback.danger.border,
|
|
203
|
+
outlineColor: theme.color.feedback.danger.border,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
triggerFocused: {
|
|
209
|
+
outlineWidth: theme.components.input.borderWidthFocused,
|
|
210
|
+
},
|
|
211
|
+
leadingIconContainer: {
|
|
212
|
+
alignItems: 'center',
|
|
213
|
+
justifyContent: 'center',
|
|
214
|
+
},
|
|
215
|
+
valueContainer: {
|
|
216
|
+
flex: 1,
|
|
217
|
+
},
|
|
218
|
+
valueText: {
|
|
219
|
+
variants: {
|
|
220
|
+
hasValue: {
|
|
221
|
+
false: {
|
|
222
|
+
color: theme.color.text.secondary,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
icon: {
|
|
228
|
+
color: theme.color.icon.primary,
|
|
229
|
+
},
|
|
230
|
+
headingContainer: {
|
|
231
|
+
paddingHorizontal: theme.components.bottomSheet.padding,
|
|
232
|
+
marginBottom: theme.components.select.gap,
|
|
233
|
+
},
|
|
234
|
+
searchContainer: {
|
|
235
|
+
paddingTop: 1,
|
|
236
|
+
paddingHorizontal: theme.components.bottomSheet.padding,
|
|
237
|
+
paddingBottom: theme.components.select.gap,
|
|
238
|
+
},
|
|
239
|
+
emptyContainer: {
|
|
240
|
+
alignItems: 'center',
|
|
241
|
+
justifyContent: 'center',
|
|
242
|
+
marginTop: theme.space.md,
|
|
243
|
+
},
|
|
244
|
+
}));
|
|
245
|
+
Combobox.displayName = 'Combobox';
|
|
246
|
+
export default Combobox;
|