@brillout/docpress 0.15.10-commit-e9efbd3 → 0.15.10-commit-36f361e

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 (38) hide show
  1. package/components/CodeSnippets/useSelectCodeLang.ts +61 -0
  2. package/components/CodeSnippets.css +47 -0
  3. package/components/CodeSnippets.tsx +80 -45
  4. package/css/tooltip.css +10 -2
  5. package/detypePlugin.ts +73 -48
  6. package/dist/+config.js +1 -1
  7. package/dist/NavItemComponent.js +38 -46
  8. package/dist/components/CodeBlockTransformer.js +2 -3
  9. package/dist/components/CodeSnippets/useSelectCodeLang.d.ts +7 -0
  10. package/dist/components/CodeSnippets/useSelectCodeLang.js +51 -0
  11. package/dist/components/CodeSnippets.d.ts +10 -6
  12. package/dist/components/CodeSnippets.js +66 -94
  13. package/dist/components/Comment.js +1 -2
  14. package/dist/components/FileRemoved.js +4 -6
  15. package/dist/components/HorizontalLine.js +1 -2
  16. package/dist/components/ImportMeta.js +2 -3
  17. package/dist/components/Link.js +34 -50
  18. package/dist/components/Note.js +17 -29
  19. package/dist/components/P.js +1 -12
  20. package/dist/components/RepoLink.js +7 -9
  21. package/dist/determineNavItemsColumnLayout.js +48 -63
  22. package/dist/detypePlugin.js +84 -120
  23. package/dist/parseMarkdownMini.js +5 -17
  24. package/dist/parsePageSections.js +41 -82
  25. package/dist/renderer/usePageContext.js +6 -7
  26. package/dist/resolvePageContext.js +91 -103
  27. package/dist/utils/Emoji/Emoji.js +13 -21
  28. package/dist/utils/assert.js +14 -16
  29. package/dist/utils/cls.js +1 -1
  30. package/dist/utils/determineSectionUrlHash.js +5 -5
  31. package/dist/utils/filter.js +2 -2
  32. package/dist/utils/getGlobalObject.js +3 -3
  33. package/dist/vite.config.js +7 -7
  34. package/package.json +1 -1
  35. package/tsconfig.json +2 -1
  36. package/dist/utils/useSelectedLanguage.d.ts +0 -7
  37. package/dist/utils/useSelectedLanguage.js +0 -49
  38. package/utils/useSelectedLanguage.ts +0 -61
