@brillout/docpress 0.15.10 → 0.15.11

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 (51) hide show
  1. package/components/CodeSnippets/useSelectCodeLang.ts +60 -0
  2. package/components/CodeSnippets.css +78 -0
  3. package/components/CodeSnippets.tsx +50 -0
  4. package/components/Pre.css +51 -0
  5. package/components/Pre.tsx +72 -0
  6. package/components/index.ts +1 -0
  7. package/components/useMDXComponents.tsx +13 -0
  8. package/css/button.css +23 -0
  9. package/css/code.css +3 -21
  10. package/css/index.css +1 -0
  11. package/css/tooltip.css +10 -2
  12. package/dist/+config.js +1 -1
  13. package/dist/NavItemComponent.js +38 -46
  14. package/dist/components/CodeBlockTransformer.js +2 -3
  15. package/dist/components/CodeSnippets/useSelectCodeLang.d.ts +7 -0
  16. package/dist/components/CodeSnippets/useSelectCodeLang.js +50 -0
  17. package/dist/components/CodeSnippets.d.ts +11 -0
  18. package/dist/components/CodeSnippets.js +35 -0
  19. package/dist/components/Comment.js +1 -2
  20. package/dist/components/FileRemoved.js +4 -6
  21. package/dist/components/HorizontalLine.js +1 -2
  22. package/dist/components/ImportMeta.js +2 -3
  23. package/dist/components/Link.js +34 -50
  24. package/dist/components/Note.js +17 -29
  25. package/dist/components/P.js +1 -12
  26. package/dist/components/RepoLink.js +7 -9
  27. package/dist/components/index.d.ts +1 -0
  28. package/dist/components/index.js +1 -0
  29. package/dist/determineNavItemsColumnLayout.js +48 -63
  30. package/dist/parseMarkdownMini.js +5 -17
  31. package/dist/parsePageSections.js +41 -82
  32. package/dist/rehypeMetaToProps.d.ts +19 -0
  33. package/dist/rehypeMetaToProps.js +62 -0
  34. package/dist/remarkDetype.d.ts +4 -0
  35. package/dist/remarkDetype.js +146 -0
  36. package/dist/renderer/usePageContext.js +6 -7
  37. package/dist/resolvePageContext.js +103 -110
  38. package/dist/utils/Emoji/Emoji.js +13 -21
  39. package/dist/utils/assert.js +14 -16
  40. package/dist/utils/cls.js +1 -1
  41. package/dist/utils/determineSectionUrlHash.js +5 -5
  42. package/dist/utils/filter.js +2 -2
  43. package/dist/utils/getGlobalObject.js +3 -3
  44. package/dist/vite.config.js +12 -7
  45. package/index.ts +15 -5
  46. package/package.json +5 -1
  47. package/rehypeMetaToProps.ts +69 -0
  48. package/remarkDetype.ts +172 -0
  49. package/resolvePageContext.ts +19 -15
  50. package/tsconfig.json +2 -1
  51. package/vite.config.ts +9 -4
