@utilitywarehouse/hearth-react-native 0.9.0 → 0.10.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 (75) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +8 -0
  4. package/build/components/PillGroup/Pill.d.ts +16 -0
  5. package/build/components/PillGroup/Pill.js +94 -0
  6. package/build/components/PillGroup/Pill.props.d.ts +10 -0
  7. package/build/components/PillGroup/Pill.props.js +1 -0
  8. package/build/components/PillGroup/PillGroup.context.d.ts +6 -0
  9. package/build/components/PillGroup/PillGroup.context.js +5 -0
  10. package/build/components/PillGroup/PillGroup.d.ts +5 -0
  11. package/build/components/PillGroup/PillGroup.js +34 -0
  12. package/build/components/PillGroup/PillGroup.props.d.ts +15 -0
  13. package/build/components/PillGroup/PillGroup.props.js +1 -0
  14. package/build/components/PillGroup/index.d.ts +4 -0
  15. package/build/components/PillGroup/index.js +2 -0
  16. package/build/components/Select/Select.js +2 -1
  17. package/build/components/Toast/Toast.context.d.ts +9 -0
  18. package/build/components/Toast/Toast.context.js +90 -0
  19. package/build/components/Toast/Toast.props.d.ts +29 -0
  20. package/build/components/Toast/Toast.props.js +1 -0
  21. package/build/components/Toast/ToastItem.d.ts +10 -0
  22. package/build/components/Toast/ToastItem.js +129 -0
  23. package/build/components/Toast/index.d.ts +3 -0
  24. package/build/components/Toast/index.js +2 -0
  25. package/build/components/index.d.ts +2 -0
  26. package/build/components/index.js +2 -0
  27. package/build/tokens/components/dark/checkbox.d.ts +3 -0
  28. package/build/tokens/components/dark/checkbox.js +3 -0
  29. package/build/tokens/components/dark/input.d.ts +6 -0
  30. package/build/tokens/components/dark/input.js +6 -0
  31. package/build/tokens/components/dark/radio.d.ts +3 -0
  32. package/build/tokens/components/dark/radio.js +3 -0
  33. package/build/tokens/components/dark/table.d.ts +2 -0
  34. package/build/tokens/components/dark/table.js +2 -0
  35. package/build/tokens/components/dark/toast.d.ts +6 -2
  36. package/build/tokens/components/dark/toast.js +6 -2
  37. package/build/tokens/components/light/checkbox.d.ts +3 -0
  38. package/build/tokens/components/light/checkbox.js +3 -0
  39. package/build/tokens/components/light/input.d.ts +6 -0
  40. package/build/tokens/components/light/input.js +6 -0
  41. package/build/tokens/components/light/radio.d.ts +3 -0
  42. package/build/tokens/components/light/radio.js +3 -0
  43. package/build/tokens/components/light/table.d.ts +2 -0
  44. package/build/tokens/components/light/table.js +2 -0
  45. package/build/tokens/components/light/toast.d.ts +6 -2
  46. package/build/tokens/components/light/toast.js +6 -2
  47. package/docs/assets/toast-ios.MP4 +0 -0
  48. package/docs/components/AllComponents.web.tsx +26 -0
  49. package/package.json +3 -3
  50. package/src/components/PillGroup/Pill.props.ts +13 -0
  51. package/src/components/PillGroup/Pill.tsx +120 -0
  52. package/src/components/PillGroup/PillGroup.context.tsx +12 -0
  53. package/src/components/PillGroup/PillGroup.docs.mdx +96 -0
  54. package/src/components/PillGroup/PillGroup.props.ts +22 -0
  55. package/src/components/PillGroup/PillGroup.stories.tsx +159 -0
  56. package/src/components/PillGroup/PillGroup.tsx +66 -0
  57. package/src/components/PillGroup/index.ts +4 -0
  58. package/src/components/Select/Select.tsx +2 -0
  59. package/src/components/Toast/Toast.context.tsx +118 -0
  60. package/src/components/Toast/Toast.docs.mdx +164 -0
  61. package/src/components/Toast/Toast.props.ts +33 -0
  62. package/src/components/Toast/Toast.stories.tsx +356 -0
  63. package/src/components/Toast/ToastItem.tsx +200 -0
  64. package/src/components/Toast/index.ts +3 -0
  65. package/src/components/index.ts +2 -0
  66. package/src/tokens/components/dark/checkbox.ts +3 -0
  67. package/src/tokens/components/dark/input.ts +6 -0
  68. package/src/tokens/components/dark/radio.ts +3 -0
  69. package/src/tokens/components/dark/table.ts +2 -0
  70. package/src/tokens/components/dark/toast.ts +6 -2
  71. package/src/tokens/components/light/checkbox.ts +3 -0
  72. package/src/tokens/components/light/input.ts +6 -0
  73. package/src/tokens/components/light/radio.ts +3 -0
  74. package/src/tokens/components/light/table.ts +2 -0
  75. package/src/tokens/components/light/toast.ts +6 -2
