@redocly/theme 0.9.0-beta.3 → 0.9.0-beta.5

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 (126) hide show
  1. package/lib/Button/Button.d.ts +1 -1
  2. package/lib/Button/Button.js +14 -2
  3. package/lib/Cards/Card.d.ts +1 -0
  4. package/lib/Catalog/Catalog.d.ts +1 -0
  5. package/lib/Catalog/CatalogCard.d.ts +1 -0
  6. package/lib/Catalog/Filter.d.ts +1 -0
  7. package/lib/Catalog/Filter.js +1 -3
  8. package/lib/Catalog/Tags.d.ts +1 -0
  9. package/lib/ColorModeSwitcher/ColorModeSwitcher.d.ts +1 -0
  10. package/lib/CopyButton/CopyButton.d.ts +1 -0
  11. package/lib/EditPageButton/EditPageButton.d.ts +1 -0
  12. package/lib/Feedback/Comment.d.ts +1 -0
  13. package/lib/Feedback/Rating.d.ts +1 -0
  14. package/lib/Feedback/Reasons.d.ts +1 -0
  15. package/lib/Feedback/ReportDialog.d.ts +1 -0
  16. package/lib/Feedback/Sentiment.d.ts +1 -0
  17. package/lib/Feedback/Thumbs.d.ts +1 -0
  18. package/lib/Footer/CustomFooter.d.ts +1 -0
  19. package/lib/Footer/CustomFooterNavItem.d.ts +1 -0
  20. package/lib/Footer/Footer.d.ts +1 -0
  21. package/lib/Footer/FooterColumn.d.ts +1 -0
  22. package/lib/Footer/FooterColumns.d.ts +1 -0
  23. package/lib/Footer/FooterCopyright.d.ts +1 -0
  24. package/lib/LastUpdated/LastUpdated.d.ts +1 -0
  25. package/lib/Markdown/Admonition.d.ts +4 -1
  26. package/lib/Markdown/Admonition.js +2 -2
  27. package/lib/Markdown/CodeSample/CodeSample.d.ts +4 -1
  28. package/lib/Markdown/CodeSample/CodeSample.js +2 -2
  29. package/lib/Markdown/Heading.d.ts +3 -1
  30. package/lib/Markdown/Heading.js +6 -4
  31. package/lib/Markdown/Mermaid.d.ts +4 -1
  32. package/lib/Markdown/Mermaid.js +2 -2
  33. package/lib/Markdown/Tabs/Tab.d.ts +1 -0
  34. package/lib/Navbar/MobileNavbarDropdown.d.ts +1 -0
  35. package/lib/Navbar/MobileNavbarItem.d.ts +1 -0
  36. package/lib/Navbar/MobileNavbarMenuButton.d.ts +1 -0
  37. package/lib/Navbar/NavbarDropdown.d.ts +1 -0
  38. package/lib/Navbar/NavbarItem.d.ts +1 -0
  39. package/lib/Navbar/NavbarMenu.d.ts +1 -0
  40. package/lib/NavbarLogo/NavbarLogo.d.ts +1 -0
  41. package/lib/PageNavigation/NextButton.d.ts +1 -0
  42. package/lib/PageNavigation/PageNavigation.d.ts +1 -0
  43. package/lib/PageNavigation/PreviousButton.d.ts +1 -0
  44. package/lib/Pages/Forbidden.d.ts +1 -0
  45. package/lib/Pages/NotFound.d.ts +1 -0
  46. package/lib/Profile/LoginLink.d.ts +1 -0
  47. package/lib/Profile/Profile.js +1 -1
  48. package/lib/Profile/UserProfile.d.ts +1 -0
  49. package/lib/ReferenceDocs/ClearButton.d.ts +8 -0
  50. package/lib/ReferenceDocs/ClearButton.js +48 -0
  51. package/lib/ReferenceDocs/DevOnboardingTryItSecurity.d.ts +3 -0
  52. package/lib/ReferenceDocs/DevOnboardingTryItSecurity.js +158 -0
  53. package/lib/ReferenceDocs/Dropdown.d.ts +28 -0
  54. package/lib/ReferenceDocs/Dropdown.js +150 -0
  55. package/lib/ReferenceDocs/TryItSecurity.d.ts +7 -2
  56. package/lib/ReferenceDocs/TryItSecurity.js +11 -1
  57. package/lib/ReferenceDocs/index.d.ts +1 -0
  58. package/lib/ReferenceDocs/index.js +18 -0
  59. package/lib/Search/Parameters.d.ts +1 -0
  60. package/lib/Search/Search.d.ts +1 -0
  61. package/lib/Search/SearchItem.d.ts +1 -0
  62. package/lib/Search/ShortcutKey.d.ts +1 -0
  63. package/lib/Search/utils.d.ts +1 -0
  64. package/lib/Sidebar/ApiCallItem.d.ts +1 -0
  65. package/lib/Sidebar/ArrowBack.d.ts +1 -0
  66. package/lib/Sidebar/DrilldownMenuItem.d.ts +1 -0
  67. package/lib/Sidebar/ExternalIcon.d.ts +1 -0
  68. package/lib/Sidebar/FooterWrapper.d.ts +3 -0
  69. package/lib/Sidebar/FooterWrapper.js +15 -0
  70. package/lib/Sidebar/HeaderWrapper.d.ts +3 -0
  71. package/lib/Sidebar/HeaderWrapper.js +15 -0
  72. package/lib/Sidebar/MenuGroup.js +1 -1
  73. package/lib/Sidebar/MenuItem.d.ts +1 -0
  74. package/lib/Sidebar/Separator.d.ts +1 -0
  75. package/lib/Sidebar/SidebarLayout.d.ts +1 -1
  76. package/lib/Sidebar/SidebarLayout.js +5 -42
  77. package/lib/Sidebar/index.d.ts +2 -0
  78. package/lib/Sidebar/index.js +2 -0
  79. package/lib/SidebarLogo/SidebarLogo.d.ts +1 -0
  80. package/lib/SourceCode/SourceCode.d.ts +1 -0
  81. package/lib/TableOfContent/TableOfContent.d.ts +1 -0
  82. package/lib/globalStyle.js +2 -1
  83. package/lib/icons/AlertIcon/AlertIcon.d.ts +1 -0
  84. package/lib/icons/AnchorIcon/AnchorIcon.d.ts +7 -0
  85. package/lib/icons/AnchorIcon/AnchorIcon.js +23 -0
  86. package/lib/icons/AnchorIcon/index.d.ts +2 -0
  87. package/lib/icons/AnchorIcon/index.js +6 -0
  88. package/lib/icons/ArrowIcon/ArrowIcon.d.ts +2 -0
  89. package/lib/icons/ArrowIcon/ArrowIcon.js +1 -0
  90. package/lib/icons/ColorModeIcon/ColorModeIcon.d.ts +1 -0
  91. package/lib/icons/index.d.ts +1 -0
  92. package/lib/icons/index.js +1 -0
  93. package/lib/index.d.ts +2 -0
  94. package/lib/index.js +2 -0
  95. package/lib/mocks/Link.d.ts +1 -0
  96. package/lib/mocks/hooks/index.d.ts +1 -1
  97. package/lib/mocks/hooks/index.js +3 -1
  98. package/lib/mocks/useGlobalData.d.ts +1 -0
  99. package/lib/mocks/useGlobalData.js +9 -0
  100. package/lib/ui/Dropdown.d.ts +1 -0
  101. package/package.json +1 -1
  102. package/src/Button/Button.tsx +22 -5
  103. package/src/Catalog/Filter.tsx +1 -1
  104. package/src/Markdown/Admonition.tsx +13 -1
  105. package/src/Markdown/CodeSample/CodeSample.tsx +15 -2
  106. package/src/Markdown/Heading.tsx +12 -18
  107. package/src/Markdown/Mermaid.tsx +9 -1
  108. package/src/Profile/Profile.tsx +1 -1
  109. package/src/ReferenceDocs/ClearButton.tsx +30 -0
  110. package/src/ReferenceDocs/DevOnboardingTryItSecurity.tsx +161 -0
  111. package/src/ReferenceDocs/Dropdown.tsx +202 -0
  112. package/src/ReferenceDocs/TryItSecurity.tsx +16 -3
  113. package/src/ReferenceDocs/index.ts +1 -0
  114. package/src/Sidebar/FooterWrapper.tsx +9 -0
  115. package/src/Sidebar/HeaderWrapper.tsx +9 -0
  116. package/src/Sidebar/MenuGroup.tsx +4 -1
  117. package/src/Sidebar/SidebarLayout.tsx +2 -46
  118. package/src/Sidebar/index.ts +2 -0
  119. package/src/globalStyle.ts +2 -1
  120. package/src/icons/AnchorIcon/AnchorIcon.tsx +36 -0
  121. package/src/icons/AnchorIcon/index.ts +2 -0
  122. package/src/icons/ArrowIcon/ArrowIcon.tsx +2 -0
  123. package/src/icons/index.ts +1 -0
  124. package/src/index.ts +2 -0
  125. package/src/mocks/hooks/index.ts +2 -0
  126. package/src/mocks/useGlobalData.tsx +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.9.0-beta.3",