@@ -0,0 +1,60 @@
1
+ export { useSelectCodeLang }
2
+
3
+ import { useState, useEffect, useCallback } from 'react'
4
+ import { assertWarning } from '../../utils/assert'
5
+
6
+ const storageKey = 'docpress:code-lang'
7
+ const codeLangDefaultSsr = 'ts'
8
+ const codeLangDefaultClient = 'js'
9
+
10
+ function useSelectCodeLang() {
11
+ const [codeLangSelected, setCodeLangSelected] = useState(codeLangDefaultSsr)
12
+ const updateState = () => {
13
+ setCodeLangSelected(getCodeLangStorage())
14
+ }
15
+ const updateStateOnStorageEvent = (event: StorageEvent) => {
16
+ if (event.key === storageKey) updateState()
17
+ }
18
+
19
+ const getCodeLangStorage = () => {
20
+ try {
21
+ return window.localStorage.getItem(storageKey) ?? codeLangDefaultClient
22
+ } catch (error) {
23
+ console.error(error)
24
+ assertWarning(false, 'Error reading from localStorage')
25
+ return codeLangDefaultClient
26
+ }
27
+ }
28
+
29
+ const selectCodeLang = useCallback((value: string) => {
30
+ try {
31
+ window.localStorage.setItem(storageKey, value)
32
+ setCodeLangSelected(value)
33
+ window.dispatchEvent(new CustomEvent('code-lang-storage'))
34
+ } catch (error) {
35
+ console.error(error)
36
+ assertWarning(false, 'Error setting localStorage')
37
+ }
38
+ }, [])
39
+
40
+ useEffect(() => {
41
+ // Initial load from localStorage
42
+ updateState()
43
+ // Update code lang in current tab
44
+ window.addEventListener('code-lang-storage', updateState)
45
+ // Update code lang if changed in another tab
46
+ window.addEventListener('storage', updateStateOnStorageEvent)
47
+ return () => {
48
+ window.removeEventListener('code-lang-storage', updateState)
49
+ window.removeEventListener('storage', updateStateOnStorageEvent)
50
+ }
51
+ }, [])
52
+
53
+ return [codeLangSelected, selectCodeLang] as const
54
+ }
55
+
56
+ declare global {
57
+ interface WindowEventMap {
58
+ 'code-lang-storage': CustomEvent
59
+ }
60
+ }
@@ -0,0 +1,78 @@
1
+ .code-snippets {
2
+ position: relative;
3
+
4
+ &:hover {
5
+ .copy-button,
6
+ .code-lang-toggle {
7
+ opacity: 1;
8
+ }
9
+ }
10
+
11
+ /* Hide language toggle for YAML */
12
+ &:has(code[data-language='yaml']) .code-lang-toggle {
13
+ display: none !important;
14
+ }
15
+
16
+ /* Language toggle styles */
17
+ .code-lang-toggle {
18
+ position: absolute !important;
19
+ top: 10px;
20
+ right: 42px;
21
+ z-index: 3;
22
+
23
+ /* Checkbox appearance reset */
24
+ appearance: none;
25
+ -webkit-appearance: none;
26
+ -moz-appearance: none;
27
+
28
+ margin: 0;
29
+ padding: 0 4px;
30
+ height: 25px;
31
+ display: flex;
32
+ background-color: #f7f7f7;
33
+ opacity: 0;
34
+ transition: opacity 0.5s ease-in-out, background-color 0.4s ease-in-out;
35
+
36
+ &:not(:hover) {
37
+ background-color: #eee;
38
+ }
39
+
40
+ /* Toggle Labels */
41
+ &::before,
42
+ &::after {
43
+ width: 24px;
44
+ display: flex;
45
+ justify-content: center;
46
+ align-items: center;
47
+ }
48
+
49
+ &::before {
50
+ content: 'JS';
51
+ }
52
+
53
+ &::after {
54
+ content: 'TS';
55
+ border-left: none;
56
+ opacity: 0.3;
57
+ }
58
+
59
+ &:checked {
60
+ &::before {
61
+ opacity: 0.3;
62
+ }
63
+
64
+ &::after {
65
+ opacity: 1;
66
+ }
67
+ }
68
+ }
69
+
70
+ /* Code block visibility based on toggle */
71
+ &:has(.code-lang-toggle:checked) figure:first-of-type {
72
+ display: none;
73
+ }
74
+
75
+ &:has(.code-lang-toggle:not(:checked)) figure:last-of-type {
76
+ display: none;
77
+ }
78
+ }
@@ -0,0 +1,50 @@
1
+ // Public
2
+ export { TypescriptOnly }
3
+
4
+ // Internal
5
+ export { CodeSnippets }
6
+
7
+ import React, { useEffect, useRef } from 'react'
8
+ import { useSelectCodeLang } from './CodeSnippets/useSelectCodeLang'
9
+ import './CodeSnippets.css'
10
+
11
+ /** Only show if TypeScript is selected */
12
+ function TypescriptOnly({ children }: { children: React.ReactNode }) {
13
+ const [codeLangSelected] = useSelectCodeLang()
14
+ return <div style={{ display: codeLangSelected === 'ts' ? 'block' : 'none' }}>{children}</div>
15
+ }
16
+
17
+ function CodeSnippets({ children }: { children: React.ReactNode }) {
18
+ const [codeLangSelected, selectCodeLang] = useSelectCodeLang()
19
+ const prevPositionRef = useRef<null | { top: number; el: Element }>(null)
20
+
21
+ // Restores the scroll position of the toggle element after toggling languages.
22
+ useEffect(() => {
23
+ if (!prevPositionRef.current) return
24
+ const { top, el } = prevPositionRef.current
25
+ const delta = el.getBoundingClientRect().top - top
26
+ if (delta !== 0) {
27
+ window.scrollBy(0, delta)
28
+ }
29
+ prevPositionRef.current = null
30
+ }, [codeLangSelected])
31
+
32
+ return (
33
+ <div className="code-snippets">
34
+ <input
35
+ type="checkbox"
36
+ name="code-lang-toggle"
37
+ className="code-lang-toggle raised"
38
+ checked={codeLangSelected === 'ts'}
39
+ onChange={onChange}
40
+ title="Toggle language"
41
+ />
42
+ {children}
43
+ </div>
44
+ )
45
+ function onChange(e: React.ChangeEvent<HTMLInputElement>) {
46
+ const element = e.target
47
+ prevPositionRef.current = { top: element.getBoundingClientRect().top, el: element }
48
+ selectCodeLang(element.checked ? 'ts' : 'js')
49
+ }
50
+ }
@@ -0,0 +1,51 @@
1
+ pre > code {
2
+ /*
3
+ background-color: #f4f4f4;
4
+ 0.043137255 = 1 - (#f4 / #ff)
5
+ */
6
+ background: rgba(0, 0, 0, 0.043137255);
7
+ font-size: 1em;
8
+ }
9
+
10
+ /* Copy button */
11
+ pre {
12
+ &:has(.copy-button) {
13
+ position: relative;
14
+ }
15
+
16
+ &:hover {
17
+ .copy-button {
18
+ opacity: 1;
19
+ }
20
+ }
21
+
22
+ .copy-button {
23
+ position: absolute !important;
24
+ top: 10px;
25
+ right: 10px;
26
+ z-index: 3;
27
+ margin: 0;
28
+ height: 25px;
29
+ width: 30px;
30
+ background-color: #f7f7f7;
31
+ opacity: 0;
32
+ transition: opacity 0.5s ease-in-out, background-color 0.4s ease-in-out;
33
+
34
+ &:not(:hover) {
35
+ background-color: #eee;
36
+ }
37
+
38
+ & svg {
39
+ width: 100%;
40
+ height: 100%;
41
+ fill: none;
42
+ stroke-linecap: round;
43
+ stroke-linejoin: round;
44
+ }
45
+ }
46
+ }
47
+
48
+ /* Workaround for shiki regression */
49
+ pre > code:not([data-language]) {
50
+ padding: 16px !important;
51
+ }
@@ -0,0 +1,72 @@
1
+ export { Pre }
2
+
3
+ import React, { ComponentPropsWithoutRef, useState } from 'react'
4
+ /* Importing it here chokes the tests. I don't know why.
5
+ import './Pre.css'
6
+ //*/
7
+
8
+ function Pre({ children, ...props }: ComponentPropsWithoutRef<'pre'> & { 'hide-menu'?: string }) {
9
+ return (
10
+ <pre {...props}>
11
+ {!props['hide-menu'] && <CopyButton />}
12
+ {children}
13
+ </pre>
14
+ )
15
+ }
16
+
17
+ function CopyButton() {
18
+ const [isSuccess, setIsSuccess] = useState(null as null | boolean)
19
+ const onCopy = (success: boolean) => {
20
+ setIsSuccess(success)
21
+ setTimeout(() => {
22
+ setIsSuccess(null)
23
+ }, 900)
24
+ }
25
+ const tooltip = isSuccess === null ? 'Copy to clipboard' : isSuccess ? 'Copied' : 'Failed'
26
+ const icon =
27
+ isSuccess === null ? (
28
+ // Copy icon
29
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
30
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
31
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
32
+ </svg>
33
+ ) : isSuccess ? (
34
+ // Green checkmark
35
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="#28a745" strokeWidth="3">
36
+ <polyline points="20 6 9 17 4 12" />
37
+ </svg>
38
+ ) : (
39
+ '❌'
40
+ )
41
+ return (
42
+ <button
43
+ className="copy-button raised"
44
+ aria-label={tooltip}
45
+ data-label-position="top"
46
+ type="button"
47
+ onClick={onClick}
48
+ >
49
+ {icon}
50
+ </button>
51
+ )
52
+ async function onClick(e: React.MouseEvent<HTMLButtonElement>) {
53
+ let success: boolean
54
+ const preEl = e.currentTarget.parentElement!
55
+ let text = preEl.textContent || ''
56
+ text = removeTrailingWhitespaces(text)
57
+ try {
58
+ await navigator.clipboard.writeText(text)
59
+ success = true
60
+ } catch (error) {
61
+ console.error(error)
62
+ success = false
63
+ }
64
+ onCopy(success)
65
+ }
66
+ }
67
+ function removeTrailingWhitespaces(text: string) {
68
+ return text
69
+ .split('\n')
70
+ .map((line) => line.trimEnd())
71
+ .join('\n')
72
+ }
@@ -8,3 +8,4 @@ export * from './HorizontalLine'
8
8
  export * from './CodeBlockTransformer'
