@redocly/theme 0.45.11 → 0.46.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 (34) hide show
  1. package/lib/components/CodeBlock/CodeBlock.d.ts +2 -1
  2. package/lib/components/CodeBlock/CodeBlock.js +33 -9
  3. package/lib/components/CodeBlock/CodeBlockContainer.d.ts +1 -0
  4. package/lib/components/CodeBlock/CodeBlockContainer.js +242 -68
  5. package/lib/components/CodeBlock/variables.js +43 -0
  6. package/lib/components/Link/Link.js +1 -1
  7. package/lib/core/hooks/use-theme-config.js +1 -1
  8. package/lib/core/hooks/use-theme-hooks.js +1 -0
  9. package/lib/core/types/hooks.d.ts +7 -0
  10. package/lib/core/utils/add-line-numbers.d.ts +6 -0
  11. package/lib/core/utils/add-line-numbers.js +18 -0
  12. package/lib/core/utils/index.d.ts +1 -1
  13. package/lib/core/utils/index.js +1 -1
  14. package/lib/markdoc/components/Cards/Card.d.ts +2 -1
  15. package/lib/markdoc/components/Cards/Card.js +2 -2
  16. package/lib/markdoc/components/Cards/CardIcon.d.ts +2 -1
  17. package/lib/markdoc/components/Cards/CardIcon.js +3 -3
  18. package/lib/markdoc/tags/card.js +5 -0
  19. package/package.json +1 -3
  20. package/src/components/CodeBlock/CodeBlock.tsx +21 -7
  21. package/src/components/CodeBlock/CodeBlockContainer.tsx +243 -68
  22. package/src/components/CodeBlock/variables.ts +43 -0
  23. package/src/components/Link/Link.tsx +1 -1
  24. package/src/core/hooks/use-theme-config.ts +1 -1
  25. package/src/core/hooks/use-theme-hooks.ts +1 -0
  26. package/src/core/types/hooks.ts +11 -0
  27. package/src/core/utils/add-line-numbers.ts +16 -0
  28. package/src/core/utils/index.ts +1 -1
  29. package/src/markdoc/components/Cards/Card.tsx +10 -1
  30. package/src/markdoc/components/Cards/CardIcon.tsx +5 -4
  31. package/src/markdoc/tags/card.ts +5 -0
  32. package/lib/core/utils/highlight.d.ts +0 -35
  33. package/lib/core/utils/highlight.js +0 -129
  34. package/src/core/utils/highlight.ts +0 -125
@@ -7,8 +7,8 @@ exports.CardIcon = CardIcon;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const styled_components_1 = __importDefault(require("styled-components"));
9
9
  const InlineSvg_1 = require("../../../markdoc/components/InlineSvg/InlineSvg");