@@ -5,6 +5,7 @@ declare const _default: {
5
5
  readonly borderRadius: 16;
6
6
  readonly cell: {
7
7
  readonly borderWidth: 1;
8
+ readonly minHeight: 48;
8
9
  readonly padding: 12;
9
10
  };
10
11
  readonly emphasis: {
@@ -13,6 +14,7 @@ declare const _default: {
13
14
  readonly headerCell: {
14
15
  readonly borderWidth: 2;
15
16
  readonly gap: 8;
17
+ readonly height: 56;
16
18
  readonly paddingHorizontal: 12;
17
19
  readonly paddingVertical: 16;
18
20
  };
@@ -5,6 +5,7 @@ export default {
5
5
  borderRadius: 16,
6
6
  cell: {
7
7
  borderWidth: 1,
8
+ minHeight: 48,
8
9
  padding: 12,
9
10
  },
10
11
  emphasis: {
@@ -13,6 +14,7 @@ export default {
13
14
  headerCell: {
14
15
  borderWidth: 2,
15
16
  gap: 8,
17
+ height: 56,
16
18
  paddingHorizontal: 12,
17
19
  paddingVertical: 16,
18
20
  },
@@ -4,10 +4,14 @@
4
4
  declare const _default: {
5
5
  readonly backgroundColor: "#3f3f3f";
6
6
  readonly borderRadius: 8;
7
- readonly gapHorizontal: 16;
7
+ readonly bottomPosition: 32;
8
+ readonly gap: 16;
8
9
  readonly padding: 14;
9
10
  readonly stack: {
10
- readonly gapHorizontal: 8;
11
+ readonly gap: 12;
12
+ };
13
+ readonly text: {
14
+ readonly gap: 8;
11
15
  };
12
16
  };
13
17
  export default _default;
@@ -4,9 +4,13 @@
4
4
  export default {
5
5
  backgroundColor: '#3f3f3f',
6
6
  borderRadius: 8,
7
- gapHorizontal: 16,
7
+ bottomPosition: 32,
8
+ gap: 16,
8
9
  padding: 14,
9
10
  stack: {
10
- gapHorizontal: 8,
11
+ gap: 12,
12
+ },
13
+ text: {
14
+ gap: 8,
11
15
  },
12
16
  };
@@ -27,6 +27,9 @@ declare const _default: {
27
27
  readonly gap: 12;
28
28
  readonly group: {
29
29
  readonly gap: 6;
30
+ readonly heading: {
31
+ readonly gap: 2;
32
+ };
30
33
  readonly stack: {
31
34
  readonly gap: 12;
32
35
  };
@@ -27,6 +27,9 @@ export default {
27
27
  gap: 12,
28
28
  group: {
29
29
  gap: 6,
30
+ heading: {
31
+ gap: 2,
32
+ },
30
33
  stack: {
31
34
  gap: 12,
32
35
  },
@@ -13,6 +13,12 @@ declare const _default: {
13
13
  readonly gap: 8;
14
14
  };
15
15
  readonly gap: 6;
16
+ readonly heading: {
17
+ readonly gap: 12;
18
+ readonly text: {
19
+ readonly gap: 2;
20
+ };
21
+ };
16
22
  readonly height: 48;
17
23
  readonly label: {
18
24
  readonly gap: 2;
@@ -13,6 +13,12 @@ export default {
13
13
  gap: 8,
14
14
  },
15
15
  gap: 6,
16
+ heading: {
17
+ gap: 12,
18
+ text: {
19
+ gap: 2,
20
+ },
21
+ },
16
22
  height: 48,
17
23
  label: {
18
24
  gap: 2,
@@ -24,6 +24,9 @@ declare const _default: {
24
24
  readonly gap: 8;
25
25
  readonly group: {
26
26
  readonly gap: 12;
27
+ readonly heading: {
28
+ readonly gap: 2;
29
+ };
27
30
  readonly stack: {
28
31
  readonly gap: 12;
29
32
  };
@@ -24,6 +24,9 @@ export default {
24
24
  gap: 8,
25
25
  group: {
26
26
  gap: 12,
27
+ heading: {
28
+ gap: 2,
29
+ },
27
30
  stack: {
28
31
  gap: 12,
29
32
  },
@@ -5,6 +5,7 @@ declare const _default: {
5
5
  readonly borderRadius: 16;
6
6
  readonly cell: {
7
7
  readonly borderWidth: 1;
8
+ readonly minHeight: 48;
8
9
  readonly padding: 12;
9
10
  };
10
11
  readonly emphasis: {
@@ -13,6 +14,7 @@ declare const _default: {
13
14
  readonly headerCell: {
14
15
  readonly borderWidth: 2;
15
16
  readonly gap: 8;
17
+ readonly height: 56;
16
18
  readonly paddingHorizontal: 12;
17
19
  readonly paddingVertical: 16;
18
20
  };
@@ -5,6 +5,7 @@ export default {
5
5
  borderRadius: 16,
6
6
  cell: {
7
7
  borderWidth: 1,
8
+ minHeight: 48,
8
9
  padding: 12,
9
10
  },
10
11
  emphasis: {
@@ -13,6 +14,7 @@ export default {
13
14
  headerCell: {
14
15
  borderWidth: 2,
15
16
  gap: 8,
17
+ height: 56,
16
18
  paddingHorizontal: 12,
17
19
  paddingVertical: 16,
18
20
  },
@@ -4,10 +4,14 @@
4
4
  declare const _default: {
5
5
  readonly backgroundColor: "#101010";
6
6
  readonly borderRadius: 8;
7
- readonly gapHorizontal: 16;
7
+ readonly bottomPosition: 32;
8
+ readonly gap: 16;
8
9
  readonly padding: 14;
9
10
  readonly stack: {
10
- readonly gapHorizontal: 8;
11
+ readonly gap: 12;
12
+ };
13
+ readonly text: {
14
+ readonly gap: 8;
11
15
  };
12
16
  };
13
17
  export default _default;
@@ -4,9 +4,13 @@
4
4
  export default {
5
5
  backgroundColor: '#101010',
6
6
  borderRadius: 8,
7
- gapHorizontal: 16,
7
+ bottomPosition: 32,
8
+ gap: 16,
8
9
  padding: 14,
9
10
  stack: {
10
- gapHorizontal: 8,
11
+ gap: 12,
12
+ },
13
+ text: {
14
+ gap: 8,
11
15
  },
12
16
  };
Binary file
@@ -68,6 +68,8 @@ import {
68
68
  MenuTrigger,
69
69
  Modal,
70
70
  OL,
71
+ Pill,
72
+ PillGroup,
71
73
  ProgressStep,
72
74
  ProgressStepper,
73
75
  Radio,
@@ -85,6 +87,7 @@ import {
85
87
  TabsList,
86
88
  Textarea,
87
89
  ThemedImage,
90
+ ToastItem,
88
91
  ToggleButtonCard,
89
92
  ToggleButtonCardGroup,
90
93
  UL,
@@ -627,6 +630,21 @@ const AllComponents: React.FC = () => {
627
630
  </OL>
628
631
  </Center>
629
632
  </ComponentWrapper>
633
+ <ComponentWrapper name="Pill Group" link="/?path=/docs/components-pill-group--docs">
634
+ <Center flex={1} p="200">
635
+ {(() => {
636
+ const [pillValue, setPillValue] = React.useState<string[]>(['energy', 'mobile']);
637
+ return (
638
+ <PillGroup value={pillValue} onChange={v => setPillValue(v as string[])} wrap={false} multiple>
639
+ <Pill value="all" label="All" />
640
+ <Pill value="energy" label="Energy" icon={ElectricityMediumIcon} />
641
+ <Pill value="broadband" label="Broadband" icon={BroadbandMediumIcon} />
642
+ <Pill value="mobile" label="Mobile" icon={MobileMediumIcon} />
643
+ </PillGroup>
644
+ );
645
+ })()}
646
+ </Center>
647
+ </ComponentWrapper>
630
648
  <ComponentWrapper
631
649
  name="Progress Stepper"
632
650
  link="/?path=/docs/components-progress-stepper--docs"
@@ -745,6 +763,14 @@ const AllComponents: React.FC = () => {
745
763
  />
746
764
  </Center>
747
765
  </ComponentWrapper>
766
+ <ComponentWrapper name="Toast" link="/?path=/docs/components-toast--docs">
767
+ <Center flex={1} p="200">
768
+ <ToastItem
769
+ onClose={() => {}}
770
+ toast={{ id: 'tst', text: "I'm a toast", duration: 0 }}
771
+ />
772
+ </Center>
773
+ </ComponentWrapper>
748
774
  <ComponentWrapper
749
775
  name="Toggle Button Card"
750
776
  link="/?path=/docs/components-toggle-button-card--docs"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilitywarehouse/hearth-react-native",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Utility Warehouse React Native UI library",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -57,8 +57,8 @@
57
57
  "vite-plugin-svgr": "^4.5.0",
58
58
  "vitest": "^3.2.4",
59
59
  "@utilitywarehouse/hearth-fonts": "^0.0.4",
60
- "@utilitywarehouse/hearth-react-icons": "^0.7.3",
61
- "@utilitywarehouse/hearth-react-native-icons": "^0.7.3",
60
+ "@utilitywarehouse/hearth-react-icons": "^0.7.4",
61
+ "@utilitywarehouse/hearth-react-native-icons": "^0.7.4",
62
62
  "@utilitywarehouse/hearth-svg-assets": "^0.2.0",
63
63
  "@utilitywarehouse/hearth-tokens": "^0.2.0"
64
64
  },
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { PressableProps } from 'react-native';
3
+
4
+ export interface PillProps extends Omit<PressableProps, 'children'> {
5
+ /** Value returned when selected */
6
+ value: string;
7
+
8
+ /** Text label shown inside the pill */
9
+ label: string;
10
+
11
+ /** Left icon */
12
+ icon?: React.ComponentType<any>;
13
+ }
@@ -0,0 +1,120 @@
1
+ import { createPressable } from '@gluestack-ui/pressable';
2
+ import { Pressable } from 'react-native';
3
+ import { StyleSheet } from 'react-native-unistyles';
4
+ import { Icon } from '../Icon';
5
+ import { BodyText } from '../BodyText';
6
+ import { usePillGroupContext } from './PillGroup.context';
7
+ import type { PillProps } from './Pill.props';
8
+
9
+ const PillRoot = ({
10
+ value,
11
+ label,
12
+ icon,
13
+ states = {},
14
+ ...props
15
+ }: PillProps & { states?: { active?: boolean } }) => {
16
+ const { active } = states;
17
+ const context = usePillGroupContext();
18
+ const isSelected = context?.value.includes(value) ?? false;
19
+
20
+ styles.useVariants({ selected: isSelected, active });
21
+
22
+ const handlePress = () => {
23
+ context?.onChange(value);
24
+ };
25
+
26
+ return (
27
+ <Pressable
28
+ {...props}
29
+ style={styles.pill}
30
+ accessibilityRole="button"
31
+ accessibilityState={{ selected: isSelected }}
32
+ onPress={handlePress}
33
+ >
34
+ {icon && <Icon as={icon} size="sm" style={styles.icon} />}
35
+ <BodyText weight="semibold" style={styles.text}>
36
+ {label}
37
+ </BodyText>
38
+ </Pressable>
39
+ );
40
+ };
41
+
42
+ export const Pill = createPressable({ Root: PillRoot });
43
+
44
+ Pill.displayName = 'Pill';
45
+
46
+ const styles = StyleSheet.create(theme => ({
47
+ pill: {
48
+ flexDirection: 'row',
49
+ alignItems: 'center',
50
+ justifyContent: 'center',
51
+ height: theme.components.pill.height,
52
+ minWidth: theme.components.pill.minWidth,
53
+ gap: theme.components.pill.gap,
54
+ paddingHorizontal: theme.components.pill.paddingHorizontal,
55
+ paddingVertical: theme.components.pill.paddingVertical,
56
+ borderRadius: theme.components.pill.borderRadius,
57
+ borderWidth: theme.components.pill.borderWidth,
58
+ borderColor: theme.color.interactive.neutral.border.subtle,
59
+ backgroundColor: 'transparent',
60
+ _web: {
61
+ _hover: {
62
+ backgroundColor: theme.color.interactive.neutral.surface.subtle.hover,
63
+ },
64
+ '_focus-visible': theme.helpers.focusVisible,
65
+ },
66
+ variants: {
67
+ active: {
68
+ true: {
69
+ backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
70
+ },
71
+ },
72
+ selected: {
73
+ true: {
74
+ backgroundColor: theme.color.interactive.brand.surface.strong.default,
75
+ borderColor: theme.color.interactive.brand.surface.strong.default,
76
+ _web: {
77
+ _hover: {
78
+ backgroundColor: theme.color.interactive.brand.surface.strong.hover,
79
+ borderColor: theme.color.interactive.brand.surface.strong.hover,
80
+ },
81
+ },
82
+ },
83
+ },
84
+ },
85
+ compoundVariants: [
86
+ {
87
+ selected: true,
88
+ active: true,
89
+ styles: {
90
+ backgroundColor: theme.color.interactive.brand.surface.strong.active,
91
+ borderColor: theme.color.interactive.brand.surface.strong.active,
92
+ },
93
+ },
94
+ ],
95
+ },
96
+ text: {
97
+ variants: {
98
+ selected: {
99
+ true: {
100
+ color: theme.color.text.inverted,
101
+ },
102
+ false: {
103
+ color: theme.color.text.primary,
104
+ },
105
+ },
106
+ },
107
+ },
108
+ icon: {
109
+ variants: {
110
+ selected: {
111
+ true: {
112
+ color: theme.color.icon.inverted,
113
+ },
114
+ false: {
115
+ color: theme.color.icon.primary,
116
+ },
117
+ },
118
+ },
119
+ },
120
+ }));
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ export interface PillGroupContextValue {
4
+ value: string[];
5
+ onChange: (value: string) => void;
6
+ }
7
+
8
+ export const PillGroupContext = createContext<PillGroupContextValue | null>(null);
9
+
10
+ export const usePillGroupContext = () => {
11
+ return useContext(PillGroupContext);
12
+ };
@@ -0,0 +1,96 @@
1
+ import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
2
+ import { BackToTopButton, ViewFigmaButton } from '../../../docs/components';
3
+ import * as PillGroupStories from './PillGroup.stories';
4
+
5
+ <Meta title="Components / Pill Group" />
6
+
7
+ <ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens" />
8
+
9
+ <BackToTopButton />
10
+
11
+ # Pill Group
12
+
13
+ A container component that groups multiple `Pill` components together for filtering and categorization. It provides layout control with optional wrapping behavior and manages selection state.
14
+
15
+ - [Playground](#playground)
16
+ - [Usage](#usage)
17
+ - [Props](#props)
18
+ - [Examples](#examples)
19
+
20
+ ## Playground
21
+
22
+ <Canvas of={PillGroupStories.Playground} />
23
+
24
+ <Controls of={PillGroupStories.Playground} />
25
+
26
+ ## Usage
27
+
28
+ The `PillGroup` component is a controlled component that manages the selection state of multiple `Pill` components. It supports both single and multi-select modes.
29
+
30
+ ### Basic Usage
31
+
32
+ ```tsx
33
+ import { Pill, PillGroup } from '@hearth/react-native';
34
+ import { useState } from 'react';
35
+
36
+ const [selectedTags, setSelectedTags] = useState(['ui']);
37
+
38
+ <PillGroup value={selectedTags} onChange={setSelectedTags}>
39
+ <Pill value="ui" label="UI" />
40
+ <Pill value="backend" label="Backend" icon={ServerMediumIcon} />
41
+ <Pill value="devops" label="DevOps" />
42
+ </PillGroup>
43
+ ```
44
+
45
+ ## Props
46
+
47
+ ### PillGroup Props
48
+
49
+ | Prop | Type | Default | Description |
50
+ |------|------|---------|-------------|
51
+ | `value` | `string \| string[]` | Required | Controlled selected value(s). Single string for single-select, array for multi-select |
52
+ | `multiple` | `boolean` | `false` | Enable multi-select mode |
53
+ | `wrap` | `boolean` | `true` | Whether pills should wrap to multiple lines when they overflow |
54
+ | `onChange` | `(value: string \| string[]) => void` | - | Handle selection changes. Returns single string in single-select mode, array in multi-select mode |
55
+ | `children` | `ReactNode` | Required | `Pill` components to group together |
56
+ | ...rest | `ViewProps` | - | All standard View props are supported |
57
+
58
+ ### Pill Props
59
+
60
+ | Prop | Type | Default | Description |
61
+ |------|------|---------|-------------|
62
+ | `value` | `string` | Required | Value returned when selected |
63
+ | `label` | `string` | Required | The text content of the pill |
64
+ | `icon` | `ComponentType<any>` | - | Optional icon component to display before the label |
65
+ | ...rest | `PressableProps` | - | All standard Pressable props are supported |
66
+
67
+
68
+ ### Multi-Select Mode
69
+
70
+ ```tsx
71
+ const [tags, setTags] = useState(['ui', 'backend']);
72
+
73
+ <PillGroup multiple value={tags} onChange={setTags}>
74
+ <Pill value="ui" label="UI" />
75
+ <Pill value="backend" label="Backend" icon={ServerMediumIcon} />
76
+ <Pill value="devops" label="DevOps" />
77
+ </PillGroup>
78
+ ```
79
+
80
+ ## Examples
81
+
82
+ ### Wrap Behavior
83
+
84
+ Compare how pills behave with and without wrapping enabled.
85
+
86
+ <Canvas of={PillGroupStories.WrapBehavior} />
87
+
88
+ ### Multi-Select Example
89
+
90
+ Select multiple options
91
+
92
+ <Canvas of={PillGroupStories.Multiple} />
93
+
94
+ ### All States of Pill
95
+
96
+ <Canvas of={PillGroupStories.PillStates} />
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { ScrollViewProps, ViewStyle } from 'react-native';
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
+
12
+ /** Allow pills to wrap lines. Default = true */
13
+ wrap?: boolean;
14
+
15
+ /** Handle selection changes */
16
+ onChange?: (value: string | string[]) => void;
17
+
18
+ /** Children must be <Pill> elements */
19
+ children: React.ReactNode;
20
+
21
+ style?: ViewStyle | ViewStyle[];
22
+ }