@apify/ui-library 0.63.2-featcodeblockwithtabs-5a4360.31 → 0.63.2-featcodeblockwithtabs-5a4360.35

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apify/ui-library",
3
- "version": "0.63.2-featcodeblockwithtabs-5a4360.31+71d988711ce",
3
+ "version": "0.63.2-featcodeblockwithtabs-5a4360.35+674d80b358d",
4
4
  "description": "React UI library used by apify.com",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -66,5 +66,5 @@
66
66
  "typescript": "^5.1.6",
67
67
  "typescript-eslint": "^8.24.0"
68
68
  },
69
- "gitHead": "71d988711ce0ad1fd229d4887d7ff538b4cc1bfc"
69
+ "gitHead": "674d80b358d5cdf4c70ebdfd5a0f99c525950b74"
70
70
  }
@@ -1,16 +1,19 @@
1
1
  import clsx from 'clsx';
2
+ import React from 'react';
2
3
  import styled from 'styled-components';
3
4
 
4
5
  import { theme } from '../../../design_system/theme.js';
6
+ import { useSharedUiDependencies } from '../../../ui_dependency_provider.js';
7
+ import { Box, type MarginSpacingProps, type RegularBoxProps } from '../../box.js';
5
8
  import { Link, type RegularLinkProps } from '../../link.js';
6
9
  import { HeadingShared } from '../../text/heading_shared.js';
7
10
  import { CodeBlock, type CodeBlockProps } from './code_block.js';
8
11
 
9
12
  export type CodeBlockTabKey = 'cli' | 'http' | 'javascript' | 'mcp' | 'openapi' | 'python' | 'typescript';
10
13
  type CodeBlockTabConfig = {
11
- label: string;
12
- language: string;
13
- src: string;
14
+ label: string;
15
+ language: string;
16
+ src: string;
14
17
  };
15
18
 
16
19
  const CODE_BLOCK_TAB_CATALOG: Record<CodeBlockTabKey, CodeBlockTabConfig> = {
@@ -54,18 +57,22 @@ const CODE_BLOCK_TAB_CATALOG: Record<CodeBlockTabKey, CodeBlockTabConfig> = {
54
57
  },
55
58
  };
56
59
 
57
- type SharedCodeBlockProps = Omit<CodeBlockProps, 'content' | 'language' | 'defaultTabKey' | 'onTabChange'>;
60
+ type SharedBoxProps = Omit<RegularBoxProps, 'as' | 'children' | 'onClick'> & MarginSpacingProps;
61
+
62
+ type SharedCodeBlockProps = Omit<CodeBlockProps, 'bashCommandsStart' | 'content' | 'language' | 'defaultTabKey' | 'onTabChange'>;
58
63
  type SharedLinkProps = Pick<RegularLinkProps, 'to' | 'rel' | 'target'>;
59
64
 
