@titan-design/react-ui 0.1.0 → 0.1.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.
Files changed (192) hide show
  1. package/package.json +10 -5
  2. package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
  3. package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
  4. package/src/components/custom/DateTime/DateTime.tsx +235 -0
  5. package/src/components/custom/DateTime/index.ts +2 -0
  6. package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
  7. package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
  8. package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
  9. package/src/components/custom/EmptyState/index.ts +2 -0
  10. package/src/components/custom/Metric/Metric.stories.tsx +133 -0
  11. package/src/components/custom/Metric/Metric.test.tsx +120 -0
  12. package/src/components/custom/Metric/Metric.tsx +92 -0
  13. package/src/components/custom/Metric/index.ts +2 -0
  14. package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
  15. package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
  16. package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
  17. package/src/components/custom/Sidebar/index.ts +18 -0
  18. package/src/components/custom/Table/Table.stories.tsx +481 -0
  19. package/src/components/custom/Table/Table.test.tsx +531 -0
  20. package/src/components/custom/Table/Table.tsx +696 -0
  21. package/src/components/custom/Table/index.ts +22 -0
  22. package/src/components/custom/Typography/Typography.stories.tsx +153 -0
  23. package/src/components/custom/Typography/Typography.test.tsx +107 -0
  24. package/src/components/custom/Typography/Typography.tsx +218 -0
  25. package/src/components/custom/Typography/index.ts +19 -0
  26. package/src/components/custom/index.ts +8 -0
  27. package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
  28. package/src/components/custom/stepper/Stepper.test.tsx +230 -0
  29. package/src/components/custom/stepper/Stepper.tsx +250 -0
  30. package/src/components/custom/stepper/index.ts +10 -0
  31. package/src/components/index.ts +5 -0
  32. package/src/components/ui/alert/Alert.stories.tsx +154 -0
  33. package/src/components/ui/alert/Alert.test.tsx +202 -0
  34. package/src/components/ui/alert/Alert.tsx +170 -0
  35. package/src/components/ui/alert/index.ts +8 -0
  36. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
  37. package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
  38. package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
  39. package/src/components/ui/autocomplete/index.ts +2 -0
  40. package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
  41. package/src/components/ui/avatar/Avatar.test.tsx +135 -0
  42. package/src/components/ui/avatar/Avatar.tsx +168 -0
  43. package/src/components/ui/avatar/index.ts +2 -0
  44. package/src/components/ui/badge/Badge.stories.tsx +100 -0
  45. package/src/components/ui/badge/Badge.test.tsx +86 -0
  46. package/src/components/ui/badge/Badge.tsx +105 -0
  47. package/src/components/ui/badge/index.ts +2 -0
  48. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
  49. package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
  50. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
  51. package/src/components/ui/breadcrumbs/index.ts +2 -0
  52. package/src/components/ui/button/Button.stories.tsx +216 -0
  53. package/src/components/ui/button/Button.test.tsx +132 -0
  54. package/src/components/ui/button/Button.tsx +242 -0
  55. package/src/components/ui/button/index.ts +10 -0
  56. package/src/components/ui/card/Card.stories.tsx +443 -0
  57. package/src/components/ui/card/Card.test.tsx +265 -0
  58. package/src/components/ui/card/Card.tsx +380 -0
  59. package/src/components/ui/card/index.ts +20 -0
  60. package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
  61. package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
  62. package/src/components/ui/checkbox/Checkbox.tsx +163 -0
  63. package/src/components/ui/checkbox/index.ts +2 -0
  64. package/src/components/ui/chip/Chip.stories.tsx +112 -0
  65. package/src/components/ui/chip/Chip.test.tsx +119 -0
  66. package/src/components/ui/chip/Chip.tsx +151 -0
  67. package/src/components/ui/chip/index.ts +2 -0
  68. package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
  69. package/src/components/ui/collapse/Collapse.test.tsx +298 -0
  70. package/src/components/ui/collapse/Collapse.tsx +275 -0
  71. package/src/components/ui/collapse/index.ts +18 -0
  72. package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
  73. package/src/components/ui/data-row/DataRow.test.tsx +78 -0
  74. package/src/components/ui/data-row/DataRow.tsx +29 -0
  75. package/src/components/ui/data-row/index.ts +2 -0
  76. package/src/components/ui/divider/Divider.stories.tsx +71 -0
  77. package/src/components/ui/divider/Divider.test.tsx +55 -0
  78. package/src/components/ui/divider/Divider.tsx +37 -0
  79. package/src/components/ui/divider/index.ts +2 -0
  80. package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
  81. package/src/components/ui/drawer/Drawer.test.tsx +142 -0
  82. package/src/components/ui/drawer/Drawer.tsx +228 -0
  83. package/src/components/ui/drawer/index.ts +9 -0
  84. package/src/components/ui/form-field/FormField.stories.tsx +260 -0
  85. package/src/components/ui/form-field/FormField.test.tsx +280 -0
  86. package/src/components/ui/form-field/FormField.tsx +308 -0
  87. package/src/components/ui/form-field/index.ts +2 -0
  88. package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
  89. package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
  90. package/src/components/ui/help-tip/HelpTip.tsx +229 -0
  91. package/src/components/ui/help-tip/index.ts +2 -0
  92. package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
  93. package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
  94. package/src/components/ui/icon-box/IconBox.tsx +57 -0
  95. package/src/components/ui/icon-box/index.ts +1 -0
  96. package/src/components/ui/index.ts +36 -0
  97. package/src/components/ui/input/Input.stories.tsx +192 -0
  98. package/src/components/ui/input/Input.test.tsx +86 -0
  99. package/src/components/ui/input/Input.tsx +273 -0
  100. package/src/components/ui/input/index.ts +2 -0
  101. package/src/components/ui/link/Link.stories.tsx +78 -0
  102. package/src/components/ui/link/Link.test.tsx +94 -0
  103. package/src/components/ui/link/Link.tsx +86 -0
  104. package/src/components/ui/link/index.ts +2 -0
  105. package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
  106. package/src/components/ui/list-item/ListItem.test.tsx +128 -0
  107. package/src/components/ui/list-item/ListItem.tsx +89 -0
  108. package/src/components/ui/list-item/index.ts +14 -0
  109. package/src/components/ui/menu/Menu.stories.tsx +180 -0
  110. package/src/components/ui/menu/Menu.test.tsx +353 -0
  111. package/src/components/ui/menu/Menu.tsx +222 -0
  112. package/src/components/ui/menu/index.ts +2 -0
  113. package/src/components/ui/modal/Modal.stories.tsx +350 -0
  114. package/src/components/ui/modal/Modal.test.tsx +159 -0
  115. package/src/components/ui/modal/Modal.tsx +254 -0
  116. package/src/components/ui/modal/index.ts +19 -0
  117. package/src/components/ui/popover/Popover.stories.tsx +190 -0
  118. package/src/components/ui/popover/Popover.test.tsx +277 -0
  119. package/src/components/ui/popover/Popover.tsx +162 -0
  120. package/src/components/ui/popover/index.ts +2 -0
  121. package/src/components/ui/progress/Progress.stories.tsx +190 -0
  122. package/src/components/ui/progress/Progress.test.tsx +181 -0
  123. package/src/components/ui/progress/Progress.tsx +320 -0
  124. package/src/components/ui/progress/index.ts +9 -0
  125. package/src/components/ui/radio/Radio.stories.tsx +199 -0
  126. package/src/components/ui/radio/Radio.test.tsx +166 -0
  127. package/src/components/ui/radio/Radio.tsx +200 -0
  128. package/src/components/ui/radio/index.ts +2 -0
  129. package/src/components/ui/section/Section.stories.tsx +111 -0
  130. package/src/components/ui/section/Section.test.tsx +121 -0
  131. package/src/components/ui/section/Section.tsx +52 -0
  132. package/src/components/ui/section/index.ts +6 -0
  133. package/src/components/ui/select/Select.stories.tsx +286 -0
  134. package/src/components/ui/select/Select.test.tsx +180 -0
  135. package/src/components/ui/select/Select.tsx +236 -0
  136. package/src/components/ui/select/index.ts +2 -0
  137. package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
  138. package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
  139. package/src/components/ui/skeleton/Skeleton.tsx +229 -0
  140. package/src/components/ui/skeleton/index.ts +16 -0
  141. package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
  142. package/src/components/ui/spinner/Spinner.test.tsx +67 -0
  143. package/src/components/ui/spinner/Spinner.tsx +72 -0
  144. package/src/components/ui/spinner/index.ts +2 -0
  145. package/src/components/ui/stack/Stack.stories.tsx +127 -0
  146. package/src/components/ui/stack/Stack.test.tsx +184 -0
  147. package/src/components/ui/stack/Stack.tsx +76 -0
  148. package/src/components/ui/stack/index.ts +2 -0
  149. package/src/components/ui/surface/Surface.stories.tsx +91 -0
  150. package/src/components/ui/surface/Surface.test.tsx +63 -0
  151. package/src/components/ui/surface/Surface.tsx +51 -0
  152. package/src/components/ui/surface/index.ts +1 -0
  153. package/src/components/ui/switch/Switch.stories.tsx +111 -0
  154. package/src/components/ui/switch/Switch.test.tsx +112 -0
  155. package/src/components/ui/switch/Switch.tsx +103 -0
  156. package/src/components/ui/switch/index.ts +2 -0
  157. package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
  158. package/src/components/ui/tabs/Tabs.test.tsx +192 -0
  159. package/src/components/ui/tabs/Tabs.tsx +253 -0
  160. package/src/components/ui/tabs/index.ts +16 -0
  161. package/src/components/ui/toast/Toast.stories.tsx +255 -0
  162. package/src/components/ui/toast/Toast.test.tsx +207 -0
  163. package/src/components/ui/toast/Toast.tsx +327 -0
  164. package/src/components/ui/toast/index.ts +8 -0
  165. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
  166. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
  167. package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
  168. package/src/components/ui/toolbar-button/index.ts +7 -0
  169. package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
  170. package/src/components/ui/tooltip/Tooltip.test.tsx +179 -0
  171. package/src/components/ui/tooltip/Tooltip.tsx +143 -0
  172. package/src/components/ui/tooltip/index.ts +2 -0
  173. package/src/index.ts +10 -0
  174. package/src/test/setup.ts +19 -0
  175. package/src/theme/Colors.stories.tsx +258 -0
  176. package/src/theme/config.ts +193 -0
  177. package/src/theme/elevation.stories.tsx +346 -0
  178. package/src/theme/elevation.test.ts +27 -0
  179. package/src/theme/elevation.ts +567 -0
  180. package/src/theme/index.ts +39 -0
  181. package/src/theme/shadows.stories.tsx +523 -0
  182. package/src/theme/shadows.ts +439 -0
  183. package/src/theme/tokens/index.ts +2 -0
  184. package/src/theme/tokens/primitives.ts +354 -0
  185. package/src/theme/tokens/semantic.ts +381 -0
  186. package/src/types/jest-axe.d.ts +16 -0
  187. package/src/types/nativewind.d.ts +54 -0
  188. package/src/utils/cn.ts +14 -0
  189. package/src/utils/colors.ts +140 -0
  190. package/src/utils/form.ts +188 -0
  191. package/src/utils/index.ts +29 -0
  192. package/src/utils/useTheme.ts +72 -0
