@utilitywarehouse/hearth-react-native 0.14.1 → 0.15.0

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.
Files changed (31) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +47 -0
  4. package/build/components/Checkbox/Checkbox.d.ts +1 -1
  5. package/build/components/Checkbox/Checkbox.js +2 -4
  6. package/build/components/DescriptionList/DescriptionListItem.js +8 -1
  7. package/build/components/HTMLElements/ListItem.d.ts +9 -1
  8. package/build/components/HTMLElements/ListItem.js +1 -2
  9. package/build/components/HTMLElements/OrderedList.d.ts +3 -2
  10. package/build/components/HTMLElements/OrderedList.js +29 -4
  11. package/build/components/HTMLElements/UnorderedList.d.ts +3 -2
  12. package/build/components/HTMLElements/UnorderedList.js +29 -4
  13. package/build/components/Helper/Helper.js +1 -1
  14. package/build/components/Helper/HelperText.js +1 -0
  15. package/build/components/Input/Input.js +2 -2
  16. package/build/components/PillGroup/PillGroup.props.d.ts +19 -7
  17. package/package.json +1 -1
  18. package/src/components/Checkbox/Checkbox.tsx +7 -2
  19. package/src/components/DescriptionList/DescriptionListItem.tsx +8 -1
  20. package/src/components/HTMLElements/ListItem.tsx +11 -3
  21. package/src/components/HTMLElements/Lists.docs.mdx +64 -16
  22. package/src/components/HTMLElements/OrderedList.stories.tsx +33 -2
  23. package/src/components/HTMLElements/OrderedList.tsx +54 -6
  24. package/src/components/HTMLElements/UnorderedList.stories.tsx +63 -5
  25. package/src/components/HTMLElements/UnorderedList.tsx +50 -6
  26. package/src/components/Helper/Helper.tsx +1 -1
  27. package/src/components/Helper/HelperText.tsx +1 -0
  28. package/src/components/Input/Input.tsx +2 -0
  29. package/src/components/PillGroup/PillGroup.props.ts +25 -11
  30. package/src/components/PillGroup/PillGroup.stories.tsx +5 -6
  31. package/src/components/PillGroup/PillGroup.tsx +3 -3
@@ -1,4 +1,4 @@
1
1
 
2
- > @utilitywarehouse/hearth-react-native@0.14.1 build /home/runner/work/hearth/hearth/packages/react-native
2
+ > @utilitywarehouse/hearth-react-native@0.15.0 build /home/runner/work/hearth/hearth/packages/react-native
3
3
  > tsc
4
4
 
@@ -1,5 +1,5 @@
1
1
 
2
- > @utilitywarehouse/hearth-react-native@0.14.1 lint /home/runner/work/hearth/hearth/packages/react-native
2
+ > @utilitywarehouse/hearth-react-native@0.15.0 lint /home/runner/work/hearth/hearth/packages/react-native
3
3
  > TIMING=1 eslint --max-warnings 0
4
4
 
5
5
  Rule | Time (ms) | Relative
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @utilitywarehouse/hearth-react-native
2
2
 