9
9
  export * from './Comment'
10
10
  export * from './FileRemoved'
11
+ export * from './CodeSnippets'
@@ -0,0 +1,13 @@
1
+ export { useMDXComponents }
2
+
3
+ import React from 'react'
4
+ import type { UseMdxComponents } from '@mdx-js/mdx'
5
+ import { Pre } from './Pre.js'
6
+ import { CodeSnippets } from './CodeSnippets.js'
7
+
8
+ const useMDXComponents: UseMdxComponents = () => {
9
+ return {
10
+ CodeSnippets,
11
+ pre: (props) => <Pre {...props} />,
12
+ }
13
+ }
package/css/button.css CHANGED
@@ -5,3 +5,26 @@ button,
5
5
  border-radius: 5px;
6
6
  cursor: pointer;
7
7
  }
8
+
9
+ /* Raised button */
10
+ .raised {
11
+ cursor: pointer;
12
+ border-radius: 5px;
13
+ border-style: solid;
14
+ border-width: 1px 2px 2px 1px;
15
+ border-color: hsl(0, 0%, 75%) hsl(0, 0%, 72%) hsl(0, 0%, 72%) hsl(0, 0%, 75%);
16
+
17
+ &:hover {
18
+ border-color: hsl(0, 0%, 72%) hsl(0, 0%, 66%) hsl(0, 0%, 66%) hsl(0, 0%, 72%);
19
+ }
20
+
21
+ &:active {
22
+ border-width: 2px 1px 1px 2px;
23
+ border-color: hsl(0, 0%, 66%) hsl(0, 0%, 72%) hsl(0, 0%, 72%) hsl(0, 0%, 66%);
24
+ }
25
+
26
+ &:disabled {
27
+ border-width: 1px;
28
+ border-color: hsl(0, 0%, 72%);
29
+ }
30
+ }
package/css/code.css CHANGED
@@ -2,29 +2,11 @@
2
2
  @import './code/block.css';
