@marigold/components 0.0.2 → 0.3.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 (224) hide show
  1. package/CHANGELOG.md +294 -0
  2. package/dist/ActionGroup/ActionGroup.d.ts +8 -0
  3. package/dist/ActionGroup/ActionGroup.stories.d.ts +5 -0
  4. package/dist/ActionGroup/index.d.ts +1 -0
  5. package/dist/Alert/Alert.d.ts +16 -3
  6. package/dist/Alert/Alert.stories.d.ts +5 -0
  7. package/dist/Badge/Badge.d.ts +11 -5
  8. package/dist/Badge/Badge.stories.d.ts +5 -0
  9. package/dist/Box.d.ts +2 -0
  10. package/dist/Button/Button.d.ts +9 -5
  11. package/dist/Button/Button.stories.d.ts +5 -0
  12. package/dist/Card/Card.d.ts +14 -0
  13. package/dist/Card/Card.stories.d.ts +5 -0
  14. package/dist/Card/index.d.ts +1 -0
  15. package/dist/Checkbox/Checkbox.d.ts +17 -5
  16. package/dist/Checkbox/Checkbox.stories.d.ts +5 -0
  17. package/dist/Checkbox/CheckboxIcons.d.ts +9 -0
  18. package/dist/Column/Column.d.ts +6 -4
  19. package/dist/Column/Column.stories.d.ts +5 -0
  20. package/dist/Columns/Columns.d.ts +10 -0
  21. package/dist/Columns/Columns.stories.d.ts +5 -0
  22. package/dist/Columns/index.d.ts +1 -0
  23. package/dist/Container/Container.d.ts +5 -4
  24. package/dist/Container/Container.stories.d.ts +5 -0
  25. package/dist/Dialog/Dialog.d.ts +17 -0
  26. package/dist/Dialog/Dialog.stories.d.ts +5 -0
  27. package/dist/Dialog/ModalDialog.d.ts +8 -0
  28. package/dist/Dialog/index.d.ts +1 -0
  29. package/dist/Divider/Divider.d.ts +10 -3
  30. package/dist/Divider/Divider.stories.d.ts +5 -0
  31. package/dist/Field/Field.d.ts +10 -5
  32. package/dist/Field/Field.stories.d.ts +5 -0
  33. package/dist/Image/Image.d.ts +11 -5
  34. package/dist/Image/Image.stories.d.ts +5 -0
  35. package/dist/Inline/Inline.d.ts +7 -0
  36. package/dist/Inline/Inline.stories.d.ts +5 -0
  37. package/dist/Inline/index.d.ts +1 -0
  38. package/dist/Input/Input.d.ts +10 -4
  39. package/dist/Input/Input.stories.d.ts +5 -0
  40. package/dist/Label/Label.d.ts +18 -5
  41. package/dist/Label/Label.stories.d.ts +5 -0
  42. package/dist/Link/Link.d.ts +10 -5
  43. package/dist/Link/Link.stories.d.ts +5 -0
  44. package/dist/Menu/Menu.d.ts +11 -4
  45. package/dist/Menu/Menu.stories.d.ts +5 -0
  46. package/dist/MenuItem/MenuItem.d.ts +11 -4
  47. package/dist/MenuItem/MenuItem.stories.d.ts +5 -0
  48. package/dist/Message/Message.d.ts +10 -4
  49. package/dist/Message/Message.stories.d.ts +5 -0
  50. package/dist/Provider/MarigoldProvider.d.ts +11 -0
  51. package/dist/Provider/index.d.ts +3 -0
  52. package/dist/Radio/Radio.d.ts +17 -4
  53. package/dist/Radio/RadioIcons.d.ts +10 -0
  54. package/dist/Select/ListBox.d.ts +9 -0
  55. package/dist/Select/ListBoxSection.d.ts +9 -0
  56. package/dist/Select/Option.d.ts +9 -0
  57. package/dist/Select/Popover.d.ts +9 -0
  58. package/dist/Select/Select.d.ts +27 -3
  59. package/dist/Select/Select.stories.d.ts +5 -0
  60. package/dist/Slider/Slider.d.ts +10 -4
  61. package/dist/Slider/Slider.stories.d.ts +5 -0
  62. package/dist/Stack/Stack.d.ts +7 -0
  63. package/dist/Stack/Stack.stories.d.ts +5 -0
  64. package/dist/Stack/index.d.ts +1 -0
  65. package/dist/Text/Text.d.ts +17 -7
  66. package/dist/Text/Text.stories.d.ts +5 -0
  67. package/dist/Textarea/Textarea.d.ts +15 -4
  68. package/dist/Textarea/Textarea.stories.d.ts +5 -0
  69. package/dist/ValidationMessage/ValidationMessage.d.ts +10 -4
  70. package/dist/ValidationMessage/ValidationMessage.stories.d.ts +5 -0
  71. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -0
  72. package/dist/VisuallyHidden/VisuallyHidden.stories.d.ts +5 -0
  73. package/dist/VisuallyHidden/index.d.ts +1 -0
  74. package/dist/components.cjs.development.js +1276 -461
  75. package/dist/components.cjs.development.js.map +1 -1
  76. package/dist/components.cjs.production.min.js +1 -1
  77. package/dist/components.cjs.production.min.js.map +1 -1
  78. package/dist/components.esm.js +1229 -461
  79. package/dist/components.esm.js.map +1 -1
  80. package/dist/index.d.ts +10 -3
  81. package/dist/theme.d.ts +23 -28
  82. package/package.json +27 -4
  83. package/src/ActionGroup/ActionGroup.stories.tsx +47 -0
  84. package/src/ActionGroup/ActionGroup.test.tsx +83 -0
  85. package/src/ActionGroup/ActionGroup.tsx +32 -0
  86. package/src/ActionGroup/index.ts +1 -0
  87. package/src/Alert/Alert.stories.tsx +32 -0
  88. package/src/Alert/Alert.test.tsx +34 -23
  89. package/src/Alert/Alert.tsx +48 -24
  90. package/src/Badge/Badge.stories.tsx +38 -0
  91. package/src/Badge/Badge.test.tsx +14 -40
  92. package/src/Badge/Badge.tsx +31 -28
  93. package/src/Box.ts +2 -0
  94. package/src/Button/Button.stories.tsx +57 -0
  95. package/src/Button/Button.test.tsx +76 -13
  96. package/src/Button/Button.tsx +58 -23
  97. package/src/Card/Card.stories.tsx +41 -0
  98. package/src/Card/Card.test.tsx +71 -0
  99. package/src/Card/Card.tsx +48 -0
  100. package/src/Card/index.ts +1 -0
  101. package/src/Checkbox/Checkbox.stories.mdx +90 -112
  102. package/src/Checkbox/Checkbox.stories.tsx +78 -0
  103. package/src/Checkbox/Checkbox.test.tsx +139 -24
  104. package/src/Checkbox/Checkbox.tsx +95 -58
  105. package/src/Checkbox/CheckboxIcons.tsx +59 -0
  106. package/src/Column/Column.stories.tsx +33 -0
  107. package/src/Column/Column.test.tsx +15 -59
  108. package/src/Column/Column.tsx +21 -19
  109. package/src/Columns/Columns.stories.tsx +75 -0
  110. package/src/Columns/Columns.test.tsx +113 -0
  111. package/src/Columns/Columns.tsx +69 -0
  112. package/src/Columns/index.ts +1 -0
  113. package/src/Container/Container.stories.tsx +14 -0
  114. package/src/Container/Container.test.tsx +8 -49
  115. package/src/Container/Container.tsx +8 -19
  116. package/src/Dialog/Dialog.stories.tsx +88 -0
  117. package/src/Dialog/Dialog.test.tsx +158 -0
  118. package/src/Dialog/Dialog.tsx +130 -0
  119. package/src/Dialog/ModalDialog.tsx +76 -0
  120. package/src/Dialog/index.ts +1 -0
  121. package/src/Divider/Divider.stories.tsx +30 -0
  122. package/src/Divider/Divider.test.tsx +14 -6
  123. package/src/Divider/Divider.tsx +20 -13
  124. package/src/Field/Field.stories.tsx +110 -0
  125. package/src/Field/Field.test.tsx +75 -34
  126. package/src/Field/Field.tsx +50 -43
  127. package/src/Image/Image.stories.tsx +34 -0
  128. package/src/Image/Image.test.tsx +6 -3
  129. package/src/Image/Image.tsx +21 -15
  130. package/src/Inline/Inline.stories.tsx +39 -0
  131. package/src/Inline/Inline.test.tsx +99 -0
  132. package/src/Inline/Inline.tsx +38 -0
  133. package/src/Inline/index.ts +1 -0
  134. package/src/Input/Input.stories.tsx +54 -0
  135. package/src/Input/Input.test.tsx +9 -5
  136. package/src/Input/Input.tsx +21 -16
  137. package/src/Label/Label.stories.tsx +41 -0
  138. package/src/Label/Label.test.tsx +41 -6
  139. package/src/Label/Label.tsx +59 -18
  140. package/src/Link/Link.stories.tsx +35 -0
  141. package/src/Link/Link.test.tsx +52 -22
  142. package/src/Link/Link.tsx +40 -20
  143. package/src/Menu/Menu.stories.tsx +62 -0
  144. package/src/Menu/Menu.test.tsx +13 -7
  145. package/src/Menu/Menu.tsx +44 -38
  146. package/src/MenuItem/MenuItem.stories.tsx +30 -0
  147. package/src/MenuItem/MenuItem.test.tsx +23 -14
  148. package/src/MenuItem/MenuItem.tsx +29 -18
  149. package/src/Message/Message.stories.tsx +30 -0
  150. package/src/Message/Message.test.tsx +5 -2
  151. package/src/Message/Message.tsx +48 -40
  152. package/src/Provider/MarigoldProvider.test.tsx +136 -0
  153. package/src/Provider/MarigoldProvider.tsx +47 -0
  154. package/src/Provider/index.ts +4 -0
  155. package/src/Radio/Radio.stories.mdx +91 -94
  156. package/src/Radio/Radio.test.tsx +92 -16
  157. package/src/Radio/Radio.tsx +114 -50
  158. package/src/Radio/RadioIcons.tsx +39 -0
  159. package/src/Select/ListBox.tsx +40 -0
  160. package/src/Select/ListBoxSection.tsx +40 -0
  161. package/src/Select/Option.tsx +48 -0
  162. package/src/Select/Popover.tsx +50 -0
  163. package/src/Select/Select.stories.tsx +81 -0
  164. package/src/Select/Select.test.tsx +311 -43
  165. package/src/Select/Select.tsx +174 -28
  166. package/src/Slider/Slider.stories.tsx +24 -0
  167. package/src/Slider/Slider.test.tsx +11 -7
  168. package/src/Slider/Slider.tsx +30 -15
  169. package/src/Stack/Stack.stories.tsx +57 -0
  170. package/src/Stack/Stack.test.tsx +138 -0
  171. package/src/Stack/Stack.tsx +39 -0
  172. package/src/Stack/index.ts +1 -0
  173. package/src/Text/Text.stories.tsx +61 -0
  174. package/src/Text/Text.test.tsx +41 -36
  175. package/src/Text/Text.tsx +55 -29
  176. package/src/Textarea/Textarea.stories.tsx +64 -0
  177. package/src/Textarea/Textarea.test.tsx +41 -5
  178. package/src/Textarea/Textarea.tsx +57 -17
  179. package/src/ValidationMessage/ValidationMessage.stories.tsx +27 -0
  180. package/src/ValidationMessage/ValidationMessage.test.tsx +19 -14
  181. package/src/ValidationMessage/ValidationMessage.tsx +36 -21
  182. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +19 -0
  183. package/src/VisuallyHidden/VisuallyHidden.test.tsx +10 -0
  184. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -0
  185. package/src/VisuallyHidden/index.ts +1 -0
  186. package/src/index.ts +11 -3
  187. package/src/theme.ts +49 -28
  188. package/dist/Heading/Heading.d.ts +0 -5
  189. package/dist/Heading/index.d.ts +0 -1
  190. package/dist/Hidden/Hidden.d.ts +0 -6
  191. package/dist/Hidden/index.d.ts +0 -1
  192. package/dist/Svg/Svg.d.ts +0 -6
  193. package/dist/Svg/index.d.ts +0 -1
  194. package/src/Alert/Alert.stories.mdx +0 -49
  195. package/src/Badge/Badge.stories.mdx +0 -41
  196. package/src/Button/Button.stories.mdx +0 -155
  197. package/src/Column/Column.stories.mdx +0 -76
  198. package/src/Container/Container.stories.mdx +0 -42
  199. package/src/Divider/Divider.stories.mdx +0 -42
  200. package/src/Field/Field.stories.mdx +0 -57
  201. package/src/Heading/Heading.stories.mdx +0 -79
  202. package/src/Heading/Heading.test.tsx +0 -63
  203. package/src/Heading/Heading.tsx +0 -22
  204. package/src/Heading/index.ts +0 -1
  205. package/src/Hidden/Hidden.stories.mdx +0 -64
  206. package/src/Hidden/Hidden.test.tsx +0 -87
  207. package/src/Hidden/Hidden.tsx +0 -25
  208. package/src/Hidden/index.ts +0 -1
  209. package/src/Image/Image.stories.mdx +0 -40
  210. package/src/Input/Input.stories.mdx +0 -44
  211. package/src/Label/Label.stories.mdx +0 -34
  212. package/src/Link/Link.stories.mdx +0 -37
  213. package/src/Menu/Menu.stories.mdx +0 -47
  214. package/src/MenuItem/MenuItem.stories.mdx +0 -32
  215. package/src/Message/Message.stories.mdx +0 -43
  216. package/src/Select/Select.stories.mdx +0 -43
  217. package/src/Slider/Slider.stories.mdx +0 -57
  218. package/src/Svg/Svg.stories.mdx +0 -47
  219. package/src/Svg/Svg.test.tsx +0 -76
  220. package/src/Svg/Svg.tsx +0 -31
  221. package/src/Svg/index.ts +0 -1
  222. package/src/Text/Text.stories.mdx +0 -60
  223. package/src/Textarea/Textarea.stories.mdx +0 -34
  224. package/src/ValidationMessage/ValidationMessage.stories.mdx +0 -36
