@brillout/docpress 0.15.10-commit-b6b1605 → 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 (41) 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 +78 -68
  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 -136
  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/contentMap.d.ts +0 -9
  37. package/dist/utils/contentMap.js +0 -22
  38. package/dist/utils/useSelectedLanguage.d.ts +0 -7
  39. package/dist/utils/useSelectedLanguage.js +0 -49
  40. package/utils/contentMap.ts +0 -34
  41. 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,111 +2,121 @@ export { detypePlugin }
2
2
 
3
3
  import type { PluginOption } from 'vite'
4
4
  import module from 'node:module'
5
- import { createContentMap, contentMapKeyRE, type ContentMap } from './utils/contentMap.js'
6
-
5
+ import { assertUsage } from './utils/assert.js'
6
+ import pc from '@brillout/picocolors'
7
7
  // Cannot use `import { transform } from 'detype'` as it results in errors,
8
8
  // and the package has no default export. Using `module.createRequire` instead.
9
- 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
10
36
 
11
37
  function detypePlugin(): PluginOption {
12
38
  return {
13
39
  name: '@brillout/docpress:detypePlugin',
14
40
  enforce: 'pre',
15
- transform: async (code: string, id: string) => {
16
- if (!id.endsWith('+Page.mdx')) {
17
- return
18
- }
19
- const contentMap = createContentMap()
20
- const codeNew = await transformCode(code, contentMap)
21
- const replaced = replaceContent(codeNew, contentMapKeyRE, (match) => {
22
- const content = contentMap.get(match[0])
23
- if (!content) {
24
- throw new Error('Content not found')
25
- }
26
- return content
27
- })
28
-
29
- return replaced
41
+ transform: async (code: string, moduleId: string) => {
42
+ if (!moduleId.endsWith('.mdx')) return
43
+ const codeNew = await transformCode(code, moduleId)
44
+ return codeNew
30
45
  },
31
46
  }
32
47
  }
33
48
 
34
- const codeBlockRE = /^([ \t]{0,3}>?[ \t]?)```(tsx?|vue)[^\n]*\n([\s\S]*?)```/gm
35
- const prettierOptions = {
36
- semi: false,
37
- singleQuote: true,
38
- printWidth: 120,
39
- }
40
-
41
- async function transformCode(code: string, contentMap: ContentMap) {
49
+ async function transformCode(code: string, moduleId: string) {
42
50
  const matches = Array.from(code.matchAll(codeBlockRE))
43
- if (matches.length === 0) {
44
- return code
45
- }
51
+ if (matches.length === 0) return
46
52
 
47
- let codeNew = `import { CodeSnippets, CodeSnippet } from '@brillout/docpress';\n`
53
+ let codeNew = `import { CodeSnippets, CodeSnippet } from '@brillout/docpress';\n\n`
48
54
  let lastIndex = 0
49
55
 
50
56
  for (const match of matches) {
51
- let [fullMatch, startsWith, lang, tsCode] = match
52
- const tsOpeningCode = fullMatch.split('\n')[0].slice(startsWith.length)
57
+ const [codeBlockOuterStr, codeBlockIndent, codeBlockLang, codeBlockContentWithIndent] = match
53
58
 
54
- const blockStart = match.index
55
- 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)
56
62
 
57
- codeNew += code.slice(lastIndex, blockStart)
63
+ const blockStartIndex = match.index
64
+ const blockEndIndex = blockStartIndex + codeBlockOuterStr.length
65
+ codeNew += code.slice(lastIndex, blockStartIndex)
58
66
 
59
- if (startsWith.length > 0) {
60
- tsCode = stripStarts(tsCode, startsWith)
61
- }
62
-
63
- if (tsOpeningCode.includes('ts-only')) {
64
- const key = contentMap.add('ts-code-snippet', fullMatch.length, fullMatch)
65
- codeNew += `${startsWith}<CodeSnippet language={'ts'} tsOnly={'true'}>\n${key}\n${startsWith}</CodeSnippet>`
67
+ if (codeBlockOpen.includes('ts-only')) {
68
+ codeNew += `${codeBlockIndent}<CodeSnippet codeLang="ts" tsOnly>\n${codeBlockOuterStr}\n${codeBlockIndent}</CodeSnippet>`
66
69
  } else {
67
- 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}`, {
68
74
  removeTsComments: true,
69
75
  prettierOptions,
70
76
  })
71
- const jsLang = lang === 'vue' ? 'vue' : lang.replace('t', 'j') // ts => js | tsx => jsx
72
- const jsOpeningCode = tsOpeningCode.replace(lang, jsLang)
73
- const closing = `\`\`\``
74
-
75
- const jsCodeSnippet = `<CodeSnippet language={'js'}>\n${jsOpeningCode}\n${jsCode}${closing}\n</CodeSnippet>`
76
- const tsCodeSnippet = `<CodeSnippet language={'ts'}>\n${tsOpeningCode}\n${tsCode}${closing}\n</CodeSnippet>`
77
- const codeSnippets = putBackStarts(`${tsCodeSnippet}\n${jsCodeSnippet}`, startsWith)
78
77
 
79
- const key = contentMap.add(`ts-js-code-snippets`, codeSnippets.length, codeSnippets)
80
- codeNew += `${startsWith}<CodeSnippets>\n${key}\n${startsWith}</CodeSnippets>`
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,
91
+ )
92
+
93
+ codeNew += codeSnippets
81
94
  }
82
95
 
83
- lastIndex = blockEnd
96
+ lastIndex = blockEndIndex
84
97
  }
85
98
  codeNew += code.slice(lastIndex)
86
99
 
87
100
  return codeNew
88
101
  }
89
102
 
90
- function stripStarts(code: string, startsWith: string) {
103
+ function removeCodeBlockIndent(code: string, codeBlockIndent: string, moduleId: string) {
104
+ if (!codeBlockIndent.length) return code
91
105
  return code
92
106
  .split('\n')
93
- .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
+ })
94
114
  .join('\n')
95
115
  }
96
-
97
- function putBackStarts(code: string, startsWith: string) {
98
- if (!startsWith.length) {
99
- return code
100
- }
116
+ function restoreCodeBlockIndent(code: string, codeBlockIndent: string) {
117
+ if (!codeBlockIndent.length) return code
101
118
  return code
102
119
  .split('\n')
103
- .map((line) => `${startsWith}${line}`)
120
+ .map((line) => `${codeBlockIndent}${line}`)
104
121
  .join('\n')
105
122
  }
106
-
107
- function replaceContent(input: string, re: RegExp, replacer: (match: RegExpMatchArray) => string): string {
108
- const replacements = Array.from(input.matchAll(re), replacer)
109
- let i = 0
110
-
111
- return input.replace(re, () => replacements[i++])
112
- }
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
+ }