@@ -0,0 +1,153 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View } from 'react-native'
3
+ import {
4
+ Typography,
5
+ Heading,
6
+ Paragraph,
7
+ Caption,
8
+ Label,
9
+ Overline,
10
+ } from './Typography'
11
+
12
+ const meta: Meta<typeof Typography> = {
13
+ title: 'Custom/Typography',
14
+ component: Typography,
15
+ tags: ['autodocs'],
16
+ argTypes: {
17
+ variant: {
18
+ control: 'select',
19
+ options: [
20
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
21
+ 'body1', 'body2', 'subtitle1', 'subtitle2',
22
+ 'caption', 'overline', 'button',
23
+ ],
24
+ },
25
+ color: {
26
+ control: 'select',
27
+ options: [
28
+ 'primary', 'secondary', 'tertiary', 'disabled',
29
+ 'inverse', 'success', 'error', 'warning', 'info', 'inherit',
30
+ ],
31
+ },
32
+ align: {
33
+ control: 'select',
34
+ options: ['left', 'center', 'right', 'justify'],
35
+ },
36
+ noWrap: { control: 'boolean' },
37
+ gutterBottom: { control: 'boolean' },
38
+ },
39
+ }
40
+
41
+ export default meta
42
+ type Story = StoryObj<typeof Typography>
43
+
44
+ export const Default: Story = {
45
+ args: {
46
+ variant: 'body1',
47
+ children: 'This is body1 text',
48
+ },
49
+ }
50
+
51
+ export const AllHeadings: Story = {
52
+ render: () => (
53
+ <View style={{ gap: 16 }}>
54
+ <Typography variant="h1">Heading 1</Typography>
55
+ <Typography variant="h2">Heading 2</Typography>
56
+ <Typography variant="h3">Heading 3</Typography>
57
+ <Typography variant="h4">Heading 4</Typography>
58
+ <Typography variant="h5">Heading 5</Typography>
59
+ <Typography variant="h6">Heading 6</Typography>
60
+ </View>
61
+ ),
62
+ }
63
+
64
+ export const AllBody: Story = {
65
+ render: () => (
66
+ <View style={{ gap: 16, maxWidth: 400 }}>
67
+ <Typography variant="body1">
68
+ Body 1 - This is the default body text style. It&apos;s used for main content
69
+ and paragraphs throughout the application.
70
+ </Typography>
71
+ <Typography variant="body2">
72
+ Body 2 - This is a smaller body text style. It&apos;s useful for secondary
73
+ content or when you need more compact text.
74
+ </Typography>
75
+ <Typography variant="subtitle1">
76
+ Subtitle 1 - Semi-bold text for emphasis
77
+ </Typography>
78
+ <Typography variant="subtitle2">
79
+ Subtitle 2 - Smaller semi-bold text
80
+ </Typography>
81
+ </View>
82
+ ),
83
+ }
84
+
85
+ export const AllUtility: Story = {
86
+ render: () => (
87
+ <View style={{ gap: 16 }}>
88
+ <Typography variant="caption">Caption - Small helper text</Typography>
89
+ <Typography variant="overline">OVERLINE - SECTION LABEL</Typography>
90
+ <Typography variant="button">Button Text</Typography>
91
+ </View>
92
+ ),
93
+ }
94
+
95
+ export const AllColors: Story = {
96
+ render: () => (
97
+ <View style={{ gap: 8 }}>
98
+ <Typography color="primary">Primary text color</Typography>
99
+ <Typography color="secondary">Secondary text color</Typography>
100
+ <Typography color="tertiary">Tertiary text color</Typography>
101
+ <Typography color="disabled">Disabled text color</Typography>
102
+ <Typography color="success">Success text color</Typography>
103
+ <Typography color="error">Error text color</Typography>
104
+ <Typography color="warning">Warning text color</Typography>
105
+ <Typography color="info">Info text color</Typography>
106
+ </View>
107
+ ),
108
+ }
109
+
110
+ export const HeadingComponent: Story = {
111
+ render: () => (
112
+ <View style={{ gap: 8 }}>
113
+ <Heading level={1}>Heading Level 1</Heading>
114
+ <Heading level={2}>Heading Level 2</Heading>
115
+ <Heading level={3}>Heading Level 3</Heading>
116
+ </View>
117
+ ),
118
+ }
119
+
120
+ export const ParagraphComponent: Story = {
121
+ render: () => (
122
+ <View style={{ gap: 16, maxWidth: 400 }}>
123
+ <Paragraph>
124
+ This is a regular paragraph using the default body1 variant.
125
+ It&apos;s great for main content.
126
+ </Paragraph>
127
+ <Paragraph small>
128
+ This is a small paragraph using the body2 variant.
129
+ It&apos;s useful for secondary content.
130
+ </Paragraph>
131
+ </View>
132
+ ),
133
+ }
134
+
135
+ export const UtilityComponents: Story = {
136
+ render: () => (
137
+ <View style={{ gap: 12 }}>
138
+ <Overline>Section Title</Overline>
139
+ <Label>Form Label</Label>
140
+ <Caption>Helper text or caption</Caption>
141
+ </View>
142
+ ),
143
+ }
144
+
145
+ export const WithTruncation: Story = {
146
+ render: () => (
147
+ <View style={{ width: 200 }}>
148
+ <Typography noWrap>
149
+ This is a very long text that will be truncated with an ellipsis
150
+ </Typography>
151
+ </View>
152
+ ),
153
+ }
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { axe } from 'jest-axe'
4
+ import { Typography, Heading, Paragraph, Caption, Label, Overline } from './Typography'
5
+
6
+ describe('Typography', () => {
7
+ it('renders children correctly', () => {
8
+ render(<Typography>Hello World</Typography>)
9
+ expect(screen.getByText('Hello World')).toBeInTheDocument()
10
+ })
11
+
12
+ it('renders different variants', () => {
13
+ const { rerender } = render(<Typography variant="h1">Heading</Typography>)
14
+ expect(screen.getByRole('heading')).toBeInTheDocument()
15
+
16
+ rerender(<Typography variant="body1">Body text</Typography>)
17
+ expect(screen.getByText('Body text')).toBeInTheDocument()
18
+ })
19
+
20
+ it('applies color styles', () => {
21
+ render(<Typography color="secondary">Secondary text</Typography>)
22
+ expect(screen.getByText('Secondary text')).toBeInTheDocument()
23
+ })
24
+
25
+ it('applies text alignment', () => {
26
+ render(<Typography align="center">Centered text</Typography>)
27
+ expect(screen.getByText('Centered text')).toBeInTheDocument()
28
+ })
29
+
30
+ it('applies noWrap truncation', () => {
31
+ render(<Typography noWrap>Long text that should truncate</Typography>)
32
+ const text = screen.getByText('Long text that should truncate')
33
+ // On web, noWrap renders as CSS truncation styles rather than numberOfLines attribute
34
+ expect(text).toBeInTheDocument()
35
+ })
36
+
37
+ describe('Heading component', () => {
38
+ it('renders correct heading level', () => {
39
+ const { rerender } = render(<Heading level={1}>H1</Heading>)
40
+ expect(screen.getByRole('heading')).toBeInTheDocument()
41
+
42
+ rerender(<Heading level={3}>H3</Heading>)
43
+ expect(screen.getByRole('heading')).toBeInTheDocument()
44
+ })
45
+ })
46
+
47
+ describe('Paragraph component', () => {
48
+ it('renders body1 by default', () => {
49
+ render(<Paragraph>Regular paragraph</Paragraph>)
50
+ expect(screen.getByText('Regular paragraph')).toBeInTheDocument()
51
+ })
52
+
53
+ it('renders body2 when small prop is true', () => {
54
+ render(<Paragraph small>Small paragraph</Paragraph>)
55
+ expect(screen.getByText('Small paragraph')).toBeInTheDocument()
56
+ })
57
+ })
58
+
59
+ describe('Caption component', () => {
60
+ it('renders with caption variant', () => {
61
+ render(<Caption>Caption text</Caption>)
62
+ expect(screen.getByText('Caption text')).toBeInTheDocument()
63
+ })
64
+ })
65
+
66
+ describe('Label component', () => {
67
+ it('renders with subtitle2 variant', () => {
68
+ render(<Label>Label text</Label>)
69
+ expect(screen.getByText('Label text')).toBeInTheDocument()
70
+ })
71
+ })
72
+
73
+ describe('Overline component', () => {
74
+ it('renders with overline variant', () => {
75
+ render(<Overline>OVERLINE TEXT</Overline>)
76
+ expect(screen.getByText('OVERLINE TEXT')).toBeInTheDocument()
77
+ })
78
+ })
79
+
80
+ describe('accessibility', () => {
81
+ it('headings have no accessibility violations', async () => {
82
+ const { container } = render(
83
+ <div>
84
+ <Typography variant="h1">Main Title</Typography>
85
+ <Typography variant="h2">Section Title</Typography>
86
+ </div>
87
+ )
88
+
89
+ const results = await axe(container)
90
+ expect(results).toHaveNoViolations()
91
+ })
92
+
93
+ it('body text has no accessibility violations', async () => {
94
+ const { container } = render(
95
+ <Typography variant="body1">Body text content</Typography>
96
+ )
97
+
98
+ const results = await axe(container)
99
+ expect(results).toHaveNoViolations()
100
+ })
101
+
102
+ it('headings have correct accessibility role', () => {
103
+ render(<Typography variant="h2">Section Heading</Typography>)
104
+ expect(screen.getByRole('heading')).toBeInTheDocument()
105
+ })
106
+ })
107
+ })
@@ -0,0 +1,218 @@
1
+ import React from 'react'
2
+ import { Text, type TextProps } from 'react-native'
3
+ import { cn } from '../../../utils/cn'
4
+
5
+ export type TypographyVariant =
6
+ | 'h1'
7
+ | 'h2'
8
+ | 'h3'
9
+ | 'h4'
10
+ | 'h5'
11
+ | 'h6'
12
+ | 'body1'
13
+ | 'body2'
14
+ | 'subtitle1'
15
+ | 'subtitle2'
16
+ | 'caption'
17
+ | 'overline'
18
+ | 'button'
19
+
20
+ export type TypographyColor =
21
+ | 'primary'
22
+ | 'secondary'
23
+ | 'tertiary'
24
+ | 'disabled'
25
+ | 'inverse'
26
+ | 'success'
27
+ | 'error'
28
+ | 'warning'
29
+ | 'info'
30
+ | 'inherit'
31
+
32
+ export type TypographyAlign = 'left' | 'center' | 'right' | 'justify'
33
+
34
+ export type TypographyMarginBottom = 'none' | 'sm' | 'md' | 'lg'
35
+
36
+ export interface TypographyProps extends TextProps {
37
+ /** Typography variant */
38
+ variant?: TypographyVariant
39
+ /** Text color */
40
+ color?: TypographyColor
41
+ /** Text alignment */
42
+ align?: TypographyAlign
43
+ /** Whether text should truncate with ellipsis */
44
+ truncate?: boolean
45
+ /** @deprecated Use truncate instead */
46
+ noWrap?: boolean
47
+ /** Margin bottom spacing */
48
+ marginBottom?: TypographyMarginBottom
49
+ /** @deprecated Use marginBottom instead */
50
+ gutterBottom?: boolean
51
+ /** Maximum number of lines before truncating */
52
+ maxLines?: number
53
+ /** Additional className */
54
+ className?: string
55
+ children?: React.ReactNode
56
+ }
57
+
58
+ // Variant styles matching the existing theme
59
+ const variantStyles: Record<TypographyVariant, string> = {
60
+ h1: 'font-heading text-5xl font-bold leading-tight',
61
+ h2: 'font-heading text-4xl font-bold leading-tight',
62
+ h3: 'font-heading text-3xl font-bold leading-tight',
63
+ h4: 'font-heading text-2xl font-bold leading-tight',
64
+ h5: 'font-heading text-xl font-semibold leading-tight',
65
+ h6: 'font-heading text-lg font-semibold leading-tight',
66
+ body1: 'font-body text-base font-normal leading-normal',
67
+ body2: 'font-body text-sm font-normal leading-normal',
68
+ subtitle1: 'font-body text-base font-medium leading-relaxed',
69
+ subtitle2: 'font-body text-sm font-medium leading-normal',
70
+ caption: 'font-body text-xs font-normal leading-loose',
71
+ overline: 'font-body text-xs font-semibold uppercase tracking-widest leading-relaxed',
72
+ button: 'font-sans text-sm font-semibold leading-relaxed',
73
+ }
74
+
75
+ const colorStyles: Record<TypographyColor, string> = {
76
+ primary: 'text-text-primary',
77
+ secondary: 'text-text-secondary',
78
+ tertiary: 'text-text-tertiary',
79
+ disabled: 'text-text-disabled',
80
+ inverse: 'text-text-inverse',
81
+ success: 'text-status-success',
82
+ error: 'text-status-error',
83
+ warning: 'text-status-warning',
84
+ info: 'text-status-info',
85
+ inherit: '', // No color class, inherit from parent
86
+ }
87
+
88
+ const alignStyles: Record<TypographyAlign, string> = {
89
+ left: 'text-left',
90
+ center: 'text-center',
91
+ right: 'text-right',
92
+ justify: 'text-justify',
93
+ }
94
+
95
+ // Heading variants for accessibility role
96
+ const headingVariants: TypographyVariant[] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
97
+
98
+ const marginBottomStyles: Record<TypographyMarginBottom, string> = {
99
+ none: '',
100
+ sm: 'mb-1',
101
+ md: 'mb-2',
102
+ lg: 'mb-4',
103
+ }
104
+
105
+ /**
106
+ * Typography component for consistent text styling.
107
+ *
108
+ * @example
109
+ * <Typography variant="h1">Page Title</Typography>
110
+ * <Typography variant="body1" color="secondary">Body text content</Typography>
111
+ * <Typography variant="caption" marginBottom="md">Small caption text</Typography>
112
+ * <Typography truncate maxLines={2}>Long text that will truncate...</Typography>
113
+ */
114
+ export function Typography({
115
+ variant = 'body1',
116
+ color = 'primary',
117
+ align,
118
+ truncate = false,
119
+ noWrap = false, // deprecated, kept for backward compatibility
120
+ marginBottom,
121
+ gutterBottom = false, // deprecated, kept for backward compatibility
122
+ maxLines,
123
+ className,
124
+ children,
125
+ ...props
126
+ }: TypographyProps) {
127
+ const isHeading = headingVariants.includes(variant)
128
+ const shouldTruncate = truncate || noWrap
129
+ const mb = marginBottom || (gutterBottom ? 'md' : 'none')
130
+
131
+ // Determine number of lines
132
+ let numLines: number | undefined
133
+ if (maxLines) {
134
+ numLines = maxLines
135
+ } else if (shouldTruncate) {
136
+ numLines = 1
137
+ }
138
+
139
+ return (
140
+ <Text
141
+ accessibilityRole={isHeading ? 'header' : 'text'}
142
+ numberOfLines={numLines}
143
+ className={cn(
144
+ variantStyles[variant],
145
+ color !== 'inherit' && colorStyles[color],
146
+ align && alignStyles[align],
147
+ shouldTruncate && 'truncate',
148
+ marginBottomStyles[mb],
149
+ className
150
+ )}
151
+ {...props}
152
+ >
153
+ {children}
154
+ </Text>
155
+ )
156
+ }
157
+
158
+ // Convenience components for common typography patterns
159
+
160
+ export interface HeadingProps extends Omit<TypographyProps, 'variant'> {
161
+ /** Heading level (1-6) */
162
+ level?: 1 | 2 | 3 | 4 | 5 | 6
163
+ }
164
+
165
+ /**
166
+ * Heading component - convenience wrapper for Typography with heading variants.
167
+ *
168
+ * @example
169
+ * <Heading level={1}>Page Title</Heading>
170
+ * <Heading level={2} gutterBottom>Section Title</Heading>
171
+ */
172
+ export function Heading({ level = 1, ...props }: HeadingProps) {
173
+ const variant = `h${level}` as TypographyVariant
174
+ return <Typography variant={variant} {...props} />
175
+ }
176
+
177
+ export interface ParagraphProps extends Omit<TypographyProps, 'variant'> {
178
+ /** Use smaller body2 variant */
179
+ small?: boolean
180
+ }
181
+
182
+ /**
183
+ * Paragraph component - convenience wrapper for body text.
184
+ *
185
+ * @example
186
+ * <Paragraph>This is body text content.</Paragraph>
187
+ * <Paragraph small>This is smaller body text.</Paragraph>
188
+ */
189
+ export function Paragraph({ small = false, ...props }: ParagraphProps) {
190
+ return <Typography variant={small ? 'body2' : 'body1'} {...props} />
191
+ }
192
+
193
+ export interface CaptionProps extends Omit<TypographyProps, 'variant'> {}
194
+
195
+ /**
196
+ * Caption component - for small helper/secondary text.
197
+ */
198
+ export function Caption(props: CaptionProps) {
199
+ return <Typography variant="caption" color="secondary" {...props} />
200
+ }
201
+
202
+ export interface LabelProps extends Omit<TypographyProps, 'variant'> {}
203
+
204
+ /**
205
+ * Label component - for form labels and similar.
206
+ */
207
+ export function Label(props: LabelProps) {
208
+ return <Typography variant="subtitle2" {...props} />
209
+ }
210
+
211
+ export interface OverlineProps extends Omit<TypographyProps, 'variant'> {}
212
+
213
+ /**
214
+ * Overline component - for section labels, categories.
215
+ */
216
+ export function Overline(props: OverlineProps) {
217
+ return <Typography variant="overline" color="secondary" {...props} />
218
+ }
@@ -0,0 +1,19 @@
1
+ export {
2
+ Typography,
3
+ Heading,
4
+ Paragraph,
5
+ Caption,
6
+ Label,
7
+ Overline,
8
+ } from './Typography'
9
+ export type {
10
+ TypographyProps,
11
+ TypographyVariant,
12
+ TypographyColor,
13
+ TypographyAlign,
14
+ HeadingProps,
15
+ ParagraphProps,
16
+ CaptionProps,
17
+ LabelProps,
18
+ OverlineProps,
19
+ } from './Typography'
@@ -0,0 +1,8 @@
1
+ // Custom components
2
+ export * from './Typography'
3
+ export * from './Sidebar'
4
+ export * from './Table'
5
+ export * from './EmptyState'
6
+ export * from './stepper'
7
+ export * from './DateTime'
8
+ export * from './Metric'