@@ -1,28 +1,174 @@
1
- import React from 'react';
2
- import { system, useStyles } from '@marigold/system';
3
- import { ArrowDown } from '@marigold/icons';
4
-
5
- type SelectProps = {};
6
-
7
- export const Select = system<SelectProps, 'select'>(
8
- ({ variant = 'select', className, ref, ...props }) => {
9
- const selectStyles = useStyles(
10
- {
11
- variant: `form.${variant}`,
12
- },
13
- className
14
- );
15
- const iconStyles = useStyles({
16
- alignSelf: 'center',
17
- pointerEvents: 'none',
18
- ml: '-28px',
19
- });
20
-
21
- return (
22
- <div className={useStyles({ display: 'flex' })}>
23
- <select ref={ref} {...props} className={selectStyles} />
24
- <ArrowDown className={iconStyles} />
25
- </div>
26
- );
27
- }
28
- );
1
+ import React, { Ref, RefObject, useRef } from 'react';
2
+ import { useSelectState } from '@react-stately/select';
3
+ import { useButton } from '@react-aria/button';
4
+ import { mergeProps } from '@react-aria/utils';
5
+ import { useFocusRing } from '@react-aria/focus';
6
+ import { HiddenSelect, useSelect } from '@react-aria/select';
7
+ import type { AriaSelectProps } from '@react-types/select';
8
+ import { useOverlayTriggerState } from '@react-stately/overlays';
9
+ import { useOverlayTrigger, useOverlayPosition } from '@react-aria/overlays';
10
+ import { SingleSelection } from '@react-types/shared';
11
+
12
+ import { ComponentProps } from '@marigold/types';
13
+ import { ArrowDown, ArrowUp, Exclamation, Required } from '@marigold/icons';
14
+ import { ResponsiveStyleValue } from '@marigold/system';
15
+
16
+ import { Box } from '../Box';
17
+ import { Label } from '../Label';
18
+ import { ValidationMessage } from '../ValidationMessage';
19
+ import { ListBox } from './ListBox';
20
+ import { Popover } from './Popover';
21
+
22
+ // Theme Extension
23
+ // ---------------
24
+ export interface SelectThemeExtension<Value> {
25
+ select?: {
26
+ __default: Value;
27
+ disabled?: Value;
28
+ listbox?: {
29
+ __default: Value;
30
+ error?: Value;
31
+ };
32
+ section?: Value;
33
+ option?: Value;
34
+ };
35
+ }
36
+
37
+ // Props
38
+ // ---------------
39
+ export type SelectProps = {
40
+ labelVariant?: string;
41
+ placeholder?: string;
42
+ disabled?: boolean;
43
+ required?: boolean;
44
+ width?: ResponsiveStyleValue<number | string>;
45
+ error?: boolean;
46
+ errorMessage?: string;
47
+ } & ComponentProps<'select'> &
48
+ AriaSelectProps<object> &
49
+ SingleSelection;
50
+
51
+ // Component
52
+ // ---------------
53
+ export const Select = ({
54
+ labelVariant = 'above',
55
+ placeholder = 'Select an option',
56
+ disabled,
57
+ required,
58
+ error,
59
+ errorMessage,
60
+ width,
61
+ className,
62
+ ...props
63
+ }: SelectProps) => {
64
+ const state = useSelectState(props);
65
+ const overlayTriggerState = useOverlayTriggerState({});
66
+ const triggerRef = useRef<HTMLElement>() as RefObject<HTMLElement>;
67
+ const overlayRef = useRef<HTMLDivElement>();
68
+
69
+ // Get props for the overlay
70
+ const { overlayProps } = useOverlayTrigger(
71
+ { type: 'listbox' },
72
+ overlayTriggerState,
73
+ triggerRef
74
+ );
75
+ // Get popover positioning props relative to the trigger
76
+ const { overlayProps: positionProps } = useOverlayPosition({
77
+ targetRef: triggerRef,
78
+ overlayRef: overlayRef as RefObject<HTMLElement>,
79
+ placement: 'bottom',
80
+ shouldFlip: false,
81
+ isOpen: state.isOpen,
82
+ onClose: state.close,
83
+ });
84
+ // Get props for child elements from useSelect
85
+ const { labelProps, triggerProps, valueProps, menuProps } = useSelect(
86
+ props,
87
+ state,
88
+ triggerRef
89
+ );
90
+ // Get props for the button based on the trigger props from useSelect
91
+ const { buttonProps } = useButton(triggerProps, triggerRef);
92
+
93
+ const { focusProps } = useFocusRing();
94
+
95
+ return (
96
+ <Box position="relative" display="inline-block" width={width && width}>
97
+ {props.label && (
98
+ <Box>
99
+ <Label {...labelProps} htmlFor={labelProps.id} variant={labelVariant}>
100
+ {required ? (
101
+ <Box as="span" display="inline-flex" alignItems="center">
102
+ {props.label}
103
+ <Box as={Required} size={16} css={{ color: 'error' }} />
104
+ </Box>
105
+ ) : (
106
+ props.label
107
+ )}
108
+ </Label>
109
+ </Box>
110
+ )}
111
+ <HiddenSelect
112
+ state={state}
113
+ triggerRef={triggerRef}
114
+ label={props.label}
115
+ name={props.name}
116
+ isDisabled={disabled}
117
+ />
118
+ <Box
119
+ as="button"
120
+ {...mergeProps(buttonProps, focusProps)}
121
+ ref={triggerRef as RefObject<HTMLButtonElement>}
122
+ variant={
123
+ error && state.isOpen && !disabled
124
+ ? 'button.select.errorOpened'
125
+ : error
126
+ ? 'button.select.error'
127
+ : state.isOpen && !disabled
128
+ ? 'button.select.open'
129
+ : 'button.select'
130
+ }
131
+ disabled={disabled}
132
+ className={className}
133
+ >
134
+ <Box
135
+ as="span"
136
+ {...valueProps}
137
+ variant={disabled ? 'select.disabled' : 'select'}
138
+ >
139
+ {state.selectedItem ? state.selectedItem.rendered : placeholder}
140
+ </Box>
141
+ {state.isOpen && !disabled ? (
142
+ <Box as={ArrowUp} size={16} css={{ fill: 'text' }} />
143
+ ) : (
144
+ <Box
145
+ as={ArrowDown}
146
+ size={16}
147
+ css={{ fill: disabled ? 'disabled' : 'text' }}
148
+ />
149
+ )}
150
+ </Box>
151
+ {state.isOpen && !disabled && (
152
+ <Box
153
+ as={Popover}
154
+ {...overlayProps}
155
+ {...positionProps}
156
+ css={{
157
+ width: triggerRef.current && triggerRef.current.offsetWidth + 'px',
158
+ }}
159
+ ref={overlayRef as Ref<HTMLDivElement>}
160
+ isOpen={state.isOpen}
161
+ onClose={state.close}
162
+ >
163
+ <ListBox error={error} {...menuProps} state={state} />
164
+ </Box>
165
+ )}
166
+ {error && errorMessage && (
167
+ <Box as="span" display="inline-flex" alignItems="center">
168
+ <Box as={Exclamation} size={16} css={{ color: 'error' }} />
169
+ <ValidationMessage>{errorMessage}</ValidationMessage>
170
+ </Box>
171
+ )}
172
+ </Box>
173
+ );
174
+ };
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Slider } from './Slider';
4
+
5
+ export default {
6
+ title: 'Components/Slider',
7
+ argTypes: {
8
+ variant: {
9
+ control: {
10
+ type: 'text',
11
+ },
12
+ description: 'Style',
13
+ table: {
14
+ defaultValue: {
15
+ summary: '__default',
16
+ },
17
+ },
18
+ },
19
+ },
20
+ } as Meta;
21
+
22
+ export const Basic: ComponentStory<typeof Slider> = args => (
23
+ <Slider name="vol" min="0" max="50" {...args} />
24
+ );
@@ -1,15 +1,19 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
3
  import { ThemeProvider } from '@marigold/system';
