@primer/doctocat-nextjs 0.0.0-20250625111807 → 0.0.0-20250626090518
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.
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# @primer/doctocat-nextjs
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20250626090518
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- Fake entry to force publishing
|
|
8
8
|
|
|
9
|
-
## 0.
|
|
9
|
+
## 0.5.4
|
|
10
10
|
|
|
11
11
|
### Patch Changes
|
|
12
12
|
|
|
13
|
-
- [#51](https://github.com/primer/doctocat-nextjs/pull/51) [`
|
|
13
|
+
- [#51](https://github.com/primer/doctocat-nextjs/pull/51) [`4c76c4f`](https://github.com/primer/doctocat-nextjs/commit/4c76c4f5ccd248ec7d1f448c054808287a3ff51d) Thanks [@rezrah](https://github.com/rezrah)! - Add auto-collapsed React code blocks for large code snippets. This feature only applies to code fences with the `jsx live` language identifiers.
|
|
14
14
|
|
|
15
15
|
E.g.
|
|
16
16
|
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
- [#48](https://github.com/primer/doctocat-nextjs/pull/48) [`ce73c24`](https://github.com/primer/doctocat-nextjs/commit/ce73c24b2e4e924667bf7446a504bd88d8f2ccf0) Thanks [@rezrah](https://github.com/rezrah)! - - Fix inline code font-size in markdown headings. Now inherits size used in the heading.
|
|
22
|
+
|
|
22
23
|
- Increased spacing below React code blocks, which was previously too small.
|
|
23
24
|
|
|
25
|
+
- [#50](https://github.com/primer/doctocat-nextjs/pull/50) [`5d67989`](https://github.com/primer/doctocat-nextjs/commit/5d679895408c1a58342419692db4234dfddefd80) Thanks [@rezrah](https://github.com/rezrah)! - Add `menu-position` frontmatter support for custom sidebar navigation ordering
|
|
26
|
+
|
|
24
27
|
## 0.5.3
|
|
25
28
|
|
|
26
29
|
### Patch Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import React, {PropsWithChildren, useCallback, useState, useRef, useEffect, useId} from 'react'
|
|
2
|
+
import React, {type PropsWithChildren, useCallback, useState, useRef, useEffect, useId} from 'react'
|
|
3
3
|
import clsx from 'clsx'
|
|
4
4
|
import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live'
|
|
5
5
|
import {useColorMode} from '../../context/color-modes/useColorMode'
|
|
@@ -21,6 +21,15 @@ type ReactCodeBlockProps = {
|
|
|
21
21
|
jsxScope: Record<string, unknown>
|
|
22
22
|
} & PropsWithChildren<HTMLElement>
|
|
23
23
|
|
|
24
|
+
const getFocusableElements = () => {
|
|
25
|
+
const focusableElementsQuery = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
26
|
+
|
|
27
|
+
return Array.from(document.querySelectorAll<HTMLElement>(focusableElementsQuery)).filter(el => {
|
|
28
|
+
const style = window.getComputedStyle(el)
|
|
29
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && !el.hasAttribute('disabled')
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
export function ReactCodeBlock(props: ReactCodeBlockProps) {
|
|
25
34
|
const uniqueId = useId()
|
|
26
35
|
const {colorMode, setColorMode} = useColorMode()
|
|
@@ -31,6 +40,7 @@ export function ReactCodeBlock(props: ReactCodeBlockProps) {
|
|
|
31
40
|
const [isCodePaneCollapsed, setIsCodePaneCollapsed] = useState<boolean | null>(null)
|
|
32
41
|
const [initialPosition, setInitialPosition] = useState<number | null>(null)
|
|
33
42
|
const editorRef = useRef<HTMLDivElement>(null)
|
|
43
|
+
const resetButtonRef = useRef<HTMLButtonElement>(null)
|
|
34
44
|
const shouldShowPreview = ['tsx', 'jsx'].includes(props['data-language'])
|
|
35
45
|
|
|
36
46
|
// scroll back to the initial y pos on collapse state change
|
|
@@ -84,6 +94,41 @@ export function ReactCodeBlock(props: ReactCodeBlockProps) {
|
|
|
84
94
|
|
|
85
95
|
const noInline = props['data-filename'] === 'noinline' || false
|
|
86
96
|
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const editor = editorRef.current
|
|
99
|
+
|
|
100
|
+
if (!editor) return
|
|
101
|
+
|
|
102
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
103
|
+
if (e.key !== 'Tab') {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (e.shiftKey) {
|
|
108
|
+
e.preventDefault()
|
|
109
|
+
// We know that the previous focusable element is always the reset button
|
|
110
|
+
resetButtonRef.current?.focus()
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const focusableElements = getFocusableElements()
|
|
115
|
+
|
|
116
|
+
const currentIndex = focusableElements.findIndex(el => el === resetButtonRef.current)
|
|
117
|
+
|
|
118
|
+
if (currentIndex !== -1) {
|
|
119
|
+
e.preventDefault()
|
|
120
|
+
const nextIndex = currentIndex + 1
|
|
121
|
+
focusableElements[nextIndex]?.focus()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
editor.addEventListener('keydown', onKeyDown)
|
|
126
|
+
|
|
127
|
+
return () => {
|
|
128
|
+
editor.removeEventListener('keydown', onKeyDown)
|
|
129
|
+
}
|
|
130
|
+
}, [])
|
|
131
|
+
|
|
87
132
|
return (
|
|
88
133
|
<>
|
|
89
134
|
<LiveProvider transformCode={transformCodeWithBasePath} code={code} scope={props.jsxScope} noInline={noInline}>
|
|
@@ -117,7 +162,7 @@ export function ReactCodeBlock(props: ReactCodeBlockProps) {
|
|
|
117
162
|
<Button size="small" leadingVisual={CopyIcon} onClick={handleCopy}>
|
|
118
163
|
Copy
|
|
119
164
|
</Button>
|
|
120
|
-
<Button size="small" leadingVisual={UndoIcon} onClick={handleReset}>
|
|
165
|
+
<Button size="small" leadingVisual={UndoIcon} onClick={handleReset} ref={resetButtonRef}>
|
|
121
166
|
Reset
|
|
122
167
|
</Button>
|
|
123
168
|
</div>
|
|
@@ -149,22 +149,40 @@ export function Theme({pageMap, children}: ThemeProps) {
|
|
|
149
149
|
{activeHeaderLink ? activeHeaderLink.title : siteTitle}
|
|
150
150
|
</Breadcrumbs.Item>
|
|
151
151
|
)}
|
|
152
|
-
{activePath.
|
|
153
|
-
|
|
152
|
+
{activePath.reduce((acc, item, index, items) => {
|
|
153
|
+
// Skip duplicate item for index pages without tab-label
|
|
154
|
+
if (
|
|
155
|
+
index > 0 &&
|
|
156
|
+
item.route === items[index - 1].route &&
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
158
|
+
!item.frontMatter?.['tab-label']
|
|
159
|
+
) {
|
|
160
|
+
return acc
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
164
|
+
const itemTitle = item.frontMatter?.['tab-label'] || item.title
|
|
165
|
+
const isLastItem = index === items.length - 1
|
|
166
|
+
|
|
167
|
+
acc.push(
|
|
154
168
|
<Breadcrumbs.Item
|
|
155
169
|
as={NextLink}
|
|
156
|
-
key={item.name}
|
|
170
|
+
key={`${item.name}-${index}`}
|
|
157
171
|
href={item.route}
|
|
158
|
-
selected={
|
|
172
|
+
selected={isLastItem}
|
|
159
173
|
sx={{
|
|
160
174
|
textTransform: 'capitalize',
|
|
161
175
|
color: 'var(--brand-InlineLink-color-rest)',
|
|
176
|
+
pointerEvents: isLastItem ? 'none' : undefined,
|
|
177
|
+
cursor: isLastItem ? 'default' : undefined,
|
|
162
178
|
}}
|
|
163
179
|
>
|
|
164
|
-
{
|
|
165
|
-
</Breadcrumbs.Item
|
|
180
|
+
{itemTitle.replace(/-/g, ' ')}
|
|
181
|
+
</Breadcrumbs.Item>,
|
|
166
182
|
)
|
|
167
|
-
|
|
183
|
+
|
|
184
|
+
return acc
|
|
185
|
+
}, [] as React.ReactNode[])}
|
|
168
186
|
</Breadcrumbs>
|
|
169
187
|
)}
|
|
170
188
|
|
|
@@ -82,7 +82,29 @@ export function Sidebar({pageMap}: SidebarProps) {
|
|
|
82
82
|
<NextLink href={item.route}>{subNavName}</NextLink>
|
|
83
83
|
</NavList.GroupHeading>
|
|
84
84
|
{item.children
|
|
85
|
-
.sort((a, b) =>
|
|
85
|
+
.sort((a, b) => {
|
|
86
|
+
// make sure index page is first
|
|
87
|
+
if ((a as MdxFile).name === 'index') return -1
|
|
88
|
+
if ((b as MdxFile).name === 'index') return 1
|
|
89
|
+
|
|
90
|
+
// Check for menu-position property in frontmatter
|
|
91
|
+
const aPos = (a as MdxFile).frontMatter?.['menu-position']
|
|
92
|
+
const bPos = (b as MdxFile).frontMatter?.['menu-position']
|
|
93
|
+
|
|
94
|
+
// If both have menu-position, sort by menu-position
|
|
95
|
+
if (typeof aPos === 'number' && typeof bPos === 'number') {
|
|
96
|
+
return aPos - bPos
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If only one has menu-position, it comes first
|
|
100
|
+
if (typeof aPos === 'number') return -1
|
|
101
|
+
if (typeof bPos === 'number') return 1
|
|
102
|
+
|
|
103
|
+
// Neither has menu-position, sort alphabetically by title or name
|
|
104
|
+
const aTitle = (a as MdxFile).frontMatter?.title || (a as MdxFile).name
|
|
105
|
+
const bTitle = (b as MdxFile).frontMatter?.title || (b as MdxFile).name
|
|
106
|
+
return aTitle.localeCompare(bTitle)
|
|
107
|
+
})
|
|
86
108
|
// only show index page if it has show-tabs
|
|
87
109
|
.filter(child => (child as MdxFile).name !== 'index' || hasShowTabs(child as ExtendedPageItem))
|
|
88
110
|
.map(child => {
|
package/package.json
CHANGED