@sudobility/components-rn 1.0.39 → 1.0.41

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.
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+ export interface AppVersionProps {
3
+ /** App display name */
4
+ appName: string;
5
+ /** Version string (e.g. from package.json) */
6
+ version: string;
7
+ /** Additional className */
8
+ className?: string;
9
+ }
10
+ /**
11
+ * AppVersion Component
12
+ *
13
+ * Displays the app name and version in a muted text style.
14
+ * Reads the version from the consuming app's package.json.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * import { version } from '../package.json';
19
+ * <AppVersion appName="MyApp" version={version} />
20
+ * // renders: "MyApp v1.0.0"
21
+ * ```
22
+ */
23
+ export declare const AppVersion: React.FC<AppVersionProps>;
24
+ //# sourceMappingURL=AppVersion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppVersion.d.ts","sourceRoot":"","sources":["../../../src/ui/AppVersion/AppVersion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,eAAe;IAC9B,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAehD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { AppVersion } from './AppVersion';
2
+ export type { AppVersionProps } from './AppVersion';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/AppVersion/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/components-rn",
3
- "version": "1.0.39",
3
+ "version": "1.0.41",
4
4
  "description": "React Native UI components and design system - Ported from @sudobility/components",
5
5
  "type": "module",
6
6
  "main": "dist/index.esm.js",
@@ -1,8 +1,16 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react-native';
2
+ import { render, screen, fireEvent, act } from '@testing-library/react-native';
3
3
  import { Text } from 'react-native';
4
4
  import { Dialog } from '../ui/Dialog';
5
5
 