4
- import { Slider } from '@marigold/components';
4
+ import { Slider } from './Slider';
5
5
 
6
6
  const theme = {
7
- form: {
8
- slider: {
9
- fontFamily: 'Oswald Regular',
7
+ fonts: {
8
+ regular: 'Oswald Regular',
9
+ body: 'Inter',
10
+ },
11
+ slider: {
12
+ __default: {
13
+ fontFamily: 'regular',
10
14
  },
11
- range: {
12
- fontFamily: 'Inter',
15
+ special: {
16
+ fontFamily: 'body',
13
17
  },
14
18
  },
15
19
  };
@@ -28,7 +32,7 @@ test('supports default variant and themeSection', () => {
28
32
  test('accepts other variant than default', () => {
29
33
  render(
30
34
  <ThemeProvider theme={theme}>
31
- <Slider variant="range" title="slider" />
35
+ <Slider variant="special" title="slider" />
32
36
  </ThemeProvider>
33
37
  );
34
38
  const slider = screen.getByTitle(/slider/);
@@ -1,20 +1,35 @@
1
1
  import React from 'react';
2
- import { useStyles, system } from '@marigold/system';
2
+ import { ComponentProps } from '@marigold/types';
3
3
 
4
- type SliderProps = {
5
- variant?: string;
6
- };
4
+ import { Box } from '../Box';
5
+
6
+ // Theme Extension
7
+ // ---------------
8
+ export interface SliderThemeExtension<Value> {
9
+ slider?: {
10
+ [key: string]: Value;
11
+ };
12
+ }
7
13
 
8
- export const Slider = system<SliderProps, 'input'>(
9
- ({ variant = 'slider', className, ...props }) => {
10
- const classNames = useStyles(
11
- {
12
- variant: `form.${variant}`,
13
- verticalAlign: 'middle',
14
- },
15
- className
16
- );
14
+ // Props
15
+ // ---------------
16
+ export type SliderProps = {
17
+ variant?: string;
18
+ } & ComponentProps<'input'>;
17
19
 
18
- return <input type="range" className={classNames} {...props} />;
19
- }
20
+ // Component
21
+ // ---------------
22
+ export const Slider: React.FC<SliderProps> = ({
23
+ variant = '',
24
+ className,
25
+ ...props
26
+ }) => (
27
+ <Box
28
+ as="input"
29
+ type="range"
30
+ css={{ verticalAlign: 'middle' }}
31
+ variant={`slider.${variant}`}
32
+ className={className}
33
+ {...props}
34
+ />
20
35
  );
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Stack } from './Stack';
4
+ import { Text } from '../Text';
5
+
6
+ export default {
7
+ title: 'Components/Stack',
8
+ argTypes: {
9
+ space: {
10
+ control: {
11
+ type: 'select',
12
+ },
13
+ options: [
14
+ 'none',
15
+ 'xxsmall',
16
+ 'xsmall',
17
+ 'small',
18
+ 'medium',
19
+ 'large',
20
+ 'xlarge',
21
+ 'xxlarge',
22
+ ],
23
+ description: 'Responsive Style Value',
24
+ table: {
25
+ defaultValue: {
26
+ summary: 'none',
27
+ },
28
+ },
29
+ },
30
+ align: {
31
+ control: {
32
+ type: 'select',
33
+ },
34
+ options: ['left', 'right', 'center'],
35
+ description: 'HTML element style',
36
+ table: {
37
+ defaultValue: {
38
+ summary: 'left',
39
+ },
40
+ },
41
+ },
42
+ },
43
+ } as Meta;
44
+
45
+ export const Basic: ComponentStory<typeof Stack> = args => (
46
+ <Stack {...args}>
47
+ <Text as="h2" variant="headline2">
48
+ Heading
49
+ </Text>
50
+ <Text>
51
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
52
+ dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada,
53
+ massa nec ultricies efficitur, lectus ante consequat magna, a porttitor
54
+ massa ex ut quam.
55
+ </Text>
56
+ </Stack>
57
+ );
@@ -0,0 +1,138 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ThemeProvider } from '@marigold/system';
4
+
5
+ import { Stack } from './Stack';
6
+ import { Text } from '../Text';
7
+
8
+ // Setup
9
+ // ---------------
10
+ const theme = {
11
+ space: {
12
+ none: 0,
13
+ small: 2,
14
+ medium: 4,
15
+ large: 8,
16
+ },
17
+ };
18
+
19
+ const getTopPadding = (element: HTMLElement) =>
20
+ getComputedStyle(element).getPropertyValue('padding-top');
21
+
22
+ test('default space is "none"', () => {
23
+ render(
24
+ <ThemeProvider theme={theme}>
25
+ <Stack>
26
+ <Text>first</Text>
27
+ <Text>second</Text>
28
+ <Text>third</Text>
29
+ </Stack>
30
+ </ThemeProvider>
31
+ );
32
+ const first = screen.getByText(/first/).parentElement!;
33
+ const second = screen.getByText(/second/).parentElement!;
34
+ const third = screen.getByText(/third/).parentElement!;
35
+
36
+ expect(getTopPadding(first)).toEqual('');
37
+ expect(second).toHaveStyle(`padding-top: 0px`);
38
+ expect(third).toHaveStyle(`padding-top: 0px`);
39
+ });
40
+
41
+ test('accepts and uses spacing from theme', () => {
42
+ render(
43
+ <ThemeProvider theme={theme}>
44
+ <Stack space="small">
45
+ <Text>first</Text>
46
+ <Text>second</Text>
47
+ <Text>third</Text>
48
+ </Stack>
49
+ </ThemeProvider>
50
+ );
51
+ const first = screen.getByText(/first/);
52
+ const second = screen.getByText(/second/);
53
+ const third = screen.getByText(/third/);
54
+
55
+ expect(getTopPadding(first)).toEqual('');
56
+ expect(second.parentElement).toHaveStyle(`padding-top: 2px`);
57
+ expect(third.parentElement).toHaveStyle(`padding-top: 2px`);
58
+ });
59
+
60
+ test('aligns children left by default', () => {
61
+ render(
62
+ <Stack data-testid="stack">
63
+ <Text>first</Text>
64
+ </Stack>
65
+ );
66
+ const stack = screen.getByTestId('stack');
67
+
68
+ expect(stack).toHaveStyle(`align-items: flex-start`);
69
+ });
70
+
71
+ test('allows to aligns children to the center', () => {
72
+ render(
73
+ <Stack align="center" data-testid="stack">
74
+ <Text>first</Text>
75
+ </Stack>
76
+ );
77
+ const stack = screen.getByTestId('stack');
78
+
79
+ expect(stack).toHaveStyle(`align-items: center`);
80
+ });
81
+
82
+ test('allows to aligns children to the right', () => {
83
+ render(
84
+ <Stack align="right" data-testid="stack">
85
+ <Text>first</Text>
86
+ </Stack>
87
+ );
88
+ const stack = screen.getByTestId('stack');
89
+
90
+ expect(stack).toHaveStyle(`align-items: flex-end`);
91
+ });
92
+
93
+ test('supports nesting', () => {
94
+ render(
95
+ <ThemeProvider theme={theme}>
96
+ <Stack space="large">
97
+ <Stack space="small" data-testid="upperStack">
98
+ <Text>first</Text>
99
+ <Text>second</Text>
100
+ </Stack>
101
+ <Stack space="small" data-testid="lowerStack">
102
+ <Text>third</Text>
103
+ <Text>fourth</Text>
104
+ </Stack>
105
+ </Stack>
106
+ </ThemeProvider>
107
+ );
108
+ const first = screen.getByText(/first/);
109
+ const second = screen.getByText(/second/);
110
+ const upperStack = screen.getByTestId('upperStack');
111
+
112
+ const third = screen.getByText(/third/);
113
+ const fourth = screen.getByText(/fourth/);
114
+ const lowerStack = screen.getByTestId('lowerStack');
115
+
116
+ expect(getTopPadding(upperStack.parentElement!)).toEqual('');
117
+ expect(lowerStack.parentElement).toHaveStyle(`padding-top: 8px`);
118
+
119
+ expect(getTopPadding(first.parentElement!)).toEqual('');
120
+ expect(second.parentElement).toHaveStyle(`padding-top: 2px`);
121
+
122
+ expect(getTopPadding(third.parentElement!)).toEqual('');
123
+ expect(fourth.parentElement).toHaveStyle(`padding-top: 2px`);
124
+ });
125
+
126
+ test('renders as div per default', () => {
127
+ render(
128
+ <ThemeProvider theme={theme}>
129
+ <Stack data-testid="stack">
130
+ <Text>first</Text>
131
+ <Text>second</Text>
132
+ </Stack>
133
+ </ThemeProvider>
134
+ );
135
+
136
+ const stack = screen.getByTestId('stack');
137
+ expect(stack instanceof HTMLDivElement).toBeTruthy();
138
+ });
@@ -0,0 +1,39 @@
1
+ import React, { Children } from 'react';
2
+ import flattenChildren from 'react-keyed-flatten-children';
3
+
4
+ import { ResponsiveStyleValue } from '@marigold/system';
5
+
6
+ import { Box } from '../Box';
7
+
8
+ export type StackProps = {
9
+ space?: ResponsiveStyleValue<string>;
10
+ align?: 'left' | 'right' | 'center';
11
+ };
12
+
13
+ const ALIGNMENT = {
14
+ left: 'flex-start',
15
+ center: 'center',
16
+ right: 'flex-end',
17
+ };
18
+
19
+ export const Stack: React.FC<StackProps> = ({
20
+ space = 'none',
21
+ align = 'left',
22
+ children,
23
+ ...props
24
+ }) => (
25
+ <Box
26
+ {...props}
27
+ display="flex"
28
+ flexDirection="column"
29
+ alignItems={ALIGNMENT[align]}
30
+ css={{ '> * + *': { pt: space } }}
31
+ >
32
+ {Children.map(
33
+ flattenChildren(children) as unknown as React.ReactElement,
34
+ (child: React.ReactElement) => (
35
+ <Box>{React.cloneElement(child, {}, child.props.children)}</Box>
36
+ )
37
+ )}
38
+ </Box>
39
+ );
@@ -0,0 +1 @@
1
+ export * from './Stack';
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Text } from './Text';
4
+
5
+ export default {
6
+ title: 'Components/Text',
7
+ argTypes: {
8
+ as: {
9
+ control: {
10
+ type: 'select',
11
+ },
12
+ options: ['span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
13
+ description: 'Set HTML element',
14
+ table: {
15
+ defaultValue: {
16
+ summary: 'span',
17
+ },
18
+ },
19
+ },
20
+ variant: {
21
+ control: {
22
+ type: 'select',
23
+ },
24
+ options: [
25
+ 'body',
26
+ 'headline1',
27
+ 'headline2',
28
+ 'headline3',
29
+ 'headline4',
30
+ 'headline5',
31
+ 'headline6',
32
+ ],
33
+ description: 'CHoose between body and different headlines',
34
+ table: {
35
+ defaultValue: {
36
+ summary: 'body',
37
+ },
38
+ },
39
+ },
40
+ color: {
41
+ control: {
42
+ type: 'text',
43
+ },
44
+ description: 'Text color',
45
+ table: {
46
+ defaultValue: {
47
+ summary: 'inherit',
48
+ },
49
+ },
50
+ },
51
+ },
52
+ } as Meta;
53
+
54
+ export const Basic: ComponentStory<typeof Text> = args => (
55
+ <Text {...args}>
56
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
57
+ dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada,
58
+ massa nec ultricies efficitur, lectus ante consequat magna, a porttitor
59
+ massa ex ut quam.
60
+ </Text>
61
+ );