10
- function CardIcon({ variant, src, rawContent }) {
11
- return (react_1.default.createElement(CardIconWrapper, { "$variant": variant }, rawContent ? react_1.default.createElement(CardSvg, { fileRawContent: rawContent }) : react_1.default.createElement(CardImg, { src: src })));
10
+ function CardIcon({ variant, src, rawContent, position }) {
11
+ return (react_1.default.createElement(CardIconWrapper, { "$variant": variant, "$position": position }, rawContent ? react_1.default.createElement(CardSvg, { fileRawContent: rawContent }) : react_1.default.createElement(CardImg, { src: src })));
12
12
  }
13
13
  const CardImg = styled_components_1.default.img `
14
14
  width: var(--card-icon-width);
@@ -29,7 +29,7 @@ const CardSvg = (0, styled_components_1.default)(InlineSvg_1.InlineSvg) `
29
29
  `;
30
30
  const CardIconWrapper = styled_components_1.default.div `
31
31
  display: flex;
32
- align-items: center;
32
+ align-self: ${({ $position }) => ($position ? $position : 'auto')};
33
33
  justify-content: center;
34
34
  min-width: var(--card-icon-width);
35
35
  min-height: var(--card-icon-height);
@@ -28,6 +28,11 @@ exports.card = {
28
28
  matches: ['start', 'end'],
29
29
  default: 'start',
30
30
  },
31
+ iconPosition: {
32
+ type: String,
33
+ matches: ['auto', 'start', 'center', 'end'],
34
+ default: 'auto',
35
+ },
31
36
  layout: {
32
37
  type: String,
33
38
  matches: ['horizontal', 'combined', 'vertical'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.45.11",
3
+ "version": "0.46.0",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -27,7 +27,6 @@
27
27
  "peerDependencies": {
28
28
  "@markdoc/markdoc": "0.4.0",
29
29
  "lodash.throttle": "^4.1.1",
30
- "prismjs": "^1.28.0",
31
30
  "react": "^17.0.0 || ^18.0.0",
32
31
  "react-dom": "^17.0.0 || ^18.0.0",
33
32
  "react-router-dom": "^6.21.1",
@@ -44,7 +43,6 @@
44
43
  "@types/jest-when": "3.5.5",
45
44
  "@types/lodash.throttle": "4.1.9",
46
45
  "@types/node": "18.19.3",
47
- "@types/prismjs": "1.26.4",
48
46
  "@types/react": "18.3.9",
49
47
  "@types/react-dom": "18.2.25",
50
48
  "@types/styled-components": "5.1.34",
@@ -4,8 +4,8 @@ import styled from 'styled-components';
4
4
  import type { CodeBlockControlsProps } from '@redocly/theme/components/CodeBlock/CodeBlockControls';
5
5
  import type { ReportDialogProps } from '@redocly/theme/components/Feedback/ReportDialog';
6
6
 
7
- import { highlight, addLineNumbers } from '@redocly/theme/core/utils';
8
- import { useModalScrollLock, useReportDialog } from '@redocly/theme/core/hooks';
7
+ import { addLineNumbers } from '@redocly/theme/core/utils';
8
+ import { useModalScrollLock, useReportDialog, useThemeHooks } from '@redocly/theme/core/hooks';
9
9
  import { ReportDialog } from '@redocly/theme/components/Feedback/ReportDialog';
10
10
  import { CodeBlockContainer } from '@redocly/theme/components/CodeBlock/CodeBlockContainer';
11
11
  import { CodeBlockControls } from '@redocly/theme/components/CodeBlock/CodeBlockControls';
@@ -26,6 +26,7 @@ export type CodeBlockProps = {
26
26
  codeBlockMaxHeight?: string;
27
27
  hideCodeColors?: boolean;
28
28
  wrapContents?: boolean;
29
+ [key: string]: unknown;
29
30
  };
30
31
 
31
32
  type UnstableExternalCodeSample = {
@@ -64,12 +65,25 @@ export function CodeBlock({
64
65
  hideCodeColors,
65
66
  wrapContents = false,
66
67
  children,
68
+ ...rest
67
69
  }: React.PropsWithChildren<CodeBlockProps>): JSX.Element {
68
70
  const [sourceCode, setSourceCode] = useState<string>(
69
71
  (source || externalSource?.sample?.get?.(externalSource)) ?? '',
70
72
  );
73
+ const { useCodeHighlight } = useThemeHooks();
74
+ const { highlight } = useCodeHighlight() || {};
71
75
 
72
- const highlightedCode = highlightedHtml || (children ? null : highlight(sourceCode, lang));
76
+ const highlightedCode = highlightedHtml
77
+ ? withLineNumbers
78
+ ? addLineNumbers(highlightedHtml, startLineNumber)
79
+ : highlightedHtml
80
+ : children
81
+ ? null
82
+ : highlight?.(sourceCode, lang, {
83
+ withLineNumbers,
84
+ startLineNumber,
85
+ highlight: rest['data-highlight'] as string | undefined,
86
+ });
73
87
 
74
88
  // The same initial value should be returned for ssr and frontend to avoid issues
75
89
  // Because we don't have session storage in ssr and can't get the security details there
@@ -102,13 +116,11 @@ export function CodeBlock({
102
116
  />
103
117
  <CodeBlockContainer
104
118
  ref={codeBlockRef}
105
- className={withLineNumbers ? 'line-numbers' : ''}
119
+ withLineNumbers={withLineNumbers}
106
120
  dangerouslySetInnerHTML={
107
121
  highlightedCode
108
122
  ? {
109
- __html: withLineNumbers
110
- ? addLineNumbers(highlightedCode, startLineNumber)
111
- : highlightedCode,
123
+ __html: highlightedCode,
112
124
  }
113
125
  : undefined
114
126
  }
@@ -142,4 +154,6 @@ const CodeBlockWrapper = styled.div`
142
154
  border-radius: var(--border-radius);
143
155
  background-color: var(--code-block-bg-color);
144
156
  margin: 0 0 var(--spacing-sm);
157
+
158
+ --md-pre-margin: 0;
145
159
  `;
@@ -9,6 +9,7 @@ export type CodeBlockContainerProps = PropsWithChildren<{
9
9
  wrapContents?: boolean;
10
10
  ref?: (instance: HTMLPreElement | null) => void;
11
11
  className?: string;
12
+ withLineNumbers?: boolean;
12
13
  dangerouslySetInnerHTML?: {
13
14
  __html: string;
14
15
  };
@@ -42,95 +43,269 @@ const CodeBlockContainerComponent = styled.pre<CodeBlockContainerProps>`
42
43
  font-family: var(--code-block-font-family);
43
44
  }
44
45
  }
45
- /**
46
- * Based on prism-dark.css
47
- */
48
- code[class*='language-'],
49
- pre[class*='language-'] {
50
- text-shadow: 0 -0.1em 0.2em black;
51
- text-align: left;
52
- word-spacing: normal;
53
- word-break: normal;
54
- word-wrap: normal;
55
- line-height: 1.5;
56
-
57
- -moz-tab-size: 4;
58
- -o-tab-size: 4;
59
- tab-size: 4;
60
-
61
- -webkit-hyphens: none;
62
- -moz-hyphens: none;
63
- -ms-hyphens: none;
64
- hyphens: none;
65
- }
66
46
 
67
- @media print {
68
- code[class*='language-'],
69
- pre[class*='language-'] {
70
- text-shadow: none;
47
+ .highlighted {
48
+ background: var(--layer-color-hover);
49
+ margin-left: calc(var(--spacing-sm) * -1);
50
+ padding-left: var(--spacing-sm);
51
+ width: calc(100% + var(--spacing-sm));
52
+ display: inline-block;
53
+
54
+ &.error {
55
+ background: var(--color-raspberry-2);
56
+ }
57
+
58
+ &.warning {
59
+ background: var(--color-carrot-2);
71
60
  }
72
61
  }
73
62
 
74
- /* Code blocks */
63
+ [data-line-number] {
64
+ &::before {
65
+ content: attr(data-line-number);
66
+ display: inline-block;
67
+ min-width: 2em;
68
+ padding-right: 0.8em;
69
+ text-align: right;
70
+ pointer-events: none;
71
+ user-select: none;
72
+ }
73
+ }
75
74
 
76
- pre[class*='language-'] {
77
- padding: 1em;
78
- margin: 0.5em 0;
79
- overflow: auto;
75
+ .has-diff {
76
+ > .line {
77
+ &::before {
78
+ content: attr(data-line-number) ' ';
79
+ display: inline-block;
80
+ padding-right: 0.4em;
81
+ text-align: right;
82
+ pointer-events: none;
83
+ user-select: none;
84
+ }
85
+ &[data-line-number]::before {
86
+ min-width: 3em;
87
+ }
88
+ }
80
89
  }
81
90
 
82
- .token.punctuation {
83
- opacity: 1;
91
+ .diff {
92
+ margin-left: calc(var(--spacing-sm) * -1);
93
+ padding-left: var(--spacing-sm);
94
+ width: calc(100% + var(--spacing-sm));
95
+ display: inline-block;
96
+
97
+ &.add {
98
+ background: var(--color-grass-2);
99
+ &:before {
100
+ content: attr(data-line-number) ' +';
101
+ color: var(--color-grass-7);
102
+ }
103
+ }
104
+ &.remove {
105
+ background: var(--color-raspberry-2);
106
+
107
+ &:before {
108
+ content: attr(data-line-number) ' -';
109
+ color: var(--color-raspberry-7);
110
+ }
111
+ }
84
112
  }
85
113
 
86
- .namespace {
87
- opacity: 0.7;
114
+ .highlighted-word {
115
+ background: var(--color-carrot-2);
116
+ border: 1px solid var(--color-carrot-5);
117
+ border-radius: 4px;
88
118
  }
89
119
 
90
- .token.selector,
91
- .token.attr-name,
92
- .token.string,
93
- .token.char,
94
- .token.builtin,
95
- .token.inserted {
96
- & + a,
97
- & + a:visited {
98
- color: var(--code-block-tokens-link-color);
99
- text-decoration: underline;
120
+ .has-focused {
121
+ .line {
122
+ margin-left: calc(var(--spacing-sm) * -1);
123
+ padding-left: var(--spacing-sm);
124
+ width: calc(100% + var(--spacing-sm));
125
+ display: inline-block;
126
+
127
+ opacity: 0.7;
128
+ filter: blur(0.095rem);
129
+ transition:
130
+ filter 0.35s,
131
+ opacity 0.35s;
132
+ &.focused {
133
+ opacity: 1;
134
+ filter: blur(0);
135
+ }
136
+ }
137
+
138
+ &:hover {
139
+ .line {
140
+ opacity: 1;
141
+ filter: blur(0);
142
+ }
100
143
  }
101
144
  }
102
145
 
103
- .token.property.string {
104
- color: var(--code-block-tokens-property-string-color);
146
+ /*
147
+ * Tree view styles
148
+ */
149
+
150
+ .shiki {
151
+ &.theme {
152
+ display: inline-block;
153
+ width: 100%;
154
+
155
+ &.tree-view-root {
156
+ display: flex;
157
+ flex-direction: column;
158
+ }
159
+ }
105
160
  }
106
161
 
107
- .token.important,
108
- .token.bold {
109
- font-weight: bold;
162
+ . .line {
163
+ display: inline-block;
110
164
  }
111
165
 
112
- .token.italic {
113
- font-style: italic;
166
+ .tree-view-line {
167
+ display: flex;
114
168
  }
115
169
 
116
- .token.entity {
117
- cursor: help;
170
+ .tree-view-branch {
171
+ color: var(--code-block-tree-view-lines-color);
118
172
  }
119
173
 
120
- .code-line {
121
- &:before {
122
- content: attr(data-line-number);
123
- display: inline-block;
124
- min-width: 2em;
125
- padding-right: 0.8em;
126
- text-align: right;
127
- pointer-events: none;
128
- user-select: none;
174
+ .tree-view-file {
175
+ display: inline-flex;
176
+ &::before {
177
+ content: '\\ea01';
178
+ margin-left: 0.3rem;
179
+ margin-right: 0.5rem;
180
+ font-family: 'TreeViewIcons';
129
181
  }
130
- }
131
182
 
132
- .highlighted {
133
- background: var(--tag-basic-bg-color);
183
+ &.no-file {
184
+ &::before {
185
+ content: '';
186
+ margin-right: 0;
187
+ }
188
+ }
189
+
190
+ &.ext-folder {
191
+ &::before {
192
+ content: '\\ea02';
193
+ }
194
+ }
195
+
196
+ &.ext-img,
197
+ &.ext-png,
198
+ &.ext-jpg,
199
+ &.ext-jpeg,
200
+ &.ext-gif,
201
+ &.ext-svg {
202
+ &::before {
203
+ content: '\\ea03';
204
+ }
205
+ }
206
+
207
+ &.ext-mp2,
208
+ &.ext-mp3,
209
+ &.ext-wav,
210
+ &.ext-ogg,
211
+ &.ext-flac {
212
+ &::before {
213
+ content: '\\ea04';
214
+ }
215
+ }
216
+
217
+ &.ext-mp4,
218
+ &.ext-mkv,
219
+ &.ext-avi,
220
+ &.ext-mov,
221
+ &.ext-wmv,
222
+ &.ext-flv {
223
+ &::before {
224
+ content: '\\ea05';
225
+ }
226
+ }
227
+
228
+ &.ext-txt,
229
+ &.ext-text,
230
+ &.ext-md,
231
+ &.ext-markdown {
232
+ &::before {
233
+ content: '\\ea06';
234
+ }
235
+ }
236
+
237
+ &.ext-js,
238
+ &.ext-ts,
239
+ &.ext-jsx,
240
+ &.ext-tsx,
241
+ &.ext-json,
242
+ &.ext-yaml,
243
+ &.ext-yml,
244
+ &.ext-xml,
245
+ &.ext-html,
246
+ &.ext-css,
247
+ &.ext-scss,
248
+ &.ext-less,
249
+ &.ext-sass,
250
+ &.ext-java,
251
+ &.ext-c,
252
+ &.ext-cpp,
253
+ &.ext-cs,
254
+ &.ext-php,
255
+ &.ext-py,
256
+ &.ext-rb,
257
+ &.ext-go,
258
+ &.ext-swift,
259
+ &.ext-sql,
260
+ &.ext-perl,
261
+ &.ext-lua,
262
+ &.ext-scala,
263
+ &.ext-sh {
264
+ &::before {
265
+ content: '\\ea07';
266
+ }
267
+ }
268
+
269
+ &.ext-zip,
270
+ &.ext-rar,
271
+ &.ext-tar,
272
+ &.ext-gz,
273
+ &.ext-iso {
274
+ &::before {
275
+ content: '\\ea08';
276
+ }
277
+ }
278
+
279
+ &.ext-pdf,
280
+ &.ext-PDF {
281
+ &::before {
282
+ content: '\\ea09';
283
+ }
284
+ }
285
+
286
+ &.ext-excel,
287
+ &.ext-xls,
288
+ &.ext-xlsx {
289
+ &::before {
290
+ content: '\\ea0a';
291
+ }
292
+ }
293
+
294
+ &.ext-powerpoint,
295
+ &.ext-ppt,
296
+ &.ext-pptx {
297
+ &::before {
298
+ content: '\\ea0b';
299
+ }
300
+ }
301
+
302
+ &.ext-doc,
303
+ &.ext-docx,
304
+ &.ext-rtf {
305
+ &::before {
306
+ content: '\\ea0c';
307
+ }
308
+ }
134
309
  }
135
310
 
136
311
  ${generateCodeBlockTokens()}
@@ -138,9 +313,9 @@ const CodeBlockContainerComponent = styled.pre<CodeBlockContainerProps>`
138
313
  ${({ hideCodeColors }) =>
139
314
  hideCodeColors &&
140
315
  css`
141
- .code-line:not(.highlighted),
142
- .code-line:not(.highlighted) > span,
143
- .code-line:not(.highlighted) > span > span {
316
+ .line-number:not(.highlighted),
317
+ .line-number:not(.highlighted) > span,
318
+ .line-number:not(.highlighted) > span > span {
144
319
  color: grey;
145
320
  }
146
321
  `}
@@ -1,6 +1,30 @@
1
1
  import { css } from 'styled-components';
2
2
 
3
3
  export const code = css`
4
+ /**
5
+ * Tree view icons font
6
+ */
7
+ @font-face {
8
+ font-family: 'TreeViewIcons';
9
+ /**
10
+ * Use the following escape sequences to refer to a specific icon:
11
+ *
12
+ * - \\ea01 file
13
+ * - \\ea02 folder
14
+ * - \\ea03 image
15
+ * - \\ea04 audio
16
+ * - \\ea05 video
17
+ * - \\ea06 text
18
+ * - \\ea07 code
19
+ * - \\ea08 archive
20
+ * - \\ea09 pdf
21
+ * - \\ea0a excel
22
+ * - \\ea0b powerpoint
23
+ * - \\ea0c word
24
+ */
25
+ src: url('data:application/font-woff;base64,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') format('woff');
26
+ }
27
+
4
28
  /**
5
29
  * @tokens Code base styles
6
30
  */
@@ -83,10 +107,29 @@ export const code = css`
83
107
  --code-block-tokens-atrule-color: var(--code-block-tokens-keyword-color); // @presenter Color
84
108
  --code-block-tokens-attr-value-color: var(--code-block-tokens-keyword-color); // @presenter Color
85
109
  --code-block-tokens-regex-color: var(--color-carrot-7); // @presenter Color
110
+ --code-block-tokens-regex-char-escape-color: var(--color-grass-8); // @presenter Color
86
111
  --code-block-tokens-important-color: var(--code-block-tokens-regex-color); // @presenter Color
87
112
  --code-block-tokens-deleted-color: var(--color-red-7); // @presenter Color
88
113
  --code-block-tokens-class-name-color: var(--color-carrot-7); // @presenter Color
89
114
  --code-block-tokens-function-color: var(--color-carrot-7); // @presenter Color
115
+ --code-block-tokens-invalid-color: var(--color-orange-8); // @presenter Color
116
+ --code-block-tokens-message-error-color: var(--code-block-tokens-invalid-color); // @presenter Color
117
+ --code-block-tokens-unmatched-color: var(--code-block-tokens-invalid-color); // @presenter Color
118
+ --code-block-tokens-markup-bg-color: var(--color-grass-1); // @presenter Color
119
+ --code-block-tokens-markup-foreground-color: var(--color-grass-8); // @presenter Color
120
+ --code-block-tokens-markup-changed-color: var(--color-carrot-1); // @presenter Color
121
+ --code-block-tokens-markup-deleted-color: var(--color-magenta-1); // @presenter Color
122
+ --code-block-tokens-markup-quote-color: var(--color-grass-8); // @presenter Color
123
+ --code-block-tokens-markup-ignored-color: var(--color-blue-1); // @presenter Color
124
+ --code-block-tokens-warm-bg-color: var(--color-warm-grey-2); // @presenter Color
125
+ --code-block-tokens-warm-foreground-color: var(--color-warm-grey-8); // @presenter Color
126
+ --code-block-tokens-meta-diff-range-color: var(--color-purple-8); // @presenter Color
127
+
128
+ /**
129
+ * @tokens Code Block tree view
130
+ */
131
+ --code-block-tree-view-icon-font-family: 'TreeViewIcons'; // @presenter FontFamily
132
+ --code-block-tree-view-lines-color: var(--border-color-primary); // @presenter Color
90
133
 
91
134
  // @tokens End
92
135
  `;
@@ -19,7 +19,7 @@ export type LinkProps = {
19
19
  export function Link(props: React.PropsWithChildren<LinkProps>): JSX.Element {
20
20
  const context = useContext(ThemeDataContext);
21
21
 
22
- if (context) {
22
+ if (context?.components) {
23
23
  const { LinkComponent } = context.components;
24
24
  return <LinkComponent {...props} />;
25
25
  } else {
@@ -10,7 +10,7 @@ export function useThemeConfig<T extends Record<string, unknown>>(
10
10
  ): T & NonNullable<UiAccessibleConfig> {
11
11
  const context = useContext(ThemeDataContext);
12
12
 
13
- if (!context) {
13
+ if (!context?.config) {
14
14
  return {} as T;
15
15
  }
16
16
  const { config, hooks } = context;
@@ -12,6 +12,7 @@ const fallbacks = {
12
12
  useSubmitFeedback: () => ({ submitFeedback: () => {} }),
13
13
  useTelemetry: () => ({ telemetry: () => {} }),
14
14
  useBreadcrumbs: () => [],
15
+ useCodeHighlight: () => ({ highlight: (rawContent: string) => rawContent }),
15
16
  };
16
17
 
17
18
  export const useThemeHooks = () => {
@@ -110,6 +110,17 @@ export type ThemeHooks = {
110
110
  useTelemetry: () => { send(action: TelemetryEvent, data: unknown): void };
111
111
  useUserTeams: () => string[];
112
112
  usePageProps: <T extends Record<string, unknown>>() => PageProps & T;
113
+ useCodeHighlight: () => {
114
+ highlight: (
115
+ code: string,
116
+ language?: string | undefined,
117
+ highlightOptions?: {
118
+ withLineNumbers?: boolean;
119
+ startLineNumber?: number;
120
+ highlight?: string;
121
+ },
122
+ ) => string;
123
+ };
113
124
  };
114
125
 
115
126
  export type L10nConfig = {
@@ -0,0 +1,16 @@
1
+ const NEW_LINE_EXP = /\n(?!$)/g;
2
+
3
+ /**
4
+ * @param highlightedCode - A string with new line breaks; the line numbers will be added before each line.
5
+ * @param start - The number to start the line numbering from; default is 1
6
+ * @returns A string with line numbers added before each line
7
+ */
8
+ export function addLineNumbers(highlightedCode: string, start = 1): string {
9
+ const codeLines = highlightedCode.split(NEW_LINE_EXP);
10
+
11
+ return codeLines
12
+ .map((line, i) => {
13
+ return `<span class='line' data-line-number='${start + i}'>${line}</span>`;
14
+ })
15
+ .join('\n');
16
+ }
@@ -1,6 +1,6 @@
1
1
  export * from '@redocly/theme/core/utils/clipboard-service';
2
2
  export * from '@redocly/theme/core/utils/css-variables';
3
- export * from '@redocly/theme/core/utils/highlight';
3
+ export * from '@redocly/theme/core/utils/add-line-numbers';
4
4
  export * from '@redocly/theme/core/utils/media-css';
5
5
  export * from '@redocly/theme/core/utils/theme-helpers';
6
6
  export * from '@redocly/theme/core/utils/class-names';
@@ -12,6 +12,7 @@ export type CardProps = React.PropsWithChildren<{
12
12
  icon?: string;
13
13
  iconRawContent?: string;
14
14
  imagePosition?: 'start' | 'end';
15
+ iconPosition?: 'auto' | 'start' | 'center' | 'end';
15
16
  lineClamp?: number;
16
17
  layout?: 'horizontal' | 'vertical' | 'combined';
17
18
  variant?: 'filled' | 'outlined' | 'elevated' | 'ghost';
@@ -26,6 +27,7 @@ export function Card({
26
27
  icon,
27
28
  iconRawContent,
28
29
  imagePosition = 'start',
30
+ iconPosition = 'auto',
29
31
  layout = 'vertical',
30
32
  variant = 'filled',
31
33
  lineClamp,
@@ -59,7 +61,14 @@ export function Card({
59
61
  $textAlign={textAlign}
60
62
  $hasImage={image !== undefined}
61
63
  >
62
- {icon && <CardIcon variant={iconVariant} src={icon} rawContent={iconRawContent} />}
64
+ {icon && (
65
+ <CardIcon
66
+ variant={iconVariant}
67
+ src={icon}
68
+ rawContent={iconRawContent}
69
+ position={iconPosition}
70
+ />
71
+ )}
63
72
  <ContentWrapper>
64
73
  <Title id={cardTitleId} $isCardLink={!!to} $justifyContent={justifyContent}>
65
74
  {title}
@@ -7,11 +7,12 @@ export type CardIconProps = {
7
7
  variant?: string;
8
8
  src: string;
9
9
  rawContent?: string;
10
+ position?: 'auto' | 'start' | 'center' | 'end';
10
11
  };
11
12
 
12
- export function CardIcon({ variant, src, rawContent }: CardIconProps) {
13
+ export function CardIcon({ variant, src, rawContent, position }: CardIconProps) {
13
14
  return (
14
- <CardIconWrapper $variant={variant}>
15
+ <CardIconWrapper $variant={variant} $position={position}>
15
16
  {rawContent ? <CardSvg fileRawContent={rawContent} /> : <CardImg src={src} />}
16
17
  </CardIconWrapper>
17
18
  );
@@ -36,9 +37,9 @@ const CardSvg = styled(InlineSvg)`
36
37
  }
37
38
  `;
38
39
 
39
- const CardIconWrapper = styled.div<{ $variant?: string }>`
40
+ const CardIconWrapper = styled.div<{ $variant?: string; $position?: string }>`
40
41
  display: flex;
41
- align-items: center;
42
+ align-self: ${({ $position }) => ($position ? $position : 'auto')};
42
43
  justify-content: center;
43
44
  min-width: var(--card-icon-width);
44
45
  min-height: var(--card-icon-height);