60
- type CodeBlockTabProps = {
61
- key: CodeBlockTabKey;
62
- content: string;
63
- onClick?: (e: React.MouseEvent) => void;
65
+ export type CodeBlockTabProps = {
66
+ key: CodeBlockTabKey;
67
+ bashCommandsStart?: number[];
68
+ content: string;
69
+ onClick?: (e: React.MouseEvent) => void;
64
70
  } & Partial<SharedLinkProps>;
65
71
 
66
- type CodeBlockWithTabsProps = SharedCodeBlockProps & {
67
- currentTabKey: CodeBlockTabKey;
68
- tabs: CodeBlockTabProps[];
72
+ type CodeBlockWithTabsProps = SharedBoxProps & {
73
+ codeBlockProps: SharedCodeBlockProps;
74
+ currentTabKey: CodeBlockTabKey;
75
+ tabs: CodeBlockTabProps[];
69
76
  };
70
77
 
71
78
  export const CODE_BLOCK_WITH_TABS_CLASSNAMES = {
@@ -75,92 +82,104 @@ export const CODE_BLOCK_WITH_TABS_CLASSNAMES = {
75
82
  CONTENT: 'CodeBlockWithTabsContent',
76
83
  };
77
84
 
78
- const CodeBlockWithTabsWrapper = styled.div`
79
- .${CODE_BLOCK_WITH_TABS_CLASSNAMES.TABS} {
80
- min-width: 266px;
81
- height: 72px;
82
- padding-inline: ${theme.space.space8};
83
- display: flex;
84
- gap: ${theme.space.space4};
85
- overflow-x: auto;
86
- background-color: ${theme.color.neutral.backgroundSubtle};
87
- border: 1px solid ${theme.color.neutral.border};
88
- border-bottom: none;
89
- border-top-right-radius: ${theme.radius.radius12};
90
- border-top-left-radius: ${theme.radius.radius12};
91
-
92
- @media ${theme.device.tablet} {
93
- height: 88px;
94
- justify-content: center;
95
- gap: ${theme.space.space24};
96
- padding-inline: ${theme.space.space24};
97
- }
98
- }
99
-
100
- .${CODE_BLOCK_WITH_TABS_CLASSNAMES.TAB} {
101
- min-width: 64px;
102
- position: relative;
103
- padding: ${theme.space.space12} ${theme.space.space8};
104
- color: ${theme.color.neutral.textMuted};
105
- display: flex;
106
- flex-direction: column;
107
- flex-shrink: 0;
108
- align-items: center;
109
- justify-content: flex-end;
110
- gap: ${theme.space.space4};
111
- cursor: pointer;
112
-
113
- img {
114
- width: 20px;
115
- height: 20px;
116
- }
117
-
118
- [role="tabpanel"] {
119
- bottom: 0;
120
- width: 100%;
121
- height: 2px;
122
- color: ${theme.color.neutral.text};
123
- background-color: ${theme.color.primaryBlack.action};
124
- border-radius: ${theme.radius.radiusFull};
125
- display: none;
126
- position: absolute;
127
- z-index: 2;
85
+ const CodeBlockWithTabsWrapper = styled(Box)`
86
+ .${CODE_BLOCK_WITH_TABS_CLASSNAMES.TABS} {
87
+ min-width: 266px;
88
+ height: 72px;
89
+ padding-inline: ${theme.space.space8};
90
+ display: flex;
91
+ gap: ${theme.space.space4};
92
+ overflow-x: auto;
93
+ background-color: ${theme.color.neutral.backgroundSubtle};
94
+ border: 1px solid ${theme.color.neutral.border};
95
+ border-bottom: none;
96
+ border-top-right-radius: ${theme.radius.radius12};
97
+ border-top-left-radius: ${theme.radius.radius12};
98
+
99
+ @media ${theme.device.tablet} {
100
+ height: 88px;
101
+ justify-content: center;
102
+ gap: ${theme.space.space24};
103
+ padding-inline: ${theme.space.space24};
104
+ }
128
105
  }
129
106
 
130
- &.selected {
131
- [role="tabpanel"] {
132
- display: block;
133
- }
107
+ .${CODE_BLOCK_WITH_TABS_CLASSNAMES.TAB} {
108
+ min-width: 64px;
109
+ position: relative;
110
+ padding: ${theme.space.space12} ${theme.space.space8};
111
+ color: ${theme.color.neutral.textMuted};
112
+ display: flex;
113
+ flex-direction: column;
114
+ flex-shrink: 0;
115
+ align-items: center;
116
+ justify-content: flex-end;
117
+ gap: ${theme.space.space4};
118
+ cursor: pointer;
119
+
120
+ img {
121
+ width: 20px;
122
+ height: 20px;
123
+ }
124
+
125
+ [role="tabpanel"] {
126
+ bottom: 0;
127
+ width: 100%;
128
+ height: 2px;
129
+ color: ${theme.color.neutral.text};
130
+ background-color: ${theme.color.primaryBlack.action};
131
+ border-radius: ${theme.radius.radiusFull};
132
+ display: none;
133
+ position: absolute;
134
+ z-index: 2;
135
+ }
136
+
137
+ &.selected {
138
+ color: ${theme.color.neutral.text};
139
+
140
+ [role="tabpanel"] {
141
+ display: block;
142
+ }
143
+ }
144
+
145
+ &:hover {
146
+ color: ${theme.color.neutral.text};
147
+ text-decoration: none;
148
+ }
134
149
  }
135
150
 
136
- &:hover {
137
- color: ${theme.color.neutral.text};
138
- text-decoration: none;
151
+ .${CODE_BLOCK_WITH_TABS_CLASSNAMES.CONTENT} {
152
+ max-width: initial;
153
+ border-top-left-radius: 0;
154
+ border-top-right-radius: 0;
139
155
  }
140
- }
141
-
142
- .${CODE_BLOCK_WITH_TABS_CLASSNAMES.CONTENT} {
143
- max-width: initial;
144
- border-top-left-radius: 0;
145
- border-top-right-radius: 0;
146
- }
147
156
  `;
148
157
 
149
- export const CodeBlockWithTabs = ({ currentTabKey, tabs, className, hideBashHeader = true, ...props }: CodeBlockWithTabsProps) => {
150
- // Math.Max(0, ) ensures that the index is not negative, in case the currentTabKey is not found in the tabs array
151
- const currentTabIndex = Math.max(0, tabs.findIndex((tab) => tab.key === currentTabKey));
152
- const currentTab = tabs[currentTabIndex];
158
+ const IMG_RESIZE = {
159
+ width: 20,
160
+ height: 20,
161
+ };
162
+
163
+ export const CodeBlockWithTabs = ({ className, codeBlockProps, currentTabKey, tabs, ...props }: CodeBlockWithTabsProps) => {
164
+ const { generateProxyImageUrl } = useSharedUiDependencies();
165
+ const currentTab = tabs.find((tab) => tab.key === currentTabKey) ?? tabs[0];
153
166
 
154
167
  return (
155
- <CodeBlockWithTabsWrapper className={clsx(CODE_BLOCK_WITH_TABS_CLASSNAMES.WRAPPER, className)}>
168
+ <CodeBlockWithTabsWrapper className={clsx(CODE_BLOCK_WITH_TABS_CLASSNAMES.WRAPPER, className)} {...props}>
156
169
  <div className={CODE_BLOCK_WITH_TABS_CLASSNAMES.TABS}>
157
170
  {tabs.map((tab) => {
158
171
  const { label, src } = CODE_BLOCK_TAB_CATALOG[tab.key];
159
172
  const selected = tab.key === currentTab?.key;
160
173
 
174
+ const commonProps = {
175
+ key: tab.key,
176
+ className: clsx(CODE_BLOCK_WITH_TABS_CLASSNAMES.TAB, { selected }),
177
+ 'data-test': `code-block-tab-${tab.key}`,
178
+ onClick: tab.onClick,
179
+ };
161
180
  const children = (
162
181
  <>
163
- <img src={src} alt={label} />
182
+ <img src={generateProxyImageUrl?.(src, { resize: IMG_RESIZE }) ?? src} alt={label} />
164
183
  <HeadingShared type="titleS" as="p">
165
184
  {label}
166
185
  </HeadingShared>
@@ -172,12 +191,10 @@ export const CodeBlockWithTabs = ({ currentTabKey, tabs, className, hideBashHead
172
191
  if (tab.to) {
173
192
  return (
174
193
  <Link
175
- key={tab.key}
176
- className={clsx(CODE_BLOCK_WITH_TABS_CLASSNAMES.TAB, { selected })}
194
+ {...commonProps}
177
195
  to={tab.to}
178
196
  rel={tab.rel}
179
197
  target={tab.target}
180
- onClick={tab.onClick}
181
198
  >
182
199
  {children}
183
200
  </Link>
@@ -186,10 +203,8 @@ export const CodeBlockWithTabs = ({ currentTabKey, tabs, className, hideBashHead
186
203
 
187
204
  return (
188
205
  <div
189
- key={tab.key}
190
- className={clsx(CODE_BLOCK_WITH_TABS_CLASSNAMES.TAB, { selected })}
206
+ {...commonProps}
191
207
  role="button"
192
- onClick={tab.onClick}
193
208
  >
194
209
  {children}
195
210
  </div>
@@ -197,11 +212,12 @@ export const CodeBlockWithTabs = ({ currentTabKey, tabs, className, hideBashHead
197
212
  })}
198
213
  </div>
199
214
  <CodeBlock
215
+ bashCommandsStart={currentTab?.bashCommandsStart}
200
216
  content={currentTab?.content ?? ''}
201
217
  language={CODE_BLOCK_TAB_CATALOG[currentTab?.key]?.language}
202
218
  className={CODE_BLOCK_WITH_TABS_CLASSNAMES.CONTENT}
203
- hideBashHeader={hideBashHeader}
204
- {...props}
219
+ hideBashHeader
220
+ {...codeBlockProps}
205
221
  />
206
222
  </CodeBlockWithTabsWrapper>
207
223
  );