@redocly/theme 0.1.1 → 0.1.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 (203) hide show
  1. package/Button/Button.d.ts +17 -0
  2. package/Button/Button.js +34 -0
  3. package/Button/index.d.ts +1 -0
  4. package/Button/index.js +1 -0
  5. package/CodeBlock/CodeBlock.d.ts +1 -0
  6. package/CodeBlock/CodeBlock.js +7 -0
  7. package/CodeBlock/index.d.ts +1 -0
  8. package/CodeBlock/index.js +1 -0
  9. package/CopyButton/CopyButton.d.ts +6 -0
  10. package/CopyButton/CopyButton.js +69 -0
  11. package/CopyButton/CopyButtonWrapper.d.ts +9 -0
  12. package/CopyButton/CopyButtonWrapper.js +37 -0
  13. package/CopyButton/index.d.ts +2 -0
  14. package/CopyButton/index.js +2 -0
  15. package/Headings/Headings.d.ts +3 -0
  16. package/Headings/Headings.js +10 -0
  17. package/Headings/index.d.ts +1 -0
  18. package/Headings/index.js +1 -0
  19. package/JsonViewer/JsonViewer.d.ts +10 -0
  20. package/JsonViewer/JsonViewer.js +92 -0
  21. package/JsonViewer/index.d.ts +1 -0
  22. package/JsonViewer/index.js +1 -0
  23. package/JsonViewer/styled.d.ts +1 -0
  24. package/JsonViewer/styled.js +7 -0
  25. package/Logo/Logo.d.ts +10 -0
  26. package/Logo/Logo.js +25 -0
  27. package/Navbar/Navbar.d.ts +9 -0
  28. package/Navbar/Navbar.js +23 -0
  29. package/Navbar/NavbarItem.d.ts +40 -0
  30. package/Navbar/NavbarItem.js +43 -0
  31. package/Navbar/NavbarMenu.d.ts +4 -0
  32. package/Navbar/NavbarMenu.js +29 -0
  33. package/Panel/CodePanel.d.ts +1 -0
  34. package/Panel/CodePanel.js +13 -0
  35. package/Panel/ContentPanel.d.ts +1 -0
  36. package/Panel/ContentPanel.js +12 -0
  37. package/Panel/DarkHeader.d.ts +1 -0
  38. package/Panel/DarkHeader.js +7 -0
  39. package/Panel/Panel.d.ts +2 -0
  40. package/Panel/Panel.js +10 -0
  41. package/Panel/PanelBody.d.ts +6 -0
  42. package/Panel/PanelBody.js +15 -0
  43. package/Panel/PanelComponent.d.ts +10 -0
  44. package/Panel/PanelComponent.js +40 -0
  45. package/Panel/PanelHeader.d.ts +7 -0
  46. package/Panel/PanelHeader.js +16 -0
  47. package/Panel/PanelHeaderTitle.d.ts +1 -0
  48. package/Panel/PanelHeaderTitle.js +7 -0
  49. package/Panel/index.d.ts +7 -0
  50. package/Panel/index.js +7 -0
  51. package/SamplesPanelControls/SamplesPanelControls.d.ts +4 -0
  52. package/SamplesPanelControls/SamplesPanelControls.js +17 -0
  53. package/SamplesPanelControls/index.d.ts +1 -0
  54. package/SamplesPanelControls/index.js +1 -0
  55. package/SidebarLogo/SidebarLogo.d.ts +9 -0
  56. package/SidebarLogo/SidebarLogo.js +29 -0
  57. package/SidebarLogo/index.d.ts +1 -0
  58. package/SidebarLogo/index.js +1 -0
  59. package/SourceCode/SourceCode.d.ts +24 -0
  60. package/SourceCode/SourceCode.js +31 -0
  61. package/SourceCode/index.d.ts +1 -0
  62. package/SourceCode/index.js +1 -0
  63. package/Tooltip/Tooltip.d.ts +12 -0
  64. package/Tooltip/Tooltip.js +57 -0
  65. package/Tooltip/index.d.ts +1 -0
  66. package/Tooltip/index.js +1 -0
  67. package/globalStyle.d.ts +1 -0
  68. package/globalStyle.js +7 -0
  69. package/hooks/index.d.ts +3 -0
  70. package/hooks/index.js +3 -0
  71. package/hooks/useControl.d.ts +6 -0
  72. package/hooks/useControl.js +12 -0
  73. package/hooks/useMount.d.ts +1 -0
  74. package/hooks/useMount.js +7 -0
  75. package/hooks/useUnmount.d.ts +1 -0
  76. package/hooks/useUnmount.js +9 -0
  77. package/icons/ShelfIcon/ShelfIcon.d.ts +10 -0
  78. package/icons/ShelfIcon/ShelfIcon.js +33 -0
  79. package/icons/ShelfIcon/index.d.ts +2 -0
  80. package/icons/ShelfIcon/index.js +1 -0
  81. package/icons/index.d.ts +1 -0
  82. package/icons/index.js +1 -0
  83. package/index.d.ts +14 -0
  84. package/mocks/Link.d.ts +2 -0
  85. package/mocks/Link.js +17 -0
  86. package/mocks/utils.d.ts +1 -0
  87. package/mocks/utils.js +3 -0
  88. package/package.json +2 -78
  89. package/src/Button/Button.stories.tsx +74 -0
  90. package/src/Button/Button.tsx +122 -0
  91. package/src/Button/__tests__/Button.test.tsx +42 -0
  92. package/src/Button/__tests__/__snapshots__/Button.test.tsx.snap +274 -0
  93. package/src/Button/index.ts +1 -0
  94. package/src/CodeBlock/CodeBlock.ts +125 -0
  95. package/src/CodeBlock/__tests__/CodeBlock.test.tsx +12 -0
  96. package/src/CodeBlock/__tests__/__snapshots__/CodeBlock.test.tsx.snap +140 -0
  97. package/src/CodeBlock/index.ts +1 -0
  98. package/src/CopyButton/CopyButton.stories.tsx +18 -0
  99. package/src/CopyButton/CopyButton.tsx +26 -0
  100. package/src/CopyButton/CopyButtonWrapper.tsx +52 -0
  101. package/src/CopyButton/__tests__/CopyButton.test.tsx +35 -0
  102. package/src/CopyButton/__tests__/CopyButtonWrapper.test.tsx +16 -0
  103. package/src/CopyButton/__tests__/__snapshots__/CopyButton.test.tsx.snap +55 -0
  104. package/src/CopyButton/__tests__/__snapshots__/CopyButtonWrapper.test.tsx.snap +46 -0
  105. package/src/CopyButton/index.ts +2 -0
  106. package/src/Headings/Headings.stories.tsx +36 -0
  107. package/src/Headings/Headings.ts +23 -0
  108. package/src/Headings/__tests__/Headings.test.tsx +24 -0
  109. package/src/Headings/__tests__/__snapshots__/Headings.test.tsx.snap +57 -0
  110. package/src/Headings/index.ts +1 -0
  111. package/src/Introduction.stories.mdx +7 -0
  112. package/src/JsonViewer/JsonViewer.stories.tsx +57 -0
  113. package/src/JsonViewer/JsonViewer.tsx +130 -0
  114. package/src/JsonViewer/__tests__/JsonViewer.test.tsx +82 -0
  115. package/src/JsonViewer/__tests__/__snapshots__/JsonViewer.test.tsx.snap +2728 -0
  116. package/src/JsonViewer/index.ts +1 -0
  117. package/src/JsonViewer/styled.ts +103 -0
  118. package/src/Logo/Logo.tsx +23 -0
  119. package/src/Navbar/Navbar.stories.tsx +38 -0
  120. package/src/Navbar/Navbar.tsx +60 -0
  121. package/src/Navbar/NavbarItem.tsx +90 -0
  122. package/src/Navbar/NavbarMenu.tsx +29 -0
  123. package/src/Panel/CodePanel.stories.tsx +27 -0
  124. package/src/Panel/CodePanel.ts +31 -0
  125. package/src/Panel/ContentPanel.stories.tsx +27 -0
  126. package/src/Panel/ContentPanel.ts +43 -0
  127. package/src/Panel/DarkHeader.ts +8 -0
  128. package/src/Panel/Panel.stories.tsx +58 -0
  129. package/src/Panel/Panel.ts +18 -0
  130. package/src/Panel/PanelBody.ts +30 -0
  131. package/src/Panel/PanelComponent.tsx +73 -0
  132. package/src/Panel/PanelHeader.ts +25 -0
  133. package/src/Panel/PanelHeaderTitle.ts +11 -0
  134. package/src/Panel/__tests__/CodePanel.test.tsx +26 -0
  135. package/src/Panel/__tests__/ContentPanel.test.tsx +26 -0
  136. package/src/Panel/__tests__/Panel.test.tsx +54 -0
  137. package/src/Panel/__tests__/__snapshots__/CodePanel.test.tsx.snap +258 -0
  138. package/src/Panel/__tests__/__snapshots__/ContentPanel.test.tsx.snap +278 -0
  139. package/src/Panel/__tests__/__snapshots__/Panel.test.tsx.snap +398 -0
  140. package/src/Panel/index.ts +7 -0
  141. package/src/SamplesPanelControls/SamplesControlButton.stories.tsx +18 -0
  142. package/src/SamplesPanelControls/SamplesPanelControls.ts +70 -0
  143. package/src/SamplesPanelControls/__tests__/SamplesPanelControls.test.tsx +36 -0
  144. package/src/SamplesPanelControls/__tests__/__snapshots__/SamplesPanelControls.test.tsx.snap +228 -0
  145. package/src/SamplesPanelControls/index.ts +1 -0
  146. package/src/SidebarLogo/SidebarLogo.stories.tsx +21 -0
  147. package/src/SidebarLogo/SidebarLogo.tsx +47 -0
  148. package/src/SidebarLogo/__tests__/SidebarLogo.test.tsx +32 -0
  149. package/src/SidebarLogo/__tests__/__snapshots__/SidebarLogo.test.tsx.snap +62 -0
  150. package/src/SidebarLogo/index.ts +1 -0
  151. package/src/SourceCode/SourceCode.stories.tsx +29 -0
  152. package/src/SourceCode/SourceCode.tsx +67 -0
  153. package/src/SourceCode/__tests__/SourceCode.test.tsx +47 -0
  154. package/src/SourceCode/__tests__/__snapshots__/SourceCode.test.tsx.snap +786 -0
  155. package/src/SourceCode/index.ts +1 -0
  156. package/src/Tooltip/Tooltip.stories.tsx +27 -0
  157. package/src/Tooltip/Tooltip.tsx +171 -0
  158. package/src/Tooltip/__tests__/Tooltip.test.tsx +41 -0
  159. package/src/Tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap +83 -0
  160. package/src/Tooltip/index.ts +1 -0
  161. package/src/globalStyle.ts +512 -0
  162. package/src/hooks/index.ts +3 -0
  163. package/src/hooks/useControl.ts +20 -0
  164. package/src/hooks/useMount.ts +8 -0
  165. package/src/hooks/useUnmount.ts +10 -0
  166. package/src/icons/ShelfIcon/ShelfIcon.stories.tsx +36 -0
  167. package/src/icons/ShelfIcon/ShelfIcon.tsx +45 -0
  168. package/src/icons/ShelfIcon/__tests__/ShelfIcon.test.tsx +54 -0
  169. package/src/icons/ShelfIcon/__tests__/__snapshots__/ShelfIcon.test.tsx.snap +235 -0
  170. package/src/icons/ShelfIcon/index.ts +2 -0
  171. package/src/icons/index.ts +1 -0
  172. package/src/index.ts +14 -0
  173. package/src/mocks/Link.tsx +7 -0
  174. package/src/mocks/utils.ts +3 -0
  175. package/src/utils/ClipboardService.ts +92 -0
  176. package/src/utils/__tests__/ClipboardService.test.ts +24 -0
  177. package/src/utils/__tests__/__snapshots__/highlight.test.ts.snap +5 -0
  178. package/src/utils/__tests__/__snapshots__/jsonToHtml.test.ts.snap +5 -0
  179. package/src/utils/__tests__/css-variables.test.ts +20 -0
  180. package/src/utils/__tests__/highlight.test.ts +51 -0
  181. package/src/utils/__tests__/jsonToHtml.test.ts +40 -0
  182. package/src/utils/__tests__/media-css.test.ts +20 -0
  183. package/src/utils/__tests__/theme-helpers.test.ts +25 -0
  184. package/src/utils/css-variables.ts +2 -0
  185. package/src/utils/highlight.ts +81 -0
  186. package/src/utils/index.ts +6 -0
  187. package/src/utils/jsonToHtml.ts +122 -0
  188. package/src/utils/media-css.ts +16 -0
  189. package/src/utils/theme-helpers.ts +34 -0
  190. package/utils/ClipboardService.d.ts +8 -0
  191. package/utils/ClipboardService.js +83 -0
  192. package/utils/css-variables.d.ts +1 -0
  193. package/utils/css-variables.js +4 -0
  194. package/utils/highlight.d.ts +32 -0
  195. package/utils/highlight.js +65 -0
  196. package/utils/index.d.ts +6 -0
  197. package/utils/index.js +6 -0
  198. package/utils/jsonToHtml.d.ts +1 -0
  199. package/utils/jsonToHtml.js +116 -0
  200. package/utils/media-css.d.ts +12 -0
  201. package/utils/media-css.js +9 -0
  202. package/utils/theme-helpers.d.ts +3 -0
  203. package/utils/theme-helpers.js +27 -0