@@ -0,0 +1,61 @@
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) return
17
+ updateState()
18
+ }
19
+
20
+ const getCodeLangStorage = () => {
21
+ try {
22
+ return window.localStorage.getItem(storageKey) ?? codeLangDefaultClient
23
+ } catch (error) {
24
+ console.error(error)
25
+ assertWarning(false, 'Error reading from localStorage')
26
+ return codeLangDefaultClient
27
+ }
28
+ }
29
+
30
+ const selectCodeLang = useCallback((value: string) => {
31
+ try {
32
+ window.localStorage.setItem(storageKey, value)
33
+ setCodeLangSelected(value)
34
+ window.dispatchEvent(new CustomEvent('code-lang-storage'))
35
+ } catch (error) {
36
+ console.error(error)
37
+ assertWarning(false, 'Error setting localStorage')
38
+ }
39
+ }, [])
40
+
41
+ useEffect(() => {
42
+ // Initial load from localStorage
43
+ updateState()
44
+ // Update code lang in current tab
45
+ window.addEventListener('code-lang-storage', updateState)
46
+ // Update code lang if changed in another tab
47
+ window.addEventListener('storage', updateStateOnStorageEvent)
48
+ return () => {
49
+ window.removeEventListener('code-lang-storage', updateState)
50
+ window.removeEventListener('storage', updateStateOnStorageEvent)
51
+ }
52
+ }, [])
53
+
54
+ return [codeLangSelected, selectCodeLang] as const
55
+ }
56
+
57
+ declare global {
58
+ interface WindowEventMap {
59
+ 'code-lang-storage': CustomEvent
60
+ }
61
+ }
@@ -0,0 +1,47 @@
1
+ /* Language select */
2
+ .code-lang-select {
3
+ right: 42px;
4
+ padding-left: 6px;
5
+ padding-right: 21px;
6
+ font-size: 14px;
7
+ background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 1'><path fill='%23666' d='M0 0l1 1 1-1z'/></svg>");
8
+ background-repeat: no-repeat;
9
+ background-position: right 7px center;
10
+ background-size: 10px;
11
+ /* Remove default arrow in some browsers */
12
+ appearance: none;
13
+ -webkit-appearance: none;
14
+ -moz-appearance: none;
15
+ }
16
+
17
+ /* Copy button */
18
+ .copy-button {
19
+ display: inline-flex;
20
+ align-items: center;
21
+ right: 10px;
22
+ width: 30px;
23
+ & svg {
24
+ width: 100%;
25
+ height: 100%;
26
+ stroke-linecap: round;
27
+ stroke-linejoin: round;
28
+ fill: none;
29
+ }
30
+ }
31
+
32
+ /* Common style */
33
+ .copy-button,
34
+ .code-lang-select {
35
+ position: absolute !important;
36
+ height: 25px;
37
+ top: 10px;
38
+ z-index: 3;
39
+ outline: none;
40
+ cursor: pointer;
41
+ border: 1px solid #ccc;
42
+ border-radius: 5px;
43
+ background-color: #f7f7f7;
44
+ &:hover {
45
+ background-color: #eee;
46
+ }
47
+ }
@@ -1,72 +1,107 @@
1
- export { CodeSnippets, CodeSnippet, TypescriptOnly }
1
+ // Public
2
+ export { TypescriptOnly }
2
3
 
3
- import React from 'react'
4
- import { useSelectedLanguage } from '../utils/useSelectedLanguage'
4
+ // Internal
5
+ export { CodeSnippets }
6
+ export { CodeSnippet }
5
7
 
6
- function CodeSnippets({ children }: { children: React.ReactNode }) {
7
- const [selectedLang, setSelectedLang] = useSelectedLanguage()
8
+ import React, { useState } from 'react'
9
+ import { useSelectCodeLang } from './CodeSnippets/useSelectCodeLang'
10
+ import './CodeSnippets.css'
8
11
 
9
- const handleOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
10
- setSelectedLang(e.target.value)
11
- }
12
+ /** Only show if TypeScript is selected */
13
+ function TypescriptOnly({ children }: { children: React.ReactNode }) {
14
+ const [codeLangSelected] = useSelectCodeLang()
15
+ return <div style={{ display: codeLangSelected === 'ts' ? 'block' : 'none' }}>{children}</div>
16
+ }
12
17
 
18
+ function CodeSnippets({ children }: { children: React.ReactNode }) {
19
+ const [codeLangSelected, selectCodeLang] = useSelectCodeLang()
13
20
  return (
14
21
  <div>
15
22
  <form style={{ position: 'relative' }}>
16
- <select
17
- name="language"
18
- id="language"
19
- onChange={handleOnChange}
20
- value={selectedLang}
21
- style={{ position: 'absolute', top: '10px', right: '60px', zIndex: 3 }}
22
- >
23
- <option value="js">Javascript</option>
24
- <option value="ts">Typescript</option>
23
+ <select className="code-lang-select" onChange={onChange} value={codeLangSelected}>
24
+ <option value="js">JavaScript</option>
25
+ <option value="ts">TypeScript</option>
25
26
  </select>
26
27
  </form>
27
28
  {children}
28
29
  </div>
29
30
  )
31
+ function onChange(e: React.ChangeEvent<HTMLSelectElement>) {
32
+ selectCodeLang(e.target.value)
33
+ }
30
34
  }
31
35
 
