@edvisor/product-language 0.2.0 → 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 (94) hide show
  1. package/.eslintrc.json +14 -6
  2. package/package.json +2 -3
  3. package/project.json +18 -7
  4. package/src/README.md +61 -0
  5. package/src/helpers/index.ts +2 -1
  6. package/src/helpers/playground.ts +16 -0
  7. package/src/lib/components/badge/badge.tsx +8 -17
  8. package/src/lib/components/badge/stories/badge.stories.mdx +44 -0
  9. package/src/lib/components/badge/stories/components.tsx +49 -0
  10. package/src/lib/components/card/card.test.tsx +4 -5
  11. package/src/lib/components/card/card.tsx +2 -2
  12. package/src/lib/components/card/components/card-section-slot.tsx +2 -2
  13. package/src/lib/components/card/storybook/card.stories.mdx +1 -1
  14. package/src/lib/components/card/storybook/components.tsx +6 -23
  15. package/src/lib/components/checkbox/checkbox.tsx +34 -95
  16. package/src/lib/components/checkbox/helpers.tsx +100 -0
  17. package/src/lib/components/checkbox/stories/checkbox.stories.mdx +27 -24
  18. package/src/lib/components/checkbox/stories/components.tsx +63 -15
  19. package/src/lib/components/divider/stories/divider.stories.mdx +7 -13
  20. package/src/lib/components/flag/flag-size-flags.tsx +55 -0
  21. package/src/lib/components/flag/flag.list.tsx +788 -0
  22. package/src/lib/components/flag/flag.test.tsx +65 -0
  23. package/src/lib/components/flag/flag.tsx +97 -0
  24. package/src/lib/components/flag/index.tsx +1 -0
  25. package/src/lib/components/flag/stories/components.tsx +403 -0
  26. package/src/lib/components/flag/stories/flag.stories.mdx +48 -0
  27. package/src/lib/components/flag/stories/playGround-select.tsx +145 -0
  28. package/src/lib/components/icon/icon-list.tsx +135 -0
  29. package/src/lib/components/icon/icon.test.tsx +48 -0
  30. package/src/lib/components/icon/icon.tsx +181 -0
  31. package/src/lib/components/icon/index.tsx +1 -0
  32. package/src/lib/components/icon/stories/components.tsx +282 -0
  33. package/src/lib/components/icon/stories/icon.stories.mdx +65 -0
  34. package/src/lib/components/index.ts +5 -0
  35. package/src/lib/components/input-field/components/labeled-input.tsx +7 -14
  36. package/src/lib/components/input-field/components/stepper.tsx +4 -3
  37. package/src/lib/components/input-field/input-field.test.tsx +5 -6
  38. package/src/lib/components/input-field/input-field.tsx +8 -8
  39. package/src/lib/components/input-field/storybook/components.tsx +9 -16
  40. package/src/lib/components/link/storybook/link.stories.mdx +1 -0
  41. package/src/lib/components/molecules/avatar/avatar-size-flags.tsx +3 -3
  42. package/src/lib/components/molecules/avatar/avatar.tsx +2 -2
  43. package/src/lib/components/molecules/avatar/stories/avatar.stories.mdx +18 -21
  44. package/src/lib/components/molecules/button/button-flags.tsx +120 -15
  45. package/src/lib/components/molecules/button/button.test.tsx +9 -9
  46. package/src/lib/components/molecules/button/button.tsx +61 -78
  47. package/src/lib/components/molecules/button/stories/button.stories.mdx +43 -42
  48. package/src/lib/components/molecules/button/stories/components.tsx +6 -8
  49. package/src/lib/components/molecules/input-checkbox/input-checkbox.tsx +23 -24
  50. package/src/lib/components/molecules/input-checkbox/stories/components.tsx +32 -15
  51. package/src/lib/components/molecules/input-checkbox/stories/input-checkbox.stories.mdx +6 -8
  52. package/src/lib/components/organisms/multi-choice-list/multi-choice-list.tsx +7 -8
  53. package/src/lib/components/organisms/multi-choice-list/stories/components.tsx +3 -5
  54. package/src/lib/components/organisms/multi-choice-list/stories/multi-choice-list.stories.mdx +4 -4
  55. package/src/lib/components/spinner/spinner.test.tsx +2 -2
  56. package/src/lib/components/spinner/spinner.tsx +15 -28
  57. package/src/lib/components/spinner/stories/components.tsx +33 -2
  58. package/src/lib/components/spinner/stories/spinner.stories.mdx +3 -10
  59. package/src/lib/components/tabs/components/index.ts +1 -0
  60. package/src/lib/components/tabs/components/tab.tsx +62 -0
  61. package/src/lib/components/tabs/index.tsx +1 -0
  62. package/src/lib/components/tabs/storybook/components.tsx +282 -0
  63. package/src/lib/components/tabs/storybook/tabs.stories.mdx +97 -0
  64. package/src/lib/components/tabs/tabs.test.tsx +86 -0
  65. package/src/lib/components/tabs/tabs.tsx +101 -0
  66. package/src/lib/components/tag/components/close-button.tsx +85 -0
  67. package/src/lib/components/tag/components/index.ts +2 -0
  68. package/src/lib/components/tag/components/tag-label.tsx +44 -0
  69. package/src/lib/components/tag/index.tsx +1 -0
  70. package/src/lib/components/tag/stories/components.tsx +86 -0
  71. package/src/lib/components/tag/stories/tag.stories.mdx +42 -0
  72. package/src/lib/components/tag/tag.test.tsx +36 -0
  73. package/src/lib/components/tag/tag.tsx +33 -0
  74. package/src/lib/components/thumbnail/thumbnail.tsx +7 -2
  75. package/src/lib/components/typography/storybook/components.tsx +47 -15
  76. package/src/lib/components/typography/storybook/typography.stories.mdx +6 -4
  77. package/src/lib/components/typography/typography.test.tsx +34 -30
  78. package/src/lib/components/typography/typography.tsx +61 -19
  79. package/src/lib/foundations/color-system/base-palette/base-palette.ts +0 -1
  80. package/src/lib/foundations/color-system/color-guidelines/color-guidelines.ts +5 -4
  81. package/src/lib/foundations/color-system/components/color-sample.tsx +3 -3
  82. package/src/lib/foundations/typography/fonts.ts +205 -0
  83. package/src/lib/foundations/typography/text-aspect-flags.ts +11 -4
  84. package/src/lib/foundations/typography/typography.tsx +38 -33
  85. package/src/lib/helpers/numbers.ts +14 -0
  86. package/src/lib/helpers/safe-navigation.ts +10 -0
  87. package/src/lib/helpers/slots.test.tsx +98 -0
  88. package/src/lib/helpers/slots.tsx +93 -12
  89. package/.storybook/preview-head.html +0 -1
  90. package/src/lib/components/badge/badge.stories.tsx +0 -16
  91. package/src/lib/components/checkbox/components/components.tsx +0 -59
  92. package/src/lib/components/checkbox/stories/index.tsx +0 -1
  93. package/src/lib/components/molecules/input-checkbox/stories/index.tsx +0 -1
  94. package/src/lib/components/organisms/multi-choice-list/stories/index.tsx +0 -1