3
3
  @import './code/diff.css';
4
4
 
5
- code {
6
- border-radius: 4px;
7
- }
8
- pre {
9
- background: none !important;
10
- }
5
+ /* For code blocks, see Pre.css instead */
11
6
 
12
- /* Inline */
7
+ /* Inline <code> */
13
8
  code {
9
+ border-radius: 4px;
14
10
  background: rgba(0, 0, 0, 0.063137255);
15
11
  font-size: 1.1em;
16
12
  }
17
-
18
- /* Block */
19
- pre > code {
20
- /*
21
- background-color: #f4f4f4;
22
- 0.043137255 = 1 - (#f4 / #ff)
23
- */
24
- background: rgba(0, 0, 0, 0.043137255);
25
- font-size: 1em;
26
- }
27
- /* Workaround for shiki regression */
28
- pre > code:not([data-language]) {
29
- padding: 16px !important;
30
- }
package/css/index.css CHANGED
@@ -7,4 +7,5 @@
7
7
  @import './code.css';
8
8
  @import './table.css';
9
9
  @import './tooltip.css';
10
+ @import '../components/Pre.css';
10
11
  @import '@docsearch/css';
package/css/tooltip.css CHANGED
@@ -17,10 +17,8 @@
17
17
  font-size: 12px;