3
+ ## 0.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#766](https://github.com/utilitywarehouse/hearth/pull/766) [`183155a`](https://github.com/utilitywarehouse/hearth/commit/183155a1aaf7713f0ab8a39ab1e5684ef6190d0c) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE] Custom `ListItem` styles for `UL` and `OL` components
8
+
9
+ Added new props to `UL`, `OL`, and `ListItem` components to support custom list markers, including icons, images, and colors. This brings the functionality closer to CSS-like list styling. We also fixed a layout issue where list item text could overflow the container.
10
+
11
+ **Components affected**:
12
+
13
+ - `UL` (UnorderedList)
14
+ - `OL` (OrderedList)
15
+ - `ListItem`
16
+
17
+ **Developer changes**:
18
+
19
+ You can now customise list bullets/markers using the new `listStyle*` props. These can be set on the list container to apply to all items, or overridden on individual list items.
20
+
21
+ ```tsx
22
+ import { UL, LI } from '@utilitywarehouse/hearth-react-native';
23
+ import { TickIcon } from '@utilitywarehouse/hearth-react-native-icons';
24
+
25
+ <UL listStyleColour="feedbackPositiveSurfaceDefault" listStyleIcon={TickIcon}>
26
+ <LI>Success item 1</LI>
27
+ <LI listStyleColour="feedbackDangerSurfaceDefault">Error item override</LI>
28
+ </UL>;
29
+ ```
30
+
31
+ Supported props:
32
+
33
+ - `listStyleImage`: React Element (e.g. `<Image />`)
34
+ - `listStyleIcon`: Icon component
35
+ - `listStyleWidth` / `listStyleHeight`: Dimensions for the marker (default: 20)
36
+ - `listStyleColour`: Color token or value for the marker
37
+
38
+ ### Patch Changes
39
+
40
+ - [#762](https://github.com/utilitywarehouse/hearth/pull/762) [`2d2bbd2`](https://github.com/utilitywarehouse/hearth/commit/2d2bbd2ba109b9acb2e0b220766eb02c0ad5710e) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Fixes Android error when passing boolean or number as a `Checkbox` value
41
+
42
+ - [#764](https://github.com/utilitywarehouse/hearth/pull/764) [`46f115d`](https://github.com/utilitywarehouse/hearth/commit/46f115dd4bd9da824496e8ec19e29276523931a1) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Fixes `HelperText` wrapping issue
43
+
44
+ - [#762](https://github.com/utilitywarehouse/hearth/pull/762) [`2d2bbd2`](https://github.com/utilitywarehouse/hearth/commit/2d2bbd2ba109b9acb2e0b220766eb02c0ad5710e) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Fixes `PillGroup` `onChange` prop types
45
+
46
+ - [#764](https://github.com/utilitywarehouse/hearth/pull/764) [`46f115d`](https://github.com/utilitywarehouse/hearth/commit/46f115dd4bd9da824496e8ec19e29276523931a1) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: `DescriptionListItem` description disappearing when direction is `column`
47
+
48
+ - [#762](https://github.com/utilitywarehouse/hearth/pull/762) [`2d2bbd2`](https://github.com/utilitywarehouse/hearth/commit/2d2bbd2ba109b9acb2e0b220766eb02c0ad5710e) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Input styles are now passed to the correct View
49
+
3
50
  ## 0.14.1
4
51
 
5
52
  ### Patch Changes
@@ -10,7 +10,7 @@ declare const CheckboxIcon: import("react").ForwardRefExoticComponent<import("re
10
10
  }>;
11
11
  declare const CheckboxLabel: import("react").ForwardRefExoticComponent<import("react").RefAttributes<import("../Label/Label.props").default> & Omit<import("../Label/Label.props").default, "ref">>;
12
12
  declare const Checkbox: {
13
- ({ children, label, disabled, checked, helperIcon, helperText, invalidText, validText, validationStatus: validation, showValidationIcon, type, image, ...props }: CheckboxProps): import("react/jsx-runtime").JSX.Element;
13
+ ({ children, label, disabled, checked, helperIcon, helperText, invalidText, validText, validationStatus: validation, showValidationIcon, type, image, value, ...props }: CheckboxProps): import("react/jsx-runtime").JSX.Element;
14
14
  displayName: string;
15
15
  };
16
16
  declare const CheckboxTile: {
@@ -25,15 +25,13 @@ CheckboxGroup.displayName = 'CheckboxGroup';
25
25
  CheckboxIndicator.displayName = 'CheckboxIndicator';
26
26
  CheckboxIcon.displayName = 'CheckboxIcon';
27
27
  CheckboxLabel.displayName = 'CheckboxLabel';
28
- const Checkbox = ({ children, label, disabled, checked, helperIcon, helperText, invalidText, validText, validationStatus: validation, showValidationIcon, type = 'default', image, ...props }) => {
28
+ const Checkbox = ({ children, label, disabled, checked, helperIcon, helperText, invalidText, validText, validationStatus: validation, showValidationIcon, type = 'default', image, value, ...props }) => {
29
29
  const { validationStatus: fieldValidationStatus } = useFormFieldContext();
30
30
  const { validationStatus: groupValidationStatus, type: groupType } = useCheckboxGroupContext();
31
31
  const validationStatus = fieldValidationStatus ?? groupValidationStatus ?? validation ?? 'initial';
32
32
  const checkboxType = groupType ?? type;
33
33
  const checkboxChildren = children ? (children) : (_jsxs(_Fragment, { children: [_jsx(CheckboxIndicator, { children: _jsx(CheckboxIcon, {}) }), image ? image : null, _jsxs(CheckboxTextContent, { children: [!!label && _jsx(CheckboxLabel, { children: label }), !!helperText && _jsx(Helper, { disabled: disabled, icon: helperIcon, text: helperText }), validationStatus === 'invalid' && !!invalidText && (_jsx(Helper, { showIcon: showValidationIcon, disabled: disabled, validationStatus: "invalid", text: invalidText })), validationStatus === 'valid' && !!validText && (_jsx(Helper, { disabled: disabled, showIcon: showValidationIcon, validationStatus: "valid", text: validText }))] })] }));
34
- return (
35
- // @ts-expect-error - type
36
- _jsx(CheckboxComponent, { ...props, isDisabled: disabled, isChecked: checked, children: checkboxType === 'tile' ? (_jsx(CheckboxTileRoot, { children: checkboxChildren })) : (checkboxChildren) }));
34
+ return (_jsx(CheckboxComponent, { ...props, value: (value ?? '').toString(), isDisabled: disabled, isChecked: checked, children: checkboxType === 'tile' ? (_jsx(CheckboxTileRoot, { children: checkboxChildren })) : (checkboxChildren) }));
37
35
  };
38
36
  const CheckboxTile = ({ type = 'tile', ...props }) => {
39
37
  return _jsx(Checkbox, { ...props, type: type });
@@ -44,7 +44,14 @@ const styles = StyleSheet.create(theme => ({
44
44
  color: theme.color.text.secondary,
45
45
  },
46
46
  descriptionWrapper: {
47
- flex: 1,
47
+ variants: {
48
+ direction: {
49
+ row: {
50
+ flex: 1,
51
+ },
52
+ column: {},
53
+ },
54
+ },
48
55
  },
49
56
  }));
50
57
  export default DescriptionListItem;
@@ -1,5 +1,13 @@
1
1
  import { ViewProps } from 'react-native';
2
- export interface ListItemProps extends ViewProps {
2
+ import { ColorValue } from '../../types';
3
+ export interface ListStyleProps {
4
+ listStyleImage?: React.ReactElement;
5
+ listStyleIcon?: React.ComponentType<any>;
6
+ listStyleWidth?: number;
7
+ listStyleHeight?: number;
8
+ listStyleColour?: ColorValue;
9
+ }
10
+ export interface ListItemProps extends ViewProps, ListStyleProps {
3
11
  children: ViewProps['children'];
4
12
  }
5
13
  declare const ListItem: {
@@ -7,8 +7,7 @@ const ListItem = ({ children, style, ...rest }) => {
7
7
  ListItem.displayName = 'ListItem';
8
8
  const styles = StyleSheet.create({
9
9
  item: {
10
- flexDirection: 'row',
11
- alignItems: 'flex-start',
10
+ flexShrink: 1,
12
11
  },
13
12
  });
14
13
  export default ListItem;
@@ -1,12 +1,13 @@
1
1
  import { ViewProps, ViewStyle } from 'react-native';
2
2
  import { SpaceValue } from '../../types';
3
- export interface OrderedListProps extends ViewProps {
3
+ import { ListStyleProps } from './ListItem';
4
+ export interface OrderedListProps extends ViewProps, ListStyleProps {
4
5
  children: ViewProps['children'];
5
6
  gap?: SpaceValue;
6
7
  bulletStyle?: ViewStyle;
7
8
  }
8
9
  declare const OrderedList: {
9
- ({ children, gap, style, ...rest }: OrderedListProps): import("react/jsx-runtime").JSX.Element;
10
+ ({ children, gap, style, listStyleImage, listStyleIcon, listStyleWidth, listStyleHeight, listStyleColour, ...rest }: OrderedListProps): import("react/jsx-runtime").JSX.Element;
10
11
  displayName: string;
11
12
  };
12
13
  export default OrderedList;
@@ -1,15 +1,40 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { StyleSheet, View } from 'react-native';
4
- import { useStyleProps } from '../../hooks';
4
+ import { useStyleProps, useTheme } from '../../hooks';
5
+ import { getFlattenedColorValue } from '../../utils';
5
6
  import { BodyText } from '../BodyText';
6
- const OrderedList = ({ children, gap = '100', style, ...rest }) => {
7
+ const OrderedList = ({ children, gap = '100', style, listStyleImage, listStyleIcon, listStyleWidth, listStyleHeight, listStyleColour, ...rest }) => {
7
8
  const { computedStyles } = useStyleProps({ gap });
9
+ const theme = useTheme();
8
10
  let itemNumber = 0;
9
11
  return (_jsx(View, { style: [computedStyles, style], ...rest, children: React.Children.map(children, child => {
10
12
  if (React.isValidElement(child)) {
11
13
  itemNumber++;
12
- return (_jsxs(View, { style: styles.listItemContainer, children: [_jsx(BodyText, { style: styles.number, children: `${itemNumber}.` }), React.cloneElement(child, {})] }));
14
+ const childProps = child.props;
15
+ const image = childProps.listStyleImage ?? listStyleImage;
16
+ const Icon = childProps.listStyleIcon ?? listStyleIcon;
17
+ const width = childProps.listStyleWidth ?? listStyleWidth ?? 20;
18
+ const height = childProps.listStyleHeight ?? listStyleHeight ?? 20;
19
+ const colourRaw = childProps.listStyleColour ?? listStyleColour;
20
+ const colour = colourRaw ? getFlattenedColorValue(colourRaw, theme.color) : undefined;
21
+ let bullet;
22
+ if (image) {
23
+ const imageEl = image;
24
+ bullet = React.cloneElement(imageEl, {
25
+ style: [{ width, height }, imageEl.props.style],
26
+ });
27
+ }
28
+ else if (Icon) {
29
+ bullet = (_jsx(Icon, { width: width, height: height, color: colour ?? theme.color.text.primary }));
30
+ }
31
+ else {
32
+ bullet = (_jsx(BodyText, { style: [styles.number, colour && { color: colour }], children: `${itemNumber}.` }));
33
+ }
34
+ const isCustom = !!(image || Icon);
35
+ return (_jsxs(View, { style: styles.listItemContainer, children: [isCustom ? _jsx(View, { style: { marginRight: 8 }, children: bullet }) : bullet, React.cloneElement(child, {
36
+ style: [childProps.style, { flex: 1 }],
37
+ })] }));
13
38
  }
14
39
  return child;
15
40
  }) }));
@@ -22,7 +47,7 @@ const styles = StyleSheet.create({
22
47
  },
23
48
  number: {
24
49
  marginRight: 8,
25
- lineHeight: undefined, // Allow number to align with first line of text
50
+ lineHeight: undefined,
26
51
  },
27
52
  });
28
53
  export default OrderedList;
@@ -1,12 +1,13 @@
1
1
  import { ViewProps, ViewStyle } from 'react-native';
2
2
  import { SpaceValue } from '../../types';
3
- export interface UnorderedListProps extends ViewProps {
3
+ import { ListStyleProps } from './ListItem';
4
+ export interface UnorderedListProps extends ViewProps, ListStyleProps {
4
5
  children: ViewProps['children'];
5
6
  gap?: SpaceValue;
6
7
  bulletStyle?: ViewStyle;
7
8
  }
8
9
  declare const UnorderedList: {
9
- ({ children, gap, style, ...rest }: UnorderedListProps): import("react/jsx-runtime").JSX.Element;
10
+ ({ children, gap, style, listStyleImage, listStyleIcon, listStyleWidth, listStyleHeight, listStyleColour, ...rest }: UnorderedListProps): import("react/jsx-runtime").JSX.Element;
10
11
  displayName: string;
11
12
  };
12
13
  export default UnorderedList;
@@ -1,13 +1,38 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { StyleSheet, View } from 'react-native';
4
- import { useStyleProps } from '../../hooks';
4
+ import { useStyleProps, useTheme } from '../../hooks';
5
+ import { getFlattenedColorValue } from '../../utils';
5
6
  import { BodyText } from '../BodyText';
6
- const UnorderedList = ({ children, gap = '100', style, ...rest }) => {
7
+ const UnorderedList = ({ children, gap = '100', style, listStyleImage, listStyleIcon, listStyleWidth, listStyleHeight, listStyleColour, ...rest }) => {
7
8
  const { computedStyles } = useStyleProps({ gap });
9
+ const theme = useTheme();
8
10
  return (_jsx(View, { style: [computedStyles, style], ...rest, children: React.Children.map(children, child => {
9
11
  if (React.isValidElement(child)) {
10
- return (_jsxs(View, { style: styles.listItemContainer, children: [_jsx(BodyText, { style: styles.bullet, children: "\u2022" }), React.cloneElement(child, {})] }));
12
+ const childProps = child.props;
13
+ const image = childProps.listStyleImage ?? listStyleImage;
14
+ const Icon = childProps.listStyleIcon ?? listStyleIcon;
15
+ const width = childProps.listStyleWidth ?? listStyleWidth ?? 20;
16
+ const height = childProps.listStyleHeight ?? listStyleHeight ?? 20;
17
+ const colourRaw = childProps.listStyleColour ?? listStyleColour;
18
+ const colour = colourRaw ? getFlattenedColorValue(colourRaw, theme.color) : undefined;
19
+ let bullet;
20
+ if (image) {
21
+ const imageEl = image;
22
+ bullet = React.cloneElement(imageEl, {
23
+ style: [{ width, height }, imageEl.props.style],
24
+ });
25
+ }
26
+ else if (Icon) {
27
+ bullet = (_jsx(Icon, { width: width, height: height, color: colour ?? theme.color.text.primary }));
28
+ }
29
+ else {
30
+ bullet = _jsx(BodyText, { style: [styles.bullet, colour && { color: colour }], children: "\u2022" });
31
+ }
32
+ const isCustom = !!(image || Icon);
33
+ return (_jsxs(View, { style: styles.listItemContainer, children: [isCustom ? _jsx(View, { style: { marginRight: 8 }, children: bullet }) : bullet, React.cloneElement(child, {
34
+ style: [childProps.style, { flex: 1 }],
35
+ })] }));
11
36
  }
12
37
  return child;
13
38
  }) }));
@@ -20,7 +45,7 @@ const styles = StyleSheet.create({
20
45
  },
21
46
  bullet: {
22
47
  marginRight: 8,
23
- lineHeight: undefined, // Allow bullet to align with first line of text
48
+ lineHeight: undefined,
24
49
  },
25
50
  });
26
51
  export default UnorderedList;
@@ -23,7 +23,7 @@ const styles = StyleSheet.create(theme => ({
23
23
  container: {
24
24
  flexDirection: 'row',
25
25
  gap: theme.components.formField.helper.gap,
26
- alignItems: 'center',
26
+ alignItems: 'flex-start',
27
27
  variants: {
28
28
  disabled: {
29
29
  true: {
@@ -11,6 +11,7 @@ HelperText.displayName = 'HelperText';
11
11
  const styles = StyleSheet.create(theme => ({
12
12
  text: {
13
13
  color: theme.color.text.secondary,
14
+ flexShrink: 1,
14
15
  variants: {
15
16
  validationStatus: {
16
17
  valid: {
@@ -19,7 +19,7 @@ export const InputComponent = createInput({
19
19
  export const InputSlot = InputComponent.Slot;
20
20
  export const InputField = InputComponent.Input;
21
21
  export const InputIcon = InputComponent.Icon;
22
- const Input = forwardRef(({ validationStatus = 'initial', children, disabled, focused, readonly, leadingIcon, trailingIcon, type, showPasswordToggle = true, onClear, format, loading, clearable = false, required, inBottomSheet = false, ...props }, ref) => {
22
+ const Input = forwardRef(({ validationStatus = 'initial', children, disabled, focused, readonly, leadingIcon, trailingIcon, type, showPasswordToggle = true, onClear, format, loading, clearable = false, required, inBottomSheet = false, style, ...props }, ref) => {
23
23
  const formFieldContext = useFormFieldContext();
24
24
  const { disabled: formFieldDisabled } = formFieldContext;
25
25
  const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
@@ -46,7 +46,7 @@ const Input = forwardRef(({ validationStatus = 'initial', children, disabled, fo
46
46
  }
47
47
  return undefined;
48
48
  })();
49
- return (_jsx(InputComponent, { ...(children ? props : {}), validationStatus: validationStatusFromContext, isInvalid: validationStatusFromContext === 'invalid', isReadOnly: readonly, isDisabled: formFieldDisabled ?? disabled, isFocused: focused, type: type, isRequired: isRequired, children: children ? (_jsx(_Fragment, { children: children })) : (_jsxs(_Fragment, { children: [!!leadingIconComponent && (_jsx(InputSlot, { children: _jsx(InputIcon, { as: leadingIconComponent }) })), _jsx(InputField
49
+ return (_jsx(InputComponent, { ...(children ? props : {}), validationStatus: validationStatusFromContext, isInvalid: validationStatusFromContext === 'invalid', isReadOnly: readonly, isDisabled: formFieldDisabled ?? disabled, isFocused: focused, type: type, isRequired: isRequired, style: style, children: children ? (_jsx(_Fragment, { children: children })) : (_jsxs(_Fragment, { children: [!!leadingIconComponent && (_jsx(InputSlot, { children: _jsx(InputIcon, { as: leadingIconComponent }) })), _jsx(InputField
50
50
  // @ts-expect-error - ref forwarding issue
51
51
  , {
52
52
  // @ts-expect-error - ref forwarding issue
@@ -1,15 +1,27 @@
1
1
  import React from 'react';
2
2
  import { ScrollViewProps, ViewStyle } from 'react-native';
3
- export interface PillGroupProps extends Omit<ScrollViewProps, 'horizontal' | 'contentContainerStyle' | 'showsHorizontalScrollIndicator'> {
4
- /** Controlled selected value(s) */
5
- value: string | string[];
6
- /** Multi-select mode. Default = false */
7
- multiple?: boolean;
3
+ export interface PillGroupBaseProps extends Omit<ScrollViewProps, 'horizontal' | 'contentContainerStyle' | 'showsHorizontalScrollIndicator'> {
8
4
  /** Allow pills to wrap lines. Default = true */
9
5
  wrap?: boolean;
10
- /** Handle selection changes */
11
- onChange?: (value: string | string[]) => void;
12
6
  /** Children must be <Pill> elements */
13
7
  children: React.ReactNode;
14
8
  style?: ViewStyle | ViewStyle[];
15
9
  }
10
+ interface SinglePillGroupProps extends PillGroupBaseProps {
11
+ /** Multi-select mode. Default = false */
12
+ multiple?: false;
13
+ /** Controlled selected value */
14
+ value: string;
15
+ /** Handle selection changes */
16
+ onChange?: (value: string) => void;
17
+ }
18
+ interface MultiPillGroupProps extends PillGroupBaseProps {
19
+ /** Multi-select mode. Default = false */
20
+ multiple: true;
21
+ /** Controlled selected value(s) */
22
+ value: string[];
23
+ /** Handle selection changes */
24
+ onChange?: (value: string[]) => void;
25
+ }
26
+ export type PillGroupProps = SinglePillGroupProps | MultiPillGroupProps;
27
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilitywarehouse/hearth-react-native",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "description": "Utility Warehouse React Native UI library",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -42,6 +42,7 @@ const Checkbox = ({
42
42
  showValidationIcon,
43
43
  type = 'default',
44
44
  image,
45
+ value,
45
46
  ...props
46
47
  }: CheckboxProps) => {
47
48
  const { validationStatus: fieldValidationStatus } = useFormFieldContext();
@@ -80,8 +81,12 @@ const Checkbox = ({
80
81
  </>
81
82
  );
82
83
  return (
83
- // @ts-expect-error - type
84
- <CheckboxComponent {...props} isDisabled={disabled} isChecked={checked}>
84
+ <CheckboxComponent
85
+ {...props}
86
+ value={(value ?? '').toString()}
87
+ isDisabled={disabled}
88
+ isChecked={checked}
89
+ >
85
90
  {checkboxType === 'tile' ? (
86
91
  <CheckboxTileRoot>{checkboxChildren}</CheckboxTileRoot>
87
92
  ) : (
@@ -86,7 +86,14 @@ const styles = StyleSheet.create(theme => ({
86
86
  color: theme.color.text.secondary,
87
87
  },
88
88
  descriptionWrapper: {
89
- flex: 1,
89
+ variants: {
90
+ direction: {
91
+ row: {
92
+ flex: 1,
93
+ },
94
+ column: {},
95
+ },
96
+ },
90
97
  },
91
98
  }));
92
99
 
@@ -1,7 +1,16 @@
1
1
  import { StyleSheet, View, ViewProps } from 'react-native';
2
+ import { ColorValue } from '../../types';
2
3
  import { BodyText } from '../BodyText';
3
4
 
4
- export interface ListItemProps extends ViewProps {
5
+ export interface ListStyleProps {
6
+ listStyleImage?: React.ReactElement;
7
+ listStyleIcon?: React.ComponentType<any>;
8
+ listStyleWidth?: number;
9
+ listStyleHeight?: number;
10
+ listStyleColour?: ColorValue;
11
+ }
12
+
13
+ export interface ListItemProps extends ViewProps, ListStyleProps {
5
14
  children: ViewProps['children'];
6
15
  }
7
16
 
@@ -17,8 +26,7 @@ ListItem.displayName = 'ListItem';
17
26
 
18
27
  const styles = StyleSheet.create({
19
28
  item: {
20
- flexDirection: 'row',
21
- alignItems: 'flex-start',
29
+ flexShrink: 1,
22
30
  },
23
31
  });
24
32
 
@@ -1,6 +1,7 @@
1
- import { Meta, Canvas, Story, Controls } from '@storybook/addon-docs/blocks';
2
- import { UL, OL, LI, Center, BodyText } from '../..';
3
- import { ViewFigmaButton, BackToTopButton, UsageWrap } from '../../../docs/components';
1
+ import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
2
+ import { BodyText, Center, LI, OL, UL } from '../..';
3
+ import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
4
+ import * as UnorderedListStory from './UnorderedList.stories';
4
5
 
5
6
  <Meta title="Utility Components / UL & OL (Lists)" />
6
7
 
@@ -11,6 +12,9 @@ import { ViewFigmaButton, BackToTopButton, UsageWrap } from '../../../docs/compo
11
12
  The `UL` (Unordered List) and `OL` (Ordered List) components are used to display lists of items. `UL` displays a bulleted list, and `OL` displays a numbered list. The `LI` (List Item) component is used to define each item within these lists.
12
13
 
13
14
  - [Usage](#usage)
15
+ - [Unordered List (UL)](#unordered-list-ul)
16
+ - [Ordered List (OL)](#ordered-list-ol)
17
+ - [Customising List Styles](#customising-list-styles)
14
18
  - [Components](#components)
15
19
 
16
20
  ## Usage
@@ -73,32 +77,76 @@ const MyComponent = () => {
73
77
  };
74
78
  ```
75
79
 
80
+ ### Customising List Styles
81
+
82
+ You can customise the appearance of list markers using props like `listStyleIcon`, `listStyleImage`, `listStyleColour`, and dimensions. These props can be applied to the `UL`/`OL` container to affect all items, or on individual `LI` components to override them.
83
+
84
+ <Canvas of={UnorderedListStory.WithCustomIcon} />
85
+
86
+ ```tsx
87
+ import { UL, LI } from '@utilitywarehouse/native-ui';
88
+ import { TickMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
89
+ import { Image } from 'react-native';
90
+
91
+ const MyComponent = () => {
92
+ return (
93
+ <UL listStyleColour="feedbackDangerSurfaceDefault">
94
+ <LI>Primary colored bullet</LI>
95
+ <LI listStyleColour="feedbackPositiveSurfaceDefault">Danger colored bullet override</LI>
96
+ <LI listStyleIcon={TickMediumIcon}>Icon bullet</LI>
97
+ <LI
98
+ listStyleImage={<Image source={{ uri: '...' }} />}
99
+ listStyleWidth={20}
100
+ listStyleHeight={20}
101
+ >
102
+ Image bullet
103
+ </LI>
104
+ </UL>
105
+ );
106
+ };
107
+ ```
108
+
76
109
  ## Components
77
110
 
78
111
  ### `UL`
79
112
 
80
113
  The `UL` component is a container for unordered list items. It inherits all the properties of React Native's [`View` component](https://reactnative.dev/docs/view).
81
114
 
82
- | Property | Type | Default | Description |
83
- | ------------- | ----------------- | ------- | --------------------------------------------------- |
84
- | `gap` | `SpaceValue` | `'100'` | The gap between the list items. |
85
- | `bulletStyle` | `ViewStyle` | - | Custom style for the bullet points. |
86
- | `children` | `React.ReactNode` | - | The `LI` components to be rendered within the list. |
115
+ | Property | Type | Default | Description |
116
+ | ----------------- | --------------------- | ------- | -------------------------------------------------------- |
117
+ | `gap` | `SpaceValue` | `'100'` | The gap between the list items. |
118
+ | `bulletStyle` | `ViewStyle` | - | Custom style for the bullet points. |
119
+ | `children` | `React.ReactNode` | - | The `LI` components to be rendered within the list. |
120
+ | `listStyleImage` | `React.ReactElement` | - | Custom element (e.g. Image) to use as the bullet/marker. |
121
+ | `listStyleIcon` | `React.ComponentType` | - | Custom icon component to use as the bullet/marker. |
122
+ | `listStyleWidth` | `number` | `20` | Width of the custom bullet/marker. |
123
+ | `listStyleHeight` | `number` | `20` | Height of the custom bullet/marker. |
124
+ | `listStyleColour` | `ColorValue` | - | Color of the bullet/marker. |
87
125
 
88
126
  ### `OL`
89
127
 
90
128
  The `OL` component is a container for ordered list items. It inherits all the properties of React Native's [`View` component](https://reactnative.dev/docs/view).
91
129
 
92
- | Property | Type | Default | Description |
93
- | ------------- | ----------------- | ------- | --------------------------------------------------- |
94
- | `gap` | `SpaceValue` | `'100'` | The gap between the list items. |
95
- | `bulletStyle` | `ViewStyle` | - | Custom style for the numbers. |
96
- | `children` | `React.ReactNode` | - | The `LI` components to be rendered within the list. |
130
+ | Property | Type | Default | Description |
131
+ | ----------------- | --------------------- | ------- | -------------------------------------------------------- |
132
+ | `gap` | `SpaceValue` | `'100'` | The gap between the list items. |
133
+ | `bulletStyle` | `ViewStyle` | - | Custom style for the numbers. |
134
+ | `children` | `React.ReactNode` | - | The `LI` components to be rendered within the list. |
135
+ | `listStyleImage` | `React.ReactElement` | - | Custom element (e.g. Image) to use as the bullet/marker. |
136
+ | `listStyleIcon` | `React.ComponentType` | - | Custom icon component to use as the bullet/marker. |
137
+ | `listStyleWidth` | `number` | `20` | Width of the custom bullet/marker. |
138
+ | `listStyleHeight` | `number` | `20` | Height of the custom bullet/marker. |
139
+ | `listStyleColour` | `ColorValue` | - | Color of the number/marker. |
97
140
 
98
141
  ### `LI`
99
142
 
100
143
  The `LI` component represents an item in a list. It wraps its children in a `BodyText` component if the children are a string. It inherits all the properties of React Native's [`View` component](https://reactnative.dev/docs/view).
101
144
 
102
- | Property | Type | Default | Description |
103
- | ---------- | ----------------- | ------- | ------------------------------------------------- |
104
- | `children` | `React.ReactNode` | - | The content to be displayed inside the list item. |
145
+ | Property | Type | Default | Description |
146
+ | ----------------- | --------------------- | ------- | -------------------------------------------------------- |
147
+ | `children` | `React.ReactNode` | - | The content to be displayed inside the list item. |
148
+ | `listStyleImage` | `React.ReactElement` | - | Custom element (e.g. Image) to use as the bullet/marker. |
149
+ | `listStyleIcon` | `React.ComponentType` | - | Custom icon component to use as the bullet/marker. |
150
+ | `listStyleWidth` | `number` | `20` | Width of the custom bullet/marker. |
151
+ | `listStyleHeight` | `number` | `20` | Height of the custom bullet/marker. |
152
+ | `listStyleColour` | `ColorValue` | - | Color of the bullet/marker/number. |
@@ -1,9 +1,10 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-vite';
2
- import OrderedList from './OrderedList';
3
- import ListItem from './ListItem';
4
2
  import { primitive } from '@utilitywarehouse/hearth-tokens/js';
3
+ import { View } from 'react-native';
5
4
  import { InputType } from 'storybook/internal/types';
6
5
  import { SpaceValue } from '../../types';
6
+ import ListItem from './ListItem';
7
+ import OrderedList from './OrderedList';
7
8
 
8
9
  const gap: InputType = {
9
10
  options: Object.keys(primitive.space),
@@ -53,3 +54,33 @@ export const WithCustomGap: Story = {
53
54
  </OrderedList>
54
55
  ),
55
56
  };
57
+
58
+ export const WithColoredNumbers: Story = {
59
+ render: ({ ...args }) => (
60
+ <OrderedList {...args} listStyleColour="piggyPink300">
61
+ <ListItem>Item 1</ListItem>
62
+ <ListItem>Item 2</ListItem>
63
+ </OrderedList>
64
+ ),
65
+ };
66
+
67
+ export const WithIconOverride: Story = {
68
+ render: ({ ...args }) => {
69
+ const CustomIcon = (props: any) => (
70
+ <View
71
+ style={{
72
+ width: props.width,
73
+ height: props.height,
74
+ backgroundColor: props.color || 'blue',
75
+ borderRadius: 4,
76
+ }}
77
+ />
78
+ );
79
+ return (
80
+ <OrderedList {...args} listStyleIcon={CustomIcon}>
81
+ <ListItem>Item 1 (overridden)</ListItem>
82
+ <ListItem>Item 2 (overridden)</ListItem>
83
+ </OrderedList>
84
+ );
85
+ },
86
+ };
@@ -1,27 +1,75 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet, View, ViewProps, ViewStyle } from 'react-native';
3
- import { useStyleProps } from '../../hooks';
3
+ import { useStyleProps, useTheme } from '../../hooks';
4
4
  import { SpaceValue } from '../../types';
5
+ import { getFlattenedColorValue } from '../../utils';
5
6
  import { BodyText } from '../BodyText';
7
+ import { ListItemProps, ListStyleProps } from './ListItem';
6
8
 
7
- export interface OrderedListProps extends ViewProps {
9
+ export interface OrderedListProps extends ViewProps, ListStyleProps {
8
10
  children: ViewProps['children'];
9
11
  gap?: SpaceValue;
10
12
  bulletStyle?: ViewStyle;
11
13
  }
12
14
 
13
- const OrderedList = ({ children, gap = '100', style, ...rest }: OrderedListProps) => {
15
+ const OrderedList = ({
16
+ children,
17
+ gap = '100',
18
+ style,
19
+ listStyleImage,
20
+ listStyleIcon,
21
+ listStyleWidth,
22
+ listStyleHeight,
23
+ listStyleColour,
24
+ ...rest
25
+ }: OrderedListProps) => {
14
26
  const { computedStyles } = useStyleProps({ gap });
27
+ const theme = useTheme();
15
28
  let itemNumber = 0;
29
+
16
30
  return (
17
31
  <View style={[computedStyles, style]} {...rest}>
18
32
  {React.Children.map(children, child => {
19
33
  if (React.isValidElement(child)) {
20
34
  itemNumber++;
35
+ const childProps = child.props as ListItemProps;
36
+
37
+ const image = childProps.listStyleImage ?? listStyleImage;
38
+ const Icon = childProps.listStyleIcon ?? listStyleIcon;
39
+ const width = childProps.listStyleWidth ?? listStyleWidth ?? 20;
40
+ const height = childProps.listStyleHeight ?? listStyleHeight ?? 20;
41
+ const colourRaw = childProps.listStyleColour ?? listStyleColour;
42
+
43
+ const colour = colourRaw ? getFlattenedColorValue(colourRaw, theme.color) : undefined;
44
+
45
+ let bullet;
46
+ if (image) {
47
+ const imageEl = image as React.ReactElement<any>;
48
+ bullet = React.cloneElement(imageEl, {
49
+ style: [{ width, height }, imageEl.props.style],
50
+ });
51
+ } else if (Icon) {
52
+ bullet = (
53
+ <Icon width={width} height={height} color={colour ?? theme.color.text.primary} />
54
+ );
55
+ } else {
56
+ bullet = (
57
+ <BodyText
58
+ style={[styles.number, colour && { color: colour }]}
59
+ >{`${itemNumber}.`}</BodyText>
60
+ );
61
+ }
62
+
63
+ const isCustom = !!(image || Icon);
64
+
21
65
  return (
22
66
  <View style={styles.listItemContainer}>
23
- <BodyText style={styles.number}>{`${itemNumber}.`}</BodyText>
24
- {React.cloneElement(child as React.ReactElement<any>, {}) as ViewProps['children']}
67
+ {isCustom ? <View style={{ marginRight: 8 }}>{bullet}</View> : bullet}
68
+ {
69
+ React.cloneElement(child as React.ReactElement<ListItemProps>, {
70
+ style: [childProps.style, { flex: 1 }],
71
+ }) as ViewProps['children']
72
+ }
25
73
  </View>
26
74
  );
27
75
  }
@@ -40,7 +88,7 @@ const styles = StyleSheet.create({
40
88
  },
41
89
  number: {
42
90
  marginRight: 8,
43
- lineHeight: undefined, // Allow number to align with first line of text
91
+ lineHeight: undefined,
44
92
  },
45
93
  });
46
94
 
@@ -1,10 +1,11 @@
1
- import { Meta, StoryObj } from '@storybook/react-vite';
2
- import UnorderedList from './UnorderedList';
3
- import ListItem from './ListItem';
1
+ import { Meta, StoryObj } from '@storybook/react-native';
2
+ import { TickMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
4
3
  import { primitive } from '@utilitywarehouse/hearth-tokens/js';
5
- import { InputType } from 'storybook/internal/types';
4
+ import { Image, View } from 'react-native';
5
+ import ListItem from './ListItem';
6
+ import UnorderedList from './UnorderedList';
6
7
 
7
- const gap: InputType = {
8
+ const gap = {
8
9
  options: Object.keys(primitive.space),
9
10
  control: 'select',
10
11
  description: 'Gap between list items.',
@@ -50,3 +51,60 @@ export const WithCustomGap: Story = {
50
51
  </UnorderedList>
51
52
  ),
52
53
  };
54
+
55
+ export const WithCustomIcon: Story = {
56
+ render: ({ ...args }) => {
57
+ return (
58
+ <UnorderedList
59
+ {...args}
60
+ listStyleIcon={TickMediumIcon}
61
+ listStyleColour="feedbackDangerSurfaceDefault"
62
+ >
63
+ <ListItem>List item 1 with icon</ListItem>
64
+ <ListItem>List item 2 with icon</ListItem>
65
+ <ListItem>
66
+ List item 3 with icon is a long example to test alignment, lorem ipsum dolor sit amet
67
+ </ListItem>
68
+ </UnorderedList>
69
+ );
70
+ },
71
+ };
72
+
73
+ export const WithCustomImage: Story = {
74
+ render: ({ ...args }) => (
75
+ <UnorderedList
76
+ {...args}
77
+ listStyleImage={
78
+ <Image
79
+ source={{ uri: 'https://placehold.co/20x20.png' }}
80
+ style={{ width: 20, height: 20 }}
81
+ />
82
+ }
83
+ >
84
+ <ListItem>List item 1 with image</ListItem>
85
+ <ListItem>List item 2 with image</ListItem>
86
+ </UnorderedList>
87
+ ),
88
+ };
89
+
90
+ export const WithIndividualItemOverride: Story = {
91
+ render: ({ ...args }) => {
92
+ const CheckIcon = (props: any) => (
93
+ <View
94
+ style={{
95
+ width: props.width,
96
+ height: props.height,
97
+ backgroundColor: 'green',
98
+ borderRadius: 10,
99
+ }}
100
+ />
101
+ );
102
+ return (
103
+ <UnorderedList {...args}>
104
+ <ListItem>Default bullet item</ListItem>
105
+ <ListItem listStyleIcon={CheckIcon}>Success item</ListItem>
106
+ <ListItem listStyleColour="blue600">Colored bullet item</ListItem>
107
+ </UnorderedList>
108
+ );
109
+ },
110
+ };
@@ -1,25 +1,69 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet, View, ViewProps, ViewStyle } from 'react-native';
3
- import { useStyleProps } from '../../hooks';
3
+ import { useStyleProps, useTheme } from '../../hooks';
4
4
  import { SpaceValue } from '../../types';
5
+ import { getFlattenedColorValue } from '../../utils';
5
6
  import { BodyText } from '../BodyText';
7
+ import { ListItemProps, ListStyleProps } from './ListItem';
6
8
 
7
- export interface UnorderedListProps extends ViewProps {
9
+ export interface UnorderedListProps extends ViewProps, ListStyleProps {
8
10
  children: ViewProps['children'];
9
11
  gap?: SpaceValue;
10
12
  bulletStyle?: ViewStyle;
11
13
  }
12
14
 
13
- const UnorderedList = ({ children, gap = '100', style, ...rest }: UnorderedListProps) => {
15
+ const UnorderedList = ({
16
+ children,
17
+ gap = '100',
18
+ style,
19
+ listStyleImage,
20
+ listStyleIcon,
21
+ listStyleWidth,
22
+ listStyleHeight,
23
+ listStyleColour,
24
+ ...rest
25
+ }: UnorderedListProps) => {
14
26
  const { computedStyles } = useStyleProps({ gap });
27
+ const theme = useTheme();
28
+
15
29
  return (
16
30
  <View style={[computedStyles, style]} {...rest}>
17
31
  {React.Children.map(children, child => {
18
32
  if (React.isValidElement(child)) {
33
+ const childProps = child.props as ListItemProps;
34
+
35
+ const image = childProps.listStyleImage ?? listStyleImage;
36
+ const Icon = childProps.listStyleIcon ?? listStyleIcon;
37
+ const width = childProps.listStyleWidth ?? listStyleWidth ?? 20;
38
+ const height = childProps.listStyleHeight ?? listStyleHeight ?? 20;
39
+ const colourRaw = childProps.listStyleColour ?? listStyleColour;
40
+
41
+ const colour = colourRaw ? getFlattenedColorValue(colourRaw, theme.color) : undefined;
42
+
43
+ let bullet;
44
+ if (image) {
45
+ const imageEl = image as React.ReactElement<any>;
46
+ bullet = React.cloneElement(imageEl, {
47
+ style: [{ width, height }, imageEl.props.style],
48
+ });
49
+ } else if (Icon) {
50
+ bullet = (
51
+ <Icon width={width} height={height} color={colour ?? theme.color.text.primary} />
52
+ );
53
+ } else {
54
+ bullet = <BodyText style={[styles.bullet, colour && { color: colour }]}>•</BodyText>;
55
+ }
56
+
57
+ const isCustom = !!(image || Icon);
58
+
19
59
  return (
20
60
  <View style={styles.listItemContainer}>
21
- <BodyText style={styles.bullet}>•</BodyText>
22
- {React.cloneElement(child as React.ReactElement<any>, {}) as ViewProps['children']}
61
+ {isCustom ? <View style={{ marginRight: 8 }}>{bullet}</View> : bullet}
62
+ {
63
+ React.cloneElement(child as React.ReactElement<ListItemProps>, {
64
+ style: [childProps.style, { flex: 1 }],
65
+ }) as ViewProps['children']
66
+ }
23
67
  </View>
24
68
  );
25
69
  }
@@ -38,7 +82,7 @@ const styles = StyleSheet.create({
38
82
  },
39
83
  bullet: {
40
84
  marginRight: 8,
41
- lineHeight: undefined, // Allow bullet to align with first line of text
85
+ lineHeight: undefined,
42
86
  },
43
87
  });
44
88
 
@@ -52,7 +52,7 @@ const styles = StyleSheet.create(theme => ({
52
52
  container: {
53
53
  flexDirection: 'row',
54
54
  gap: theme.components.formField.helper.gap,
55
- alignItems: 'center',
55
+ alignItems: 'flex-start',
56
56
  variants: {
57
57
  disabled: {
58
58
  true: {
@@ -23,6 +23,7 @@ HelperText.displayName = 'HelperText';
23
23
  const styles = StyleSheet.create(theme => ({
24
24
  text: {
25
25
  color: theme.color.text.secondary,
26
+ flexShrink: 1,
26
27
  variants: {
27
28
  validationStatus: {
28
29
  valid: {
@@ -48,6 +48,7 @@ const Input = forwardRef<TextInput, InputProps>(
48
48
  clearable = false,
49
49
  required,
50
50
  inBottomSheet = false,
51
+ style,
51
52
  ...props
52
53
  },
53
54
  ref
@@ -96,6 +97,7 @@ const Input = forwardRef<TextInput, InputProps>(
96
97
  isFocused={focused}
97
98
  type={type as undefined}
98
99
  isRequired={isRequired}
100
+ style={style}
99
101
  >
100
102
  {children ? (
101
103
  <>{children}</>
@@ -1,22 +1,36 @@
1
1
  import React from 'react';
2
2
  import { ScrollViewProps, ViewStyle } from 'react-native';
3
3
 
4
- export interface PillGroupProps
5
- extends Omit<ScrollViewProps, 'horizontal' | 'contentContainerStyle' | 'showsHorizontalScrollIndicator'> {
6
- /** Controlled selected value(s) */
7
- value: string | string[];
8
-
9
- /** Multi-select mode. Default = false */
10
- multiple?: boolean;
11
-
4
+ export interface PillGroupBaseProps
5
+ extends Omit<
6
+ ScrollViewProps,
7
+ 'horizontal' | 'contentContainerStyle' | 'showsHorizontalScrollIndicator'
8
+ > {
12
9
  /** Allow pills to wrap lines. Default = true */
13
10
  wrap?: boolean;
14
11
 
15
- /** Handle selection changes */
16
- onChange?: (value: string | string[]) => void;
17
-
18
12
  /** Children must be <Pill> elements */
19
13
  children: React.ReactNode;
20
14
 
21
15
  style?: ViewStyle | ViewStyle[];
22
16
  }
17
+
18
+ interface SinglePillGroupProps extends PillGroupBaseProps {
19
+ /** Multi-select mode. Default = false */
20
+ multiple?: false;
21
+ /** Controlled selected value */
22
+ value: string;
23
+ /** Handle selection changes */
24
+ onChange?: (value: string) => void;
25
+ }
26
+
27
+ interface MultiPillGroupProps extends PillGroupBaseProps {
28
+ /** Multi-select mode. Default = false */
29
+ multiple: true;
30
+ /** Controlled selected value(s) */
31
+ value: string[];
32
+ /** Handle selection changes */
33
+ onChange?: (value: string[]) => void;
34
+ }
35
+
36
+ export type PillGroupProps = SinglePillGroupProps | MultiPillGroupProps;
@@ -1,12 +1,11 @@
1
- import React, { useState } from 'react';
2
1
  import { Meta, StoryObj } from '@storybook/react-vite';
3
2
  import { HeartMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
3
+ import { useState } from 'react';
4
4
  import { PillGroup } from '.';
5
- import { Pill } from './Pill';
6
5
  import { VariantTitle } from '../../../docs/components';
7
6
  import { BodyText } from '../BodyText';
8
7
  import { Flex } from '../Flex';
9
- import { Heading } from '../Heading';
8
+ import { Pill } from './Pill';
10
9
 
11
10
  const meta = {
12
11
  title: 'Stories / PillGroup',
@@ -104,7 +103,7 @@ export const WrapBehavior: Story = {
104
103
  return (
105
104
  <Flex space="xl" direction="column" align="center">
106
105
  <VariantTitle title="Wrap: False">
107
- <PillGroup wrap={false} value={value1} onChange={v => setValue1(v as string)}>
106
+ <PillGroup wrap={false} value={value1} onChange={setValue1}>
108
107
  <Pill value="1" label="New" />
109
108
  <Pill value="2" label="Some label" />
110
109
  <Pill value="3" label="Short" />
@@ -113,7 +112,7 @@ export const WrapBehavior: Story = {
113
112
  </PillGroup>
114
113
  </VariantTitle>
115
114
  <VariantTitle title="Wrap: True">
116
- <PillGroup wrap={true} value={value2} onChange={v => setValue2(v as string)}>
115
+ <PillGroup wrap={true} value={value2} onChange={setValue2}>
117
116
  <Pill value="6" label="New" />
118
117
  <Pill value="7" label="Some label" />
119
118
  <Pill value="8" label="Short" />
@@ -141,7 +140,7 @@ export const Multiple: Story = {
141
140
 
142
141
  return (
143
142
  <Flex space="lg" direction="column" align="center" style={{ maxWidth: 400 }}>
144
- <PillGroup wrap={true} multiple value={selectedCategories} onChange={v => setSelectedCategories(v as string[])}>
143
+ <PillGroup wrap={true} multiple value={selectedCategories} onChange={setSelectedCategories}>
145
144
  <Pill value="unread" label="Unread" />
146
145
  <Pill value="new" label="New" icon={HeartMediumIcon} />
147
146
  <Pill value="favourites" label="My favourites" icon={HeartMediumIcon} />
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { ScrollView } from 'react-native';
3
3
  import { StyleSheet } from 'react-native-unistyles';
4
4
  import { Box } from '../Box';
@@ -24,9 +24,9 @@ export const PillGroup = ({
24
24
  const newValue = normalizedValue.includes(pillValue)
25
25
  ? normalizedValue.filter(v => v !== pillValue)
26
26
  : [...normalizedValue, pillValue];
27
- onChange?.(newValue);
27
+ (onChange as (value: string[]) => void)?.(newValue);
28
28
  } else {
29
- onChange?.(pillValue);
29
+ (onChange as (value: string) => void)?.(pillValue);
30
30
  }
31
31
  },
32
32
  }),