6
+ beforeEach(() => {
7
+ jest.useFakeTimers();
8
+ });
9
+
10
+ afterEach(() => {
11
+ jest.useRealTimers();
12
+ });
13
+
6
14
  describe('Dialog', () => {
7
15
  const defaultProps = {
8
16
  isOpen: true,
@@ -16,11 +24,17 @@ describe('Dialog', () => {
16
24
 
17
25
  it('renders children when open', () => {
18
26
  render(<Dialog {...defaultProps} />);
27
+ act(() => {
28
+ jest.runAllTimers();
29
+ });
19
30
  expect(screen.getByText('Dialog content')).toBeTruthy();
20
31
  });
21
32
 
22
33
  it('renders close button by default when onClose is provided', () => {
23
34
  render(<Dialog {...defaultProps} />);
35
+ act(() => {
36
+ jest.runAllTimers();
37
+ });
24
38
  const closeButton = screen.getByLabelText('Close dialog');
25
39
  expect(closeButton).toBeTruthy();
26
40
  });
@@ -32,12 +46,18 @@ describe('Dialog', () => {
32
46
  <Text>Content</Text>
33
47
  </Dialog>
34
48
  );
49
+ act(() => {
50
+ jest.runAllTimers();
51
+ });
35
52
  fireEvent.press(screen.getByLabelText('Close dialog'));
36
53
  expect(onClose).toHaveBeenCalledTimes(1);
37
54
  });
38
55
 
39
56
  it('hides close button when showCloseButton is false', () => {
40
57
  render(<Dialog {...defaultProps} showCloseButton={false} />);
58
+ act(() => {
59
+ jest.runAllTimers();
60
+ });
41
61
  expect(screen.queryByLabelText('Close dialog')).toBeNull();
42
62
  });
43
63
 
@@ -50,6 +70,9 @@ describe('Dialog', () => {
50
70
  <Text>{size}</Text>
51
71
  </Dialog>
52
72
  );
73
+ act(() => {
74
+ jest.runAllTimers();
75
+ });
53
76
  expect(screen.getByText(size)).toBeTruthy();
54
77
  unmount();
55
78
  });
@@ -61,6 +84,9 @@ describe('Dialog', () => {
61
84
  <Text>No close</Text>
62
85
  </Dialog>
63
86
  );
87
+ act(() => {
88
+ jest.runAllTimers();
89
+ });
64
90
  expect(screen.queryByLabelText('Close dialog')).toBeNull();
65
91
  });
66
92
 
@@ -70,6 +96,9 @@ describe('Dialog', () => {
70
96
  <Text>No X button</Text>
71
97
  </Dialog>
72
98
  );
99
+ act(() => {
100
+ jest.runAllTimers();
101
+ });
73
102
  expect(screen.getByText('No X button')).toBeTruthy();
74
103
  expect(screen.queryByLabelText('Close dialog')).toBeNull();
75
104
  });
@@ -1,8 +1,16 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react-native';
2
+ import { render, screen, fireEvent, act } from '@testing-library/react-native';
3
3
  import { Text } from 'react-native';
4
4
  import { Sheet } from '../ui/Sheet';
5
5
 
6
+ beforeEach(() => {
7
+ jest.useFakeTimers();
8
+ });
9
+
10
+ afterEach(() => {
11
+ jest.useRealTimers();
12
+ });
13
+
6
14
  describe('Sheet', () => {
7
15
  const defaultProps = {
8
16
  isOpen: true,
@@ -16,11 +24,17 @@ describe('Sheet', () => {
16
24
 
17
25
  it('renders children when open', () => {
18
26
  render(<Sheet {...defaultProps} />);
27
+ act(() => {
28
+ jest.runAllTimers();
29
+ });
19
30
  expect(screen.getByText('Sheet content')).toBeTruthy();
20
31
  });
21
32
 
22
33
  it('renders title when provided', () => {
23
34
  render(<Sheet {...defaultProps} title='Sheet Title' />);
35
+ act(() => {
36
+ jest.runAllTimers();
37
+ });
24
38
  expect(screen.getByText('Sheet Title')).toBeTruthy();
25
39
  });
26
40
 
@@ -28,11 +42,17 @@ describe('Sheet', () => {
28
42
  render(
29
43
  <Sheet {...defaultProps} title='Title' description='Sheet description' />
30
44
  );
45
+ act(() => {
46
+ jest.runAllTimers();
47
+ });
31
48
  expect(screen.getByText('Sheet description')).toBeTruthy();
32
49
  });
33
50
 
34
51
  it('renders close button by default', () => {
35
52
  render(<Sheet {...defaultProps} title='Title' />);
53
+ act(() => {
54
+ jest.runAllTimers();
55
+ });
36
56
  const closeButton = screen.getByLabelText('Close sheet');
37
57
  expect(closeButton).toBeTruthy();
38
58
  });
@@ -44,17 +64,26 @@ describe('Sheet', () => {
44
64
  <Text>Content</Text>
45
65
  </Sheet>
46
66
  );
67
+ act(() => {
68
+ jest.runAllTimers();
69
+ });
47
70
  fireEvent.press(screen.getByLabelText('Close sheet'));
48
71
  expect(onClose).toHaveBeenCalledTimes(1);
49
72
  });
50
73
 
51
74
  it('hides close button when showCloseButton is false', () => {
52
75
  render(<Sheet {...defaultProps} title='Title' showCloseButton={false} />);
76
+ act(() => {
77
+ jest.runAllTimers();
78
+ });
53
79
  expect(screen.queryByLabelText('Close sheet')).toBeNull();
54
80
  });
55
81
 
56
82
  it('renders footer when provided', () => {
57
83
  render(<Sheet {...defaultProps} footer={<Text>Footer area</Text>} />);
84
+ act(() => {
85
+ jest.runAllTimers();
86
+ });
58
87
  expect(screen.getByText('Footer area')).toBeTruthy();
59
88
  });
60
89
 
@@ -67,6 +96,9 @@ describe('Sheet', () => {
67
96
  <Text>Size {size}</Text>
68
97
  </Sheet>
69
98
  );
99
+ act(() => {
100
+ jest.runAllTimers();
101
+ });
70
102
  expect(screen.getByText(`Size ${size}`)).toBeTruthy();
71
103
  unmount();
72
104
  });
@@ -81,6 +113,9 @@ describe('Sheet', () => {
81
113
  <Text>Side {side}</Text>
82
114
  </Sheet>
83
115
  );
116
+ act(() => {
117
+ jest.runAllTimers();
118
+ });
84
119
  expect(screen.getByText(`Side ${side}`)).toBeTruthy();
85
120
  unmount();
86
121
  });
@@ -88,6 +123,9 @@ describe('Sheet', () => {
88
123
 
89
124
  it('renders without drag handle when showHandle is false', () => {
90
125
  const { toJSON } = render(<Sheet {...defaultProps} showHandle={false} />);
126
+ act(() => {
127
+ jest.runAllTimers();
128
+ });
91
129
  // When showHandle is false, the drag handle View is not rendered
92
130
  expect(screen.getByText('Sheet content')).toBeTruthy();
93
131
  expect(toJSON()).toBeTruthy();
@@ -105,6 +143,9 @@ describe('Sheet', () => {
105
143
  <Text>Main content</Text>
106
144
  </Sheet>
107
145
  );
146
+ act(() => {
147
+ jest.runAllTimers();
148
+ });
108
149
  expect(screen.getByText('Full Sheet')).toBeTruthy();
109
150
  expect(screen.getByText('A full sheet example')).toBeTruthy();
110
151
  expect(screen.getByText('Main content')).toBeTruthy();
@@ -4,6 +4,14 @@ import { Text, Pressable } from 'react-native';
4
4
  import { Toast, ToastProvider, useToast } from '../ui/Toast';
5
5
  import type { ToastMessage } from '../ui/Toast';
6
6
 
7
+ beforeEach(() => {
8
+ jest.useFakeTimers();
9
+ });
10
+
11
+ afterEach(() => {
12
+ jest.useRealTimers();
13
+ });
14
+
7
15
  describe('Toast', () => {
8
16
  const baseToast: ToastMessage = {
9
17
  id: 'test-1',
@@ -14,16 +22,25 @@ describe('Toast', () => {
14
22
 
15
23
  it('renders title', () => {
16
24
  render(<Toast toast={baseToast} onRemove={jest.fn()} />);
25
+ act(() => {
26
+ jest.runAllTimers();
27
+ });
17
28
  expect(screen.getByText('Test Toast')).toBeTruthy();
18
29
  });
19
30
 
20
31
  it('renders description', () => {
21
32
  render(<Toast toast={baseToast} onRemove={jest.fn()} />);
33
+ act(() => {
34
+ jest.runAllTimers();
35
+ });
22
36
  expect(screen.getByText('This is a test toast')).toBeTruthy();
23
37
  });
24
38
 
25
39
  it('renders close button', () => {
26
40
  render(<Toast toast={baseToast} onRemove={jest.fn()} />);
41
+ act(() => {
42
+ jest.runAllTimers();
43
+ });
27
44
  const closeButton = screen.getByLabelText('Close notification');
28
45
  expect(closeButton).toBeTruthy();
29
46
  });
@@ -31,6 +48,9 @@ describe('Toast', () => {
31
48
  it('calls onRemove when close button is pressed', () => {
32
49
  const onRemove = jest.fn();
33
50
  render(<Toast toast={baseToast} onRemove={onRemove} />);
51
+ act(() => {
52
+ jest.runAllTimers();
53
+ });
34
54
  fireEvent.press(screen.getByLabelText('Close notification'));
35
55
  expect(onRemove).toHaveBeenCalledWith('test-1');
36
56
  });
@@ -42,6 +62,9 @@ describe('Toast', () => {
42
62
  action: { label: 'Undo', onPress: onAction },
43
63
  };
44
64
  render(<Toast toast={toastWithAction} onRemove={jest.fn()} />);
65
+ act(() => {
66
+ jest.runAllTimers();
67
+ });
45
68
  expect(screen.getByText('Undo')).toBeTruthy();
46
69
  fireEvent.press(screen.getByText('Undo'));
47
70
  expect(onAction).toHaveBeenCalledTimes(1);
@@ -59,6 +82,9 @@ describe('Toast', () => {
59
82
  variants.forEach(variant => {
60
83
  const toast: ToastMessage = { ...baseToast, variant, id: variant };
61
84
  const { unmount } = render(<Toast toast={toast} onRemove={jest.fn()} />);
85
+ act(() => {
86
+ jest.runAllTimers();
87
+ });
62
88
  expect(screen.getByText('Test Toast')).toBeTruthy();
63
89
  unmount();
64
90
  });
@@ -70,6 +96,9 @@ describe('Toast', () => {
70
96
  description: 'Description only',
71
97
  };
72
98
  render(<Toast toast={toast} onRemove={jest.fn()} />);
99
+ act(() => {
100
+ jest.runAllTimers();
101
+ });
73
102
  expect(screen.getByText('Description only')).toBeTruthy();
74
103
  });
75
104
 
@@ -79,6 +108,9 @@ describe('Toast', () => {
79
108
  title: 'Title only',
80
109
  };
81
110
  render(<Toast toast={toast} onRemove={jest.fn()} />);
111
+ act(() => {
112
+ jest.runAllTimers();
113
+ });
82
114
  expect(screen.getByText('Title only')).toBeTruthy();
83
115
  });
84
116
  });
package/src/index.ts CHANGED
@@ -44,6 +44,7 @@ export * from './ui/Code';
44
44
  export * from './ui/TruncatedText';
45
45
 
46
46
  // UI Components - Display
47
+ export * from './ui/AppVersion';
47
48
  export * from './ui/Badge';
48
49
  export * from './ui/Avatar';
49
50
  export * from './ui/Skeleton';
@@ -0,0 +1,42 @@
1
+ import * as React from 'react';
2
+ import { Text } from 'react-native';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ export interface AppVersionProps {
6
+ /** App display name */
7
+ appName: string;
8
+ /** Version string (e.g. from package.json) */
9
+ version: string;
10
+ /** Additional className */
11
+ className?: string;
12
+ }
13
+
14
+ /**
15
+ * AppVersion Component
16
+ *
17
+ * Displays the app name and version in a muted text style.
18
+ * Reads the version from the consuming app's package.json.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * import { version } from '../package.json';
23
+ * <AppVersion appName="MyApp" version={version} />
24
+ * // renders: "MyApp v1.0.0"
25
+ * ```
26
+ */
27
+ export const AppVersion: React.FC<AppVersionProps> = ({
28
+ appName,
29
+ version,
30
+ className,
31
+ }) => {
32
+ return (
33
+ <Text
34
+ className={cn(
35
+ 'text-sm text-gray-500 dark:text-gray-400 text-center',
36
+ className
37
+ )}
38
+ >
39
+ {appName} v{version}
40
+ </Text>
41
+ );
42
+ };
@@ -0,0 +1,2 @@
1
+ export { AppVersion } from './AppVersion';
2
+ export type { AppVersionProps } from './AppVersion';