@chayns-components/code-highlighter 5.5.4 → 5.5.8

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 (28) hide show
  1. package/AGENTS.md +37 -0
  2. package/lib/cjs/components/code-highlighter/CodeHighlighter.js +39 -23
  3. package/lib/cjs/components/code-highlighter/CodeHighlighter.js.map +1 -1
  4. package/lib/cjs/components/code-highlighter/CodeHighlighter.styles.js +9 -7
  5. package/lib/cjs/components/code-highlighter/CodeHighlighter.styles.js.map +1 -1
  6. package/lib/cjs/components/code-highlighter/CodeHighlighter.test.js +78 -0
  7. package/lib/cjs/components/code-highlighter/CodeHighlighter.test.js.map +1 -0
  8. package/lib/cjs/components/code-highlighter/copy-to-clipboard/CopyToClipboard.js +77 -24
  9. package/lib/cjs/components/code-highlighter/copy-to-clipboard/CopyToClipboard.js.map +1 -1
  10. package/lib/cjs/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.js +86 -2
  11. package/lib/cjs/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.js.map +1 -1
  12. package/lib/cjs/constants/textStrings.js +12 -0
  13. package/lib/cjs/constants/textStrings.js.map +1 -1
  14. package/lib/esm/components/code-highlighter/CodeHighlighter.js +40 -24
  15. package/lib/esm/components/code-highlighter/CodeHighlighter.js.map +1 -1
  16. package/lib/esm/components/code-highlighter/CodeHighlighter.styles.js +9 -7
  17. package/lib/esm/components/code-highlighter/CodeHighlighter.styles.js.map +1 -1
  18. package/lib/esm/components/code-highlighter/CodeHighlighter.test.js +74 -0
  19. package/lib/esm/components/code-highlighter/CodeHighlighter.test.js.map +1 -0
  20. package/lib/esm/components/code-highlighter/copy-to-clipboard/CopyToClipboard.js +77 -26
  21. package/lib/esm/components/code-highlighter/copy-to-clipboard/CopyToClipboard.js.map +1 -1
  22. package/lib/esm/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.js +85 -1
  23. package/lib/esm/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.js.map +1 -1
  24. package/lib/esm/constants/textStrings.js +12 -0
  25. package/lib/esm/constants/textStrings.js.map +1 -1
  26. package/lib/types/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.d.ts +21 -1
  27. package/lib/types/constants/textStrings.d.ts +12 -0
  28. package/package.json +11 -6
@@ -3,13 +3,97 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.StyledCopyToClipboardText = exports.StyledCopyToClipboard = void 0;
6
+ exports.StyledCopyToClipboardText = exports.StyledCopyToClipboardButton = exports.StyledCopyToClipboardActionGroup = exports.StyledCopyToClipboard = void 0;
7
7
  var _styledComponents = _interopRequireDefault(require("styled-components"));
8
8
  var _codeHighlighter = require("../../../types/codeHighlighter");
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
10
  const StyledCopyToClipboard = exports.StyledCopyToClipboard = _styledComponents.default.div`
11
+ position: sticky;
12
+ top: var(--code-highlighter-action-inset);
13
+ z-index: 1;
11
14
  display: flex;
12
- align-items: center;
15
+ justify-content: flex-end;
16
+ height: calc(var(--code-highlighter-action-size) + var(--code-highlighter-action-inset));
17
+ margin-top: calc(
18
+ (var(--code-highlighter-action-size) + var(--code-highlighter-action-inset)) * -1
19
+ );
20
+ padding-right: var(--code-highlighter-action-inset);
21
+ `;
22
+ const getActionGroupBorder = ({
23
+ $codeTheme,
24
+ $isSticky
25
+ }) => {
26
+ if (!$isSticky) {
27
+ return 'transparent';
28
+ }
29
+ return $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#5a6474' : '#d4d4d4';
30
+ };
31
+ const getActionGroupBackground = ({
32
+ $codeTheme,
33
+ $isSticky
34
+ }) => {
35
+ if (!$isSticky) {
36
+ return 'transparent';
37
+ }
38
+ return $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#343a46' : '#fafafa';
39
+ };
40
+ const getButtonHoverBackground = ({
41
+ $codeTheme
42
+ }) => $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#454c59' : 'rgba(128, 128, 128, 0.2)';
43
+ const getButtonActiveBackground = ({
44
+ $codeTheme
45
+ }) => $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#545d6d' : 'rgba(128, 128, 128, 0.3)';
46
+ const getButtonHoverBorder = ({
47
+ $codeTheme
48
+ }) => $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#6a7485' : '#c2c2c2';
49
+ const getButtonShadow = ({
50
+ $isSticky
51
+ }) => $isSticky ? '0 2px 8px rgba(0, 0, 0, 0.28)' : 'none';
52
+ const getButtonHoverShadow = ({
53
+ $isSticky
54
+ }) => {
55
+ const insetShadow = 'inset 0 0 0 1px rgba(255, 255, 255, 0.08)';
56
+ return $isSticky ? `0 2px 8px rgba(0, 0, 0, 0.32), ${insetShadow}` : insetShadow;
57
+ };
58
+ const StyledCopyToClipboardActionGroup = exports.StyledCopyToClipboardActionGroup = _styledComponents.default.div`
59
+ display: flex;
60
+ gap: 4px;
61
+ height: var(--code-highlighter-action-size);
62
+ `;
63
+ const StyledCopyToClipboardButton = exports.StyledCopyToClipboardButton = _styledComponents.default.button`
64
+ box-sizing: border-box;
65
+ border: 1px solid ${getActionGroupBorder};
66
+ border-radius: 4px;
67
+ width: var(--code-highlighter-action-size);
68
+ height: var(--code-highlighter-action-size);
69
+ padding: 0;
70
+ cursor: pointer;
71
+ background-color: ${getActionGroupBackground};
72
+ color: ${({
73
+ $codeTheme
74
+ }) => $codeTheme === _codeHighlighter.CodeHighlighterTheme.Dark ? '#f4f6f8' : '#999999'};
75
+ box-shadow: ${getButtonShadow};
76
+ transition:
77
+ background-color 0.15s ease,
78
+ border-color 0.15s ease,
79
+ box-shadow 0.15s ease,
80
+ transform 0.15s ease;
81
+
82
+ &:hover {
83
+ border-color: ${getButtonHoverBorder};
84
+ background-color: ${getButtonHoverBackground};
85
+ box-shadow: ${getButtonHoverShadow};
86
+ }
87
+
88
+ &:active {
89
+ background-color: ${getButtonActiveBackground};
90
+ transform: scale(0.94);
91
+ }
92
+
93
+ &:focus-visible {
94
+ outline: 2px solid currentColor;
95
+ outline-offset: 2px;
96
+ }
13
97
  `;