3
+ "version": "0.9.0-beta.5",
4
4
  "description": "Shared UI components lib",
5
5
  "author": "team@redocly.com",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -6,7 +6,7 @@ import type { FlattenSimpleInterpolation, Keyframes } from 'styled-components';
6
6
  import { Link } from '@portal/Link';
7
7
 
8
8
  export type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge' | string;
9
- export type ButtonColor = 'primary' | 'secondary' | 'default' | string;
9
+ export type ButtonColor = 'primary' | 'secondary' | 'tertiary' | 'default' | string;
10
10
  export type ButtonVariant = 'outlined' | 'contained';
11
11
 
12
12
  export interface ButtonProps {
@@ -67,10 +67,14 @@ export const baseButtonStyles = css`
67
67
  }
68
68
  `;
69
69
 
70
- const StyledButton = styled.button.attrs(({ color = 'default', extraClass }: ButtonProps) => ({
71
- className: `button-color-${color}${extraClass ? ` ${extraClass}` : ''}`,
72
- 'data-component-name': 'Button/Button',
73
- }))<ButtonProps>`
70
+ const StyledButton = styled.button.attrs(
71
+ ({ color = 'default', extraClass, variant }: ButtonProps) => ({
72
+ className: `button-color-${color}${variant ? ` ${variant}` : ''}${
73
+ extraClass ? ` ${extraClass}` : ''
74
+ }`,
75
+ 'data-component-name': 'Button/Button',
76
+ }),
77
+ )<ButtonProps>`
74
78
  text-decoration: none;
75
79
  text-align: center;
76
80
 
@@ -127,6 +131,19 @@ const StyledButton = styled.button.attrs(({ color = 'default', extraClass }: But
127
131
  animation: ${getBlink()} 1.2s infinite;
128
132
  `}
129
133
 
134
+ ${({ color }) =>
135
+ color === 'tertiary' &&
136
+ css`
137
+ background-color: transparent;
138
+ border: none;
139
+ color: var(--text-color);
140
+
141
+ :hover {
142
+ border: none;
143
+ background: rgba(255, 255, 255, 0.65);
144
+ }
145
+ `}
146
+
130
147
  ${({ disabled }) =>
131
148
  disabled &&
132
149
  css`
@@ -8,7 +8,7 @@ export function Filter({ filter }: { filter: ResolvedFilter }) {
8
8
  if (!filter.parentUsed) return null;
9
9
  return (
10
10
  <FilterGroup key={filter.property + filter.title}>
11
- <FilterTitle>{filter.title} filter</FilterTitle>
11
+ <FilterTitle>{filter.title}</FilterTitle>
12
12
  {filter.type === 'select' ? (
13
13
  <StyledSelect
14
14
  onChange={(e) => filter.selectOption(e.target.value)}
@@ -9,15 +9,27 @@ interface AdmonitionTypeProps {
9
9
 
10
10
  export interface AdmonitionProps extends Partial<AdmonitionTypeProps> {
11
11
  name?: string;
12
+ className?: string;
13
+ 'data-source'?: string;
14
+ 'data-hash'?: string;
12
15
  }
13
16
 
14
17
  export function Admonition({
15
18
  type = 'info',
16
19
  name,
17
20
  children,
21
+ className,
22
+ 'data-source': dataSource,
23
+ 'data-hash': dataHash,
18
24
  }: React.PropsWithChildren<AdmonitionProps>): JSX.Element {
19
25
  return (
20
- <Wrapper type={type} data-component-name="Markdown/Admonition">
26
+ <Wrapper
27
+ type={type}
28
+ className={className}
29
+ data-component-name="Markdown/Admonition"
30
+ data-source={dataSource}
31
+ data-hash={dataHash}
32
+ >
21
33
  <AlertIcon type={type} />
22
34
  {name ? <Heading type={type}>{name}</Heading> : null}
23
35
  <Content>{children}</Content>
@@ -9,9 +9,17 @@ export type CodeSampleProps = {
9
9
  language: string;
10
10
  highlighted: string;
11
11
  rawContent: string;
12
+ 'data-source'?: string;
13
+ 'data-hash'?: string;
12
14
  };
13
15
 
14
- export function CodeSample({ rawContent, highlighted, language }: CodeSampleProps): JSX.Element {
16
+ export function CodeSample({
17
+ rawContent,
18
+ highlighted,
19
+ language,
20
+ 'data-source': dataSource,
21
+ 'data-hash': dataHash,
22
+ }: CodeSampleProps): JSX.Element {
15
23
  const langClassName = language ? `language-${language}` : '';
16
24
  const { codeSnippet: { copy = {}, report = {} } = {} } = useThemeConfig();
17
25
 
@@ -26,7 +34,12 @@ export function CodeSample({ rawContent, highlighted, language }: CodeSampleProp
26
34
  };
27
35
 
28
36
  return (
29
- <Wrapper className="code-sample" data-component-name="Markdown/CodeSample/CodeSample">
37
+ <Wrapper
38
+ className="code-sample"
39
+ data-component-name="Markdown/CodeSample/CodeSample"
40
+ data-source={dataSource}
41
+ data-hash={dataHash}
42
+ >
30
43
  <CodeSampleButtonContainer>
31
44
  {!copy.hide && (
32
45
  <>
@@ -3,36 +3,28 @@ import React, { createElement } from 'react';
3
3
  import type { PropsWithChildren } from 'react';
4
4
 
5
5
  import { concatClassNames } from '@theme/utils';
6
+ import { AnchorIcon } from '@theme/icons';
6
7
 
7
8
  /**
8
9
  * Class name for all MD tags
9
10
  */
10
11
  const mdClassName = 'md';
11
12
 
12
- const SvgIcon = (
13
- <svg
14
- aria-hidden="true"
15
- focusable="false"
16
- height="16"
17
- version="1.1"
18
- viewBox="0 0 16 16"
19
- width="16"
20
- >
21
- <path
22
- fillRule="evenodd"
23
- d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"
24
- ></path>
25
- </svg>
26
- );
27
-
28
13
  export function Heading({
29
14
  level,
30
15
  id,
31
16
  children,
32
- }: PropsWithChildren<{ level: number; id: string }>): JSX.Element {
17
+ 'data-source': dataSource,
18
+ 'data-hash': dataHash,
19
+ }: PropsWithChildren<{
20
+ level: number;
21
+ id: string;
22
+ 'data-source'?: string;
23
+ 'data-hash'?: string;
24
+ }>): JSX.Element {
33
25
  const linkEl = (
34
26
  <a href={`#${id}`} className={concatClassNames('anchor', 'before')}>
35
- {SvgIcon}
27
+ <AnchorIcon />
36
28
  </a>
37
29
  );
38
30
 
@@ -42,6 +34,8 @@ export function Heading({
42
34
  id,
43
35
  className: concatClassNames('heading-anchor', mdClassName),
44
36
  'data-component-name': 'Markdown/Heading',
37
+ 'data-source': dataSource,
38
+ 'data-hash': dataHash,
45
39
  },
46
40
  <>
47
41
  {linkEl}
@@ -3,14 +3,22 @@ import styled from 'styled-components';
3
3
 
4
4
  type MermaidProps = {
5
5
  diagramHtml: string;
6
+ 'data-source'?: string;
7
+ 'data-hash'?: string;
6
8
  };
7
9
 
8
- export function Mermaid({ diagramHtml }: MermaidProps): JSX.Element {
10
+ export function Mermaid({
11
+ diagramHtml,
12
+ 'data-source': dataSource,
13
+ 'data-hash': dataHash,
14
+ }: MermaidProps): JSX.Element {
9
15
  return (
10
16
  <Wrapper
11
17
  className="mermaid-wrapper"
12
18
  dangerouslySetInnerHTML={{ __html: diagramHtml }}
13
19
  data-component-name="Markdown/Mermaid"
20
+ data-source={dataSource}
21
+ data-hash={dataHash}
14
22
  />
15
23
  );
16
24
  }
@@ -10,7 +10,7 @@ export interface ProfileProps {
10
10
  onClick?: () => void;
11
11
  }
12
12
 
13
- function ProfileComponent({ name, imageUrl, onClick, color }: ProfileProps): JSX.Element {
13
+ function ProfileComponent({ name = 'User', imageUrl, onClick, color }: ProfileProps): JSX.Element {
14
14
  if (imageUrl) {
15
15
  return (
16
16
  <ProfileWrapper onClick={onClick}>
@@ -0,0 +1,30 @@
1
+ import React, { memo } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ interface ClearButtonProps {
5
+ className?: string;
6
+ style?: React.CSSProperties;
7
+ handleClear?: () => void;
8
+ }
9
+
10
+ const ClearButtonComponent = ({ className, style, handleClear }: ClearButtonProps): JSX.Element => (
11
+ <button className={className} style={style} onClick={handleClear}>
12
+
13
+ </button>
14
+ );
15
+
16
+ export const ClearButton = styled(memo<ClearButtonProps>(ClearButtonComponent))`
17
+ z-index: 1;
18
+ position: absolute;
19
+ right: 24px;
20
+ top: 50%;
21
+ transform: translateY(-50%);
22
+ color: #89949f;
23
+ background: none;
24
+ border: none;
25
+ cursor: pointer;
26
+
27
+ &:hover {
28
+ color: #fff;
29
+ }
30
+ `;
@@ -0,0 +1,161 @@
1
+ import * as React from 'react';
2
+ import { Button } from '@theme';
3
+ import styled from 'styled-components';
4
+
5
+ import type { TryItSecurityProps } from './TryItSecurity';
6
+
7
+ import { usePageData } from '@portal/hooks/usePageData';
8
+
9
+ import { Dropdown } from './Dropdown';
10
+
11
+ export function DevOnboardingTryItSecurity(props: TryItSecurityProps) {
12
+ const apiId = (props as any).apiId;
13
+
14
+ // @ts-ignore
15
+ const { userData } = usePageData('userData') || {};
16
+
17
+ // TODO: handle error
18
+ const [_error, setError] = React.useState<string | undefined>();
19
+ const [apps, setApps] = React.useState<{ id: string; title: string }[] | undefined>();
20
+ const [appId, setAppId] = React.useState<string | undefined>('');
21
+ const [loading, setLoading] = React.useState(true);
22
+ const [appLoading, setAppLoading] = React.useState(false);
23
+
24
+ const [selectedAppSecret, setSelectedAppSecret] = React.useState<string | undefined>();
25
+
26
+ const [acceptValueUpdate, setAcceptValueUpdate] = React.useState(true);
27
+ const initialRender = React.useRef(true);
28
+
29
+ React.useEffect(() => {
30
+ if (!props.value && initialRender.current) return;
31
+ if (acceptValueUpdate) {
32
+ setAcceptValueUpdate(false);
33
+ } else {
34
+ setAppId('');
35
+ }
36
+ }, [props.value]);
37
+
38
+ React.useEffect(() => {
39
+ initialRender.current = false;
40
+ const prevAppId = sessionStorage.getItem('redocly_onboarding:prevAppId');
41
+ if (prevAppId) {
42
+ setAppId(prevAppId);
43
+ }
44
+ if (userData?.isAuthenticated) {
45
+ fetch(`/api/api-keys/api-products/${apiId}/access?expand=1`).then((res) => {
46
+ return res
47
+ .json()
48
+ .then((data: any) => {
49
+ if (res.ok) {
50
+ setApps(data.apps);
51
+ } else {
52
+ setError(data.message);
53
+ }
54
+ })
55
+ .catch(() => setError('Something went wrong'))
56
+ .finally(() => setLoading(false));
57
+ });
58
+ }
59
+ }, []);
60
+
61
+ React.useEffect(() => {
62
+ sessionStorage.setItem('redocly_onboarding:prevAppId', appId || '');
63
+ }, [appId]);
64
+
65
+ if (!apiId) {
66
+ return null;
67
+ }
68
+
69
+ const loadAppCredentials = (appId: string) => {
70
+ setAppLoading(true);
71
+ fetch(`/api/api-keys/apps/${appId}`).then((res) => {
72
+ return res
73
+ .json()
74
+ .then((data: any) => {
75
+ if (res.ok) {
76
+ const cred = data.credentials.find((cred: any) => cred.status === 'approved');
77
+ setAcceptValueUpdate(true);
78
+ setSelectedAppSecret(cred.clientSecret);
79
+ } else {
80
+ setError(data.message);
81
+ }
82
+ })
83
+ .catch(() => setError('Something went wrong'))
84
+ .finally(() => setAppLoading(false));
85
+ });
86
+ };
87
+
88
+ const placeholder = loading ? 'Loading your apps...' : undefined;
89
+
90
+ return (
91
+ <>
92
+ <FormLabel htmlFor="server">Select app: </FormLabel>
93
+ <FormControl>
94
+ <TryItDropdown
95
+ placeholder={placeholder}
96
+ value={appId || placeholder}
97
+ options={apps?.map((app) => ({ title: app.title, value: app.id })) || []}
98
+ fullWidth
99
+ onChange={({ value }: { value: string }) => {
100
+ setAppId(value);
101
+ loadAppCredentials(value);
102
+ }}
103
+ />
104
+ <UseKeyButton
105
+ disabled={!selectedAppSecret || appLoading}
106
+ color="secondary"
107
+ blinking={appLoading}
108
+ onClick={() => selectedAppSecret && props.onChange(selectedAppSecret)}
109
+ >
110
+ Use key
111
+ </UseKeyButton>
112
+ </FormControl>
113
+ </>
114
+ );
115
+ }
116
+
117
+ const TryItDropdown = styled(Dropdown)`
118
+ .dropdown-select,
119
+ label {
120
+ background-color: var(--panel-try-it-dropdown-background-color);
121
+ border: var(--panel-try-it-dropdown-border);
122
+ color: var(--panel-try-it-dropdown-color);
123
+ }
124
+ `;
125
+
126
+ const FormControl = styled.div`
127
+ width: 100%;
128
+ /* font-family: var(--code-font-family); */
129
+ display: flex;
130
+ flex-direction: column;
131
+ margin-bottom: 10px;
132
+
133
+ &:last-child {
134
+ margin-bottom: 0;
135
+ }
136
+ `;
137
+
138
+ const FormLabel = styled.label<{ required?: boolean }>`
139
+ padding-bottom: 6px;
140
+ display: block;
141
+ white-space: nowrap;
142
+ line-height: 1em;
143
+
144
+ ${({ required }) =>
145
+ required &&
146
+ `
147
+ &:after {
148
+ display: inline-block;
149
+ content: '*';
150
+ margin-left: 4px;
151
+ color: var(--color-error-500);
152
+ }
153
+ `}
154
+ `;
155
+
156
+ const UseKeyButton = styled(Button)`
157
+ width: 100px;
158
+ align-self: flex-end;
159
+ margin-top: 16px;
160
+ margin-right: 0;
161
+ `;
@@ -0,0 +1,202 @@
1
+ import React, { memo, useMemo } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ export interface DropdownOption {
5
+ idx?: number;
6
+ value: string;
7
+ title?: string;
8
+ serverUrl?: string;
9
+ label?: string;
10
+ }
11
+
12
+ export interface DropdownProps {
13
+ options: DropdownOption[];
14
+ onChange: (option: DropdownOption) => void;
15
+ handleClear?: () => void;
16
+ clearable?: boolean;
17
+ ariaLabel?: string;
18
+ className?: string;
19
+ placeholder?: string;
20
+ value?: string;
21
+ dense?: boolean;
22
+ fullWidth?: boolean;
23
+ variant?: 'dark' | 'light';
24
+ }
25
+
26
+ export interface ArrowIconProps {
27
+ className?: string;
28
+ variant?: 'light' | 'dark';
29
+ style?: React.CSSProperties;
30
+ }
31
+
32
+ import { ClearButton } from './ClearButton';
33
+
34
+ const ArrowSvg = ({ className, style }: ArrowIconProps): JSX.Element => (
35
+ <svg
36
+ className={className}
37
+ style={style}
38
+ xmlns="http://www.w3.org/2000/svg"
39
+ width="16"
40
+ height="16"
41
+ viewBox="0 0 24 24"
42
+ fill="none"
43
+ stroke="currentColor"
44
+ strokeWidth="2"
45
+ strokeLinecap="round"
46
+ strokeLinejoin="round"
47
+ >
48
+ <polyline points="6 9 12 15 18 9" />
49
+ </svg>
50
+ );
51
+
52
+ const ArrowIcon = styled(ArrowSvg)`
53
+ position: absolute;
54
+ pointer-events: none;
55
+ z-index: 1;
56
+ top: 50%;
57
+ -webkit-transform: translateY(-50%);
58
+ -ms-transform: translateY(-50%);
59
+ transform: translateY(-50%);
60
+ right: 8px;
61
+ margin: auto;
62
+ text-align: center;
63
+ polyline {
64
+ color: ${(props) => props.variant === 'dark' && 'white'};
65
+ }
66
+ `;
67
+
68
+ const DropdownComponent = ({
69
+ options,
70
+ onChange,
71
+ handleClear,
72
+ clearable,
73
+ placeholder,
74
+ value = '',
75
+ className,
76
+ variant = 'light',
77
+ }: DropdownProps): JSX.Element => {
78
+ const handleOnChange = (event: any) => {
79
+ const { selectedIndex } = event.target;
80
+ const index = placeholder || !value ? selectedIndex - 1 : selectedIndex;
81
+ onChange(options[index]);
82
+ };
83
+
84
+ const renderOptions = useMemo(
85
+ () =>
86
+ options.map(({ idx, value, title }: DropdownOption, index) => {
87
+ const normalizedValue = normalizeText(value);
88
+ return (
89
+ <option
90
+ key={idx || normalizedValue + index}
91
+ value={normalizedValue}
92
+ className="dropdown-option"
93
+ >
94
+ {title || normalizedValue}
95
+ </option>
96
+ );
97
+ }),
98
+ [options],
99
+ );
100
+
101
+ const normalizedValue = normalizeText(value);
102
+ const title = options.find((option) => option.value === value)?.title || normalizedValue;
103
+
104
+ return (
105
+ <div className={className + ' dropdown-wrapper'}>
106
+ <ArrowIcon variant={variant} />
107
+ {clearable && normalizedValue?.length > 0 && <ClearButton handleClear={handleClear} />}
108
+ <select onChange={handleOnChange} value={normalizedValue} className="dropdown-select">
109
+ {placeholder && (
110
+ <option disabled hidden value={placeholder}>
111
+ {placeholder}
112
+ </option>
113
+ )}
114
+ {!normalizedValue && !placeholder && <option disabled />}
115
+ {renderOptions}
116
+ </select>
117
+ <label>{title}</label>
118
+ </div>
119
+ );
120
+ };
121
+
122
+ export const Dropdown = styled(memo<DropdownProps>(DropdownComponent))`
123
+
124
+ box-sizing: border-box;
125
+ outline: none;
126
+ display: inline-block;
127
+ border-radius: var(--border-radius);
128
+ vertical-align: bottom;
129
+ position: relative;
130
+ width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
131
+ cursor: pointer;
132
+ text-transform: none;
133
+
134
+ label {
135
+ box-sizing: border-box;
136
+ min-width: 90px;
137
+ height: 36px;
138
+ outline: none;
139
+ display: inline-block;
140
+ color: var(--dropdown-text-color);
141
+ border-radius: var(--border-radius);
142
+ border: var(--dropdown-border);
143
+ padding: var(--dropdown-padding);
144
+ vertical-align: bottom;
145
+ width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
146
+ text-transform: none;
147
+ line-height: inherit;
148
+ font-size: var(--dropdown-font-size);
149
+ font-family: inherit;
150
+ text-overflow: ellipsis;
151
+ overflow: hidden;
152
+ white-space: nowrap;
153
+
154
+ &,
155
+ &:hover,
156
+ &:focus-within {
157
+ border: 1px solid var(--border-color);
158
+ box-shadow: none;
159
+ }
160
+
161
+ ${({ variant }) => (variant === 'dark' ? darkDropdownStyle : '')};
162
+ }
163
+
164
+ .dropdown-select {
165
+ position: absolute;
166
+ top: 0;
167
+ left: 0;
168
+ width: 100%;
169
+ height: 100%;
170
+ opacity: 0;
171
+ border: none;
172
+ appearance: none;
173
+ cursor: pointer;
174
+
175
+ color: var(--text-color);
176
+ line-height: inherit;
177
+ font-size: 14px;
178
+ font-family: inherit;
179
+ padding: var(--dropdown-padding);
180
+ ${({ variant }) => (variant === 'dark' ? darkDropdownStyle : '')};
181
+
182
+ `;
183
+
184
+ const darkDropdownStyle = `
185
+ background-color: var(--panel-samples-dropdown-background-color);
186
+ border: var(--panel-samples-dropdown-border);
187
+ color: var(--panel-samples-dropdown-color);
188
+
189
+ &,
190
+ &:hover,
191
+ &:focus-within {
192
+ border: none;
193
+ box-shadow: none;
194
+ }
195
+ `;
196
+
197
+ function isString<T>(value: T | string): value is string {
198
+ return typeof value === 'string';
199
+ }
200
+
201
+ export const normalizeText = (description?: string | Record<string, any>): string =>
202
+ isString(description) ? description : description?.raw;
@@ -1,4 +1,17 @@
1
- import type { BeforeSecurityPanelHookProps } from '@redocly/openapi-docs';
1
+ import React from 'react';
2
2
 
3
- export const TryItSecurity: ((props: BeforeSecurityPanelHookProps) => JSX.Element) | undefined =
4
- undefined;
3
+ import { useGlobalData } from '@portal/hooks';
4
+
5
+ import { DevOnboardingTryItSecurity } from './DevOnboardingTryItSecurity';
6
+
7
+ export type TryItSecurityProps = {
8
+ apiId?: string;
9
+ value?: string;
10
+ onChange: (newSecretKey: string) => void;
11
+ };
12
+
13
+ export function TryItSecurity(props: TryItSecurityProps) {
14
+ const { hasDeveloperOnboarding } = useGlobalData() || {};
15
+
16
+ return hasDeveloperOnboarding && props.apiId ? <DevOnboardingTryItSecurity {...props} /> : null;
17
+ }
@@ -0,0 +1 @@
1
+ export * from './TryItSecurity';
@@ -0,0 +1,9 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const FooterWrapper = styled.div.attrs(() => ({
4
+ 'data-component-name': 'Sidebar/FooterWrapper',
5
+ }))`
6
+ margin: var(--sidebar-offset-top) 0 var(--sidebar-spacing-unit) var(--sidebar-offset-left);
7
+ padding-top: var(--sidebar-spacing-unit);
8
+ border-top: solid 1px #daddde;
9
+ `;
@@ -0,0 +1,9 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const HeaderWrapper = styled.div.attrs(() => ({
4
+ 'data-component-name': 'Sidebar/HeaderWrapper',
5
+ }))`
6
+ margin: var(--sidebar-offset-top) 0 0 var(--sidebar-offset-left);
7
+ padding-bottom: var(--sidebar-spacing-unit);
8
+ border-bottom: solid 1px #daddde;
9
+ `;
@@ -43,7 +43,10 @@ export function MenuGroup({
43
43
  isAlwaysExpanded={item.expanded === 'always'}
44
44
  active={item.active}
45
45
  >
46
- <MenuGroupArrow direction={isExpanded ? 'down' : 'right'} />
46
+ <MenuGroupArrow
47
+ visibility={item.items.length ? 'visible' : 'hidden'}
48
+ direction={isExpanded ? 'down' : 'right'}
49
+ />
47
50
  {item.label}
48
51
  </MenuGroupLabel>
49
52
  </MenuLinkItem>