@channel.io/bezier-react 4.0.0-next.2 → 4.0.0-next.4

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 (194) hide show
  1. package/dist/cjs/components/Button/Button.module.scss.js +1 -1
  2. package/dist/cjs/styles.css +1 -1
  3. package/dist/cjs/types/props-helpers.js +8 -0
  4. package/dist/cjs/types/props-helpers.js.map +1 -1
  5. package/dist/cjs/v3/BaseStack/BaseStack.js +46 -0
  6. package/dist/cjs/v3/BaseStack/BaseStack.js.map +1 -0
  7. package/dist/cjs/v3/BaseStack/BaseStack.module.scss.js +8 -0
  8. package/dist/cjs/v3/BaseStack/BaseStack.module.scss.js.map +1 -0
  9. package/dist/cjs/v3/Box/Box.js +56 -0
  10. package/dist/cjs/v3/Box/Box.js.map +1 -0
  11. package/dist/cjs/v3/Box/Box.module.scss.js +8 -0
  12. package/dist/cjs/v3/Box/Box.module.scss.js.map +1 -0
  13. package/dist/cjs/v3/Divider/Divider.js +32 -0
  14. package/dist/cjs/v3/Divider/Divider.js.map +1 -0
  15. package/dist/cjs/v3/Divider/Divider.module.scss.js +8 -0
  16. package/dist/cjs/v3/Divider/Divider.module.scss.js.map +1 -0
  17. package/dist/cjs/v3/HStack/HStack.js +19 -0
  18. package/dist/cjs/v3/HStack/HStack.js.map +1 -0
  19. package/dist/cjs/v3/Icon/Icon.js +51 -0
  20. package/dist/cjs/v3/Icon/Icon.js.map +1 -0
  21. package/dist/cjs/v3/Icon/Icon.module.scss.js +8 -0
  22. package/dist/cjs/v3/Icon/Icon.module.scss.js.map +1 -0
  23. package/dist/cjs/v3/SmoothCornersBox/SmoothCornersBox.js +53 -0
  24. package/dist/cjs/v3/SmoothCornersBox/SmoothCornersBox.js.map +1 -0
  25. package/dist/cjs/v3/SmoothCornersBox/SmoothCornersBox.module.scss.js +8 -0
  26. package/dist/cjs/v3/SmoothCornersBox/SmoothCornersBox.module.scss.js.map +1 -0
  27. package/dist/cjs/v3/Spinner/Spinner.js +45 -0
  28. package/dist/cjs/v3/Spinner/Spinner.js.map +1 -0
  29. package/dist/cjs/v3/Spinner/Spinner.module.scss.js +8 -0
  30. package/dist/cjs/v3/Spinner/Spinner.module.scss.js.map +1 -0
  31. package/dist/cjs/v3/Text/Text.js +60 -0
  32. package/dist/cjs/v3/Text/Text.js.map +1 -0
  33. package/dist/cjs/v3/Text/Text.module.scss.js +8 -0
  34. package/dist/cjs/v3/Text/Text.module.scss.js.map +1 -0
  35. package/dist/cjs/v3/VStack/VStack.js +19 -0
  36. package/dist/cjs/v3/VStack/VStack.js.map +1 -0
  37. package/dist/cjs/v3/index.js +22 -0
  38. package/dist/cjs/v3/index.js.map +1 -0
  39. package/dist/esm/components/Button/Button.module.scss.mjs +1 -1
  40. package/dist/esm/styles.css +1 -1
  41. package/dist/esm/types/props-helpers.mjs +5 -1
  42. package/dist/esm/types/props-helpers.mjs.map +1 -1
  43. package/dist/esm/v3/BaseStack/BaseStack.mjs +44 -0
  44. package/dist/esm/v3/BaseStack/BaseStack.mjs.map +1 -0
  45. package/dist/esm/v3/BaseStack/BaseStack.module.scss.mjs +4 -0
  46. package/dist/esm/v3/BaseStack/BaseStack.module.scss.mjs.map +1 -0
  47. package/dist/esm/v3/Box/Box.mjs +54 -0
  48. package/dist/esm/v3/Box/Box.mjs.map +1 -0
  49. package/dist/esm/v3/Box/Box.module.scss.mjs +4 -0
  50. package/dist/esm/v3/Box/Box.module.scss.mjs.map +1 -0
  51. package/dist/esm/v3/Divider/Divider.mjs +30 -0
  52. package/dist/esm/v3/Divider/Divider.mjs.map +1 -0
  53. package/dist/esm/v3/Divider/Divider.module.scss.mjs +4 -0
  54. package/dist/esm/v3/Divider/Divider.module.scss.mjs.map +1 -0
  55. package/dist/esm/v3/HStack/HStack.mjs +17 -0
  56. package/dist/esm/v3/HStack/HStack.mjs.map +1 -0
  57. package/dist/esm/v3/Icon/Icon.mjs +49 -0
  58. package/dist/esm/v3/Icon/Icon.mjs.map +1 -0
  59. package/dist/esm/v3/Icon/Icon.module.scss.mjs +4 -0
  60. package/dist/esm/v3/Icon/Icon.module.scss.mjs.map +1 -0
  61. package/dist/esm/v3/SmoothCornersBox/SmoothCornersBox.mjs +51 -0
  62. package/dist/esm/v3/SmoothCornersBox/SmoothCornersBox.mjs.map +1 -0
  63. package/dist/esm/v3/SmoothCornersBox/SmoothCornersBox.module.scss.mjs +4 -0
  64. package/dist/esm/v3/SmoothCornersBox/SmoothCornersBox.module.scss.mjs.map +1 -0
  65. package/dist/esm/v3/Spinner/Spinner.mjs +43 -0
  66. package/dist/esm/v3/Spinner/Spinner.mjs.map +1 -0
  67. package/dist/esm/v3/Spinner/Spinner.module.scss.mjs +4 -0
  68. package/dist/esm/v3/Spinner/Spinner.module.scss.mjs.map +1 -0
  69. package/dist/esm/v3/Text/Text.mjs +58 -0
  70. package/dist/esm/v3/Text/Text.mjs.map +1 -0
  71. package/dist/esm/v3/Text/Text.module.scss.mjs +4 -0
  72. package/dist/esm/v3/Text/Text.module.scss.mjs.map +1 -0
  73. package/dist/esm/v3/VStack/VStack.mjs +17 -0
  74. package/dist/esm/v3/VStack/VStack.mjs.map +1 -0
  75. package/dist/esm/v3/index.mjs +9 -0
  76. package/dist/esm/v3/index.mjs.map +1 -0
  77. package/dist/types/types/beta-tokens.d.ts +4 -0
  78. package/dist/types/types/beta-tokens.d.ts.map +1 -1
  79. package/dist/types/types/props-helpers.d.ts +48 -1
  80. package/dist/types/types/props-helpers.d.ts.map +1 -1
  81. package/dist/types/types/props.d.ts +44 -0
  82. package/dist/types/types/props.d.ts.map +1 -1
  83. package/dist/types/v3/BaseStack/BaseStack.d.ts +6 -0
  84. package/dist/types/v3/BaseStack/BaseStack.d.ts.map +1 -0
  85. package/dist/types/v3/BaseStack/BaseStack.types.d.ts +45 -0
  86. package/dist/types/v3/BaseStack/BaseStack.types.d.ts.map +1 -0
  87. package/dist/types/v3/Box/Box.d.ts +19 -0
  88. package/dist/types/v3/Box/Box.d.ts.map +1 -0
  89. package/dist/types/v3/Box/Box.types.d.ts +12 -0
  90. package/dist/types/v3/Box/Box.types.d.ts.map +1 -0
  91. package/dist/types/v3/Box/index.d.ts +3 -0
  92. package/dist/types/v3/Box/index.d.ts.map +1 -0
  93. package/dist/types/v3/Divider/Divider.d.ts +13 -0
  94. package/dist/types/v3/Divider/Divider.d.ts.map +1 -0
  95. package/dist/types/v3/Divider/Divider.types.d.ts +27 -0
  96. package/dist/types/v3/Divider/Divider.types.d.ts.map +1 -0
  97. package/dist/types/v3/Divider/index.d.ts +3 -0
  98. package/dist/types/v3/Divider/index.d.ts.map +1 -0
  99. package/dist/types/v3/HStack/HStack.d.ts +7 -0
  100. package/dist/types/v3/HStack/HStack.d.ts.map +1 -0
  101. package/dist/types/v3/HStack/HStack.types.d.ts +2 -0
  102. package/dist/types/v3/HStack/HStack.types.d.ts.map +1 -0
  103. package/dist/types/v3/HStack/index.d.ts +3 -0
  104. package/dist/types/v3/HStack/index.d.ts.map +1 -0
  105. package/dist/types/v3/Icon/Icon.d.ts +19 -0
  106. package/dist/types/v3/Icon/Icon.d.ts.map +1 -0
  107. package/dist/types/v3/Icon/Icon.types.d.ts +21 -0
  108. package/dist/types/v3/Icon/Icon.types.d.ts.map +1 -0
  109. package/dist/types/v3/Icon/index.d.ts +3 -0
  110. package/dist/types/v3/Icon/index.d.ts.map +1 -0
  111. package/dist/types/v3/SmoothCornersBox/SmoothCornersBox.d.ts +15 -0
  112. package/dist/types/v3/SmoothCornersBox/SmoothCornersBox.d.ts.map +1 -0
  113. package/dist/types/v3/SmoothCornersBox/SmoothCornersBox.types.d.ts +61 -0
  114. package/dist/types/v3/SmoothCornersBox/SmoothCornersBox.types.d.ts.map +1 -0
  115. package/dist/types/v3/SmoothCornersBox/index.d.ts +3 -0
  116. package/dist/types/v3/SmoothCornersBox/index.d.ts.map +1 -0
  117. package/dist/types/v3/Spinner/Spinner.d.ts +15 -0
  118. package/dist/types/v3/Spinner/Spinner.d.ts.map +1 -0
  119. package/dist/types/v3/Spinner/Spinner.types.d.ts +5 -0
  120. package/dist/types/v3/Spinner/Spinner.types.d.ts.map +1 -0
  121. package/dist/types/v3/Spinner/index.d.ts +3 -0
  122. package/dist/types/v3/Spinner/index.d.ts.map +1 -0
  123. package/dist/types/v3/Text/Text.d.ts +16 -0
  124. package/dist/types/v3/Text/Text.d.ts.map +1 -0
  125. package/dist/types/v3/Text/Text.types.d.ts +44 -0
  126. package/dist/types/v3/Text/Text.types.d.ts.map +1 -0
  127. package/dist/types/v3/Text/index.d.ts +3 -0
  128. package/dist/types/v3/Text/index.d.ts.map +1 -0
  129. package/dist/types/v3/VStack/VStack.d.ts +7 -0
  130. package/dist/types/v3/VStack/VStack.d.ts.map +1 -0
  131. package/dist/types/v3/VStack/VStack.types.d.ts +2 -0
  132. package/dist/types/v3/VStack/VStack.types.d.ts.map +1 -0
  133. package/dist/types/v3/VStack/index.d.ts +3 -0
  134. package/dist/types/v3/VStack/index.d.ts.map +1 -0
  135. package/dist/types/v3/index.d.ts +9 -0
  136. package/dist/types/v3/index.d.ts.map +1 -0
  137. package/package.json +6 -1
  138. package/src/components/AlphaButton/Button.module.scss +1 -1
  139. package/src/components/AlphaFloatingButton/FloatingButton.module.scss +1 -1
  140. package/src/components/Button/Button.module.scss +9 -1
  141. package/src/types/beta-tokens.ts +8 -0
  142. package/src/types/props-helpers.ts +22 -1
  143. package/src/types/props.ts +52 -0
  144. package/src/v3/BaseStack/BaseStack.module.scss +73 -0
  145. package/src/v3/BaseStack/BaseStack.test.tsx +83 -0
  146. package/src/v3/BaseStack/BaseStack.tsx +72 -0
  147. package/src/v3/BaseStack/BaseStack.types.ts +59 -0
  148. package/src/v3/Box/Box.module.scss +13 -0
  149. package/src/v3/Box/Box.stories.tsx +27 -0
  150. package/src/v3/Box/Box.test.tsx +57 -0
  151. package/src/v3/Box/Box.tsx +77 -0
  152. package/src/v3/Box/Box.types.ts +24 -0
  153. package/src/v3/Box/index.ts +2 -0
  154. package/src/v3/Divider/Divider.module.scss +52 -0
  155. package/src/v3/Divider/Divider.stories.tsx +95 -0
  156. package/src/v3/Divider/Divider.test.tsx +47 -0
  157. package/src/v3/Divider/Divider.tsx +57 -0
  158. package/src/v3/Divider/Divider.types.ts +32 -0
  159. package/src/v3/Divider/index.ts +2 -0
  160. package/src/v3/HStack/HStack.stories.tsx +58 -0
  161. package/src/v3/HStack/HStack.test.tsx +14 -0
  162. package/src/v3/HStack/HStack.tsx +21 -0
  163. package/src/v3/HStack/HStack.types.ts +1 -0
  164. package/src/v3/HStack/index.ts +2 -0
  165. package/src/v3/Icon/Icon.module.scss +20 -0
  166. package/src/v3/Icon/Icon.stories.tsx +173 -0
  167. package/src/v3/Icon/Icon.test.tsx +64 -0
  168. package/src/v3/Icon/Icon.tsx +67 -0
  169. package/src/v3/Icon/Icon.types.ts +32 -0
  170. package/src/v3/Icon/index.ts +2 -0
  171. package/src/v3/SmoothCornersBox/SmoothCornersBox.module.scss +48 -0
  172. package/src/v3/SmoothCornersBox/SmoothCornersBox.stories.tsx +41 -0
  173. package/src/v3/SmoothCornersBox/SmoothCornersBox.test.tsx +83 -0
  174. package/src/v3/SmoothCornersBox/SmoothCornersBox.tsx +84 -0
  175. package/src/v3/SmoothCornersBox/SmoothCornersBox.types.ts +69 -0
  176. package/src/v3/SmoothCornersBox/index.ts +2 -0
  177. package/src/v3/Spinner/Spinner.module.scss +58 -0
  178. package/src/v3/Spinner/Spinner.stories.tsx +28 -0
  179. package/src/v3/Spinner/Spinner.test.tsx +65 -0
  180. package/src/v3/Spinner/Spinner.tsx +61 -0
  181. package/src/v3/Spinner/Spinner.types.ts +12 -0
  182. package/src/v3/Spinner/index.ts +2 -0
  183. package/src/v3/Text/Text.module.scss +69 -0
  184. package/src/v3/Text/Text.stories.tsx +52 -0
  185. package/src/v3/Text/Text.test.tsx +84 -0
  186. package/src/v3/Text/Text.tsx +81 -0
  187. package/src/v3/Text/Text.types.ts +70 -0
  188. package/src/v3/Text/index.ts +2 -0
  189. package/src/v3/VStack/VStack.stories.tsx +58 -0
  190. package/src/v3/VStack/VStack.test.tsx +14 -0
  191. package/src/v3/VStack/VStack.tsx +21 -0
  192. package/src/v3/VStack/VStack.types.ts +1 -0
  193. package/src/v3/VStack/index.ts +2 -0
  194. package/src/v3/index.ts +10 -0