@@ -0,0 +1 @@
1
+ export * from './JsonViewer';
@@ -0,0 +1,103 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const jsonStyles = css`
4
+ .redoc-json code > .collapser {
5
+ display: none;
6
+ pointer-events: none;
7
+ }
8
+
9
+ contain: content;
10
+ overflow-x: auto;
11
+ padding: 10px;
12
+ border-radius: var(--global-border-radius);
13
+ background-color: var(--samples-panel-controls-background-color);
14
+ color: var(--color-content-inverse);
15
+ font-size: var(--code-font-size);
16
+ font-family: var(--code-font-family);
17
+ white-space: var(--code-wrap, pre);
18
+
19
+ .callback-function {
20
+ color: gray;
21
+ }
22
+
23
+ .collapser:after {
24
+ content: '-';
25
+ cursor: pointer;
26
+ }
27
+
28
+ .collapsed > .collapser:after {
29
+ content: '+';
30
+ cursor: pointer;
31
+ }
32
+
33
+ .ellipsis:after {
34
+ content: ' … ';
35
+ }
36
+
37
+ .collapsible {
38
+ margin-left: 2ch;
39
+ }
40
+
41
+ .hoverable {
42
+ padding: 1px 2px;
43
+ }
44
+
45
+ .hovered {
46
+ background-color: rgba(235, 238, 249, 1);
47
+ }
48
+
49
+ .collapser {
50
+ background-color: transparent;
51
+ border: 0;
52
+ color: #fff;
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 15px;
57
+ height: 15px;
58
+ position: absolute;
59
+ top: 4px;
60
+ left: -1.5em;
61
+ cursor: default;
62
+ user-select: none;
63
+ -webkit-user-select: none;
64
+ padding: 2px;
65
+ font-family: var(--code-font-family);
66
+ font-size: var(--code-font-size);
67
+ &:focus {
68
+ outline: #fff dotted 1px;
69
+ }
70
+ }
71
+
72
+ ul {
73
+ list-style-type: none;
74
+ padding: 0;
75
+ margin: 0 0 0 26px;
76
+ }
77
+
78
+ li {
79
+ position: relative;
80
+ display: block;
81
+ }
82
+
83
+ .hoverable {
84
+ display: inline-block;
85
+ }
86
+
87
+ .selected {
88
+ outline-width: 1px;
89
+ outline-style: dotted;
90
+ }
91
+
92
+ .collapsed > .collapsible {
93
+ display: none;
94
+ }
95
+
96
+ .ellipsis {
97
+ display: none;
98
+ }
99
+
100
+ .collapsed > .ellipsis {
101
+ display: inherit;
102
+ }
103
+ `;
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { Link } from '@portal/Link';
5
+
6
+ export interface LogoConfig {
7
+ image?: string;
8
+ altText?: string;
9
+ link?: string;
10
+ favicon?: string;
11
+ }
12
+
13
+ export function Logo({ logo }: { logo: LogoConfig }): JSX.Element | null {
14
+ const img = <NavLogo src={logo.image} alt={logo.altText} data-component-name="Logo/Logo" />;
15
+ return logo?.image ? logo.link ? <Link to={logo.link}>{img}</Link> : img : null;
16
+ }
17
+
18
+ const NavLogo = styled.img`
19
+ max-width: var(--logo-max-width);
20
+ max-height: var(--logo-max-height);
21
+ height: var(--logo-height);
22
+ margin: var(--logo-margin);
23
+ `;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+
4
+ import Navbar from './Navbar';
5
+ import NavbarMenu from './NavbarMenu';
6
+
7
+ import { Logo } from '@theme/Logo/Logo';
8
+
9
+ export default {
10
+ title: 'Navbar',
11
+ component: Navbar,
12
+ // argTypes: {
13
+ // size: {
14
+ // control: 'radio',
15
+ // options: ['small', 'medium', 'large', 'xlarge'],
16
+ // },
17
+ // color: {
18
+ // control: 'radio',
19
+ // options: ['primary', 'secondary', 'default'],
20
+ // },
21
+ // },
22
+ } as ComponentMeta<typeof Navbar>;
23
+
24
+ const Template: ComponentStory<typeof Navbar> = (args) => <Navbar {...args}>Click</Navbar>;
25
+
26
+ export const Main = Template.bind({});
27
+ Main.args = {
28
+ logo: <Logo logo={{ link: '/test/', image: 'https://picsum.photos/400/100' }} />,
29
+ menu: (
30
+ <NavbarMenu
31
+ menuItems={[
32
+ { type: 'link', link: 'https://google.com', label: 'Google' },
33
+ { type: 'link', link: '/test/', label: 'Test' },
34
+ ]}
35
+ />
36
+ ),
37
+ search: <span> search </span>,
38
+ };
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ // import { mediaQueries } from '@portal/media-css';
5
+
6
+ interface NavbarProps {
7
+ menu: React.ReactNode;
8
+ logo: React.ReactNode;
9
+ search: React.ReactNode;
10
+ }
11
+
12
+ export default function Navbar({ menu, logo, search }: NavbarProps): JSX.Element {
13
+ return (
14
+ <NavbarContainer data-component-name="Navbar/Navbar">
15
+ {logo}
16
+ {menu}
17
+ {search}
18
+ </NavbarContainer>
19
+ );
20
+ }
21
+
22
+ export const NavbarContainer = styled.nav`
23
+ height: var(--navbar-height);
24
+ box-sizing: border-box;
25
+ display: flex;
26
+ color: var(--navbar-color-text);
27
+ align-items: center;
28
+ justify-content: space-between;
29
+ flex-shrink: 0;
30
+
31
+ font-size: 0.875rem;
32
+ position: sticky;
33
+ top: 0;
34
+ z-index: 200;
35
+ padding: 1.25rem;
36
+ padding: 10px var(--sidebar-margin-left);
37
+ background: var(--navbar-color-background);
38
+ font-family: var(--font-family-h);
39
+ `;
40
+
41
+ // ${mediaQueries.medium} {
42
+ // padding: 10px var(--sidebar-margin-left);
43
+ // }
44
+
45
+ // ${mediaQueries.medium} {
46
+ // font-size: 1rem;
47
+ // }
48
+
49
+ // ${mediaQueries.print} {
50
+ // background: transparent;
51
+ // display: none;
52
+
53
+ // > :not(a, img) {
54
+ // display: none !important;
55
+ // }
56
+ // img {
57
+ // padding: 0;
58
+ // margin: 0;
59
+ // }
60
+ // }
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { useLocation } from 'react-router-dom';
4
+
5
+ import { Link } from '@portal/Link';
6
+ import { withPathPrefix } from '@portal/utils';
7
+
8
+ export enum MenuStyle {
9
+ Drilldown = 'drilldown',
10
+ }
11
+
12
+ export type ResolvedNavLinkItem = {
13
+ type: 'link';
14
+ link: string;
15
+ label: string;
16
+ items?: ResolvedNavItem[];
17
+ external?: boolean;
18
+ version?: string;
19
+ default?: string;
20
+ httpVerb?: string; // TODO: make a separate type of item
21
+ separatorLine?: boolean;
22
+ active?: boolean;
23
+ };
24
+
25
+ export type ResolvedNavGroupItem = {
26
+ type: 'group';
27
+ link?: string;
28
+ label: string;
29
+ items: ResolvedNavItem[];
30
+ version?: string;
31
+ default?: string;
32
+ menuStyle?: MenuStyle;
33
+ separatorLine?: boolean;
34
+ active?: boolean;
35
+ };
36
+
37
+ export type ResolvedNavItem =
38
+ | ResolvedNavLinkItem
39
+ | ResolvedNavGroupItem
40
+ | {
41
+ type: 'separator';
42
+ label?: string;
43
+ separatorLine?: boolean;
44
+ }
45
+ | {
46
+ type: 'error';
47
+ label: string;
48
+ };
49
+
50
+ interface NavbarItemProps {
51
+ navItem: ResolvedNavLinkItem;
52
+ }
53
+
54
+ export default function NavbarItem({ navItem }: NavbarItemProps): JSX.Element {
55
+ const { pathname } = useLocation();
56
+ const isActive = pathname === withPathPrefix(navItem.link);
57
+
58
+ return (
59
+ <NavMenuItem active={isActive} data-component-name="Navbar/NavbarItem">
60
+ <NavLink to={navItem.link} active={isActive}>
61
+ <NavLabel>{navItem.label}</NavLabel>
62
+ </NavLink>
63
+ </NavMenuItem>
64
+ );
65
+ }
66
+
67
+ const NavMenuItem = styled.li<{ active?: boolean }>`
68
+ display: inline-block;
69
+ padding: 20px calc(var(--sidebar-padding-horizontal) * 2);
70
+ text-align: center;
71
+ line-height: 1;
72
+ font-size: var(--navbar-item-font-size);
73
+ margin-left: var(--navbar-item-margin-horizontal);
74
+ margin-right: var(--navbar-item-margin-horizontal);
75
+ border-radius: var(--navbar-item-border-radius);
76
+ font-weight: var(--navbar-item-font-weight);
77
+ background: ${({ active }) => (active ? 'var(--navbar-item-active-background-color)' : 'none')};
78
+ `;
79
+
80
+ const NavLink = styled(Link)`
81
+ color: ${({ active }) =>
82
+ active ? 'var(--navbar-item-active-text-color)' : 'var(--navbar-color-text)'};
83
+ text-decoration: ${({ active }) =>
84
+ active ? 'var(--navbar-item-active-text-decoration)' : 'none'};
85
+ `;
86
+
87
+ const NavLabel = styled.span`
88
+ cursor: pointer;
89
+ vertical-align: middle;
90
+ `;
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import NavbarItem from '@theme/Navbar/NavbarItem';
5
+
6
+ export default function NavbarMenu({ menuItems }: { menuItems: any[] }): JSX.Element | null {
7
+ if (!menuItems || !menuItems.length) {
8
+ return null;
9
+ }
10
+
11
+ return (
12
+ <NavItemsContainer data-component-name="Navbar/NavbarMenu">
13
+ {menuItems.map((navItem, index) => {
14
+ return <NavbarItem key={index} data-cy={navItem.label} navItem={navItem} />;
15
+ })}
16
+ </NavItemsContainer>
17
+ );
18
+ }
19
+
20
+ const NavItemsContainer = styled.ul`
21
+ list-style: none;
22
+ margin: 0;
23
+ padding: 0;
24
+ display: block;
25
+ `;
26
+
27
+ // ${mediaQueries.small} {
28
+ // display: block;
29
+ // }
@@ -0,0 +1,27 @@
1
+ import React, { JSXElementConstructor } from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+
4
+ import { CodePanel } from './CodePanel';
5
+ import { PanelComponentProps } from './PanelComponent';
6
+
7
+ export default {
8
+ title: 'Components/Panels/CodePanel',
9
+ component: CodePanel,
10
+ } as ComponentMeta<typeof CodePanel>;
11
+
12
+ // TODO: find the way to avoid using JSXElementConstructor<PanelComponentProps> and fix types for ComponentStory<typeof CodePanel>
13
+ const Template: ComponentStory<JSXElementConstructor<PanelComponentProps>> = (args) => (
14
+ <CodePanel {...args}>Code Panel body</CodePanel>
15
+ );
16
+
17
+ export const Collapsed = Template.bind({});
18
+ Collapsed.args = {
19
+ header: 'Code Panel header',
20
+ expanded: false,
21
+ };
22
+
23
+ export const Expanded = Template.bind({});
24
+ Expanded.args = {
25
+ header: 'Code Panel header',
26
+ expanded: true,
27
+ };
@@ -0,0 +1,31 @@
1
+ import styled from 'styled-components';
2
+
3
+ import { ShelfIcon } from '../icons/ShelfIcon';
4
+
5
+ import { Panel } from './Panel';
6
+ import { PanelHeader } from './PanelHeader';
7
+ import { DarkHeader } from './DarkHeader';
8
+ import { PanelBody } from './PanelBody';
9
+ import { PanelHeaderTitle } from './PanelHeaderTitle';
10
+
11
+ export const CodePanel = styled(Panel)`
12
+ > ${PanelHeader} {
13
+ ${DarkHeader};
14
+ min-height: 50px;
15
+ ${ShelfIcon} {
16
+ fill: var(--color-content-inverse);
17
+ position: relative;
18
+ }
19
+ ${PanelHeaderTitle} {
20
+ color: var(--color-content-inverse);
21
+ }
22
+ }
23
+
24
+ && {
25
+ ${PanelBody} {
26
+ padding: 10px 20px 20px;
27
+ background-color: var(--samples-panel-background-color);
28
+ color: var(--color-content-inverse);
29
+ }
30
+ }
31
+ `;
@@ -0,0 +1,27 @@
1
+ import React, { JSXElementConstructor } from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+
4
+ import { ContentPanel } from './ContentPanel';
5
+ import { PanelComponentProps } from './PanelComponent';
6
+
7
+ export default {
8
+ title: 'Components/Panels/ContentPanel',
9
+ component: ContentPanel,
10
+ } as ComponentMeta<typeof ContentPanel>;
11
+
12
+ // TODO: find the way to avoid using JSXElementConstructor<PanelComponentProps> and fix types for ComponentStory<typeof CodePanel>
13
+ const Template: ComponentStory<JSXElementConstructor<PanelComponentProps>> = (args) => (
14
+ <ContentPanel {...args}>Content Panel Body</ContentPanel>
15
+ );
16
+
17
+ export const Collapsed = Template.bind({});
18
+ Collapsed.args = {
19
+ header: 'Content Panel Header',
20
+ expanded: false,
21
+ };
22
+
23
+ export const Expanded = Template.bind({});
24
+ Expanded.args = {
25
+ header: 'Content Panel Header',
26
+ expanded: true,
27
+ };
@@ -0,0 +1,43 @@
1
+ import styled from 'styled-components';
2
+
3
+ import { ShelfIcon } from '../icons/ShelfIcon';
4
+
5
+ import { PanelHeaderTitle } from './PanelHeaderTitle';
6
+ import { Panel } from './Panel';
7
+ import { PanelBody } from './PanelBody';
8
+ import { PanelHeader } from './PanelHeader';
9
+
10
+ export const ContentPanel = styled(Panel)`
11
+ border: 1px solid var(--global-border-color);
12
+
13
+ font-size: var(--font-size-base);
14
+ font-weight: var(--font-weight-regular);
15
+ line-height: var(--line-height-base);
16
+
17
+ &:not(:last-child) {
18
+ margin-bottom: 20px;
19
+ }
20
+
21
+ > ${PanelHeader} {
22
+ padding: calc(var(--spacing-unit) * 4);
23
+ font-size: 18px;
24
+ font-weight: var(--font-weight-bold);
25
+ background-color: var(--panels-background-color);
26
+
27
+ ${PanelHeaderTitle} {
28
+ color: var(--color-content);
29
+ }
30
+
31
+ ${ShelfIcon} {
32
+ fill: var(--color-content);
33
+ }
34
+ }
35
+
36
+ > ${PanelBody} {
37
+ padding: calc(var(--spacing-unit) * 4);
38
+ }
39
+
40
+ > ${PanelHeader} + ${PanelBody} {
41
+ padding-top: 1px; /* to prevent border overflow */
42
+ }
43
+ `;
@@ -0,0 +1,8 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const DarkHeader = css`
4
+ padding: 10px 20px;
5
+ line-height: 30px;
6
+ z-index: 0;
7
+ background-color: var(--samples-panel-controls-background-color);
8
+ `;
@@ -0,0 +1,58 @@
1
+ import React, { JSXElementConstructor } from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+ import { within, userEvent } from '@storybook/testing-library';
4
+
5
+ import { Panel } from './Panel';
6
+ import { PanelHeaderProps } from './PanelHeader';
7
+ import { PanelComponentProps } from './PanelComponent';
8
+
9
+ export default {
10
+ title: 'Components/Panels/Panel (base)',
11
+ component: Panel,
12
+ } as ComponentMeta<typeof Panel>;
13
+
14
+ const Template: ComponentStory<JSXElementConstructor<PanelComponentProps>> = (args) => (
15
+ <Panel {...args}>Panel body</Panel>
16
+ );
17
+
18
+ export const Default = Template.bind({});
19
+ Default.args = {
20
+ header: 'Panel header',
21
+ };
22
+
23
+ export const Collapsed = Template.bind({});
24
+ Collapsed.args = {
25
+ header: 'Panel header (click me)',
26
+ expanded: false,
27
+ };
28
+
29
+ export const Expanded = Template.bind({});
30
+ Expanded.args = {
31
+ header: 'Panel header (click me)',
32
+ expanded: true,
33
+ };
34
+
35
+ export const HeaderAsFunction = Template.bind({});
36
+ HeaderAsFunction.args = {
37
+ header: (props: PanelHeaderProps) => <div>Custom Header component: {JSON.stringify(props)}</div>,
38
+ };
39
+
40
+ export const HeaderAsComponent = Template.bind({});
41
+ HeaderAsComponent.args = {
42
+ header: <i>Header component</i>,
43
+ };
44
+
45
+ export const WithoutHeader = Template.bind({});
46
+ WithoutHeader.args = {};
47
+
48
+ // TODO: change to normal name after fixing problem with stories order!
49
+ export const WithDemoAnimation = Template.bind({});
50
+ WithDemoAnimation.args = {
51
+ expanded: false,
52
+ header: 'Panel header',
53
+ };
54
+ WithDemoAnimation.play = async ({ canvasElement }) => {
55
+ const canvas = within(canvasElement);
56
+
57
+ await userEvent.click(canvas.getByTestId('panel-header'));
58
+ };
@@ -0,0 +1,18 @@
1
+ import styled from 'styled-components';
2
+
3
+ import { PanelBody } from './PanelBody';
4
+ import { PanelComponent } from './PanelComponent';
5
+ import { PanelHeader } from './PanelHeader';
6
+
7
+ export const Panel = styled(PanelComponent)`
8
+ border-radius: var(--panels-border-radius);
9
+
10
+ ${PanelHeader} + ${PanelBody} {
11
+ border-top-left-radius: 0;
12
+ border-top-right-radius: 0;
13
+ }
14
+
15
+ &:not(:last-child) {
16
+ margin-bottom: 10px;
17
+ }
18
+ `;
@@ -0,0 +1,30 @@
1
+ import styled, { keyframes, css } from 'styled-components';
2
+
3
+ const showPanel = keyframes`
4
+ 0% {
5
+ transform: translateY(-10px);
6
+ }
7
+ 100% {
8
+ transform: translateY(0);
9
+ }
10
+ `;
11
+
12
+ const showPanelAnimation = css`
13
+ animation: ${showPanel} 0.2s;
14
+ `;
15
+
16
+ interface PanelBodyProps {
17
+ animate?: boolean;
18
+ hidden?: boolean;
19
+ }
20
+
21
+ export const PanelBody = styled.div<PanelBodyProps>`
22
+ ${({ animate }) => animate && showPanelAnimation};
23
+ ${({ hidden }) => hidden && 'visibility: hidden'};
24
+
25
+ border-top-left-radius: var(--panels-border-radius);
26
+ border-top-right-radius: var(--panels-border-radius);
27
+ border-bottom-right-radius: var(--panels-border-radius);
28
+ border-bottom-left-radius: var(--panels-border-radius);
29
+ background-color: var(--panels-background-color);
30
+ `;
@@ -0,0 +1,73 @@
1
+ import React, {
2
+ BaseSyntheticEvent,
3
+ PropsWithChildren,
4
+ ReactNode,
5
+ useEffect,
6
+ useState,
7
+ } from 'react';
8
+ import styled from 'styled-components';
9
+
10
+ import { ShelfIcon } from '../icons';
11
+
12
+ import { PanelBody } from './PanelBody';
13
+ import { PanelHeader, PanelHeaderProps } from './PanelHeader';
14
+ import { PanelHeaderTitle } from './PanelHeaderTitle';
15
+
16
+ export interface PanelComponentProps {
17
+ expanded?: boolean;
18
+ className?: string;
19
+ header?: ReactNode | ((props: PanelHeaderProps) => ReactNode);
20
+ onToggle?: (expanded: boolean) => void;
21
+ }
22
+
23
+ export function PanelComponent({
24
+ expanded = true,
25
+ header,
26
+ className,
27
+ children,
28
+ onToggle,
29
+ }: PropsWithChildren<PanelComponentProps>): JSX.Element {
30
+ const [isExpanded, setExpanded] = useState(expanded);
31
+ const [animate, setAnimate] = useState(false);
32
+
33
+ const toggle = ({ target }: BaseSyntheticEvent): void => {
34
+ if (target instanceof HTMLAnchorElement) return;
35
+ setAnimate(true);
36
+ setExpanded(!isExpanded);
37
+ onToggle?.(!isExpanded);
38
+ };
39
+
40
+ useEffect(() => setExpanded(expanded), [expanded]);
41
+
42
+ return (
43
+ <div
44
+ className={className}
45
+ data-cy={
46
+ typeof header === 'string' ? ('panel-' + header).replace(/ /g, '-').toLowerCase() : null
47
+ }
48
+ >
49
+ {header &&
50
+ (typeof header === 'function' ? (
51
+ header({ expanded: isExpanded, toggle })
52
+ ) : (
53
+ <PanelHeader data-cy="panel-header" onClick={toggle} expanded={isExpanded}>
54
+ <InlineBox>
55
+ <PanelHeaderTitle data-cy="title">{header}</PanelHeaderTitle>
56
+ <ShelfIcon direction={isExpanded ? 'down' : 'right'} />
57
+ </InlineBox>
58
+ </PanelHeader>
59
+ ))}
60
+
61
+ {isExpanded && (
62
+ <PanelBody data-cy="panel-body" hidden={!isExpanded} animate={animate}>
63
+ {children}
64
+ </PanelBody>
65
+ )}
66
+ </div>
67
+ );
68
+ }
69
+
70
+ export const InlineBox = styled.div`
71
+ display: inline-flex;
72
+ align-items: center;
73
+ `;