32
36
  function CodeSnippet({
33
37
  children,
34
- language,
38
+ codeLang,
35
39
  tsOnly = false,
36
- }: { children: React.ReactNode; language: string; tsOnly: boolean }) {
37
- const [selectedLang] = useSelectedLanguage()
40
+ }: { children: React.ReactNode; codeLang: string; tsOnly: boolean }) {
41
+ const [codeLangSelected] = useSelectCodeLang()
38
42
 
39
- const style = tsOnly ? {} : { display: selectedLang === language ? 'block' : 'none' }
40
-
41
- const copyToClipboard = async (e: React.MouseEvent<HTMLButtonElement>) => {
42
- try {
43
- const figureEl = e.currentTarget.nextElementSibling
44
- if (figureEl?.tagName === 'FIGURE') {
45
- await navigator.clipboard.writeText(figureEl.textContent ?? '')
46
- console.log('Copied to clipboard!')
47
- }
48
- } catch (error) {
49
- console.warn('Copy failed', error)
50
- }
51
- }
43
+ const displayStyle = tsOnly ? {} : { display: codeLangSelected === codeLang ? 'block' : 'none' }
52
44
 
53
45
  return (
54
- <div style={{ ...style, position: 'relative' }}>
55
- <button
56
- type="button"
57
- style={{ position: 'absolute', top: '10px', right: '10px', zIndex: 3 }}
58
- onClick={copyToClipboard}
59
- >
60
- Copy
61
- </button>
46
+ <div style={{ ...displayStyle, position: 'relative' }}>
47
+ <CopyButton />
62
48
  {children}
63
49
  </div>
64
50
  )
65
51
  }
66
52
 