@@ -1,4 +1,5 @@
1
1
  import { Body, Heading4 } from '@components'
2
+ import { isDefined } from '@helpers'
2
3
  import { Playground } from 'storybook-addon-jarle-monaco'
3
4
  import { MultiChoiceList } from '../index'
4
5
 
@@ -10,7 +11,6 @@ const [withError, setWithError] = useState(false);
10
11
 
11
12
  <form onSubmit={(e) => {
12
13
  e.preventDefault()
13
- console.log('form submitted')
14
14
  }}
15
15
  >
16
16
  <MultiChoiceList options={[
@@ -24,14 +24,12 @@ const [withError, setWithError] = useState(false);
24
24
  setWithError(true);
25
25
  },
26
26
  onChange: function(e){
27
- console.log('at stories', e);
28
27
  setWithError(false);
29
28
  }
30
29
  },
31
30
  {
32
31
  label: "My Awesome label",
33
32
  id: 'My checkbox 2',
34
- checked: true,
35
33
  helpfulMessage: 'Alternative text here',
36
34
  },
37
35
  ]}
@@ -76,7 +74,7 @@ const [withError, setWithError] = useState(false);
76
74
  const options = Locations.map((location) => {
77
75
  return {
78
76
  ...location,
79
- checked: locations.find((l) => l.id === location.id),
77
+ checked: isDefined(locations.find((l) => l.id === location.id)),
80
78
  onChange: (checked) => {
81
79
  if (checked) {
82
80
  setLocations([
@@ -97,7 +95,6 @@ const options = Locations.map((location) => {
97
95
  <>
98
96
  <form onSubmit={(e) => {
99
97
  e.preventDefault()
100
- console.log('locations', locations)
101
98
  }}
102
99
  >
103
100
  <MultiChoiceList options={options}
@@ -120,6 +117,7 @@ const options = Locations.map((location) => {
120
117
  MultiChoiceList,
121
118
  Heading4,
122
119
  Body,
120
+ isDefined,
123
121
  },
124
122
  }}
125
123
  />
@@ -1,6 +1,6 @@
1
1
  import { Canvas, Meta, Story } from '@storybook/addon-docs';
2
- import { MultiChoiceList } from '../index'
3
- import { PlainHTMLFormExample, ExampleWithStateManagement } from './index'
2
+ import { MultiChoiceList } from '../multi-choice-list'
3
+ import { PlainHTMLFormExample, ExampleWithStateManagement } from './components'
4
4
 
5
5
  <Meta
6
6
  title="Components/MultiChoiceList"
@@ -35,7 +35,7 @@ import { MultiChoiceList } from './index'
35
35
  <MultiChoiceList options={[
36
36
  {
37
37
  label: "My Awesome label",
38
- checked: true,
38
+ defaultChecked: true,
39
39
  id: '1',
40
40
  },
41
41
  {
@@ -59,7 +59,7 @@ Also, you can send the altive text in order to helping user
59
59
  {
60
60
  label: "My Awesome label",
61
61
  id: 'My checkbox 1',
62
- checked: true,
62
+ defaultChecked: true,
63
63
  error: true,
64
64
  helpfulMessage: 'Alternative text here',
65
65
  },
@@ -8,7 +8,7 @@ describe('Spinner Tests', () => {
8
8
  <Spinner />
9
9
  )
10
10
 
11
- const spinner = screen.getByRole('progressbar')
11
+ const spinner = screen.getByRole('icon')
12
12
 
13
13
  expect(spinner).toBeInTheDocument()
14
14
  expect(spinner).toHaveStyle('height: 40px')
@@ -20,7 +20,7 @@ describe('Spinner Tests', () => {
20
20
  <Spinner small/>
21
21
  )
22
22
 
23
- const spinner = screen.getByRole('progressbar')
23
+ const spinner = screen.getByRole('icon')
24
24
 
25
25
  expect(spinner).toBeInTheDocument()
26
26
  expect(spinner).toHaveStyle('height: 18px')
@@ -2,6 +2,7 @@ import { getValuesBySize, SpinnerProps } from './spinner-size-flags'
2
2
  import { FC, is } from '@helpers'
3
3
  import styled, { keyframes } from 'styled-components'
4
4
  import { Icons } from '@foundations'
5
+ import { IconMinor } from 'components/icon'
5
6
 
6
7
  const spinAnimation = keyframes`
7
8
  0% {
@@ -18,26 +19,15 @@ const spinAnimation = keyframes`
18
19
  }
19
20
  `
20
21
 
21
- const Spin = styled.svg<{ size: string, onPrimary: boolean, onCritical: boolean }>`
22
- width: ${({ size }) => size};
23
- height: ${({ size }) => size};
24
- fill: none;
25
- path {
26
- fill-rule: evenodd;
27
- clip-rule: evenodd;
28
- fill: ${({ onPrimary, onCritical }) => (onPrimary || onCritical) ? Icons.OnPrimary : Icons.Default};
29
- stroke: ${({ onPrimary, onCritical }) => (onPrimary || onCritical) ? Icons.OnPrimary : Icons.Default};
30
- -webkit-transform-origin: 20px 20 0;
31
- -moz-transform-origin: 20px 20px 0;
32
- -ms-transform-origin: 20px 20px 0;
33
- -o-transform-origin: 20px 20px 0;
34
- transform-origin: 20px 20px 0;
35
- -webkit-animation: spinner 2s linear infinite;
36
- -moz-animation: spinner 2s linear infinite;
37
- -ms-animation: spinner 2s linear infinite;
38
- -o-animation: spinner 2s linear infinite;
39
- animation: spinner 2s linear infinite;
40
- animation-name: ${spinAnimation};
22
+ const Spin = styled.div<{ $size: string, $onPrimary: boolean, $onCritical: boolean }>`
23
+ svg {
24
+ width: ${({ $size }) => $size};
25
+ height: ${({ $size }) => $size};
26
+ position: unset;
27
+ path {
28
+ fill: ${({ $onPrimary, $onCritical }) => ($onPrimary || $onCritical) ? Icons.OnPrimary : Icons.Default};
29
+ }
30
+ animation: ${spinAnimation} infinite 2s linear;
41
31
  }
42
32
  `
43
33
 
@@ -52,15 +42,12 @@ export const Spinner : FC<IProps> = (props) => {
52
42
 
53
43
  return (
54
44
  <Spin
55
- onPrimary={is(props.onPrimary)}
56
- onCritical={is(props.onCritical)}
57
- className={props.className}
58
- size={size}
59
- role="progressbar"
60
- viewBox="0 0 40 40"
61
- xmlns="http://www.w3.org/2000/svg"
45
+ $onPrimary={is(props.onPrimary)}
46
+ $onCritical={is(props.onCritical)}
47
+ $size={size}
48
+ className={props.className}
62
49
  >
63
- <path d="M20 3.5C10.8873 3.5 3.5 10.8873 3.5 20C3.5 29.1127 10.8873 36.5 20 36.5C20.2593 36.5 20.517 36.494 20.7732 36.4822C21.6007 36.4441 22.3578 37.0111 22.4704 37.8319C22.5831 38.6526 22.0089 39.4152 21.182 39.4647C20.7908 39.4881 20.3967 39.5 20 39.5C9.23045 39.5 0.5 30.7696 0.5 20C0.5 9.23045 9.23045 0.5 20 0.5C26.0299 0.5 31.4203 3.23815 34.9953 7.53374C35.5252 8.17049 35.3622 9.11117 34.6867 9.59078C34.0113 10.0704 33.0798 9.90641 32.5411 9.27701C29.5131 5.73882 25.018 3.5 20 3.5Z" />
50
+ <IconMinor.Spinner />
64
51
  </Spin>
65
52
  )
66
53
  }
@@ -1,8 +1,39 @@
1
1
  import styled from 'styled-components'
2
2
  import { Padding, Surface } from '@foundations'
3
+ import { Playground } from 'storybook-addon-jarle-monaco'
4
+ import { Button } from 'components/molecules'
5
+ import { Spinner } from '../spinner'
3
6
 
4
- export const WrapperStories = styled.div`
5
- width: 100%;
7
+ export const Div = styled.div`
6
8
  padding: ${Padding.s};
7
9
  background: ${Surface.Default.Default};
10
+ display: flex;
11
+ gap: 20px;
8
12
  `
13
+
14
+ export const SpinnerCodeExample = () => (
15
+ <Playground
16
+ code={`
17
+ // Try replacing the Button types.
18
+ <Div>
19
+ <Button primary>
20
+ <Spinner onPrimary />
21
+ </Button>
22
+ <Button destructive primary>
23
+ <Spinner onCritical />
24
+ </Button>
25
+ <Button destructive>
26
+ <Spinner onCritical />
27
+ </Button>
28
+ </Div>
29
+ `}
30
+ providerProps={{
31
+ renderAsComponent: true,
32
+ scope: {
33
+ Button,
34
+ Spinner,
35
+ Div,
36
+ },
37
+ }}
38
+ />
39
+ )
@@ -1,9 +1,9 @@
1
1
  import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
2
2
  import { StoryComponent, talesOf, StorybookFrame } from '@stories'
3
3
  import { Spinner } from '../index'
4
- import { ButtonPrimary, ButtonDestructive } from 'components/molecules/button'
4
+ import { Button } from 'components/molecules/button'
5
5
 
6
- import { WrapperStories } from './components'
6
+ import { SpinnerCodeExample } from './components'
7
7
 
8
8
  <Meta title="Components/Spinner" />
9
9
 
@@ -32,11 +32,4 @@ import { Spinner } from './index'
32
32
 
33
33
  When rendering the spinner on a primary or critical surface, use onPrimary or onCritical.
34
34
 
35
- <Canvas>
36
- <ButtonPrimary>
37
- <Spinner onPrimary />
38
- </ButtonPrimary>
39
- <ButtonDestructive primary>
40
- <Spinner onCritical />
41
- </ButtonDestructive>
42
- </Canvas>
35
+ <SpinnerCodeExample/>
@@ -0,0 +1 @@
1
+ export * from './tab'
@@ -0,0 +1,62 @@
1
+ import { CSSProperties, HTMLAttributes, useEffect, useRef } from 'react'
2
+ import { FC, isDefined, Nothing, PropsWithChildren } from '@helpers'
3
+ import { Borders, Margin, Padding } from '@foundations'
4
+ import { Label } from 'components/typography'
5
+
6
+ const styles: (props: { selected: boolean }) => CSSProperties = ({ selected }) => ({
7
+ display: 'flex',
8
+ padding: Padding.m,
9
+ cursor: 'pointer',
10
+ outline: 'none',
11
+ borderBottom: selected ? `3px solid ${Borders.Highlight.Default}` : '',
12
+ ':focus': {
13
+ borderBottom: `3px solid ${Borders.Highlight.Default}`
14
+ },
15
+ })
16
+
17
+ export interface ITabProps extends PropsWithChildren, HTMLAttributes<HTMLDivElement> {
18
+ Prefix?: FC<HTMLAttributes<HTMLElement>>
19
+ selected?: boolean
20
+ }
21
+
22
+ export const Tab: FC<ITabProps> = (props) => {
23
+ const {
24
+ Prefix,
25
+ selected = false,
26
+ ...rest
27
+ } = props
28
+
29
+ // eslint-disable-next-line no-null/no-null
30
+ const ref = useRef<HTMLDivElement>(null)
31
+
32
+ useEffect(() => {
33
+ selected ? ref.current?.focus() : ref.current?.blur()
34
+ }, [selected])
35
+
36
+ /**
37
+ * @TODO this is a hack to be able to use the ref in react-web-client
38
+ * RWC uses styled-components < v4 and expects the ref to be passes as
39
+ * "innerRef" not just "ref", but product-language uses > v4 and wants
40
+ * to use ref. So for some components that need a ref, like this one
41
+ * we will have to use a div and style it the old fashioned way until
42
+ * we upgrade rwc's styled-components or drop rwc
43
+ */
44
+ return (
45
+ <div
46
+ {...rest}
47
+ tabIndex={0}
48
+ onClick={() => {
49
+ ref.current?.focus()
50
+ }}
51
+ role={'tab'}
52
+ aria-selected={selected}
53
+ ref={ref}
54
+ style={styles({ selected })}
55
+ >
56
+ {isDefined(Prefix) ? <Prefix style={{ marginRight: Margin.xs}} /> : <Nothing />}
57
+ <Label strong subdued={!selected}>
58
+ {props.children}
59
+ </Label>
60
+ </div>
61
+ )
62
+ }
@@ -0,0 +1 @@
1
+ export * from './tabs'
@@ -0,0 +1,282 @@
1
+ import styled from 'styled-components'
2
+
3
+ import { Padding, Margin } from '@foundations'
4
+ import { CardPlayground, Playground } from '@stories'
5
+
6
+ import { CardFrame } from 'components/card/atoms'
7
+ import { Tab, Tabs } from '../tabs'
8
+ import { InputField as InputFieldBase } from 'components/input-field'
9
+ import { Button } from 'components/molecules'
10
+ import { Flex } from 'components/layout'
11
+ import { Label } from 'components/typography'
12
+ import { FC, Nothing } from '@helpers'
13
+ import { Card } from 'components/card'
14
+ import { IconMinor as Icon } from 'components/icon'
15
+
16
+ const ContentFrame = styled(Tabs.Content)`
17
+ padding: ${Padding.l};
18
+ `
19
+
20
+ export const AdditionalControlsExample = () => (
21
+ <Playground
22
+ code={`
23
+ const [selected, setSelected] = useState(0);
24
+
25
+ <Tabs selected={selected} onChange={setSelected}>
26
+ <Tabs.TabList>
27
+ <div>This is not a tab.</div>
28
+ <Tab>No Icon</Tab>
29
+ <Tab Prefix={Icon.Comment}>With Icon</Tab>
30
+ <div>This is also not a tab.</div>
31
+ </Tabs.TabList>
32
+ <ContentFrame>
33
+ One
34
+ </ContentFrame>
35
+ <ContentFrame>
36
+ Two
37
+ </ContentFrame>
38
+ </Tabs>
39
+ `}
40
+ providerProps={{
41
+ renderAsComponent: true,
42
+ scope: {
43
+ Tabs,
44
+ Tab,
45
+ ContentFrame,
46
+ Icon,
47
+ Card,
48
+ },
49
+ }}
50
+ />
51
+ )
52
+
53
+ export const CrazyTabsExample = () => (
54
+ <Playground
55
+ code={`
56
+ const [selected, setSelected] = useState(0);
57
+
58
+ <Tabs selected={selected} onChange={setSelected}>
59
+ <ContentFrame>
60
+ One
61
+ </ContentFrame>
62
+ <ContentFrame>
63
+ Two
64
+ </ContentFrame>
65
+ <div>This message will render on every tab</div>
66
+ <Tabs.TabList>
67
+ <Tab>No Icon</Tab>
68
+ <Tab Prefix={Icon.Comment}>With Icon</Tab>
69
+ </Tabs.TabList>
70
+ </Tabs>
71
+ `}
72
+ providerProps={{
73
+ renderAsComponent: true,
74
+ scope: {
75
+ Tabs,
76
+ Tab,
77
+ ContentFrame,
78
+ Icon,
79
+ Card,
80
+ },
81
+ }}
82
+ />
83
+ )
84
+
85
+ export const TabsWithIconsExample = () => (
86
+ <Playground
87
+ code={`
88
+ const [selected, setSelected] = useState(0);
89
+
90
+ <Tabs selected={selected} onChange={setSelected}>
91
+ <Tabs.TabList>
92
+ <Tab>No Icon</Tab>
93
+ <Tab Prefix={Icon.Comment}>With Icon</Tab>
94
+ </Tabs.TabList>
95
+ <ContentFrame>
96
+ One
97
+ </ContentFrame>
98
+ <ContentFrame>
99
+ Two
100
+ </ContentFrame>
101
+ </Tabs>
102
+ `}
103
+ providerProps={{
104
+ renderAsComponent: true,
105
+ scope: {
106
+ Tabs,
107
+ Tab,
108
+ ContentFrame,
109
+ Icon,
110
+ Card,
111
+ },
112
+ }}
113
+ />
114
+ )
115
+
116
+ export const RenderingContentExample = () => (
117
+ <Playground
118
+ code={`
119
+ const [selected, setSelected] = useState(0);
120
+
121
+ <Tabs selected={selected} onChange={setSelected}>
122
+ <Tabs.TabList>
123
+ <Tab Prefix={Icon.Comment}>Style Directly</Tab>
124
+ <Tab Prefix={Icon.GraduationCap}>Use sub-components</Tab>
125
+ </Tabs.TabList>
126
+ <ContentFrame>
127
+ This was styled directly.
128
+ </ContentFrame>
129
+ <Tabs.Content>
130
+ <Card>This is in a Card.</Card>
131
+ </Tabs.Content>
132
+ </Tabs>
133
+ `}
134
+ providerProps={{
135
+ renderAsComponent: true,
136
+ scope: {
137
+ Tabs,
138
+ Tab,
139
+ ContentFrame,
140
+ Icon,
141
+ Card,
142
+ },
143
+ }}
144
+ />
145
+ )
146
+
147
+ const InputField = styled(InputFieldBase)`
148
+ margin-right: ${Margin.s};
149
+ flex-grow: 1;
150
+ `
151
+
152
+ const Controls = styled(Flex)`
153
+ width: 100%;
154
+ justify-content: end;
155
+ align-items: center;
156
+ padding-right: ${Padding.l};
157
+ `
158
+
159
+ const NationalityButton = styled(Button)`
160
+ display: flex;
161
+ `
162
+
163
+ const NationalityButtonPrefix: FC = () => {
164
+ return (
165
+ <Flex>
166
+ <Icon.Comment />
167
+ <Icon.GraduationCap />
168
+ </Flex>
169
+ )
170
+ }
171
+
172
+ export const TabsExample = () => (
173
+ <CardPlayground
174
+ code={`
175
+ const [selected, setSelected] = useState(0);
176
+
177
+ <Card>
178
+ <Tabs selected={selected} onChange={setSelected}>
179
+ <Tabs.TabList>
180
+ <Tab Prefix={Icon.Comment}>Language</Tab>
181
+ <Tab Prefix={Icon.GraduationCap}>Higher Ed.</Tab>
182
+ <Controls>
183
+ <NationalityButton
184
+ plain subtle
185
+ IconPrefix={NationalityButtonPrefix}
186
+ >
187
+ Brazil, Onshore
188
+ </NationalityButton>
189
+ </Controls>
190
+ </Tabs.TabList>
191
+ <ContentFrame>
192
+ <Flex center>
193
+ <InputField
194
+ label='Destination'
195
+ placeholder='Search'
196
+ />
197
+ <InputField
198
+ label='Provider'
199
+ placeholder='Any'
200
+ />
201
+ <InputField
202
+ label='Min. Number of Weeks'
203
+ placeholder='4'
204
+ />
205
+ <Button large primary>Search</Button>
206
+ </Flex>
207
+ </ContentFrame>
208
+ <ContentFrame>
209
+ In progress...
210
+ </ContentFrame>
211
+ </Tabs>
212
+ </Card>
213
+ `}
214
+ providerProps={{
215
+ renderAsComponent: true,
216
+ scope: {
217
+ Tabs,
218
+ ContentFrame,
219
+ Tab,
220
+ InputField,
221
+ Flex,
222
+ Controls,
223
+ NationalityButton,
224
+ Label,
225
+ NationalityButtonPrefix,
226
+ Button,
227
+ Card: CardFrame,
228
+ Icon,
229
+ },
230
+ }}
231
+ />
232
+ )
233
+
234
+ export const StateManagementExample = () => (
235
+ <CardPlayground
236
+ code={`
237
+ const [selected, setSelected] = useState(0);
238
+
239
+ <Card>
240
+ <Tabs selected={selected} onChange={setSelected}>
241
+ <Tabs.TabList>
242
+ <Tab Prefix={Icon.Comment}>One</Tab>
243
+ <Tab Prefix={Icon.GraduationCap}>Two</Tab>
244
+ <Tab Prefix={Icon.Check}>Three</Tab>
245
+ {selected > 0 ? <Button onClick={() => setSelected(0)}>Reset</Button> : <Nothing />}
246
+ </Tabs.TabList>
247
+ <ContentFrame>
248
+ ONE
249
+ <Button onClick={() => setSelected(1)}>Next</Button>
250
+ </ContentFrame>
251
+ <ContentFrame>
252
+ TWO
253
+ <Button onClick={() => setSelected(2)}>Next</Button>
254
+ <Button onClick={() => setSelected(0)}>Back</Button>
255
+ </ContentFrame>
256
+ <ContentFrame>
257
+ THREE
258
+ <Button onClick={() => setSelected(1)}>Back</Button>
259
+ </ContentFrame>
260
+ </Tabs>
261
+ </Card>
262
+ `}
263
+ providerProps={{
264
+ renderAsComponent: true,
265
+ scope: {
266
+ Tabs,
267
+ ContentFrame,
268
+ Tab,
269
+ InputField,
270
+ Flex,
271
+ Controls,
272
+ NationalityButton,
273
+ Label,
274
+ NationalityButtonPrefix,
275
+ Nothing,
276
+ Button,
277
+ Card: CardFrame,
278
+ Icon,
279
+ },
280
+ }}
281
+ />
282
+ )
@@ -0,0 +1,97 @@
1
+ import { Meta } from '@storybook/addon-docs';
2
+ import { TabsExample, TabsWithIconsExample, RenderingContentExample, AdditionalControlsExample, StateManagementExample, CrazyTabsExample } from './components';
3
+
4
+ <Meta title="Components/Tabs"/>
5
+
6
+ # Tabs
7
+
8
+ Tabs are used to organize content on a page into sections.
9
+
10
+ For more details, check out the guidelines on [Figma](https://www.figma.com/file/ue1CurHfZ426o2T2l8Dk64/Edvisor-Product-Language?node-id=734%3A7384)
11
+
12
+ ## How to Use It
13
+
14
+ ```tsx
15
+ import { Tabs, Tab } from '@edvisor/product-language'
16
+
17
+ const [selected, setSelected] = useState(0)
18
+
19
+ <Tabs selected={selected} onChange={setSelected}>
20
+ <Tabs.TabList>
21
+ <Tab>One</Tab>
22
+ <Tab>Two</Tab>
23
+ </Tabs.TabList>
24
+
25
+ <Tabs.Content>
26
+ One
27
+ </Tabs.Content>
28
+ <Tabs.Content>
29
+ Two
30
+ </Tabs.Content>
31
+ </Tabs>
32
+ ```
33
+
34
+ ### Rendering Content
35
+
36
+ Put whatever you want in the `Content` part of the `Tabs` layout, or style the `Content` slot directly.
37
+
38
+ ```tsx
39
+ // Add padding to the content slot
40
+ const ContentFrame = styled(Tabs.Content)`
41
+ padding: ${Padding.l};
42
+ `
43
+ ```
44
+
45
+ <RenderingContentExample />
46
+
47
+ ### Tabs with Icons
48
+
49
+ Add an icon of other simple components to the left of the `Tab` label.
50
+
51
+ <TabsWithIconsExample />
52
+
53
+ ### Tabs with additional layout
54
+
55
+ The `Tabs.TabList` slot will render all of its children. Only `Tab` children will be used to control the tabs.
56
+
57
+ <AdditionalControlsExample />
58
+
59
+ Use this to implement additional controls and configuration shared by the tabs.
60
+
61
+ <TabsExample />
62
+
63
+ ### Content with additional layout
64
+
65
+ The Tabs component will render any and all children in the order they are given. You can add children between the tabs and content, or you can put the tabs on the bottom.
66
+
67
+ <CrazyTabsExample />
68
+
69
+ ### Managing State
70
+
71
+ Pass an integer into the `selected` property of `Tabs` to manage its state.
72
+
73
+ <StateManagementExample />
74
+
75
+ ## API
76
+
77
+ ### `Tabs`
78
+
79
+ | Prop | Type | Description |
80
+ | ---------- | ---------------------------- | ------------------------------------------------------- |
81
+ | `selected` | `number` | Determines which tab is selected |
82
+ | `onChange` | `(selected: number) => void` | Announces when the currently selected tab should change |
83
+
84
+ ### `Tab`
85
+
86
+ Extends `HTMLAttributes<HTMLDivElement>`
87
+
88
+ | Prop | Type | Description |
89
+ | ---------- | ------------ | ------------------------------------------- |
90
+ | `selected` | `boolean?` | Whether this tab is selected |
91
+ | `Prefix` | `Component?` | A component to render in front of the label |
92
+
93
+ ## Changelog
94
+
95
+ ### [0.0.1]
96
+ - add primary tabs
97
+ - currently we can control the tabs with the "tab" key, but later we should implement the UX described here: https://www.w3.org/WAI/ARIA/apg/example-index/tabs/tabs-automatic