18
18
  content: attr(aria-label);
19
19
  position: absolute;
20
- top: 100%;
21
20
  left: 50%;
22
21
  transform: translate(-50%, 0);
23
- margin-top: 5px;
24
22
  background: #fdfdfd;
25
23
  padding: 3px 10px;
26
24
  box-shadow: rgb(0 0 0 / 8%) 2px 4px 7px 0px;
@@ -34,4 +32,14 @@
34
32
  */
35
33
  white-space: nowrap;
36
34
  }
35
+ /* Show below */
36
+ [aria-label]:not([data-label-position])::before {
37
+ top: 100%;
38
+ margin-top: 5px;
39
+ }
40
+ /* Show above */
41
+ [aria-label][data-label-position='top']::before {
42
+ bottom: 100%;
43
+ margin-bottom: 7px;
44
+ }
37
45
  }
package/dist/+config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { config as default };
2
2
  import { viteConfig } from './vite.config.js';
3
- var config = {
3
+ const config = {
4
4
  name: '@brillout/docpress',
5
5
  require: { vike: '>=0.4.234' },
6
6
  vite: viteConfig,
@@ -1,53 +1,39 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
7
- }
8
- return t;
9
- };
10
- return __assign.apply(this, arguments);
11
- };
12
1
  export { NavItemComponent };
13
2
  export { getNavItemsWithComputed };
14
3
  import React from 'react';
15
4
  import { assert, assertWarning, jsxToTextContent } from './utils/server';
16
5
  import './NavItemComponent.css';
17
6
  import { parseMarkdownMini } from './parseMarkdownMini';