67
- // Show/hide TypeScript sections (code and/or plain)
68
- function TypescriptOnly({ children }: { children: React.ReactNode }) {
69
- const [selectedLang] = useSelectedLanguage()
53
+ function CopyButton() {
54
+ const [isSuccess, setIsSuccess] = useState(null as null | boolean)
55
+ const onCopy = (success: boolean) => {
56
+ setIsSuccess(success)
57
+ setTimeout(() => {
58
+ setIsSuccess(null)
59
+ }, 900)
60
+ }
61
+ const tooltip = isSuccess === null ? 'Copy to clipboard' : isSuccess ? 'Copied' : 'Failed'
62
+ const text =
63
+ isSuccess === null ? (
64
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
65
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
66
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
67
+ </svg>
68
+ ) : isSuccess ? (
69
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="#28a745" strokeWidth="3">
70
+ <polyline points="20 6 9 17 4 12" />
71
+ </svg>
72
+ ) : (
73
+ '❌'
74
+ )
75
+ return (
76
+ <button className="copy-button" aria-label={tooltip} data-label-position="top" type="button" onClick={onClick}>
77
+ {text}
78
+ </button>
79
+ )
80
+ async function onClick(e: React.MouseEvent<HTMLButtonElement>) {
81
+ let success: boolean
82
+ try {
83
+ await copyToClipboard(e)
84
+ success = true
85
+ } catch (error) {
86
+ console.error(error)
87
+ success = false
88
+ }
89
+ onCopy(success)
90
+ }
91
+ }
92
+
93
+ async function copyToClipboard(e: React.MouseEvent<HTMLButtonElement>) {
94
+ const figureEl = e.currentTarget.nextElementSibling
95
+ if (figureEl?.tagName === 'FIGURE') {
96
+ let text = figureEl.textContent ?? ''
97
+ text = removeTrailingWhitespaces(text)
98
+ await navigator.clipboard.writeText(text)
99
+ }
100
+ }
70
101
 
71
- return <div style={{ display: selectedLang === 'ts' ? 'block' : 'none' }}>{children}</div>
102
+ function removeTrailingWhitespaces(text: string) {
103
+ return text
104
+ .split('\n')
105
+ .map((line) => line.trimEnd())
106
+ .join('\n')
72
107
  }
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/detypePlugin.ts CHANGED
@@ -2,96 +2,121 @@ export { detypePlugin }
2
2
 
3
3
  import type { PluginOption } from 'vite'
4
4
  import module from 'node:module'
5
-
5
+ import { assertUsage } from './utils/assert.js'
6
+ import pc from '@brillout/picocolors'
6
7
  // Cannot use `import { transform } from 'detype'` as it results in errors,
7
8
  // and the package has no default export. Using `module.createRequire` instead.
8
- const { transform } = module.createRequire(import.meta.url)('detype') as typeof import('detype')
9
+ const { transform: detype } = module.createRequire(import.meta.url)('detype') as typeof import('detype')
10
+
11
+ const prettierOptions: NonNullable<Parameters<typeof detype>[2]>['prettierOptions'] = {
12
+ semi: false,
13
+ singleQuote: true,
14
+ printWidth: 100,
15
+ trailingComma: 'none',
16
+ }
17
+ // RegExp to find TypeScript code blocks.
18
+ //
19
+ // For example:
20
+ // ~~~mdx
21
+ // ```ts
22
+ // const hello: string = 'world'
23
+ // ```
24
+ // ~~~
25
+ //
26
+ // But also indented code blocks:
27
+ // ~~~mdx
28
+ // > Also works:
29
+ // > - In blockquotes
30
+ // > - In bullet points
31
+ // > ```ts
32
+ // > const hello: string = 'world'
33
+ // > ```
34
+ // ~~~
35
+ const codeBlockRE = /^(.*)```(tsx?|vue)[^\n]*\n([\s\S]*?)```/gm
9
36
 
10
37
  function detypePlugin(): PluginOption {
11
38
  return {
12
39
  name: '@brillout/docpress:detypePlugin',
13
40
  enforce: 'pre',
14
- transform: async (code: string, id: string) => {
15
- if (!id.endsWith('+Page.mdx')) {
16
- return
17
- }
18
- const codeNew = await transformCode(code)
19
-
41
+ transform: async (code: string, moduleId: string) => {
42
+ if (!moduleId.endsWith('.mdx')) return
43
+ const codeNew = await transformCode(code, moduleId)
20
44
  return codeNew
21
45
  },
22
46
  }
23
47
  }
24
48
 
25
- const codeBlockRE = /^([ \t]{0,3}>?[ \t]?)```(tsx?|vue)[^\n]*\n([\s\S]*?)```/gm
26
- const prettierOptions = {
27
- semi: false,
28
- singleQuote: true,
29
- printWidth: 100,
30
- }
31
-
32
- async function transformCode(code: string) {
49
+ async function transformCode(code: string, moduleId: string) {
33
50
  const matches = Array.from(code.matchAll(codeBlockRE))
34
- if (matches.length === 0) {
35
- return code
36
- }
51
+ if (matches.length === 0) return
37
52
 
38
53
  let codeNew = `import { CodeSnippets, CodeSnippet } from '@brillout/docpress';\n\n`
39
54
  let lastIndex = 0
40
55
 
41
56
  for (const match of matches) {
42
- let [fullMatch, startsWith, lang, tsCode] = match
43
- const tsOpeningCode = fullMatch.split('\n')[0].slice(startsWith.length)
57
+ const [codeBlockOuterStr, codeBlockIndent, codeBlockLang, codeBlockContentWithIndent] = match
44
58
 
45
- const blockStart = match.index
46
- const blockEnd = blockStart + fullMatch.length
59
+ // Remove indentation
60
+ const codeBlockOpen = codeBlockOuterStr.split('\n')[0].slice(codeBlockIndent.length)
61
+ const codeBlockContent = removeCodeBlockIndent(codeBlockContentWithIndent, codeBlockIndent, moduleId)
47
62
 
48
- codeNew += code.slice(lastIndex, blockStart)
63
+ const blockStartIndex = match.index
64
+ const blockEndIndex = blockStartIndex + codeBlockOuterStr.length
65
+ codeNew += code.slice(lastIndex, blockStartIndex)
49
66
 
50
- if (startsWith.length > 0) {
51
- tsCode = stripStarts(tsCode, startsWith)
52
- }
53
-
54
- if (tsOpeningCode.includes('ts-only')) {
55
- codeNew += `${startsWith}<CodeSnippet language={'ts'} tsOnly={'true'}>\n${fullMatch}\n${startsWith}</CodeSnippet>`
67
+ if (codeBlockOpen.includes('ts-only')) {
68
+ codeNew += `${codeBlockIndent}<CodeSnippet codeLang="ts" tsOnly>\n${codeBlockOuterStr}\n${codeBlockIndent}</CodeSnippet>`
56
69
  } else {
57
- const jsCode = await transform(tsCode.replaceAll('.ts', '.js'), `tsCode.${lang}`, {
70
+ // someFileName.ts => someFileName.js
71
+ let codeBlockContentJs = codeBlockContent.replaceAll('.ts', '.js')
72
+ // Remove TypeScript
73
+ codeBlockContentJs = await detype(codeBlockContentJs, `some-dummy-filename.${codeBlockLang}`, {
58
74
  removeTsComments: true,
59
75
  prettierOptions,
60
76
  })
61
- const jsLang = lang === 'vue' ? 'vue' : lang.replace('t', 'j') // ts => js | tsx => jsx
62
- const jsOpeningCode = tsOpeningCode.replace(lang, jsLang)
63
- const closing = `\`\`\``
64
77
 
65
- const jsCodeSnippet = `<CodeSnippet language={'js'}>\n${jsOpeningCode}\n${jsCode}${closing}\n</CodeSnippet>`
66
- const tsCodeSnippet = `<CodeSnippet language={'ts'}>\n${tsOpeningCode}\n${tsCode}${closing}\n</CodeSnippet>`
67
- const codeSnippets = putBackStarts(
68
- `<CodeSnippets>\n${tsCodeSnippet}\n${jsCodeSnippet}\n</CodeSnippets>`,
69
- startsWith,
78
+ const codeBlockLangJs =
79
+ codeBlockLang === 'vue'
80
+ ? 'vue'
81
+ : // ts => js | tsx => jsx
82
+ codeBlockLang.replace('t', 'j')
83
+ const codeBlockOpenJs = codeBlockOpen.replace(codeBlockLang, codeBlockLangJs)
84
+ const codeBlockClose = '```'
85
+
86
+ const codeSnippetTs = `<CodeSnippet codeLang="ts">\n${codeBlockOpen}\n${codeBlockContent}${codeBlockClose}\n</CodeSnippet>`
87
+ const codeSnippetJs = `<CodeSnippet codeLang="js">\n${codeBlockOpenJs}\n${codeBlockContentJs}${codeBlockClose}\n</CodeSnippet>`
88
+ const codeSnippets = restoreCodeBlockIndent(
89
+ `<CodeSnippets>\n${codeSnippetJs}\n${codeSnippetTs}\n</CodeSnippets>`,
90
+ codeBlockIndent,
70
91
  )
71
92
 
72
93
  codeNew += codeSnippets
73
94
  }
74
95
 
75
- lastIndex = blockEnd
96
+ lastIndex = blockEndIndex
76
97
  }
77
98
  codeNew += code.slice(lastIndex)
78
99
 
79
100
  return codeNew
80
101
  }
81
102
 
82
- function stripStarts(code: string, startsWith: string) {
103
+ function removeCodeBlockIndent(code: string, codeBlockIndent: string, moduleId: string) {
104
+ if (!codeBlockIndent.length) return code
83
105
  return code
84
106
  .split('\n')
85
- .map((line) => line.slice(startsWith.length))
107
+ .map((line) => {
108
+ assertUsage(
109
+ line.startsWith(codeBlockIndent),
110
+ `In ${pc.bold(pc.blue(moduleId))} the line ${pc.bold(line)} must start with ${pc.bold(codeBlockIndent)}`,
111
+ )
112
+ return line.slice(codeBlockIndent.length)
113
+ })
86
114
  .join('\n')
87
115
  }
88
-
89
- function putBackStarts(code: string, startsWith: string) {
90
- if (!startsWith.length) {
91
- return code
92
- }
116
+ function restoreCodeBlockIndent(code: string, codeBlockIndent: string) {
117
+ if (!codeBlockIndent.length) return code
93
118
  return code
94
119
  .split('\n')
95
- .map((line) => `${startsWith}${line}`)
120
+ .map((line) => `${codeBlockIndent}${line}`)
96
121
  .join('\n')
97
122
  }
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
+ }