14
98
  const StyledCopyToClipboardText = exports.StyledCopyToClipboardText = _styledComponents.default.span`
15
99
  color: ${({
@@ -1 +1 @@
1
- {"version":3,"file":"CopyToClipboard.styles.js","names":["_styledComponents","_interopRequireDefault","require","_codeHighlighter","e","__esModule","default","StyledCopyToClipboard","exports","styled","div","StyledCopyToClipboardText","span","$codeTheme","CodeHighlighterTheme","Dark"],"sources":["../../../../../src/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\nimport { CodeHighlighterTheme } from '../../../types/codeHighlighter';\n\nexport const StyledCopyToClipboard = styled.div`\n display: flex;\n align-items: center;\n`;\n\ntype StyledCopyToClipboardTextProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\nexport const StyledCopyToClipboardText = styled.span<StyledCopyToClipboardTextProps>`\n color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'};\n font-size: small;\n margin-left: 4px;\n`;\n"],"mappings":";;;;;;AACA,IAAAA,iBAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AAAsE,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE/D,MAAMG,qBAAqB,GAAAC,OAAA,CAAAD,qBAAA,GAAGE,yBAAM,CAACC,GAAG;AAC/C;AACA;AACA,CAAC;AAKM,MAAMC,yBAAyB,GAAAH,OAAA,CAAAG,yBAAA,GAAGF,yBAAM,CAACG,IAAoC;AACpF,aAAa,CAAC;EAAEC;AAAW,CAAC,KACpBA,UAAU,KAAKC,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE;AACA;AACA,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"CopyToClipboard.styles.js","names":["_styledComponents","_interopRequireDefault","require","_codeHighlighter","e","__esModule","default","StyledCopyToClipboard","exports","styled","div","getActionGroupBorder","$codeTheme","$isSticky","CodeHighlighterTheme","Dark","getActionGroupBackground","getButtonHoverBackground","getButtonActiveBackground","getButtonHoverBorder","getButtonShadow","getButtonHoverShadow","insetShadow","StyledCopyToClipboardActionGroup","StyledCopyToClipboardButton","button","StyledCopyToClipboardText","span"],"sources":["../../../../../src/components/code-highlighter/copy-to-clipboard/CopyToClipboard.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\nimport { CodeHighlighterTheme } from '../../../types/codeHighlighter';\n\ntype StyledCopyToClipboardProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\n\nexport const StyledCopyToClipboard = styled.div<StyledCopyToClipboardProps>`\n position: sticky;\n top: var(--code-highlighter-action-inset);\n z-index: 1;\n display: flex;\n justify-content: flex-end;\n height: calc(var(--code-highlighter-action-size) + var(--code-highlighter-action-inset));\n margin-top: calc(\n (var(--code-highlighter-action-size) + var(--code-highlighter-action-inset)) * -1\n );\n padding-right: var(--code-highlighter-action-inset);\n`;\n\ntype StyledCopyToClipboardButtonProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n $isSticky: boolean;\n}>;\n\nconst getActionGroupBorder = ({ $codeTheme, $isSticky }: StyledCopyToClipboardButtonProps) => {\n if (!$isSticky) {\n return 'transparent';\n }\n\n return $codeTheme === CodeHighlighterTheme.Dark ? '#5a6474' : '#d4d4d4';\n};\n\nconst getActionGroupBackground = ({ $codeTheme, $isSticky }: StyledCopyToClipboardButtonProps) => {\n if (!$isSticky) {\n return 'transparent';\n }\n\n return $codeTheme === CodeHighlighterTheme.Dark ? '#343a46' : '#fafafa';\n};\n\nconst getButtonHoverBackground = ({ $codeTheme }: StyledCopyToClipboardButtonProps) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#454c59' : 'rgba(128, 128, 128, 0.2)';\n\nconst getButtonActiveBackground = ({ $codeTheme }: StyledCopyToClipboardButtonProps) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#545d6d' : 'rgba(128, 128, 128, 0.3)';\n\nconst getButtonHoverBorder = ({ $codeTheme }: StyledCopyToClipboardButtonProps) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#6a7485' : '#c2c2c2';\n\nconst getButtonShadow = ({ $isSticky }: StyledCopyToClipboardButtonProps) =>\n $isSticky ? '0 2px 8px rgba(0, 0, 0, 0.28)' : 'none';\n\nconst getButtonHoverShadow = ({ $isSticky }: StyledCopyToClipboardButtonProps) => {\n const insetShadow = 'inset 0 0 0 1px rgba(255, 255, 255, 0.08)';\n\n return $isSticky ? `0 2px 8px rgba(0, 0, 0, 0.32), ${insetShadow}` : insetShadow;\n};\n\nexport const StyledCopyToClipboardActionGroup = styled.div`\n display: flex;\n gap: 4px;\n height: var(--code-highlighter-action-size);\n`;\n\nexport const StyledCopyToClipboardButton = styled.button<StyledCopyToClipboardButtonProps>`\n box-sizing: border-box;\n border: 1px solid ${getActionGroupBorder};\n border-radius: 4px;\n width: var(--code-highlighter-action-size);\n height: var(--code-highlighter-action-size);\n padding: 0;\n cursor: pointer;\n background-color: ${getActionGroupBackground};\n color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#f4f6f8' : '#999999'};\n box-shadow: ${getButtonShadow};\n transition:\n background-color 0.15s ease,\n border-color 0.15s ease,\n box-shadow 0.15s ease,\n transform 0.15s ease;\n\n &:hover {\n border-color: ${getButtonHoverBorder};\n background-color: ${getButtonHoverBackground};\n box-shadow: ${getButtonHoverShadow};\n }\n\n &:active {\n background-color: ${getButtonActiveBackground};\n transform: scale(0.94);\n }\n\n &:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n }\n`;\n\ntype StyledCopyToClipboardTextProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\nexport const StyledCopyToClipboardText = styled.span<StyledCopyToClipboardTextProps>`\n color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'};\n font-size: small;\n margin-left: 4px;\n`;\n"],"mappings":";;;;;;AACA,IAAAA,iBAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AAAsE,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAM/D,MAAMG,qBAAqB,GAAAC,OAAA,CAAAD,qBAAA,GAAGE,yBAAM,CAACC,GAA+B;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAOD,MAAMC,oBAAoB,GAAGA,CAAC;EAAEC,UAAU;EAAEC;AAA4C,CAAC,KAAK;EAC1F,IAAI,CAACA,SAAS,EAAE;IACZ,OAAO,aAAa;EACxB;EAEA,OAAOD,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AAC3E,CAAC;AAED,MAAMC,wBAAwB,GAAGA,CAAC;EAAEJ,UAAU;EAAEC;AAA4C,CAAC,KAAK;EAC9F,IAAI,CAACA,SAAS,EAAE;IACZ,OAAO,aAAa;EACxB;EAEA,OAAOD,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AAC3E,CAAC;AAED,MAAME,wBAAwB,GAAGA,CAAC;EAAEL;AAA6C,CAAC,KAC9EA,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,0BAA0B;AAErF,MAAMG,yBAAyB,GAAGA,CAAC;EAAEN;AAA6C,CAAC,KAC/EA,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,0BAA0B;AAErF,MAAMI,oBAAoB,GAAGA,CAAC;EAAEP;AAA6C,CAAC,KAC1EA,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AAEpE,MAAMK,eAAe,GAAGA,CAAC;EAAEP;AAA4C,CAAC,KACpEA,SAAS,GAAG,+BAA+B,GAAG,MAAM;AAExD,MAAMQ,oBAAoB,GAAGA,CAAC;EAAER;AAA4C,CAAC,KAAK;EAC9E,MAAMS,WAAW,GAAG,2CAA2C;EAE/D,OAAOT,SAAS,GAAG,kCAAkCS,WAAW,EAAE,GAAGA,WAAW;AACpF,CAAC;AAEM,MAAMC,gCAAgC,GAAAf,OAAA,CAAAe,gCAAA,GAAGd,yBAAM,CAACC,GAAG;AAC1D;AACA;AACA;AACA,CAAC;AAEM,MAAMc,2BAA2B,GAAAhB,OAAA,CAAAgB,2BAAA,GAAGf,yBAAM,CAACgB,MAAwC;AAC1F;AACA,wBAAwBd,oBAAoB;AAC5C;AACA;AACA;AACA;AACA;AACA,wBAAwBK,wBAAwB;AAChD,aAAa,CAAC;EAAEJ;AAAW,CAAC,KACpBA,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE,kBAAkBK,eAAe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwBD,oBAAoB;AAC5C,4BAA4BF,wBAAwB;AACpD,sBAAsBI,oBAAoB;AAC1C;AACA;AACA;AACA,4BAA4BH,yBAAyB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAKM,MAAMQ,yBAAyB,GAAAlB,OAAA,CAAAkB,yBAAA,GAAGjB,yBAAM,CAACkB,IAAoC;AACpF,aAAa,CAAC;EAAEf;AAAW,CAAC,KACpBA,UAAU,KAAKE,qCAAoB,CAACC,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE;AACA;AACA,CAAC","ignoreList":[]}
@@ -8,9 +8,21 @@ var _default = exports.default = {
8
8
  components: {
9
9
  codeHighlighter: {
10
10
  copyToClipboard: {
11
+ copy: {
12
+ stringName: 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copy',
13
+ fallback: 'Kopieren'
14
+ },
11
15
  copied: {
12
16
  stringName: 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copied',
13
17
  fallback: 'Kopiert!'
18
+ },
19
+ copyFailed: {
20
+ stringName: 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copyFailed',
21
+ fallback: 'Kopieren fehlgeschlagen'
22
+ },
23
+ share: {
24
+ stringName: 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_share',
25
+ fallback: 'Teilen'
14
26
  }
15
27
  }
16
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"textStrings.js","names":["components","codeHighlighter","copyToClipboard","copied","stringName","fallback"],"sources":["../../../src/constants/textStrings.ts"],"sourcesContent":["export default {\n components: {\n codeHighlighter: {\n copyToClipboard: {\n copied: {\n stringName:\n 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copied',\n fallback: 'Kopiert!',\n },\n },\n },\n },\n} as const;\n"],"mappings":";;;;;;iCAAe;EACXA,UAAU,EAAE;IACRC,eAAe,EAAE;MACbC,eAAe,EAAE;QACbC,MAAM,EAAE;UACJC,UAAU,EACN,0FAA0F;UAC9FC,QAAQ,EAAE;QACd;MACJ;IACJ;EACJ;AACJ,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"textStrings.js","names":["components","codeHighlighter","copyToClipboard","copy","stringName","fallback","copied","copyFailed","share"],"sources":["../../../src/constants/textStrings.ts"],"sourcesContent":["export default {\n components: {\n codeHighlighter: {\n copyToClipboard: {\n copy: {\n stringName:\n 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copy',\n fallback: 'Kopieren',\n },\n copied: {\n stringName:\n 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copied',\n fallback: 'Kopiert!',\n },\n copyFailed: {\n stringName:\n 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_copyFailed',\n fallback: 'Kopieren fehlgeschlagen',\n },\n share: {\n stringName:\n 'txt_chayns_components_code_highlighter_components_codeHighlighter_copyToClipboard_share',\n fallback: 'Teilen',\n },\n },\n },\n },\n} as const;\n"],"mappings":";;;;;;iCAAe;EACXA,UAAU,EAAE;IACRC,eAAe,EAAE;MACbC,eAAe,EAAE;QACbC,IAAI,EAAE;UACFC,UAAU,EACN,wFAAwF;UAC5FC,QAAQ,EAAE;QACd,CAAC;QACDC,MAAM,EAAE;UACJF,UAAU,EACN,0FAA0F;UAC9FC,QAAQ,EAAE;QACd,CAAC;QACDE,UAAU,EAAE;UACRH,UAAU,EACN,8FAA8F;UAClGC,QAAQ,EAAE;QACd,CAAC;QACDG,KAAK,EAAE;UACHJ,UAAU,EACN,yFAAyF;UAC7FC,QAAQ,EAAE;QACd;MACJ;IACJ;EACJ;AACJ,CAAC","ignoreList":[]}
@@ -1,7 +1,8 @@
1
1
  import { format } from 'prettier/standalone';
2
2
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter';
3
+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
4
4
  import { oneDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
5
+ import { useColorScheme } from '@chayns-components/core';
5
6
  import { CodeHighlighterTheme } from '../../types/codeHighlighter';
6
7
  import { formatLanguage, getParserForLanguage } from '../../utils/codeHighlighter';
7
8
  import { StyledCodeHighlighter, StyledCodeHighlighterFileName, StyledCodeHighlighterHeader } from './CodeHighlighter.styles';
@@ -16,7 +17,7 @@ const addScrollbarClassToPre = ({
16
17
  preElement.classList.add(className);
17
18
  };
18
19
  const CodeHighlighter = ({
19
- theme = CodeHighlighterTheme.Dark,
20
+ theme,
20
21
  code,
21
22
  copyButtonText,
22
23
  language,
@@ -26,8 +27,11 @@ const CodeHighlighter = ({
26
27
  shouldShowLineNumbers = false,
27
28
  shouldWrapLines
28
29
  }) => {
30
+ const colorScheme = useColorScheme();
29
31
  const [width, setWidth] = useState(0);
32
+ const [formattedCode, setFormattedCode] = useState(code);
30
33
  const ref = useRef(null);
34
+ const resolvedTheme = theme ?? (colorScheme?.theme.colorMode === 'dark' ? CodeHighlighterTheme.Dark : CodeHighlighterTheme.Light);
31
35
  useEffect(() => {
32
36
  addScrollbarClassToPre({
33
37
  root: ref.current,
@@ -86,21 +90,32 @@ const CodeHighlighter = ({
86
90
  const lineNumberStyle = useMemo(() => ({
87
91
  WebkitUserSelect: 'none'
88
92
  }), []);
89
- const formattedCode = useMemo(() => {
90
- if (language) {
91
- void getParserForLanguage(language).then(config => {
92
- if (shouldFormatCode && config) {
93
- try {
94
- return format(code, config);
95
- } catch (error) {
96
- if (typeof onFormatError !== 'undefined') onFormatError(error);
97
- }
98
- }
99
- return code;
100
- });
93
+ const syntaxHighlighterStyle = useMemo(() => ({
94
+ padding: '0 15px 15px'
95
+ }), []);
96
+ useEffect(() => {
97
+ let isCurrent = true;
98
+ if (!shouldFormatCode) {
99
+ setFormattedCode(code);
100
+ return () => {
101
+ isCurrent = false;
102
+ };
101
103
  }
102
- return code;
103
- }, [code, language, shouldFormatCode, onFormatError]);
104
+ void getParserForLanguage(language).then(config => {
105
+ if (!config || !isCurrent) {
106
+ return;
107
+ }
108
+ try {
109
+ setFormattedCode(format(code, config));
110
+ } catch (error) {
111
+ onFormatError?.(error);
112
+ setFormattedCode(code);
113
+ }
114
+ });
115
+ return () => {
116
+ isCurrent = false;
117
+ };
118
+ }, [code, language, onFormatError, shouldFormatCode]);
104
119
  useEffect(() => {
105
120
  const elements = document.getElementsByClassName('linenumber');
106
121
  Array.from(elements).forEach(element => {
@@ -113,25 +128,26 @@ const CodeHighlighter = ({
113
128
  }, []);
114
129
  return useMemo(() => /*#__PURE__*/React.createElement(StyledCodeHighlighter, {
115
130
  $shouldWrapLines: shouldWrapLines,
116
- $codeTheme: theme,
131
+ $codeTheme: resolvedTheme,
117
132
  ref: ref
118
133
  }, /*#__PURE__*/React.createElement(StyledCodeHighlighterHeader, {
119
- $codeTheme: theme
134
+ $codeTheme: resolvedTheme
120
135
  }, /*#__PURE__*/React.createElement(StyledCodeHighlighterFileName, {
121
- $codeTheme: theme
122
- }, /*#__PURE__*/React.createElement("tw-ignore", null, formatLanguage(language))), /*#__PURE__*/React.createElement(CopyToClipboard, {
136
+ $codeTheme: resolvedTheme
137
+ }, /*#__PURE__*/React.createElement("tw-ignore", null, formatLanguage(language)))), /*#__PURE__*/React.createElement(CopyToClipboard, {
123
138
  text: code,
124
- theme: theme,
139
+ theme: resolvedTheme,
125
140
  copyButtonText: copyButtonText
126
- })), /*#__PURE__*/React.createElement(SyntaxHighlighter, {
141
+ }), /*#__PURE__*/React.createElement(SyntaxHighlighter, {
142
+ customStyle: syntaxHighlighterStyle,
127
143
  language: language ?? '',
128
144
  lineNumberStyle: lineNumberStyle,
129
145
  showLineNumbers: shouldShowLineNumbers,
130
- style: theme === CodeHighlighterTheme.Dark ? oneDark : oneLight,
146
+ style: resolvedTheme === CodeHighlighterTheme.Dark ? oneDark : oneLight,
131
147
  wrapLines: true,
132
148
  wrapLongLines: shouldWrapLines,
133
149
  lineProps: lineWrapper
134
- }, formattedCode)), [shouldWrapLines, theme, language, code, copyButtonText, lineNumberStyle, shouldShowLineNumbers, lineWrapper, formattedCode]);
150
+ }, formattedCode)), [shouldWrapLines, resolvedTheme, language, code, copyButtonText, lineNumberStyle, syntaxHighlighterStyle, shouldShowLineNumbers, lineWrapper, formattedCode]);
135
151
  };
136
152
  CodeHighlighter.displayName = 'CodeHighlighter';
137
153
  export default CodeHighlighter;
@@ -1 +1 @@
1
- {"version":3,"file":"CodeHighlighter.js","names":["format","React","useCallback","useEffect","useMemo","useRef","useState","PrismAsyncLight","SyntaxHighlighter","oneDark","oneLight","CodeHighlighterTheme","formatLanguage","getParserForLanguage","StyledCodeHighlighter","StyledCodeHighlighterFileName","StyledCodeHighlighterHeader","CopyToClipboard","addScrollbarClassToPre","root","className","preElement","querySelector","classList","add","CodeHighlighter","theme","Dark","code","copyButtonText","language","highlightedLines","shouldFormatCode","onFormatError","shouldShowLineNumbers","shouldWrapLines","width","setWidth","ref","current","handleResize","children","Array","from","find","tagName","toLowerCase","scrollWidth","window","addEventListener","removeEventListener","lineWrapper","lineNumber","style","backgroundColor","display","borderRadius","added","includes","removed","marked","lineNumberStyle","WebkitUserSelect","formattedCode","then","config","error","elements","document","getElementsByClassName","forEach","element","wrapper","createElement","firstChild","appendChild","$shouldWrapLines","$codeTheme","text","showLineNumbers","wrapLines","wrapLongLines","lineProps","displayName"],"sources":["../../../../src/components/code-highlighter/CodeHighlighter.tsx"],"sourcesContent":["import { format } from 'prettier/standalone';\nimport React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { oneDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport {\n CodeHighlighterLanguage,\n CodeHighlighterTheme,\n HighlightedLines,\n} from '../../types/codeHighlighter';\nimport { formatLanguage, getParserForLanguage } from '../../utils/codeHighlighter';\nimport {\n StyledCodeHighlighter,\n StyledCodeHighlighterFileName,\n StyledCodeHighlighterHeader,\n} from './CodeHighlighter.styles';\nimport CopyToClipboard from './copy-to-clipboard/CopyToClipboard';\n\ntype AddScrollbarClassOptions = {\n root: HTMLDivElement | null;\n className: string;\n};\n\nconst addScrollbarClassToPre = ({ root, className }: AddScrollbarClassOptions) => {\n if (!root) return;\n\n const preElement = root.querySelector('pre');\n if (!preElement) return;\n\n preElement.classList.add(className);\n};\n\nexport type CodeHighlighterProps = {\n /**\n * The code that should be displayed.\n */\n code: string;\n /**\n * The text that should be displayed after the copy button.\n * If not set, just the button is displayed without text.\n */\n copyButtonText?: string;\n /**\n * The lines of code that should be highlighted.\n * Following lines can be highlighted: added, removed and just marked.\n */\n highlightedLines?: HighlightedLines;\n /**\n * The language of the displayed code.\n */\n language: CodeHighlighterLanguage;\n /**\n * Function to be executed when the formatting of the code fails.\n */\n onFormatError?: (error: unknown) => void;\n /**\n * Whether the code should be formatted with prettier.\n */\n shouldFormatCode?: boolean;\n /**\n * Whether the line numbers should be displayed.\n */\n shouldShowLineNumbers?: boolean;\n /**\n * Whether long lines should be wrapped.\n */\n shouldWrapLines?: boolean;\n /**\n * The theme of the code block. Decide between dark and light.\n */\n theme?: CodeHighlighterTheme;\n};\n\nconst CodeHighlighter: FC<CodeHighlighterProps> = ({\n theme = CodeHighlighterTheme.Dark,\n code,\n copyButtonText,\n language,\n highlightedLines,\n shouldFormatCode = false,\n onFormatError,\n shouldShowLineNumbers = false,\n shouldWrapLines,\n}) => {\n const [width, setWidth] = useState(0);\n\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n addScrollbarClassToPre({ root: ref.current, className: 'chayns-scrollbar' });\n }, []);\n\n useEffect(() => {\n const handleResize = () => {\n if (ref.current) {\n const { children } = ref.current;\n\n const preElement = Array.from(children).find(\n ({ tagName }) => tagName.toLowerCase() === 'pre',\n );\n\n if (preElement) {\n setWidth(preElement.scrollWidth);\n }\n }\n };\n\n handleResize();\n\n window.addEventListener('resize', handleResize);\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, []);\n\n // function to style highlighted code\n const lineWrapper = useCallback(\n (lineNumber: number) => {\n let style = {\n backgroundColor: 'none',\n display: 'block',\n borderRadius: '2px',\n width: width - 15,\n };\n\n if (highlightedLines?.added && highlightedLines.added.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#2EF29930' };\n } else if (highlightedLines?.removed && highlightedLines.removed.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#F22E5B30' };\n } else if (highlightedLines?.marked && highlightedLines.marked.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#cccccc40' };\n }\n\n return { style };\n },\n [highlightedLines, width],\n );\n\n const lineNumberStyle = useMemo(\n () => ({\n WebkitUserSelect: 'none' as const,\n }),\n [],\n );\n\n const formattedCode = useMemo(() => {\n if (language) {\n void getParserForLanguage(language).then((config) => {\n if (shouldFormatCode && config) {\n try {\n return format(code, config) as unknown as string;\n } catch (error) {\n if (typeof onFormatError !== 'undefined') onFormatError(error);\n }\n }\n\n return code;\n });\n }\n\n return code;\n }, [code, language, shouldFormatCode, onFormatError]);\n\n useEffect(() => {\n const elements = document.getElementsByClassName('linenumber');\n\n Array.from(elements).forEach((element) => {\n const wrapper = document.createElement('tw-ignore');\n\n while (element.firstChild) {\n wrapper.appendChild(element.firstChild);\n }\n\n element.appendChild(wrapper);\n });\n }, []);\n\n return useMemo(\n () => (\n <StyledCodeHighlighter $shouldWrapLines={shouldWrapLines} $codeTheme={theme} ref={ref}>\n <StyledCodeHighlighterHeader $codeTheme={theme}>\n <StyledCodeHighlighterFileName $codeTheme={theme}>\n {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}\n {/* @ts-ignore */}\n <tw-ignore>{formatLanguage(language)}</tw-ignore>\n </StyledCodeHighlighterFileName>\n <CopyToClipboard text={code} theme={theme} copyButtonText={copyButtonText} />\n </StyledCodeHighlighterHeader>\n <SyntaxHighlighter\n language={language ?? ''}\n lineNumberStyle={lineNumberStyle}\n showLineNumbers={shouldShowLineNumbers}\n style={theme === CodeHighlighterTheme.Dark ? oneDark : oneLight}\n wrapLines\n wrapLongLines={shouldWrapLines}\n lineProps={lineWrapper}\n >\n {formattedCode}\n </SyntaxHighlighter>\n </StyledCodeHighlighter>\n ),\n [\n shouldWrapLines,\n theme,\n language,\n code,\n copyButtonText,\n lineNumberStyle,\n shouldShowLineNumbers,\n lineWrapper,\n formattedCode,\n ],\n );\n};\n\nCodeHighlighter.displayName = 'CodeHighlighter';\n\nexport default CodeHighlighter;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"CodeHighlighter.js","names":["format","React","useCallback","useEffect","useMemo","useRef","useState","Prism","SyntaxHighlighter","oneDark","oneLight","useColorScheme","CodeHighlighterTheme","formatLanguage","getParserForLanguage","StyledCodeHighlighter","StyledCodeHighlighterFileName","StyledCodeHighlighterHeader","CopyToClipboard","addScrollbarClassToPre","root","className","preElement","querySelector","classList","add","CodeHighlighter","theme","code","copyButtonText","language","highlightedLines","shouldFormatCode","onFormatError","shouldShowLineNumbers","shouldWrapLines","colorScheme","width","setWidth","formattedCode","setFormattedCode","ref","resolvedTheme","colorMode","Dark","Light","current","handleResize","children","Array","from","find","tagName","toLowerCase","scrollWidth","window","addEventListener","removeEventListener","lineWrapper","lineNumber","style","backgroundColor","display","borderRadius","added","includes","removed","marked","lineNumberStyle","WebkitUserSelect","syntaxHighlighterStyle","padding","isCurrent","then","config","error","elements","document","getElementsByClassName","forEach","element","wrapper","createElement","firstChild","appendChild","$shouldWrapLines","$codeTheme","text","customStyle","showLineNumbers","wrapLines","wrapLongLines","lineProps","displayName"],"sources":["../../../../src/components/code-highlighter/CodeHighlighter.tsx"],"sourcesContent":["import { format } from 'prettier/standalone';\nimport React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { oneDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport { useColorScheme } from '@chayns-components/core';\nimport {\n CodeHighlighterLanguage,\n CodeHighlighterTheme,\n HighlightedLines,\n} from '../../types/codeHighlighter';\nimport { formatLanguage, getParserForLanguage } from '../../utils/codeHighlighter';\nimport {\n StyledCodeHighlighter,\n StyledCodeHighlighterFileName,\n StyledCodeHighlighterHeader,\n} from './CodeHighlighter.styles';\nimport CopyToClipboard from './copy-to-clipboard/CopyToClipboard';\n\ntype AddScrollbarClassOptions = {\n root: HTMLDivElement | null;\n className: string;\n};\n\nconst addScrollbarClassToPre = ({ root, className }: AddScrollbarClassOptions) => {\n if (!root) return;\n\n const preElement = root.querySelector('pre');\n if (!preElement) return;\n\n preElement.classList.add(className);\n};\n\nexport type CodeHighlighterProps = {\n /**\n * The code that should be displayed.\n */\n code: string;\n /**\n * The text that should be displayed after the copy button.\n * If not set, just the button is displayed without text.\n */\n copyButtonText?: string;\n /**\n * The lines of code that should be highlighted.\n * Following lines can be highlighted: added, removed and just marked.\n */\n highlightedLines?: HighlightedLines;\n /**\n * The language of the displayed code.\n */\n language: CodeHighlighterLanguage;\n /**\n * Function to be executed when the formatting of the code fails.\n */\n onFormatError?: (error: unknown) => void;\n /**\n * Whether the code should be formatted with prettier.\n */\n shouldFormatCode?: boolean;\n /**\n * Whether the line numbers should be displayed.\n */\n shouldShowLineNumbers?: boolean;\n /**\n * Whether long lines should be wrapped.\n */\n shouldWrapLines?: boolean;\n /**\n * The theme of the code block. Decide between dark and light.\n */\n theme?: CodeHighlighterTheme;\n};\n\nconst CodeHighlighter: FC<CodeHighlighterProps> = ({\n theme,\n code,\n copyButtonText,\n language,\n highlightedLines,\n shouldFormatCode = false,\n onFormatError,\n shouldShowLineNumbers = false,\n shouldWrapLines,\n}) => {\n const colorScheme = useColorScheme();\n\n const [width, setWidth] = useState(0);\n const [formattedCode, setFormattedCode] = useState(code);\n\n const ref = useRef<HTMLDivElement>(null);\n\n const resolvedTheme =\n theme ??\n (colorScheme?.theme.colorMode === 'dark'\n ? CodeHighlighterTheme.Dark\n : CodeHighlighterTheme.Light);\n\n useEffect(() => {\n addScrollbarClassToPre({ root: ref.current, className: 'chayns-scrollbar' });\n }, []);\n\n useEffect(() => {\n const handleResize = () => {\n if (ref.current) {\n const { children } = ref.current;\n\n const preElement = Array.from(children).find(\n ({ tagName }) => tagName.toLowerCase() === 'pre',\n );\n\n if (preElement) {\n setWidth(preElement.scrollWidth);\n }\n }\n };\n\n handleResize();\n\n window.addEventListener('resize', handleResize);\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, []);\n\n // function to style highlighted code\n const lineWrapper = useCallback(\n (lineNumber: number) => {\n let style = {\n backgroundColor: 'none',\n display: 'block',\n borderRadius: '2px',\n width: width - 15,\n };\n\n if (highlightedLines?.added && highlightedLines.added.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#2EF29930' };\n } else if (highlightedLines?.removed && highlightedLines.removed.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#F22E5B30' };\n } else if (highlightedLines?.marked && highlightedLines.marked.includes(lineNumber)) {\n style = { ...style, backgroundColor: '#cccccc40' };\n }\n\n return { style };\n },\n [highlightedLines, width],\n );\n\n const lineNumberStyle = useMemo(\n () => ({\n WebkitUserSelect: 'none' as const,\n }),\n [],\n );\n\n const syntaxHighlighterStyle = useMemo(\n () => ({\n padding: '0 15px 15px',\n }),\n [],\n );\n\n useEffect(() => {\n let isCurrent = true;\n\n if (!shouldFormatCode) {\n setFormattedCode(code);\n\n return () => {\n isCurrent = false;\n };\n }\n\n void getParserForLanguage(language).then((config) => {\n if (!config || !isCurrent) {\n return;\n }\n\n try {\n setFormattedCode(format(code, config) as unknown as string);\n } catch (error) {\n onFormatError?.(error);\n setFormattedCode(code);\n }\n });\n\n return () => {\n isCurrent = false;\n };\n }, [code, language, onFormatError, shouldFormatCode]);\n\n useEffect(() => {\n const elements = document.getElementsByClassName('linenumber');\n\n Array.from(elements).forEach((element) => {\n const wrapper = document.createElement('tw-ignore');\n\n while (element.firstChild) {\n wrapper.appendChild(element.firstChild);\n }\n\n element.appendChild(wrapper);\n });\n }, []);\n\n return useMemo(\n () => (\n <StyledCodeHighlighter\n $shouldWrapLines={shouldWrapLines}\n $codeTheme={resolvedTheme}\n ref={ref}\n >\n <StyledCodeHighlighterHeader $codeTheme={resolvedTheme}>\n <StyledCodeHighlighterFileName $codeTheme={resolvedTheme}>\n {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}\n {/* @ts-ignore */}\n <tw-ignore>{formatLanguage(language)}</tw-ignore>\n </StyledCodeHighlighterFileName>\n </StyledCodeHighlighterHeader>\n <CopyToClipboard\n text={code}\n theme={resolvedTheme}\n copyButtonText={copyButtonText}\n />\n <SyntaxHighlighter\n customStyle={syntaxHighlighterStyle}\n language={language ?? ''}\n lineNumberStyle={lineNumberStyle}\n showLineNumbers={shouldShowLineNumbers}\n style={resolvedTheme === CodeHighlighterTheme.Dark ? oneDark : oneLight}\n wrapLines\n wrapLongLines={shouldWrapLines}\n lineProps={lineWrapper}\n >\n {formattedCode}\n </SyntaxHighlighter>\n </StyledCodeHighlighter>\n ),\n [\n shouldWrapLines,\n resolvedTheme,\n language,\n code,\n copyButtonText,\n lineNumberStyle,\n syntaxHighlighterStyle,\n shouldShowLineNumbers,\n lineWrapper,\n formattedCode,\n ],\n );\n};\n\nCodeHighlighter.displayName = 'CodeHighlighter';\n\nexport default CodeHighlighter;\n"],"mappings":"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","ignoreList":[]}
@@ -6,12 +6,17 @@ export const StyledCodeHighlighter = styled.div`
6
6
  $codeTheme
7
7
  }) => $codeTheme === CodeHighlighterTheme.Dark ? '#282c34' : '#fafafa'};
8
8
  border-radius: 8px;
9
+ --code-highlighter-action-size: 32px;
10
+ --code-highlighter-action-inset: 8px;
9
11
  padding-bottom: 6px;
12
+ padding-top: calc(
13
+ var(--code-highlighter-action-size) + var(--code-highlighter-action-inset) * 2
14
+ );
10
15
 
11
16
  pre {
12
17
  margin: 0 !important;
13
18
  overflow: auto;
14
- padding: 15px;
19
+ padding: 0 15px 15px;
15
20
  line-height: 1.5;
16
21
 
17
22
  code {
@@ -29,12 +34,9 @@ export const StyledCodeHighlighter = styled.div`
29
34
  export const StyledCodeHighlighterHeader = styled.div`
30
35
  display: flex;
31
36
  align-items: center;
32
- justify-content: space-between;
33
- border-bottom: 1px solid
34
- ${({
35
- $codeTheme
36
- }) => $codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'};
37
- padding: 4px 12px;
37
+ padding: 0 12px;
38
+ height: 0;
39
+ transform: translateY(-26px);
38
40
  `;
39
41
  export const StyledCodeHighlighterFileName = styled.span`
40
42
  color: ${({
@@ -1 +1 @@
1
- {"version":3,"file":"CodeHighlighter.styles.js","names":["styled","CodeHighlighterTheme","StyledCodeHighlighter","div","$codeTheme","Dark","$shouldWrapLines","StyledCodeHighlighterHeader","StyledCodeHighlighterFileName","span"],"sources":["../../../../src/components/code-highlighter/CodeHighlighter.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\nimport { CodeHighlighterTheme } from '../../types/codeHighlighter';\n\ntype StyledCodeHighlighterProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n $shouldWrapLines?: boolean;\n}>;\n\nexport const StyledCodeHighlighter = styled.div<StyledCodeHighlighterProps>`\n margin: 4px 0;\n background-color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#282c34' : '#fafafa'};\n border-radius: 8px;\n padding-bottom: 6px;\n\n pre {\n margin: 0 !important;\n overflow: auto;\n padding: 15px;\n line-height: 1.5;\n\n code {\n white-space: ${({ $shouldWrapLines }) =>\n $shouldWrapLines ? 'pre-wrap' : 'pre'} !important;\n }\n }\n\n // Fixes display of tables in code highlighter for markdown.\n .language-markdown .token.table {\n display: inline;\n }\n`;\n\ntype StyledCodeHighlighterHeaderProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\n\nexport const StyledCodeHighlighterHeader = styled.div<StyledCodeHighlighterHeaderProps>`\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-bottom: 1px solid\n ${({ $codeTheme }) => ($codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999')};\n padding: 4px 12px;\n`;\n\ntype StyledCodeHighlighterFileNameProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\n\nexport const StyledCodeHighlighterFileName = styled.span<StyledCodeHighlighterFileNameProps>`\n color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'};\n`;\n"],"mappings":"AACA,OAAOA,MAAM,MAAM,mBAAmB;AACtC,SAASC,oBAAoB,QAAQ,6BAA6B;AAOlE,OAAO,MAAMC,qBAAqB,GAAGF,MAAM,CAACG,GAA+B;AAC3E;AACA,wBAAwB,CAAC;EAAEC;AAAW,CAAC,KAC/BA,UAAU,KAAKH,oBAAoB,CAACI,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,CAAC;EAAEC;AAAiB,CAAC,KAChCA,gBAAgB,GAAG,UAAU,GAAG,KAAK;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAMD,OAAO,MAAMC,2BAA2B,GAAGP,MAAM,CAACG,GAAqC;AACvF;AACA;AACA;AACA;AACA,UAAU,CAAC;EAAEC;AAAW,CAAC,KAAMA,UAAU,KAAKH,oBAAoB,CAACI,IAAI,GAAG,SAAS,GAAG,SAAU;AAChG;AACA,CAAC;AAMD,OAAO,MAAMG,6BAA6B,GAAGR,MAAM,CAACS,IAAwC;AAC5F,aAAa,CAAC;EAAEL;AAAW,CAAC,KACpBA,UAAU,KAAKH,oBAAoB,CAACI,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"CodeHighlighter.styles.js","names":["styled","CodeHighlighterTheme","StyledCodeHighlighter","div","$codeTheme","Dark","$shouldWrapLines","StyledCodeHighlighterHeader","StyledCodeHighlighterFileName","span"],"sources":["../../../../src/components/code-highlighter/CodeHighlighter.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\nimport { CodeHighlighterTheme } from '../../types/codeHighlighter';\n\ntype StyledCodeHighlighterProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n $shouldWrapLines?: boolean;\n}>;\n\nexport const StyledCodeHighlighter = styled.div<StyledCodeHighlighterProps>`\n margin: 4px 0;\n background-color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#282c34' : '#fafafa'};\n border-radius: 8px;\n --code-highlighter-action-size: 32px;\n --code-highlighter-action-inset: 8px;\n padding-bottom: 6px;\n padding-top: calc(\n var(--code-highlighter-action-size) + var(--code-highlighter-action-inset) * 2\n );\n\n pre {\n margin: 0 !important;\n overflow: auto;\n padding: 0 15px 15px;\n line-height: 1.5;\n\n code {\n white-space: ${({ $shouldWrapLines }) =>\n $shouldWrapLines ? 'pre-wrap' : 'pre'} !important;\n }\n }\n\n // Fixes display of tables in code highlighter for markdown.\n .language-markdown .token.table {\n display: inline;\n }\n`;\n\ntype StyledCodeHighlighterHeaderProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\n\nexport const StyledCodeHighlighterHeader = styled.div<StyledCodeHighlighterHeaderProps>`\n display: flex;\n align-items: center;\n padding: 0 12px;\n height: 0;\n transform: translateY(-26px);\n`;\n\ntype StyledCodeHighlighterFileNameProps = WithTheme<{\n $codeTheme: CodeHighlighterTheme;\n}>;\n\nexport const StyledCodeHighlighterFileName = styled.span<StyledCodeHighlighterFileNameProps>`\n color: ${({ $codeTheme }) =>\n $codeTheme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'};\n`;\n"],"mappings":"AACA,OAAOA,MAAM,MAAM,mBAAmB;AACtC,SAASC,oBAAoB,QAAQ,6BAA6B;AAOlE,OAAO,MAAMC,qBAAqB,GAAGF,MAAM,CAACG,GAA+B;AAC3E;AACA,wBAAwB,CAAC;EAAEC;AAAW,CAAC,KAC/BA,UAAU,KAAKH,oBAAoB,CAACI,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,CAAC;EAAEC;AAAiB,CAAC,KAChCA,gBAAgB,GAAG,UAAU,GAAG,KAAK;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAMD,OAAO,MAAMC,2BAA2B,GAAGP,MAAM,CAACG,GAAqC;AACvF;AACA;AACA;AACA;AACA;AACA,CAAC;AAMD,OAAO,MAAMK,6BAA6B,GAAGR,MAAM,CAACS,IAAwC;AAC5F,aAAa,CAAC;EAAEL;AAAW,CAAC,KACpBA,UAAU,KAAKH,oBAAoB,CAACI,IAAI,GAAG,SAAS,GAAG,SAAS;AACxE,CAAC","ignoreList":[]}
@@ -0,0 +1,74 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
2
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3
+ import React from 'react';
4
+ import { describe, expect, it, vi } from 'vitest';
5
+ import { CodeHighlighterTheme } from '../../types/codeHighlighter';
6
+ import CodeHighlighter from './CodeHighlighter';
7
+ vi.mock('@chayns-components/core', () => ({
8
+ Icon: () => /*#__PURE__*/React.createElement("span", null),
9
+ SharingContextMenu: ({
10
+ children
11
+ }) => children,
12
+ useColorScheme: () => undefined
13
+ }));
14
+ vi.mock('@chayns-components/textstring', () => ({
15
+ ttsToITextString: value => value,
16
+ useTextstringValue: ({
17
+ textstring
18
+ }) => textstring.fallback
19
+ }));
20
+ vi.mock('chayns-api', () => ({
21
+ DialogType: {
22
+ TOAST: 1
23
+ },
24
+ ToastType: {
25
+ ERROR: 4,
26
+ SUCCESS: 2
27
+ },
28
+ createDialog: vi.fn(() => ({
29
+ open: vi.fn()
30
+ }))
31
+ }));
32
+ describe('CodeHighlighter', () => {
33
+ it('keeps the copy operation and renders sticky actions', () => {
34
+ const writeText = vi.spyOn(navigator.clipboard, 'writeText').mockResolvedValue();
35
+ const {
36
+ container
37
+ } = render(/*#__PURE__*/React.createElement(CodeHighlighter, {
38
+ code: "const value = true;",
39
+ copyButtonText: "Copy code",
40
+ language: "typescript",
41
+ shouldShowLineNumbers: true,
42
+ theme: CodeHighlighterTheme.Dark
43
+ }));
44
+ fireEvent.click(screen.getByRole('button', {
45
+ name: 'Copy code'
46
+ }));
47
+ expect(writeText).toHaveBeenCalledWith('const value = true;');
48
+ expect(container.querySelector('pre')).toHaveStyle({
49
+ overflow: 'auto',
50
+ padding: '0px 15px 15px'
51
+ });
52
+ expect(container.firstChild).toHaveStyle({
53
+ backgroundColor: 'rgb(40, 44, 52)'
54
+ });
55
+ });
56
+ it('formats code before highlighting when requested', async () => {
57
+ const {
58
+ container
59
+ } = render(/*#__PURE__*/React.createElement(CodeHighlighter, {
60
+ code: "const value={label:'Ada'};",
61
+ language: "typescript",
62
+ shouldFormatCode: true,
63
+ theme: CodeHighlighterTheme.Light
64
+ }));
65
+ await waitFor(() => {
66
+ expect(container.querySelector('pre')).toHaveTextContent("const value = { label: 'Ada' };");
67
+ });
68
+ expect(container.querySelector('pre span')).toBeInTheDocument();
69
+ expect(container.firstChild).toHaveStyle({
70
+ backgroundColor: 'rgb(250, 250, 250)'
71
+ });
72
+ });
73
+ });
74
+ //# sourceMappingURL=CodeHighlighter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeHighlighter.test.js","names":["fireEvent","render","screen","waitFor","React","describe","expect","it","vi","CodeHighlighterTheme","CodeHighlighter","mock","Icon","createElement","SharingContextMenu","children","useColorScheme","undefined","ttsToITextString","value","useTextstringValue","textstring","fallback","DialogType","TOAST","ToastType","ERROR","SUCCESS","createDialog","fn","open","writeText","spyOn","navigator","clipboard","mockResolvedValue","container","code","copyButtonText","language","shouldShowLineNumbers","theme","Dark","click","getByRole","name","toHaveBeenCalledWith","querySelector","toHaveStyle","overflow","padding","firstChild","backgroundColor","shouldFormatCode","Light","toHaveTextContent","toBeInTheDocument"],"sources":["../../../../src/components/code-highlighter/CodeHighlighter.test.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-call */\nimport { fireEvent, render, screen, waitFor } from '@testing-library/react';\nimport React from 'react';\nimport { describe, expect, it, vi } from 'vitest';\nimport { CodeHighlighterTheme } from '../../types/codeHighlighter';\nimport CodeHighlighter from './CodeHighlighter';\n\nvi.mock('@chayns-components/core', () => ({\n Icon: () => <span />,\n SharingContextMenu: ({ children }: { children: React.ReactNode }) => children,\n useColorScheme: () => undefined,\n}));\n\nvi.mock('@chayns-components/textstring', () => ({\n ttsToITextString: (value: unknown) => value,\n useTextstringValue: ({ textstring }: { textstring: { fallback: string } }) =>\n textstring.fallback,\n}));\n\nvi.mock('chayns-api', () => ({\n DialogType: { TOAST: 1 },\n ToastType: { ERROR: 4, SUCCESS: 2 },\n createDialog: vi.fn(() => ({ open: vi.fn() })),\n}));\n\ndescribe('CodeHighlighter', () => {\n it('keeps the copy operation and renders sticky actions', () => {\n const writeText = vi.spyOn(navigator.clipboard, 'writeText').mockResolvedValue();\n const { container } = render(\n <CodeHighlighter\n code=\"const value = true;\"\n copyButtonText=\"Copy code\"\n language=\"typescript\"\n shouldShowLineNumbers\n theme={CodeHighlighterTheme.Dark}\n />,\n );\n\n fireEvent.click(screen.getByRole('button', { name: 'Copy code' }));\n\n expect(writeText).toHaveBeenCalledWith('const value = true;');\n expect(container.querySelector('pre')).toHaveStyle({\n overflow: 'auto',\n padding: '0px 15px 15px',\n });\n expect(container.firstChild).toHaveStyle({ backgroundColor: 'rgb(40, 44, 52)' });\n });\n\n it('formats code before highlighting when requested', async () => {\n const { container } = render(\n <CodeHighlighter\n code=\"const value={label:'Ada'};\"\n language=\"typescript\"\n shouldFormatCode\n theme={CodeHighlighterTheme.Light}\n />,\n );\n\n await waitFor(() => {\n expect(container.querySelector('pre')).toHaveTextContent(\n \"const value = { label: 'Ada' };\",\n );\n });\n expect(container.querySelector('pre span')).toBeInTheDocument();\n expect(container.firstChild).toHaveStyle({ backgroundColor: 'rgb(250, 250, 250)' });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -1,38 +1,89 @@
1
- import { Icon, Popup } from '@chayns-components/core';
2
- import React from 'react';
1
+ import { Icon, SharingContextMenu } from '@chayns-components/core';
2
+ import { ttsToITextString, useTextstringValue } from '@chayns-components/textstring';
3
+ import { createDialog, DialogType, ToastType } from 'chayns-api';
4
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
3
5
  import { CodeHighlighterTheme } from '../../../types/codeHighlighter';
4
- import { StyledCopyToClipboard, StyledCopyToClipboardText } from './CopyToClipboard.styles';
5
- import { Textstring, TextstringProvider, ttsToITextString } from '@chayns-components/textstring';
6
+ import { StyledCopyToClipboard, StyledCopyToClipboardActionGroup, StyledCopyToClipboardButton } from './CopyToClipboard.styles';
6
7
  import textStrings from '../../../constants/textStrings';
8
+ const STICKY_ACTION_OFFSET = 8;
7
9
  const CopyToClipboard = ({
8
10
  copyButtonText,
9
11
  text,
10
12
  theme
11
13
  }) => {
12
- const handleClick = () => {
13
- void navigator.clipboard.writeText(text);
14
- };
15
- const popupContent = /*#__PURE__*/React.createElement(TextstringProvider, {
16
- libraryName: "@chayns-components-code-highlighter"
17
- }, /*#__PURE__*/React.createElement("span", {
18
- style: {
19
- display: 'block',
20
- padding: '5px'
14
+ const [isActionGroupSticky, setIsActionGroupSticky] = useState(false);
15
+ const actionGroupRef = useRef(null);
16
+ const defaultCopyText = useTextstringValue({
17
+ textstring: ttsToITextString(textStrings.components.codeHighlighter.copyToClipboard.copy)
18
+ });
19
+ const copiedText = useTextstringValue({
20
+ textstring: ttsToITextString(textStrings.components.codeHighlighter.copyToClipboard.copied)
21
+ });
22
+ const copyFailedText = useTextstringValue({
23
+ textstring: ttsToITextString(textStrings.components.codeHighlighter.copyToClipboard.copyFailed)
24
+ });
25
+ const shareText = useTextstringValue({
26
+ textstring: ttsToITextString(textStrings.components.codeHighlighter.copyToClipboard.share)
27
+ });
28
+ const copyText = copyButtonText ?? defaultCopyText;
29
+ const iconColor = theme === CodeHighlighterTheme.Dark ? '#f4f6f8' : '#5f6368';
30
+ useEffect(() => {
31
+ const updateStickyState = () => {
32
+ const actionGroupTop = actionGroupRef.current?.getBoundingClientRect().top;
33
+ setIsActionGroupSticky(actionGroupTop !== undefined && actionGroupTop <= STICKY_ACTION_OFFSET);
34
+ };
35
+ updateStickyState();
36
+ document.addEventListener('scroll', updateStickyState, true);
37
+ window.addEventListener('resize', updateStickyState);
38
+ return () => {
39
+ document.removeEventListener('scroll', updateStickyState, true);
40
+ window.removeEventListener('resize', updateStickyState);
41
+ };
42
+ }, []);
43
+ const handleCopy = useCallback(async () => {
44
+ try {
45
+ await navigator.clipboard.writeText(text);
46
+ void createDialog({
47
+ showCloseIcon: true,
48
+ text: copiedText,
49
+ toastType: ToastType.SUCCESS,
50
+ type: DialogType.TOAST
51
+ }).open();
52
+ } catch {
53
+ void createDialog({
54
+ showCloseIcon: true,
55
+ text: copyFailedText,
56
+ toastType: ToastType.ERROR,
57
+ type: DialogType.TOAST
58
+ }).open();
21
59
  }
22
- }, /*#__PURE__*/React.createElement(Textstring, {
23
- textstring: ttsToITextString(textStrings.components.codeHighlighter.copyToClipboard.copied),
24
- childrenTagName: "p"
25
- })));
26
- return /*#__PURE__*/React.createElement(Popup, {
27
- content: popupContent
28
- }, /*#__PURE__*/React.createElement(StyledCopyToClipboard, {
29
- onClick: handleClick
60
+ }, [copiedText, copyFailedText, text]);
61
+ return /*#__PURE__*/React.createElement(StyledCopyToClipboard, {
62
+ $codeTheme: theme,
63
+ ref: actionGroupRef
64
+ }, /*#__PURE__*/React.createElement(StyledCopyToClipboardActionGroup, null, /*#__PURE__*/React.createElement(StyledCopyToClipboardButton, {
65
+ $codeTheme: theme,
66
+ $isSticky: isActionGroupSticky,
67
+ "aria-label": copyText,
68
+ onClick: () => {
69
+ void handleCopy();
70
+ },
71
+ type: "button"
30
72
  }, /*#__PURE__*/React.createElement(Icon, {
31
- icons: ['fa-light fa-clipboard'],
32
- color: theme === CodeHighlighterTheme.Dark ? '#e5e5e5' : '#999999'
33
- }), copyButtonText && /*#__PURE__*/React.createElement(StyledCopyToClipboardText, {
34
- $codeTheme: theme
35
- }, /*#__PURE__*/React.createElement("tw-ignore", null, copyButtonText))));
73
+ color: iconColor,
74
+ icons: ['fa-light fa-copy']
75
+ })), /*#__PURE__*/React.createElement(SharingContextMenu, {
76
+ link: text,
77
+ shouldUseDefaultTriggerStyles: false
78
+ }, /*#__PURE__*/React.createElement(StyledCopyToClipboardButton, {
79
+ $codeTheme: theme,
80
+ $isSticky: isActionGroupSticky,
81
+ "aria-label": shareText,
82
+ type: "button"
83
+ }, /*#__PURE__*/React.createElement(Icon, {
84
+ color: iconColor,
85
+ icons: ['fa fa-share-nodes']
86
+ })))));
36
87
  };
37
88
  CopyToClipboard.displayName = 'CopyToClipboard';
38
89
  export default CopyToClipboard;