18
- function NavItemComponent(_a) {
19
- var _b;
20
- var _c;
21
- var navItem = _a.navItem, onClick = _a.onClick;
7
+ function NavItemComponent({ navItem, onClick, }) {
22
8
  assert([1, 2, 3, 4].includes(navItem.level), navItem);
23
- var titleJsx = parseMarkdownMini(navItem.title);
24
- var titleInNavJsx = parseMarkdownMini(navItem.titleInNav);
25
- var iconSize = 25;
26
- var icon = navItem.titleIcon && (React.createElement("img", { src: navItem.titleIcon, style: __assign({ height: iconSize, width: iconSize, marginRight: 8, marginLeft: 4 }, navItem.titleIconStyle) }));
9
+ const titleJsx = parseMarkdownMini(navItem.title);
10
+ const titleInNavJsx = parseMarkdownMini(navItem.titleInNav);
11
+ const iconSize = 25;
12
+ const icon = navItem.titleIcon && (React.createElement("img", { src: navItem.titleIcon, style: { height: iconSize, width: iconSize, marginRight: 8, marginLeft: 4, ...navItem.titleIconStyle } }));
27
13
  if (navItem.level === 1 || navItem.level === 4) {
28
14
  assert(navItem.url === undefined);
29
15
  }
30
16
  else {
31
- var sectionTitle = jsxToTextContent(titleJsx);
17
+ const sectionTitle = jsxToTextContent(titleJsx);
32
18
  assertWarning(navItem.url, [
33
- "".concat(jsxToTextContent(titleInNavJsx), " is missing a URL hash."),
34
- "Add a URL hash with: `## ".concat(sectionTitle, "{#some-hash}`."),
19
+ `${jsxToTextContent(titleInNavJsx)} is missing a URL hash.`,
20
+ `Add a URL hash with: \`## ${sectionTitle}{#some-hash}\`.`,
35
21
  /* TO-DO/eventually: not implemented yet.
36
22
  `Use \`<h2 id="url-hash">${sectionTitle}</h2>\` instead of \`## ${sectionTitle}\`.`,
37
23
  */
38
24
  ].join(' '));
39
25
  }
40
- var children = titleInNavJsx;
26
+ let children = titleInNavJsx;
41
27
  if (navItem.level === 1) {
42
28
  children = (React.createElement(React.Fragment, null,
43
29
  icon,
44
30
  children,
45
31
  React.createElement(Chevron, { className: "collapsible-icon", height: 9 })));
46
32
  }
47
- var props = {
48
- href: (_c = navItem.url) !== null && _c !== void 0 ? _c : undefined,
49
- children: children,
50
- onClick: onClick,
33
+ const props = {
34
+ href: navItem.url ?? undefined,
35
+ children,
36
+ onClick,
51
37
  className: [
52
38
  'nav-item',
53
39
  'nav-item-level-' + navItem.level,
@@ -59,45 +45,51 @@ function NavItemComponent(_a) {
59
45
  .join(' '),
60
46
  };
61
47
  if (navItem.level === 1) {
62
- props.style = (_b = {},
63
- _b['--category-color'] = navItem.color,
64
- _b);
48
+ props.style = {
49
+ ['--category-color']: navItem.color,
50
+ };
65
51
  }
66
52
  if (navItem.level === 2 || navItem.level === 3) {
67
- return React.createElement("a", __assign({}, props));
53
+ return React.createElement("a", { ...props });
68
54
  }
69
55
  else {
70
- return React.createElement("span", __assign({}, props));
56
+ return React.createElement("span", { ...props });
71
57
  }
72
58
  }
73
59
  function getNavItemsWithComputed(navItems, currentUrl) {
74
- var navItemIdx;
75
- var navItemsWithComputed = navItems.map(function (navItem, i) {
60
+ let navItemIdx;
61
+ const navItemsWithComputed = navItems.map((navItem, i) => {
76
62
  assert([1, 2, 3, 4].includes(navItem.level), navItem);
77
- var navItemPrevious = navItems[i - 1];
78
- var navItemNext = navItems[i + 1];
79
- var isActive = false;
63
+ const navItemPrevious = navItems[i - 1];
64
+ const navItemNext = navItems[i + 1];
65
+ let isActive = false;
80
66
  if (navItem.url === currentUrl) {
81
- assert(navItem.level === 2, { currentUrl: currentUrl });
67
+ assert(navItem.level === 2, { currentUrl });
82
68
  assert(navItemIdx === undefined);
83
69
  navItemIdx = i;
84
70
  isActive = true;
85
71
  }
86
- var isFirstOfItsKind = navItem.level !== (navItemPrevious === null || navItemPrevious === void 0 ? void 0 : navItemPrevious.level);
87
- var isLastOfItsKind = navItem.level !== (navItemNext === null || navItemNext === void 0 ? void 0 : navItemNext.level);
88
- var navItemComputed = __assign(__assign({}, navItem), { isActive: isActive, isRelevant: false, isFirstOfItsKind: isFirstOfItsKind, isLastOfItsKind: isLastOfItsKind });
72
+ const isFirstOfItsKind = navItem.level !== navItemPrevious?.level;
73
+ const isLastOfItsKind = navItem.level !== navItemNext?.level;
74
+ const navItemComputed = {
75
+ ...navItem,
76
+ isActive,
77
+ isRelevant: false,
78
+ isFirstOfItsKind,
79
+ isLastOfItsKind,
80
+ };
89
81
  return navItemComputed;
90
82
  });
91
83
  // Set `isRelevant`
92
84
  if (navItemIdx !== undefined) {
93
- for (var i = navItemIdx; i >= 0; i--) {
94
- var navItem = navItemsWithComputed[i];
85
+ for (let i = navItemIdx; i >= 0; i--) {
86
+ const navItem = navItemsWithComputed[i];
95
87
  navItem.isRelevant = true;
96
88
  if (navItem.level === 1)
97
89
  break;
98
90
  }
99
- for (var i = navItemIdx; i < navItemsWithComputed.length; i++) {
100
- var navItem = navItemsWithComputed[i];
91
+ for (let i = navItemIdx; i < navItemsWithComputed.length; i++) {
92
+ const navItem = navItemsWithComputed[i];
101
93
  if (navItem.level === 1)
102
94
  break;
103
95
  navItem.isRelevant = true;
@@ -106,6 +98,6 @@ function getNavItemsWithComputed(navItems, currentUrl) {
106
98
  return navItemsWithComputed;
107
99
  }
108
100
  function Chevron(props) {
109
- return (React.createElement("svg", __assign({ viewBox: "0 0 512 292.52", xmlns: "http://www.w3.org/2000/svg" }, props),
101
+ return (React.createElement("svg", { viewBox: "0 0 512 292.52", xmlns: "http://www.w3.org/2000/svg", ...props },
110
102
  React.createElement("path", { fill: "#aaa", d: "M10.725 82.42L230.125 261.82c6.8 6.8 16.2 10.7 25.9 10.7s19.1-3.9 25.9-10.7l219.4-179.4c14.3-14.3 14.3-37.4 0-51.7s-37.4-14.3-51.7 0l-193.6 153.6-193.6-153.6c-14.3-14.3-37.4-14.3-51.7 0s-14.3 37.5 0 51.7z" })));
111
103
  }
@@ -2,9 +2,8 @@ export { CodeBlockTransformer };
2
2
  import React from 'react';
3
3
  import { assert } from '../utils/server';
4
4
  import './CodeBlockTransformer.css';
5
- function CodeBlockTransformer(_a) {
6
- var children = _a.children, lineBreak = _a.lineBreak;
5
+ function CodeBlockTransformer({ children, lineBreak }) {
7
6
  assert(lineBreak === 'white-space' || lineBreak === 'break-word', '`lineBreak` is currently the only use case for <CodeBlockTransformer>');
8
- var className = "with-line-break_".concat(lineBreak);
7
+ const className = `with-line-break_${lineBreak}`;
9
8
  return React.createElement("div", { className: className }, children);
10
9
  }
@@ -0,0 +1,7 @@
1
+ export { useSelectCodeLang };
2
+ declare function useSelectCodeLang(): readonly [string, (value: string) => void];
3
+ declare global {
4
+ interface WindowEventMap {
5
+ 'code-lang-storage': CustomEvent;
6
+ }
7
+ }
@@ -0,0 +1,50 @@
1
+ export { useSelectCodeLang };
2
+ import { useState, useEffect, useCallback } from 'react';
3
+ import { assertWarning } from '../../utils/assert';
4
+ const storageKey = 'docpress:code-lang';
5
+ const codeLangDefaultSsr = 'ts';
6
+ const codeLangDefaultClient = 'js';
7
+ function useSelectCodeLang() {
8
+ const [codeLangSelected, setCodeLangSelected] = useState(codeLangDefaultSsr);
9
+ const updateState = () => {
10
+ setCodeLangSelected(getCodeLangStorage());
11
+ };
12
+ const updateStateOnStorageEvent = (event) => {
13
+ if (event.key === storageKey)
14
+ updateState();
15
+ };
16
+ const getCodeLangStorage = () => {
17
+ try {
18
+ return window.localStorage.getItem(storageKey) ?? codeLangDefaultClient;
19
+ }
20
+ catch (error) {
21
+ console.error(error);
22
+ assertWarning(false, 'Error reading from localStorage');
23
+ return codeLangDefaultClient;
24
+ }
25
+ };
26
+ const selectCodeLang = useCallback((value) => {
27
+ try {
28
+ window.localStorage.setItem(storageKey, value);
29
+ setCodeLangSelected(value);
30
+ window.dispatchEvent(new CustomEvent('code-lang-storage'));
31
+ }
32
+ catch (error) {
33
+ console.error(error);
34
+ assertWarning(false, 'Error setting localStorage');
35
+ }
36
+ }, []);
37
+ useEffect(() => {
38
+ // Initial load from localStorage
39
+ updateState();
40
+ // Update code lang in current tab
41
+ window.addEventListener('code-lang-storage', updateState);
42
+ // Update code lang if changed in another tab
43
+ window.addEventListener('storage', updateStateOnStorageEvent);
44
+ return () => {
45
+ window.removeEventListener('code-lang-storage', updateState);
46
+ window.removeEventListener('storage', updateStateOnStorageEvent);
47
+ };
48
+ }, []);
49
+ return [codeLangSelected, selectCodeLang];
50
+ }
@@ -0,0 +1,11 @@
1
+ export { TypescriptOnly };
2
+ export { CodeSnippets };
3
+ import React from 'react';
4
+ import './CodeSnippets.css';
5
+ /** Only show if TypeScript is selected */
6
+ declare function TypescriptOnly({ children }: {
7
+ children: React.ReactNode;
8
+ }): React.JSX.Element;
9
+ declare function CodeSnippets({ children }: {
10
+ children: React.ReactNode;
11
+ }): React.JSX.Element;