@@ -0,0 +1,58 @@
1
+ @use '../../styles/mixins/dimension';
2
+
3
+ @keyframes spin {
4
+ 0% {
5
+ transform: rotate(0deg);
6
+ }
7
+
8
+ 100% {
9
+ transform: rotate(360deg);
10
+ }
11
+ }
12
+
13
+ .Spinner {
14
+ --b-v3-spinner-color: initial;
15
+
16
+ display: inline-block;
17
+ flex-shrink: 0;
18
+
19
+ border-style: solid;
20
+ border-top-color: transparent;
21
+ border-right-color: var(--b-v3-spinner-color);
22
+ border-bottom-color: var(--b-v3-spinner-color);
23
+ /* stylelint-disable-next-line declaration-block-no-redundant-longhand-properties */
24
+ border-left-color: var(--b-v3-spinner-color);
25
+ border-radius: 50%;
26
+
27
+ animation: spin 1s linear infinite;
28
+
29
+ &:where(.size-xl) {
30
+ @include dimension.square(50px);
31
+
32
+ border-width: 4px;
33
+ }
34
+
35
+ &:where(.size-l, .size-m) {
36
+ border-width: 3px;
37
+ }
38
+
39
+ &:where(.size-l) {
40
+ @include dimension.square(24px);
41
+ }
42
+
43
+ &:where(.size-m) {
44
+ @include dimension.square(20px);
45
+ }
46
+
47
+ &:where(.size-s, .size-xs) {
48
+ border-width: 2px;
49
+ }
50
+
51
+ &:where(.size-s) {
52
+ @include dimension.square(16px);
53
+ }
54
+
55
+ &:where(.size-xs) {
56
+ @include dimension.square(12px);
57
+ }
58
+ }
@@ -0,0 +1,28 @@
1
+ import { type Meta, type StoryFn } from '@storybook/react'
2
+
3
+ import { Spinner } from './Spinner'
4
+ import { type SpinnerProps } from './Spinner.types'
5
+
6
+ const meta: Meta<typeof Spinner> = {
7
+ title: 'V3 components/Spinner',
8
+ component: Spinner,
9
+ argTypes: {
10
+ size: {
11
+ control: {
12
+ type: 'radio',
13
+ },
14
+ options: ['xs', 's', 'm', 'l', 'xl'],
15
+ },
16
+ },
17
+ }
18
+ export default meta
19
+
20
+ const Template: StoryFn<SpinnerProps> = ({ ...args }) => <Spinner {...args} />
21
+
22
+ export const Primary = {
23
+ render: Template,
24
+
25
+ args: {
26
+ size: 'm',
27
+ },
28
+ }
@@ -0,0 +1,65 @@
1
+ import * as React from 'react'
2
+
3
+ import { colorTokenCssVar } from '~/src/utils/style'
4
+ import { render } from '~/src/utils/test'
5
+
6
+ import { Spinner } from './Spinner'
7
+ import { type SpinnerProps } from './Spinner.types'
8
+
9
+ import styles from './Spinner.module.scss'
10
+
11
+ describe('Spinner', () => {
12
+ const renderSpinner = (props?: SpinnerProps) => render(<Spinner {...props} />)
13
+
14
+ it('should render loading status by default', () => {
15
+ const { getByRole } = renderSpinner()
16
+ const spinner = getByRole('status', { name: 'Loading' })
17
+
18
+ expect(spinner).toHaveClass(styles.Spinner)
19
+ expect(spinner).toHaveClass(styles['size-m'])
20
+ expect(spinner).toHaveStyle(
21
+ `--b-v3-spinner-color: ${colorTokenCssVar('icon-neutral')}`
22
+ )
23
+ })
24
+
25
+ it('should allow overriding accessibility status', () => {
26
+ const { getByRole } = renderSpinner({
27
+ role: 'progressbar',
28
+ 'aria-label': 'Submitting',
29
+ })
30
+
31
+ expect(getByRole('progressbar', { name: 'Submitting' })).toBeInTheDocument()
32
+ })
33
+
34
+ it('should forward ref', () => {
35
+ const ref = React.createRef<HTMLDivElement>()
36
+
37
+ render(<Spinner ref={ref} />)
38
+
39
+ expect(ref.current).toBeInTheDocument()
40
+ })
41
+
42
+ it('should receive style and class name', () => {
43
+ const { getByRole } = renderSpinner({
44
+ style: { color: 'red' },
45
+ className: 'test-class',
46
+ })
47
+ const spinner = getByRole('status')
48
+
49
+ expect(spinner).toHaveStyle('color: red')
50
+ expect(spinner).toHaveClass('test-class')
51
+ })
52
+
53
+ it('should receive color and size', () => {
54
+ const { getByRole } = renderSpinner({
55
+ color: 'icon-neutral-heavier',
56
+ size: 'xl',
57
+ })
58
+ const spinner = getByRole('status')
59
+
60
+ expect(spinner).toHaveClass(styles['size-xl'])
61
+ expect(spinner).toHaveStyle(
62
+ `--b-v3-spinner-color: ${colorTokenCssVar('icon-neutral-heavier')}`
63
+ )
64
+ })
65
+ })
@@ -0,0 +1,61 @@
1
+ 'use client'
2
+
3
+ import { forwardRef } from 'react'
4
+ import * as React from 'react'
5
+
6
+ import classNames from 'classnames'
7
+
8
+ import type { BetaSemanticColor } from '~/src/types/beta-tokens'
9
+ import { colorTokenCssVar } from '~/src/utils/style'
10
+
11
+ import type { SpinnerProps } from './Spinner.types'
12
+
13
+ import styles from './Spinner.module.scss'
14
+
15
+ const DEFAULT_SPINNER_COLOR = 'icon-neutral' satisfies BetaSemanticColor
16
+
17
+ /**
18
+ * `Spinner` is a component for indicating loading state.
19
+ * @example
20
+ *
21
+ * ```tsx
22
+ * <Spinner
23
+ * size="m"
24
+ * color="icon-neutral"
25
+ * />
26
+ * ```
27
+ */
28
+ export const Spinner = forwardRef<HTMLDivElement, SpinnerProps>(
29
+ function Spinner(
30
+ {
31
+ style,
32
+ className,
33
+ size = 'm',
34
+ color = DEFAULT_SPINNER_COLOR,
35
+ role = 'status',
36
+ 'aria-label': ariaLabel,
37
+ ...rest
38
+ },
39
+ forwardedRef
40
+ ) {
41
+ return (
42
+ <div
43
+ {...rest}
44
+ ref={forwardedRef}
45
+ role={role}
46
+ aria-label={ariaLabel ?? (role === 'status' ? 'Loading' : undefined)}
47
+ style={
48
+ {
49
+ '--b-v3-spinner-color': colorTokenCssVar(color),
50
+ ...style,
51
+ } as React.CSSProperties
52
+ }
53
+ className={classNames(
54
+ styles.Spinner,
55
+ styles[`size-${size}`],
56
+ className
57
+ )}
58
+ />
59
+ )
60
+ }
61
+ )
@@ -0,0 +1,12 @@
1
+ import type {
2
+ BezierComponentProps,
3
+ SizeProps,
4
+ V3ColorProps,
5
+ } from '~/src/types/props'
6
+
7
+ export type SpinnerSize = 'xl' | 'l' | 'm' | 's' | 'xs'
8
+
9
+ export interface SpinnerProps
10
+ extends Omit<BezierComponentProps<'div'>, keyof V3ColorProps>,
11
+ SizeProps<SpinnerSize>,
12
+ V3ColorProps {}
@@ -0,0 +1,2 @@
1
+ export { Spinner } from './Spinner'
2
+ export type { SpinnerProps, SpinnerSize } from './Spinner.types'
@@ -0,0 +1,69 @@
1
+ @use '../../styles/mixins/typography';
2
+
3
+ $typo-sizes: 11, 12, 13, 14, 15, 16, 17, 18, 22, 24, 30, 36;
4
+
5
+ .Text {
6
+ --b-text-color: initial;
7
+ --b-text-font-weight: var(--typography-font-weight-400);
8
+ --b-text-line-clamp: 1;
9
+ --b-text-line-height: initial;
10
+ --b-text-font-size: initial;
11
+ --b-text-letter-spacing: initial;
12
+
13
+ font-size: var(--b-text-font-size);
14
+ font-weight: var(--b-text-font-weight);
15
+ font-style: normal;
16
+ line-height: var(--b-text-line-height);
17
+ color: var(--b-text-color);
18
+ letter-spacing: var(--b-text-letter-spacing);
19
+
20
+ &:where(.bold) {
21
+ --b-text-font-weight: var(--typography-font-weight-600);
22
+ }
23
+
24
+ &:where(.italic) {
25
+ font-style: italic;
26
+ }
27
+
28
+ &:where(.truncated) {
29
+ overflow: hidden;
30
+ display: block;
31
+ text-overflow: ellipsis;
32
+ white-space: nowrap;
33
+ }
34
+
35
+ &:where(.multi-line-truncated) {
36
+ overflow: hidden;
37
+ display: -webkit-box;
38
+ -webkit-box-orient: vertical;
39
+
40
+ max-height: calc(var(--b-text-line-clamp) * var(--b-text-line-height));
41
+
42
+ text-overflow: ellipsis;
43
+
44
+ -webkit-line-clamp: var(--b-text-line-clamp);
45
+ }
46
+
47
+ &:where(.align-left) {
48
+ text-align: left;
49
+ }
50
+
51
+ &:where(.align-center) {
52
+ text-align: center;
53
+ }
54
+
55
+ &:where(.align-right) {
56
+ text-align: right;
57
+ }
58
+
59
+ @each $size in $typo-sizes {
60
+ &:where(.typo-#{$size}) {
61
+ @include typography.size(
62
+ $size,
63
+ 'b-text-font-size',
64
+ 'b-text-line-height',
65
+ 'b-text-letter-spacing'
66
+ );
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,52 @@
1
+ import { type Meta, type StoryFn, type StoryObj } from '@storybook/react'
2
+
3
+ import { Box } from '~/src/v3/Box'
4
+
5
+ import { Text } from './Text'
6
+ import { type TextProps } from './Text.types'
7
+
8
+ const meta: Meta<typeof Text> = {
9
+ title: 'V3 components/Text',
10
+ component: Text,
11
+ }
12
+
13
+ const Template: StoryFn<TextProps> = ({ children, ...rest }) => (
14
+ <Box width={200}>
15
+ <Text {...rest}>{children}</Text>
16
+ </Box>
17
+ )
18
+
19
+ export const Primary: StoryObj<typeof Text> = {
20
+ render: Template,
21
+ args: {
22
+ bold: false,
23
+ italic: false,
24
+ truncated: false,
25
+ color: 'text-neutral',
26
+ children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
27
+ typo: '15',
28
+ },
29
+ }
30
+
31
+ const MultiLineTruncated: StoryFn<TextProps> = ({ children, ...rest }) => (
32
+ <Box width={200}>
33
+ <Text
34
+ {...rest}
35
+ color="text-neutral"
36
+ >
37
+ {children}
38
+ </Text>
39
+ </Box>
40
+ )
41
+
42
+ export const Secondary: StoryObj<typeof Text> = {
43
+ render: MultiLineTruncated,
44
+ args: {
45
+ truncated: 4,
46
+ children:
47
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dolor nunc, bibendum vel neque eget, facilisis ornare justo. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In laoreet ipsum in commodo eleifend. Duis vestibulum, nulla ut tincidunt molestie, eros massa commodo risus, non sollicitudin turpis diam vitae elit.',
48
+ },
49
+ name: 'Multi-line truncated',
50
+ }
51
+
52
+ export default meta
@@ -0,0 +1,84 @@
1
+ import * as React from 'react'
2
+
3
+ import { colorTokenCssVar } from '~/src/utils/style'
4
+ import { render } from '~/src/utils/test'
5
+
6
+ import { Text } from './Text'
7
+ import { type TextProps } from './Text.types'
8
+
9
+ import styles from './Text.module.scss'
10
+
11
+ const TEXT = 'Hello, Channel!'
12
+
13
+ describe('Text', () => {
14
+ const renderText = (props?: Partial<TextProps>) =>
15
+ render(<Text {...props}>{TEXT}</Text>)
16
+
17
+ it('should have default style', () => {
18
+ const { getByText } = renderText()
19
+ const rendered = getByText(TEXT)
20
+
21
+ expect(rendered).toHaveClass(styles.Text)
22
+ expect(rendered).toHaveClass(styles['typo-15'])
23
+ })
24
+
25
+ it('should render as the given element', () => {
26
+ const { getByText } = renderText({ as: 'p' })
27
+ const rendered = getByText(TEXT)
28
+
29
+ expect(rendered.tagName).toBe('P')
30
+ })
31
+
32
+ it('should forward ref', () => {
33
+ const ref = React.createRef<HTMLElement>()
34
+
35
+ render(<Text ref={ref}>{TEXT}</Text>)
36
+
37
+ expect(ref.current).toBeInTheDocument()
38
+ })
39
+
40
+ it('should receive color and font weight', () => {
41
+ const { getByText } = renderText({
42
+ color: 'text-neutral',
43
+ fontWeight: '600',
44
+ })
45
+ const rendered = getByText(TEXT)
46
+
47
+ expect(rendered).toHaveStyle(
48
+ `--b-text-color: ${colorTokenCssVar('text-neutral')}`
49
+ )
50
+ expect(rendered).toHaveStyle(
51
+ '--b-text-font-weight: var(--typography-font-weight-600)'
52
+ )
53
+ })
54
+
55
+ it('should receive text styles', () => {
56
+ const { getByText } = renderText({
57
+ bold: true,
58
+ italic: true,
59
+ align: 'center',
60
+ typo: '24',
61
+ })
62
+ const rendered = getByText(TEXT)
63
+
64
+ expect(rendered).toHaveClass(styles.bold)
65
+ expect(rendered).toHaveClass(styles.italic)
66
+ expect(rendered).toHaveClass(styles['align-center'])
67
+ expect(rendered).toHaveClass(styles['typo-24'])
68
+ })
69
+
70
+ it('should receive truncated style', () => {
71
+ const { getByText } = renderText({ truncated: true })
72
+ const rendered = getByText(TEXT)
73
+
74
+ expect(rendered).toHaveClass(styles.truncated)
75
+ })
76
+
77
+ it('should receive multi-line truncated style', () => {
78
+ const { getByText } = renderText({ truncated: 2 })
79
+ const rendered = getByText(TEXT)
80
+
81
+ expect(rendered).toHaveClass(styles['multi-line-truncated'])
82
+ expect(rendered).toHaveStyle('--b-text-line-clamp: 2')
83
+ })
84
+ })
@@ -0,0 +1,81 @@
1
+ 'use client'
2
+
3
+ import { createElement, forwardRef } from 'react'
4
+
5
+ import classNames from 'classnames'
6
+
7
+ import { getMarginStyles, splitByMarginProps } from '~/src/types/props-helpers'
8
+ import { colorTokenCssVar } from '~/src/utils/style'
9
+ import { isNumber } from '~/src/utils/type'
10
+
11
+ import { type TextProps } from './Text.types'
12
+
13
+ import styles from './Text.module.scss'
14
+
15
+ function fontWeightTokenCssVar(fontWeight?: TextProps['fontWeight']) {
16
+ return fontWeight ? `var(--typography-font-weight-${fontWeight})` : undefined
17
+ }
18
+
19
+ /**
20
+ * `Text` is a component for representing the typography of a design system.
21
+ * @example
22
+ *
23
+ * ```tsx
24
+ * <Text
25
+ * typo="15"
26
+ * color="text-neutral"
27
+ * >
28
+ * Hello, Channel!
29
+ * </Text>
30
+ * ```
31
+ */
32
+ export const Text = forwardRef<HTMLElement, TextProps>(
33
+ function Text(props, forwardedRef) {
34
+ const [marginProps, marginRest] = splitByMarginProps(props)
35
+ const marginStyles = getMarginStyles(marginProps)
36
+
37
+ const {
38
+ children,
39
+ style,
40
+ className,
41
+ as = 'span',
42
+ typo = '15',
43
+ color,
44
+ bold,
45
+ fontWeight,
46
+ italic,
47
+ truncated,
48
+ align,
49
+ ...rest
50
+ } = marginRest
51
+ const isMultiLineTruncated = isNumber(truncated) && truncated >= 1
52
+
53
+ return createElement(
54
+ as,
55
+ {
56
+ ref: forwardedRef,
57
+ style: {
58
+ '--b-text-color': colorTokenCssVar(color),
59
+ '--b-text-font-weight': fontWeightTokenCssVar(fontWeight),
60
+ '--b-text-line-clamp': isMultiLineTruncated ? truncated : undefined,
61
+ ...marginStyles.style,
62
+ ...style,
63
+ },
64
+ className: classNames(
65
+ styles.Text,
66
+ styles[`typo-${typo}`],
67
+ bold && styles.bold,
68
+ italic && styles.italic,
69
+ truncated === true
70
+ ? styles.truncated
71
+ : isMultiLineTruncated && styles['multi-line-truncated'],
72
+ align && styles[`align-${align}`],
73
+ marginStyles.className,
74
+ className
75
+ ),
76
+ ...rest,
77
+ },
78
+ children
79
+ )
80
+ }
81
+ )
@@ -0,0 +1,70 @@
1
+ import {
2
+ type BetaTextSemanticColor,
3
+ type BetaTypographyFontWeight,
4
+ } from '~/src/types/beta-tokens'
5
+ import {
6
+ type BezierComponentProps,
7
+ type ChildrenProps,
8
+ type PolymorphicProps,
9
+ type V3MarginProps,
10
+ } from '~/src/types/props'
11
+
12
+ type Typography =
13
+ | '11'
14
+ | '12'
15
+ | '13'
16
+ | '14'
17
+ | '15'
18
+ | '16'
19
+ | '17'
20
+ | '18'
21
+ | '22'
22
+ | '24'
23
+ | '30'
24
+ | '36'
25
+
26
+ type TextAlign = 'left' | 'center' | 'right'
27
+
28
+ interface TextOwnProps {
29
+ /**
30
+ * Typography style of the text.
31
+ * @default '15'
32
+ */
33
+ typo?: Typography
34
+ /**
35
+ * Color of the text. If no value is specified, it inherits the color of the parent element.
36
+ */
37
+ color?: BetaTextSemanticColor
38
+ /**
39
+ * Whether the text is bold.
40
+ * @default false
41
+ */
42
+ bold?: boolean
43
+ /**
44
+ * Font weight of the text.
45
+ * If `bold` and `fontWeight` are used together, `fontWeight` takes precedence.
46
+ */
47
+ fontWeight?: BetaTypographyFontWeight
48
+ /**
49
+ * Whether the text is italic.
50
+ * @default false
51
+ */
52
+ italic?: boolean
53
+ /**
54
+ * Whether the text is truncated.
55
+ * If it is a positive integer, it means the maximum number of lines.
56
+ * @default false
57
+ */
58
+ truncated?: boolean | number
59
+ /**
60
+ * Horizontal alignment of the text.
61
+ */
62
+ align?: TextAlign
63
+ }
64
+
65
+ export interface TextProps
66
+ extends Omit<BezierComponentProps, keyof TextOwnProps>,
67
+ PolymorphicProps,
68
+ ChildrenProps,
69
+ V3MarginProps,
70
+ TextOwnProps {}
@@ -0,0 +1,2 @@
1
+ export { Text } from './Text'
2
+ export type { TextProps } from './Text.types'
@@ -0,0 +1,58 @@
1
+ import React from 'react'
2
+
3
+ import { type Meta, type StoryFn, type StoryObj } from '@storybook/react'
4
+
5
+ import { range } from '~/src/utils/number'
6
+ import { Box } from '~/src/v3/Box'
7
+ import { Text } from '~/src/v3/Text'
8
+
9
+ import { VStack } from './VStack'
10
+
11
+ const meta = {
12
+ title: 'V3 components/VStack',
13
+ component: VStack,
14
+ } satisfies Meta<typeof VStack>
15
+
16
+ type Story = StoryObj<typeof meta>
17
+
18
+ function DecorativeBox({ children }: React.PropsWithChildren<{}>) {
19
+ return (
20
+ <Box
21
+ width={50}
22
+ height={50}
23
+ backgroundColor="fill-neutral"
24
+ borderRadius="8"
25
+ borderWidth={1}
26
+ borderColor="border-neutral"
27
+ >
28
+ <Text>{children}</Text>
29
+ </Box>
30
+ )
31
+ }
32
+
33
+ const Template: StoryFn<typeof VStack> = (args) => (
34
+ <VStack
35
+ {...args}
36
+ borderColor="border-neutral"
37
+ borderWidth={1}
38
+ >
39
+ {range(4).map((i) => (
40
+ <DecorativeBox key={`item-${i}`}>{i + 1}</DecorativeBox>
41
+ ))}
42
+ </VStack>
43
+ )
44
+
45
+ export const Primary: Story = {
46
+ render: Template,
47
+ args: {
48
+ justify: 'start',
49
+ align: 'start',
50
+ reverse: false,
51
+ wrap: true,
52
+ width: 300,
53
+ height: 300,
54
+ spacing: 6,
55
+ },
56
+ }
57
+
58
+ export default meta
@@ -0,0 +1,14 @@
1
+ import { render } from '~/src/utils/test'
2
+ import styles from '~/src/v3/BaseStack/BaseStack.module.scss'
3
+
4
+ import { VStack } from './VStack'
5
+
6
+ describe('VStack', () => {
7
+ it('should render vertical stack', () => {
8
+ const { getByText } = render(<VStack>Hello, Channel!</VStack>)
9
+ const rendered = getByText('Hello, Channel!')
10
+
11
+ expect(rendered).toHaveClass(styles.BaseStack)
12
+ expect(rendered).toHaveClass(styles['direction-vertical'])
13
+ })
14
+ })
@@ -0,0 +1,21 @@
1
+ 'use client'
2
+
3
+ import { createElement, forwardRef } from 'react'
4
+
5
+ import { BaseStack } from '~/src/v3/BaseStack/BaseStack'
6
+
7
+ import type { VStackProps } from './VStack.types'
8
+
9
+ /**
10
+ * `VStack` is a shorthand component equivalent to `Stack` with a vertical direction property.
11
+ * @see BaseStack
12
+ */
13
+ export const VStack = forwardRef<HTMLElement, VStackProps>(
14
+ function VStack(props, forwardedRef) {
15
+ return createElement(BaseStack, {
16
+ ...props,
17
+ direction: 'vertical',
18
+ ref: forwardedRef,
19
+ })
20
+ }
21
+ )
@@ -0,0 +1 @@
1
+ export type { VStackProps } from '~/src/v3/BaseStack/BaseStack.types'
@@ -0,0 +1,2 @@
1
+ export { VStack } from './VStack'
2
+ export type { VStackProps } from './VStack.types'