@brillout/docpress 0.16.38 → 0.16.40

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.
@@ -49,6 +49,28 @@
49
49
  transition: background 120ms ease;
50
50
  }
51
51
 
52
+ .choice-select__option-content {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ gap: 2px;
56
+ }
57
+
58
+ .choice-select__option img {
59
+ width: 14px;
60
+ height: 14px;
61
+
62
+ filter: grayscale(100%);
63
+ opacity: 0.8;
64
+ --transition: 500ms ease;
65
+ transition: filter var(--transition), opacity var(--transition);
66
+ }
67
+
68
+ .choice-select:hover .choice-select__option img,
69
+ .choice-select[aria-expanded='true'] .choice-select__option img {
70
+ filter: grayscale(0%);
71
+ opacity: 1;
72
+ }
73
+
52
74
  .choice-select[aria-expanded='false'] {
53
75
  overflow: hidden;
54
76
  border-width: 1px 2px 2px 1px;
@@ -1,33 +1,14 @@
1
1
  export { ChoiceGroup, CustomSelectsContainer }
2
2
 
3
- import React, { createContext, useContext, useEffect, useState } from 'react'
3
+ import type { ChoiceGroup as TChoiceGroup, ChoiceGroupWithParent } from '../types.js'
4
+ import React, { createContext, useContext, useState } from 'react'
5
+ import { usePageContext } from '../../renderer/usePageContext.js'
4
6
  import { useCurrentSelection } from '../hooks/useCurrentSelection.js'
5
7
  import { useRestoreScroll } from '../hooks/useRestoreScroll.js'
6
8
  import { cls } from '../../utils/cls.js'
7
9
  import './ChoiceGroup.css'
8
10
 
9
- type TChoiceGroup = {
10
- name: string
11
- choices: string[]
12
- emptyChoices: string[]
13
- default: string
14
- hidden: boolean
15
- lvl: number
16
- }
17
-
18
- type ParentChoiceGroup = {
19
- name: string
20
- default: string
21
- }
22
-
23
- type ChoiceGroupWithParent = TChoiceGroup & { parentChoiceGroup?: ParentChoiceGroup & { choices: string[] } }
24
-
25
- type ContextType = {
26
- choiceGroupAll: ChoiceGroupWithParent[]
27
- registerChoiceGroup: (choiceGroup: TChoiceGroup, parentChoiceGroup?: ParentChoiceGroup & { choice: string }) => void
28
- }
29
-
30
- const CustomSelectsContainerContext = createContext<ContextType | undefined>(undefined)
11
+ const CustomSelectsContainerContext = createContext<{ choiceGroupAll: ChoiceGroupWithParent[] } | undefined>(undefined)
31
12
 
32
13
  function useCustomSelectsContext() {
33
14
  const ctx = useContext(CustomSelectsContainerContext)
@@ -35,75 +16,24 @@ function useCustomSelectsContext() {
35
16
  return ctx
36
17
  }
37
18
 
38
- function CustomSelectsContainer({ children }: { children: React.ReactNode }) {
39
- const [choiceGroupAll, setChoiceGroupAll] = useState<ChoiceGroupWithParent[]>([])
40
-
41
- function registerChoiceGroup(choiceGroup: TChoiceGroup, parentChoiceGroup?: ParentChoiceGroup & { choice: string }) {
42
- setChoiceGroupAll((prev) => {
43
- const index = prev.findIndex((g) => g.name === choiceGroup.name)
44
- const existing = prev[index]
45
-
46
- if (!existing) {
47
- return [
48
- ...prev,
49
- {
50
- ...choiceGroup,
51
- ...(parentChoiceGroup && {
52
- parentChoiceGroup: {
53
- ...parentChoiceGroup,
54
- choices: !choiceGroup.hidden ? [parentChoiceGroup.choice] : [],
55
- },
56
- }),
57
- },
58
- ]
59
- }
60
-
61
- if (!parentChoiceGroup || !existing.parentChoiceGroup) return prev
62
-
63
- const existingChoices = existing.parentChoiceGroup.choices
64
- if (!choiceGroup.hidden) existing.parentChoiceGroup.choices.push(parentChoiceGroup.choice)
65
-
66
- const mergedChoices = new Set([...existing.parentChoiceGroup.choices])
67
- if (mergedChoices.size === existingChoices.length) return prev
68
-
69
- const next = [...prev]
70
- next[index] = {
71
- ...existing,
72
- parentChoiceGroup: {
73
- ...existing.parentChoiceGroup,
74
- choices: [...mergedChoices],
75
- },
76
- }
77
- return next
78
- })
79
- }
80
-
81
- return (
82
- <CustomSelectsContainerContext.Provider value={{ choiceGroupAll, registerChoiceGroup }}>
83
- {children}
84
- </CustomSelectsContainerContext.Provider>
85
- )
86
- }
87
-
88
- type ChoiceGroupProps = {
89
- children: React.ReactNode
90
- choiceGroup: TChoiceGroup
91
- parentChoiceGroup?: ParentChoiceGroup & { choice: string }
19
+ function CustomSelectsContainer({
20
+ children,
21
+ choiceGroupAll,
22
+ }: { children: React.ReactNode; choiceGroupAll: ChoiceGroupWithParent[] }) {
23
+ return <CustomSelectsContainerContext value={{ choiceGroupAll }}>{children}</CustomSelectsContainerContext>
92
24
  }
93
25
 
94
- function ChoiceGroup({ children, choiceGroup, parentChoiceGroup }: ChoiceGroupProps) {
26
+ function ChoiceGroup({ children, choiceGroup }: { children: React.ReactNode; choiceGroup: TChoiceGroup }) {
95
27
  const { name: groupName, choices, default: defaultChoice, lvl } = choiceGroup
96
28
  const [selectedChoice] = useCurrentSelection(groupName, defaultChoice)
97
- const { choiceGroupAll, registerChoiceGroup } = useCustomSelectsContext()
98
-
99
- useEffect(() => registerChoiceGroup(choiceGroup, parentChoiceGroup), [])
29
+ const { choiceGroupAll } = useCustomSelectsContext()
100
30
 
101
31
  return (
102
32
  <div data-choice-group={groupName} data-lvl={lvl} className="choice-group">
103
33
  {/* Hidden select used to control choice visibility via CSS */}
104
34
  <select name={`choicesFor-${groupName}`} value={selectedChoice} hidden disabled>
105
- {choices.map((choice, i) => (
106
- <option key={i} value={choice}>
35
+ {choices.map(({ name: choice }) => (
36
+ <option key={choice} value={choice}>
107
37
  {choice}
108
38
  </option>
109
39
  ))}
@@ -111,49 +41,38 @@ function ChoiceGroup({ children, choiceGroup, parentChoiceGroup }: ChoiceGroupPr
111
41
  {children}
112
42
  {lvl === 0 && !choiceGroup.hidden && (
113
43
  <div className={`choice-group__selects`}>
114
- {choiceGroupAll
115
- .slice()
116
- .sort((a, b) => a.lvl - b.lvl)
117
- .map((choiceGroup, i) => (
118
- <CustomSelect key={i} choiceGroup={choiceGroup} />
119
- ))}
44
+ {choiceGroupAll.map((choiceGroup) => (
45
+ <CustomSelect key={choiceGroup.name} choiceGroup={choiceGroup} />
46
+ ))}
120
47
  </div>
121
48
  )}
122
49
  </div>
123
50
  )
124
51
  }
125
52
 
53
+ const OPTION_HEIGHT = 25
126
54
  function CustomSelect({ choiceGroup }: { choiceGroup: ChoiceGroupWithParent }) {
127
- const { name: groupName, choices, emptyChoices, default: defaultChoice, hidden, parentChoiceGroup } = choiceGroup
55
+ const choicesAll = usePageContext().config.docpress.choices
56
+ const { name: groupName, emptyChoices, default: defaultChoice, hidden, parentChoiceGroup, isBuiltIn } = choiceGroup
128
57
  const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice)
129
- const setPrevPosition = useRestoreScroll([selectedChoice])
130
58
  const [expanded, setExpanded] = useState(false)
59
+ const [parentSelectedChoice] = useCurrentSelection(parentChoiceGroup?.name || '', parentChoiceGroup?.default || '')
60
+ const setPrevPosition = useRestoreScroll([selectedChoice])
131
61
 
62
+ const { choices } = isBuiltIn ? choiceGroup : choicesAll![groupName]!
63
+ const isHidden = parentChoiceGroup ? !parentChoiceGroup.choices.includes(parentSelectedChoice) : hidden
132
64
  const isEmptyChoice = (choice: string) => emptyChoices.includes(choice)
133
- const filteredChoices = choices.filter((choice) => !isEmptyChoice(choice))
134
- const selectedIndex = filteredChoices.indexOf(selectedChoice)
135
- const height = 25
136
- const rectTop = -selectedIndex * height
137
-
138
- function next() {
139
- const nextIndex = (selectedIndex + 1) % filteredChoices.length
140
- setSelectedChoice(filteredChoices[nextIndex]!)
141
- }
142
- function isHidden() {
143
- if (parentChoiceGroup) {
144
- const [parentSelectedChoice] = useCurrentSelection(parentChoiceGroup.name, parentChoiceGroup.default)
145
- return !parentChoiceGroup.choices.includes(parentSelectedChoice)
146
- }
147
- return hidden
148
- }
65
+ const filteredChoices = choices.filter((choice) => !isEmptyChoice(choice.name))
66
+ const selectedIndex = filteredChoices.findIndex((choice) => choice.name === selectedChoice)
67
+ const rectTop = -selectedIndex * OPTION_HEIGHT
149
68
 
150
69
  return (
151
70
  <div
152
71
  id={`choicesFor-${groupName}`}
153
72
  aria-haspopup="listbox"
154
73
  aria-expanded={expanded}
155
- className={cls(['choice-select', (isHidden() || isEmptyChoice(selectedChoice)) && 'hidden'])}
156
- style={{ height }}
74
+ className={cls(['choice-select', (isHidden || isEmptyChoice(selectedChoice)) && 'hidden'])}
75
+ style={{ height: OPTION_HEIGHT }}
157
76
  onMouseEnter={() => setExpanded(true)}
158
77
  onMouseLeave={() => setExpanded(false)}
159
78
  onClick={() => {
@@ -164,32 +83,40 @@ function CustomSelect({ choiceGroup }: { choiceGroup: ChoiceGroupWithParent }) {
164
83
  aria-activedescendant={`choice-${selectedChoice}`}
165
84
  role="listbox"
166
85
  className="choice-select__list"
167
- style={{ top: rectTop, height: filteredChoices.length * height }}
86
+ style={{ top: rectTop, height: filteredChoices.length * OPTION_HEIGHT }}
168
87
  >
169
- {filteredChoices.map((choice, i) => (
88
+ {filteredChoices.map(({ name: choice, icon, iconStyle }, i) => (
170
89
  <div
171
- id={choice}
172
- key={i}
90
+ id={`choice-${choice}`}
91
+ key={choice}
173
92
  aria-selected={i === selectedIndex}
174
93
  role="option"
175
94
  className="choice-select__option"
176
- style={{ height }}
177
- onClick={handleOnClick}
95
+ style={{ height: OPTION_HEIGHT }}
96
+ onClick={(e) => handleOnClick(e, choice)}
178
97
  >
179
- {choice}
98
+ <span className="choice-select__option-content">
99
+ <img src={icon} alt="" aria-hidden="true" style={iconStyle} />
100
+ {choice}
101
+ </span>
180
102
  </div>
181
103
  ))}
182
104
  </div>
183
105
  </div>
184
106
  )
185
- function handleOnClick(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
107
+
108
+ function next() {
109
+ const nextIndex = (selectedIndex + 1) % filteredChoices.length
110
+ setSelectedChoice(filteredChoices[nextIndex]!.name)
111
+ }
112
+ function handleOnClick(e: React.MouseEvent<HTMLDivElement, MouseEvent>, choice: string) {
186
113
  e.stopPropagation()
187
114
  const el = e.currentTarget
188
115
  setPrevPosition(el)
189
116
  if (el.getAttribute('aria-selected') === 'true') {
190
117
  next()
191
118
  } else {
192
- setSelectedChoice(el.id)
119
+ setSelectedChoice(choice)
193
120
  }
194
121
  }
195
122
  }
@@ -11,6 +11,7 @@
11
11
  select:has(option:nth-of-type(7):checked) ~ ul[role='tablist'] li:nth-of-type(7) {
12
12
  border-bottom: 2px solid #aaa;
13
13
  color: var(--color-text);
14
+ font-weight: 600;
14
15
  }
15
16
  }
16
17
 
@@ -32,6 +33,17 @@
32
33
  color: color-mix(in srgb, var(--color-text) 80%, white 20%);
33
34
  }
34
35
 
36
+ .choice-tabs__tab-content {
37
+ display: inline-flex;
38
+ align-items: center;
39
+ gap: 2px;
40
+ }
41
+
42
+ .choice-tabs__tab img {
43
+ width: 14px;
44
+ height: 14px;
45
+ }
46
+
35
47
  @media screen and (max-width: 400px) {
36
48
  .choice-tabs__tab {
37
49
  padding: 6px 4px;
@@ -7,7 +7,7 @@ import { usePageContext } from '../../renderer/usePageContext.js'
7
7
  import { assertUsage } from '../../utils/assert.js'
8
8
  import './Tabs.css'
9
9
 
10
- function Tabs({ choice, hiddenChoices = [] }: { choice: string; hiddenChoices: string[] }) {
10
+ function Tabs({ choice, hide = [] }: { choice: string; hide: string[] }) {
11
11
  const groupName = choice
12
12
  const pageContext = usePageContext()
13
13
  const choicesAll = pageContext.config.docpress.choices
@@ -16,44 +16,46 @@ function Tabs({ choice, hiddenChoices = [] }: { choice: string; hiddenChoices: s
16
16
  const { choices, default: defaultChoice } = choicesAll[groupName]
17
17
  const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice)
18
18
  const setPrevPosition = useRestoreScroll([selectedChoice])
19
- const isHidden = (choice: string) => hiddenChoices.includes(choice)
20
- const filteredChoices = choices.filter((choice) => !isHidden(choice))
21
- const selectedIndex = filteredChoices.indexOf(selectedChoice)
19
+ const isHidden = (choice: string) => hide.includes(choice)
20
+ const filteredChoices = choices.filter((choice) => !isHidden(choice.name))
21
+ const selectedIndex = filteredChoices.findIndex((choice) => choice.name === selectedChoice)
22
22
 
23
23
  return (
24
24
  <div className="choice-tabs" data-choice-group={groupName}>
25
25
  {/* Hidden select used to control tablist styling via CSS. */}
26
26
  <select name={`choicesFor-${groupName}`} value={selectedChoice} hidden disabled>
27
- {choices.map((choice, i) => (
28
- <option key={i} value={choice}>
27
+ {choices.map(({ name: choice }) => (
28
+ <option key={choice} value={choice}>
29
29
  {choice}
30
30
  </option>
31
31
  ))}
32
32
  </select>
33
33
  <ul id={`choicesFor-${groupName}`} className="choice-tabs__tab-list" role="tablist">
34
- {choices.map((choice, i) => (
34
+ {choices.map(({ name: choice, icon, iconStyle }, i) => (
35
35
  <li
36
- key={i}
37
- id={choice}
36
+ key={choice}
37
+ id={`tab-${choice}`}
38
38
  style={{ display: isHidden(choice) ? 'none' : undefined }}
39
39
  className="choice-tabs__tab"
40
40
  role="tab"
41
41
  aria-selected={i === selectedIndex}
42
42
  tabIndex={i === selectedIndex ? 0 : -1}
43
- onClick={(e) => handleOnClick(e, i)}
43
+ onClick={(e) => handleOnClick(e, choice)}
44
44
  onKeyDown={handleOnKeyDown}
45
45
  >
46
- {choice}
46
+ <span className="choice-tabs__tab-content">
47
+ <img src={icon} alt="" aria-hidden="true" style={iconStyle} />
48
+ {choice}
49
+ </span>
47
50
  </li>
48
51
  ))}
49
52
  </ul>
50
53
  </div>
51
54
  )
52
55
 
53
- function handleOnClick(e: React.MouseEvent<HTMLLIElement, MouseEvent>, index: number) {
54
- const el = e.currentTarget
55
- setPrevPosition(el)
56
- setSelectedChoice(choices[index]!)
56
+ function handleOnClick(e: React.MouseEvent<HTMLLIElement, MouseEvent>, choice: string) {
57
+ setPrevPosition(e.currentTarget)
58
+ setSelectedChoice(choice)
57
59
  }
58
60
 
59
61
  function handleOnKeyDown(e: React.KeyboardEvent<HTMLLIElement>) {
@@ -80,7 +82,7 @@ function Tabs({ choice, hiddenChoices = [] }: { choice: string; hiddenChoices: s
80
82
  e.preventDefault()
81
83
  setPrevPosition(el)
82
84
  const nextChoice = filteredChoices[nextIndex]!
83
- setSelectedChoice(nextChoice)
85
+ setSelectedChoice(nextChoice.name)
84
86
  const tabEl = el.parentElement?.parentElement as HTMLDivElement
85
87
 
86
88
  if (!isInViewport(tabEl)) tabEl.scrollIntoView({ block: 'start', behavior: 'smooth' })
@@ -1,14 +1,18 @@
1
1
  export { remarkChoiceGroup }
2
2
 
3
3
  import type { Root } from 'mdast'
4
+ import type { Plugin, Transformer } from 'unified'
4
5
  import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx'
5
6
  import type { ChoiceNode } from './utils/generateChoiceGroupCode.js'
7
+ import type { ChoiceGroup, ChoiceGroupWithParent, ParentChoiceGroup } from './types.js'
6
8
  import { visit } from 'unist-util-visit'
7
9
  import { parseMetaString } from './rehypeMetaToProps.js'
8
- import { generateChoiceGroupCode } from './utils/generateChoiceGroupCode.js'
10
+ import { generateChoiceGroupCode, expressionToAttribute } from './utils/generateChoiceGroupCode.js'
11
+ import { remarkPkgManager } from './remarkPkgManager.js'
12
+ import { remarkDetype } from './remarkDetype.js'
9
13
 
10
- function remarkChoiceGroup() {
11
- return function (tree: Root) {
14
+ const remarkChoiceGroup: Plugin<[], Root> = (): Transformer<Root> => {
15
+ return async (tree, file) => {
12
16
  visit(tree, (node) => {
13
17
  if (node.type === 'code') {
14
18
  if (!node.meta) return
@@ -74,6 +78,53 @@ function remarkChoiceGroup() {
74
78
 
75
79
  process()
76
80
  })
81
+
82
+ await remarkDetype.call(this)(tree, file)
83
+ remarkPkgManager.call(this)(tree, file)
84
+
85
+ visit(tree, 'mdxJsxFlowElement', (node) => {
86
+ if (node.name !== 'CustomSelectsContainer') return 'skip'
87
+
88
+ const choiceGroupAll: ChoiceGroupWithParent[] = []
89
+
90
+ visit(node, 'mdxJsxFlowElement', (child) => {
91
+ if (child.name !== 'ChoiceGroup') return
92
+
93
+ const choiceGroup = child.data?.customDataChoiceGroup
94
+ const parentChoiceGroup = child.data?.customDataParentChoiceGroup
95
+
96
+ if (!choiceGroup) return
97
+
98
+ const existing = choiceGroupAll.find((g) => g.name === choiceGroup.name)
99
+
100
+ // first occurrence
101
+ if (!existing) {
102
+ choiceGroupAll.push({
103
+ ...choiceGroup,
104
+ ...(parentChoiceGroup && {
105
+ parentChoiceGroup: {
106
+ name: parentChoiceGroup.name,
107
+ default: parentChoiceGroup.default,
108
+ choices: !choiceGroup.hidden ? [parentChoiceGroup.choice] : [],
109
+ },
110
+ }),
111
+ })
112
+
113
+ return
114
+ }
115
+
116
+ // merge parent choices
117
+ if (parentChoiceGroup && existing.parentChoiceGroup && !choiceGroup.hidden) {
118
+ existing.parentChoiceGroup.choices = [
119
+ ...new Set([...existing.parentChoiceGroup.choices, parentChoiceGroup.choice]),
120
+ ]
121
+ }
122
+ })
123
+
124
+ node.attributes.push(expressionToAttribute('choiceGroupAll', choiceGroupAll))
125
+
126
+ return 'skip'
127
+ })
77
128
  }
78
129
  }
79
130
 
@@ -104,10 +155,9 @@ declare module 'mdast' {
104
155
  customDataIsVisited?: boolean
105
156
  customDataChoice?: string
106
157
  customDataFilter?: string
107
- customDataParentChoiceGroup?: {
108
- name: string
158
+ customDataChoiceGroup?: ChoiceGroup
159
+ customDataParentChoiceGroup?: ParentChoiceGroup & {
109
160
  choice: string
110
- default: string
111
161
  lvl: number
112
162
  }
113
163
  }
@@ -0,0 +1,13 @@
1
+ export type { ChoiceGroup, ChoiceGroupWithParent, ParentChoiceGroup }
2
+
3
+ import type { Config } from '../types/Config.js'
4
+
5
+ type ChoiceGroup = NonNullable<Config['choices']>[string] & {
6
+ name: string
7
+ emptyChoices: string[]
8
+ hidden: boolean
9
+ lvl: number
10
+ isBuiltIn?: boolean
11
+ }
12
+ type ParentChoiceGroup = { name: string; default: string }
13
+ type ChoiceGroupWithParent = ChoiceGroup & { parentChoiceGroup?: ParentChoiceGroup & { choices: string[] } }
@@ -1,8 +1,10 @@
1
- export { generateChoiceGroupCode }
1
+ export { generateChoiceGroupCode, expressionToAttribute }
2
2
  export type { ChoiceNode }
3
3
 
4
+ import type { Config } from '../../types/Config.js'
5
+ import type { ChoiceGroup } from '../types.js'
4
6
  import type { BlockContent, DefinitionContent, Parent } from 'mdast'
5
- import type { MdxJsxAttribute, MdxJsxFlowElement } from 'mdast-util-mdx-jsx'
7
+ import type { MdxJsxAttribute, MdxJsxFlowElement, MdxJsxFlowElementData } from 'mdast-util-mdx-jsx'
6
8
  import { getVikeConfig } from 'vike/plugin'
7
9
  import { assertUsage } from '../../utils/assert.js'
8
10
  import { valueToEstree } from 'estree-util-value-to-estree'
@@ -12,13 +14,39 @@ type ChoiceNode = {
12
14
  children: (BlockContent | DefinitionContent)[]
13
15
  }
14
16
 
15
- const CHOICES_BUILT_IN: Record<string, { choices: string[]; default: string }> = {
17
+ // TODO: determine icon representation for CHOICES_BUILT_IN given lack of SVG/file import support
18
+ // use SVG URLs for now
19
+ const CHOICES_BUILT_IN: NonNullable<Config['choices']> = {
16
20
  codeLang: {
17
- choices: ['JavaScript', 'TypeScript'],
21
+ choices: [
22
+ {
23
+ name: 'JavaScript',
24
+ icon: 'https://www.svgrepo.com/show/452045/js.svg',
25
+ iconStyle: { position: 'relative', top: -0.5 },
26
+ },
27
+ {
28
+ name: 'TypeScript',
29
+ icon: 'https://www.svgrepo.com/show/349540/typescript.svg',
30
+ iconStyle: { position: 'relative', top: -0.5 },
31
+ },
32
+ ],
18
33
  default: 'JavaScript',
19
34
  },
20
35
  pkgManager: {
21
- choices: ['npm', 'pnpm', 'Bun', 'Yarn'],
36
+ choices: [
37
+ {
38
+ name: 'npm',
39
+ icon: 'https://www.svgrepo.com/show/452077/npm.svg',
40
+ iconStyle: { position: 'relative', top: 1.5 },
41
+ },
42
+ { name: 'pnpm', icon: 'https://www.svgrepo.com/show/373778/light-pnpm.svg' },
43
+ { name: 'Bun', icon: 'https://bun.com/logo.svg' },
44
+ {
45
+ name: 'Yarn',
46
+ icon: 'https://www.svgrepo.com/show/354588/yarn.svg',
47
+ iconStyle: { position: 'relative', top: -0.5 },
48
+ },
49
+ ],
22
50
  default: 'npm',
23
51
  },
24
52
  }
@@ -33,6 +61,15 @@ function generateChoiceGroupCode(choiceNodes: ChoiceNode[], parent: Parent, hide
33
61
  const { choiceGroup, mergedChoiceNodes } = resolveChoiceGroupNodes(choiceNodes)
34
62
  const attributes: MdxJsxAttribute[] = []
35
63
  const children: MdxJsxFlowElement[] = []
64
+ let data: MdxJsxFlowElementData = {}
65
+
66
+ if (parent.data?.customDataParentChoiceGroup) {
67
+ const { lvl: parentLvl } = parent.data.customDataParentChoiceGroup
68
+ lvl = parentLvl + 1
69
+
70
+ data.customDataParentChoiceGroup = parent.data.customDataParentChoiceGroup
71
+ parent.data = undefined
72
+ }
36
73
 
37
74
  for (const choiceNode of mergedChoiceNodes) {
38
75
  const choiceChildren: (BlockContent | DefinitionContent)[] = []
@@ -51,34 +88,36 @@ function generateChoiceGroupCode(choiceNodes: ChoiceNode[], parent: Parent, hide
51
88
  ],
52
89
  children: choiceChildren,
53
90
  data: {
54
- customDataParentChoiceGroup: {
55
- name: choiceGroup.name,
56
- choice: choiceNode.choiceValue,
57
- default: choiceGroup.default,
58
- lvl,
59
- },
91
+ ...(!Object.keys(CHOICES_BUILT_IN).includes(choiceGroup.name) && {
92
+ customDataParentChoiceGroup: {
93
+ name: choiceGroup.name,
94
+ choice: choiceNode.choiceValue,
95
+ default: choiceGroup.default,
96
+ lvl,
97
+ },
98
+ }),
60
99
  },
61
100
  })
62
101
  }
63
102
 
64
- if (parent.data?.customDataParentChoiceGroup) {
65
- const { lvl: parentLvl, ...parentChoiceGroup } = parent.data.customDataParentChoiceGroup
66
-
67
- attributes.push(expressionToAttribute('parentChoiceGroup', parentChoiceGroup))
68
-
69
- lvl = parentLvl + 1
70
- parent.data.customDataParentChoiceGroup = undefined
103
+ const choiceGroupAttr: ChoiceGroup = {
104
+ ...choiceGroup,
105
+ hidden: choiceNodes.length === 1 || hidden,
106
+ lvl,
107
+ isBuiltIn: Object.keys(CHOICES_BUILT_IN).includes(choiceGroup.name),
71
108
  }
72
109
 
73
- attributes.push(
74
- expressionToAttribute('choiceGroup', { ...choiceGroup, hidden: choiceNodes.length === 1 || hidden, lvl }),
75
- )
110
+ attributes.push(expressionToAttribute('choiceGroup', choiceGroupAttr))
76
111
 
77
112
  const choiceGroupNode: MdxJsxFlowElement = {
78
113
  type: 'mdxJsxFlowElement',
79
114
  name: 'ChoiceGroup',
80
115
  attributes,
81
116
  children,
117
+ data: {
118
+ ...data,
119
+ customDataChoiceGroup: choiceGroupAttr,
120
+ },
82
121
  }
83
122
 
84
123
  if (lvl === 0) {
@@ -99,16 +138,17 @@ function resolveChoiceGroupNodes(choiceNodes: ChoiceNode[]) {
99
138
  const { choices: choicesConfig } = vikeConfig.config.docpress
100
139
  const choicesAll = { ...CHOICES_BUILT_IN, ...choicesConfig }
101
140
 
102
- const groupName = Object.keys(choicesAll).find((key) => {
103
- // get only the values that exist in both choices and choicesAll[key].choices
104
- const existsChoices = choicesAll[key]!.choices.filter((choice) => choices.includes(choice))
105
- // if nothing exists, skip this key
106
- if (existsChoices.length === 0) return false
107
- return true
108
- })
141
+ // Resolve to the group that defines ALL of the block's values. Matching a group that merely
142
+ // shares ANY value would mis-resolve a custom group that collides with a built-in on a single
143
+ // value e.g. a `runtime` group [Node, Bun, Deno, Cloudflare] sharing `Bun` with `pkgManager`.
144
+ const groupName = Object.keys(choicesAll).find((key) =>
145
+ choices.every((choice) => choicesAll[key]!.choices.some(({ name }) => name === choice)),
146
+ )
109
147
  assertUsage(groupName, `Missing group name for [${choices}]. Define it in +docpress.choices.`)
110
148
 
111
- const emptyChoices = choicesAll[groupName]!.choices.filter((choice) => !choices.includes(choice))
149
+ const emptyChoices = choicesAll[groupName]!.choices.filter((choice) => !choices.includes(choice.name)).map(
150
+ (choice) => choice.name,
151
+ )
112
152
 
113
153
  const choiceGroup = {
114
154
  name: groupName,
@@ -117,10 +157,10 @@ function resolveChoiceGroupNodes(choiceNodes: ChoiceNode[]) {
117
157
  }
118
158
 
119
159
  const mergedChoiceNodes: ChoiceNode[] = choiceGroup.choices.map((choice) => {
120
- const node = choiceNodes.find((node) => node.choiceValue === choice)
160
+ const node = choiceNodes.find((node) => node.choiceValue === choice.name)
121
161
 
122
162
  return {
123
- choiceValue: choice,
163
+ choiceValue: choice.name,
124
164
  children: node?.children ?? [],
125
165
  }
126
166
  })
@@ -1,7 +1,7 @@
1
1
  export { Tabs };
2
2
  import React from 'react';
3
3
  import './Tabs.css';
4
- declare function Tabs({ choice, hiddenChoices }: {
4
+ declare function Tabs({ choice, hide }: {
5
5
  choice: string;
6
- hiddenChoices: string[];
6
+ hide: string[];
7
7
  }): React.JSX.Element;
@@ -5,7 +5,7 @@ import { useRestoreScroll } from '../hooks/useRestoreScroll.js';
5
5
  import { usePageContext } from '../../renderer/usePageContext.js';
6
6
  import { assertUsage } from '../../utils/assert.js';
7
7
  import './Tabs.css';
8
- function Tabs({ choice, hiddenChoices = [] }) {
8
+ function Tabs({ choice, hide = [] }) {
9
9
  const groupName = choice;
10
10
  const pageContext = usePageContext();
11
11
  const choicesAll = pageContext.config.docpress.choices;
@@ -13,16 +13,18 @@ function Tabs({ choice, hiddenChoices = [] }) {
13
13
  const { choices, default: defaultChoice } = choicesAll[groupName];
14
14
  const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice);
15
15
  const setPrevPosition = useRestoreScroll([selectedChoice]);
16
- const isHidden = (choice) => hiddenChoices.includes(choice);
17
- const filteredChoices = choices.filter((choice) => !isHidden(choice));
18
- const selectedIndex = filteredChoices.indexOf(selectedChoice);
16
+ const isHidden = (choice) => hide.includes(choice);
17
+ const filteredChoices = choices.filter((choice) => !isHidden(choice.name));
18
+ const selectedIndex = filteredChoices.findIndex((choice) => choice.name === selectedChoice);
19
19
  return (React.createElement("div", { className: "choice-tabs", "data-choice-group": groupName },
20
- React.createElement("select", { name: `choicesFor-${groupName}`, value: selectedChoice, hidden: true, disabled: true }, choices.map((choice, i) => (React.createElement("option", { key: i, value: choice }, choice)))),
21
- React.createElement("ul", { id: `choicesFor-${groupName}`, className: "choice-tabs__tab-list", role: "tablist" }, choices.map((choice, i) => (React.createElement("li", { key: i, id: choice, style: { display: isHidden(choice) ? 'none' : undefined }, className: "choice-tabs__tab", role: "tab", "aria-selected": i === selectedIndex, tabIndex: i === selectedIndex ? 0 : -1, onClick: (e) => handleOnClick(e, i), onKeyDown: handleOnKeyDown }, choice))))));
22
- function handleOnClick(e, index) {
23
- const el = e.currentTarget;
24
- setPrevPosition(el);
25
- setSelectedChoice(choices[index]);
20
+ React.createElement("select", { name: `choicesFor-${groupName}`, value: selectedChoice, hidden: true, disabled: true }, choices.map(({ name: choice }) => (React.createElement("option", { key: choice, value: choice }, choice)))),
21
+ React.createElement("ul", { id: `choicesFor-${groupName}`, className: "choice-tabs__tab-list", role: "tablist" }, choices.map(({ name: choice, icon, iconStyle }, i) => (React.createElement("li", { key: choice, id: `tab-${choice}`, style: { display: isHidden(choice) ? 'none' : undefined }, className: "choice-tabs__tab", role: "tab", "aria-selected": i === selectedIndex, tabIndex: i === selectedIndex ? 0 : -1, onClick: (e) => handleOnClick(e, choice), onKeyDown: handleOnKeyDown },
22
+ React.createElement("span", { className: "choice-tabs__tab-content" },
23
+ React.createElement("img", { src: icon, alt: "", "aria-hidden": "true", style: iconStyle }),
24
+ choice)))))));
25
+ function handleOnClick(e, choice) {
26
+ setPrevPosition(e.currentTarget);
27
+ setSelectedChoice(choice);
26
28
  }
27
29
  function handleOnKeyDown(e) {
28
30
  const el = e.currentTarget;
@@ -46,7 +48,7 @@ function Tabs({ choice, hiddenChoices = [] }) {
46
48
  e.preventDefault();
47
49
  setPrevPosition(el);
48
50
  const nextChoice = filteredChoices[nextIndex];
49
- setSelectedChoice(nextChoice);
51
+ setSelectedChoice(nextChoice.name);
50
52
  const tabEl = el.parentElement?.parentElement;
51
53
  if (!isInViewport(tabEl))
52
54
  tabEl.scrollIntoView({ block: 'start', behavior: 'smooth' });
@@ -1,15 +1,16 @@
1
1
  export { remarkChoiceGroup };
2
2
  import type { Root } from 'mdast';
3
- declare function remarkChoiceGroup(): (tree: Root) => void;
3
+ import type { Plugin } from 'unified';
4
+ import type { ChoiceGroup, ParentChoiceGroup } from './types.js';
5
+ declare const remarkChoiceGroup: Plugin<[], Root>;
4
6
  declare module 'mdast' {
5
7
  interface Data {
6
8
  customDataIsVisited?: boolean;
7
9
  customDataChoice?: string;
8
10
  customDataFilter?: string;
9
- customDataParentChoiceGroup?: {
10
- name: string;
11
+ customDataChoiceGroup?: ChoiceGroup;
12
+ customDataParentChoiceGroup?: ParentChoiceGroup & {
11
13
  choice: string;
12
- default: string;
13
14
  lvl: number;
14
15
  };
15
16
  }
@@ -1,9 +1,11 @@
1
1
  export { remarkChoiceGroup };
2
2
  import { visit } from 'unist-util-visit';
3
3
  import { parseMetaString } from './rehypeMetaToProps.js';
4
- import { generateChoiceGroupCode } from './utils/generateChoiceGroupCode.js';
5
- function remarkChoiceGroup() {
6
- return function (tree) {
4
+ import { generateChoiceGroupCode, expressionToAttribute } from './utils/generateChoiceGroupCode.js';
5
+ import { remarkPkgManager } from './remarkPkgManager.js';
6
+ import { remarkDetype } from './remarkDetype.js';
7
+ const remarkChoiceGroup = () => {
8
+ return async (tree, file) => {
7
9
  visit(tree, (node) => {
8
10
  if (node.type === 'code') {
9
11
  if (!node.meta)
@@ -62,8 +64,46 @@ function remarkChoiceGroup() {
62
64
  }
63
65
  process();
64
66
  });
67
+ await remarkDetype.call(this)(tree, file);
68
+ remarkPkgManager.call(this)(tree, file);
69
+ visit(tree, 'mdxJsxFlowElement', (node) => {
70
+ if (node.name !== 'CustomSelectsContainer')
71
+ return 'skip';
72
+ const choiceGroupAll = [];
73
+ visit(node, 'mdxJsxFlowElement', (child) => {
74
+ if (child.name !== 'ChoiceGroup')
75
+ return;
76
+ const choiceGroup = child.data?.customDataChoiceGroup;
77
+ const parentChoiceGroup = child.data?.customDataParentChoiceGroup;
78
+ if (!choiceGroup)
79
+ return;
80
+ const existing = choiceGroupAll.find((g) => g.name === choiceGroup.name);
81
+ // first occurrence
82
+ if (!existing) {
83
+ choiceGroupAll.push({
84
+ ...choiceGroup,
85
+ ...(parentChoiceGroup && {
86
+ parentChoiceGroup: {
87
+ name: parentChoiceGroup.name,
88
+ default: parentChoiceGroup.default,
89
+ choices: !choiceGroup.hidden ? [parentChoiceGroup.choice] : [],
90
+ },
91
+ }),
92
+ });
93
+ return;
94
+ }
95
+ // merge parent choices
96
+ if (parentChoiceGroup && existing.parentChoiceGroup && !choiceGroup.hidden) {
97
+ existing.parentChoiceGroup.choices = [
98
+ ...new Set([...existing.parentChoiceGroup.choices, parentChoiceGroup.choice]),
99
+ ];
100
+ }
101
+ });
102
+ node.attributes.push(expressionToAttribute('choiceGroupAll', choiceGroupAll));
103
+ return 'skip';
104
+ });
65
105
  };
66
- }
106
+ };
67
107
  function filterChoices(nodes) {
68
108
  const filteredChoices = new Set();
69
109
  const filters = [...new Set(nodes.flat().map((node) => node.data.customDataFilter))];
@@ -0,0 +1,18 @@
1
+ export type { ChoiceGroup, ChoiceGroupWithParent, ParentChoiceGroup };
2
+ import type { Config } from '../types/Config.js';
3
+ type ChoiceGroup = NonNullable<Config['choices']>[string] & {
4
+ name: string;
5
+ emptyChoices: string[];
6
+ hidden: boolean;
7
+ lvl: number;
8
+ isBuiltIn?: boolean;
9
+ };
10
+ type ParentChoiceGroup = {
11
+ name: string;
12
+ default: string;
13
+ };
14
+ type ChoiceGroupWithParent = ChoiceGroup & {
15
+ parentChoiceGroup?: ParentChoiceGroup & {
16
+ choices: string[];
17
+ };
18
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,10 @@
1
- export { generateChoiceGroupCode };
1
+ export { generateChoiceGroupCode, expressionToAttribute };
2
2
  export type { ChoiceNode };
3
3
  import type { BlockContent, DefinitionContent, Parent } from 'mdast';
4
- import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
4
+ import type { MdxJsxAttribute, MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
5
5
  type ChoiceNode = {
6
6
  choiceValue: string;
7
7
  children: (BlockContent | DefinitionContent)[];
8
8
  };
9
9
  declare function generateChoiceGroupCode(choiceNodes: ChoiceNode[], parent: Parent, hide?: boolean): MdxJsxFlowElement;
10
+ declare function expressionToAttribute(name: string, value: unknown): MdxJsxAttribute;
@@ -1,14 +1,40 @@
1
- export { generateChoiceGroupCode };
1
+ export { generateChoiceGroupCode, expressionToAttribute };
2
2
  import { getVikeConfig } from 'vike/plugin';
3
3
  import { assertUsage } from '../../utils/assert.js';
4
4
  import { valueToEstree } from 'estree-util-value-to-estree';
5
+ // TODO: determine icon representation for CHOICES_BUILT_IN given lack of SVG/file import support
6
+ // use SVG URLs for now
5
7
  const CHOICES_BUILT_IN = {
6
8
  codeLang: {
7
- choices: ['JavaScript', 'TypeScript'],
9
+ choices: [
10
+ {
11
+ name: 'JavaScript',
12
+ icon: 'https://www.svgrepo.com/show/452045/js.svg',
13
+ iconStyle: { position: 'relative', top: -0.5 },
14
+ },
15
+ {
16
+ name: 'TypeScript',
17
+ icon: 'https://www.svgrepo.com/show/349540/typescript.svg',
18
+ iconStyle: { position: 'relative', top: -0.5 },
19
+ },
20
+ ],
8
21
  default: 'JavaScript',
9
22
  },
10
23
  pkgManager: {
11
- choices: ['npm', 'pnpm', 'Bun', 'Yarn'],
24
+ choices: [
25
+ {
26
+ name: 'npm',
27
+ icon: 'https://www.svgrepo.com/show/452077/npm.svg',
28
+ iconStyle: { position: 'relative', top: 1.5 },
29
+ },
30
+ { name: 'pnpm', icon: 'https://www.svgrepo.com/show/373778/light-pnpm.svg' },
31
+ { name: 'Bun', icon: 'https://bun.com/logo.svg' },
32
+ {
33
+ name: 'Yarn',
34
+ icon: 'https://www.svgrepo.com/show/354588/yarn.svg',
35
+ iconStyle: { position: 'relative', top: -0.5 },
36
+ },
37
+ ],
12
38
  default: 'npm',
13
39
  },
14
40
  };
@@ -19,6 +45,13 @@ function generateChoiceGroupCode(choiceNodes, parent, hide = false) {
19
45
  const { choiceGroup, mergedChoiceNodes } = resolveChoiceGroupNodes(choiceNodes);
20
46
  const attributes = [];
21
47
  const children = [];
48
+ let data = {};
49
+ if (parent.data?.customDataParentChoiceGroup) {
50
+ const { lvl: parentLvl } = parent.data.customDataParentChoiceGroup;
51
+ lvl = parentLvl + 1;
52
+ data.customDataParentChoiceGroup = parent.data.customDataParentChoiceGroup;
53
+ parent.data = undefined;
54
+ }
22
55
  for (const choiceNode of mergedChoiceNodes) {
23
56
  const choiceChildren = [];
24
57
  if (choiceNode.children.every((node) => node.type === 'containerDirective')) {
@@ -36,27 +69,33 @@ function generateChoiceGroupCode(choiceNodes, parent, hide = false) {
36
69
  ],
37
70
  children: choiceChildren,
38
71
  data: {
39
- customDataParentChoiceGroup: {
40
- name: choiceGroup.name,
41
- choice: choiceNode.choiceValue,
42
- default: choiceGroup.default,
43
- lvl,
44
- },
72
+ ...(!Object.keys(CHOICES_BUILT_IN).includes(choiceGroup.name) && {
73
+ customDataParentChoiceGroup: {
74
+ name: choiceGroup.name,
75
+ choice: choiceNode.choiceValue,
76
+ default: choiceGroup.default,
77
+ lvl,
78
+ },
79
+ }),
45
80
  },
46
81
  });
47
82
  }
48
- if (parent.data?.customDataParentChoiceGroup) {
49
- const { lvl: parentLvl, ...parentChoiceGroup } = parent.data.customDataParentChoiceGroup;
50
- attributes.push(expressionToAttribute('parentChoiceGroup', parentChoiceGroup));
51
- lvl = parentLvl + 1;
52
- parent.data.customDataParentChoiceGroup = undefined;
53
- }
54
- attributes.push(expressionToAttribute('choiceGroup', { ...choiceGroup, hidden: choiceNodes.length === 1 || hidden, lvl }));
83
+ const choiceGroupAttr = {
84
+ ...choiceGroup,
85
+ hidden: choiceNodes.length === 1 || hidden,
86
+ lvl,
87
+ isBuiltIn: Object.keys(CHOICES_BUILT_IN).includes(choiceGroup.name),
88
+ };
89
+ attributes.push(expressionToAttribute('choiceGroup', choiceGroupAttr));
55
90
  const choiceGroupNode = {
56
91
  type: 'mdxJsxFlowElement',
57
92
  name: 'ChoiceGroup',
58
93
  attributes,
59
94
  children,
95
+ data: {
96
+ ...data,
97
+ customDataChoiceGroup: choiceGroupAttr,
98
+ },
60
99
  };
61
100
  if (lvl === 0) {
62
101
  return {
@@ -73,25 +112,21 @@ function resolveChoiceGroupNodes(choiceNodes) {
73
112
  const choices = choiceNodes.map((choiceNode) => choiceNode.choiceValue);
74
113
  const { choices: choicesConfig } = vikeConfig.config.docpress;
75
114
  const choicesAll = { ...CHOICES_BUILT_IN, ...choicesConfig };
76
- const groupName = Object.keys(choicesAll).find((key) => {
77
- // get only the values that exist in both choices and choicesAll[key].choices
78
- const existsChoices = choicesAll[key].choices.filter((choice) => choices.includes(choice));
79
- // if nothing exists, skip this key
80
- if (existsChoices.length === 0)
81
- return false;
82
- return true;
83
- });
115
+ // Resolve to the group that defines ALL of the block's values. Matching a group that merely
116
+ // shares ANY value would mis-resolve a custom group that collides with a built-in on a single
117
+ // value e.g. a `runtime` group [Node, Bun, Deno, Cloudflare] sharing `Bun` with `pkgManager`.
118
+ const groupName = Object.keys(choicesAll).find((key) => choices.every((choice) => choicesAll[key].choices.some(({ name }) => name === choice)));
84
119
  assertUsage(groupName, `Missing group name for [${choices}]. Define it in +docpress.choices.`);
85
- const emptyChoices = choicesAll[groupName].choices.filter((choice) => !choices.includes(choice));
120
+ const emptyChoices = choicesAll[groupName].choices.filter((choice) => !choices.includes(choice.name)).map((choice) => choice.name);
86
121
  const choiceGroup = {
87
122
  name: groupName,
88
123
  ...choicesAll[groupName],
89
124
  emptyChoices,
90
125
  };
91
126
  const mergedChoiceNodes = choiceGroup.choices.map((choice) => {
92
- const node = choiceNodes.find((node) => node.choiceValue === choice);
127
+ const node = choiceNodes.find((node) => node.choiceValue === choice.name);
93
128
  return {
94
- choiceValue: choice,
129
+ choiceValue: choice.name,
95
130
  children: node?.children ?? [],
96
131
  };
97
132
  });
@@ -48,6 +48,10 @@ type Category = string | {
48
48
  hide?: boolean;
49
49
  };
50
50
  type Choice = {
51
- choices: string[];
51
+ choices: {
52
+ name: string;
53
+ icon: string;
54
+ iconStyle?: React.CSSProperties;
55
+ }[];
52
56
  default: string;
53
57
  };
@@ -12,9 +12,7 @@ import { transformerNotationDiff, transformerNotationWordHighlight } from '@shik
12
12
  // https://github.com/shikijs/shiki/compare/main...brillout:shiki:brillout/highlight-color-param
13
13
  import { transformerNotationHighlight } from '@brillout/shiki-transformers';
14
14
  import { rehypeMetaToProps } from './code-blocks/rehypeMetaToProps.js';
15
- import { remarkDetype } from './code-blocks/remarkDetype.js';
16
15
  import { shikiTransformerAutoLinks } from './code-blocks/shikiTransformerAutoLinks.js';
17
- import { remarkPkgManager } from './code-blocks/remarkPkgManager.js';
18
16
  import { remarkChoiceGroup } from './code-blocks/remarkChoiceGroup.js';
19
17
  const root = process.cwd();
20
18
  const prettyCode = [
@@ -31,7 +29,7 @@ const prettyCode = [
31
29
  },
32
30
  ];
33
31
  const rehypePlugins = [prettyCode, [rehypeMetaToProps]];
34
- const remarkPlugins = [remarkGfm, remarkDirective, remarkChoiceGroup, remarkDetype, remarkPkgManager];
32
+ const remarkPlugins = [remarkGfm, remarkDirective, remarkChoiceGroup];
35
33
  const config = {
36
34
  root,
37
35
  plugins: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/docpress",
3
- "version": "0.16.38",
3
+ "version": "0.16.40",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "@brillout/picocolors": "^1.0.10",
@@ -62,6 +62,7 @@
62
62
  "@vitejs/plugin-react": "^6.0.1",
63
63
  "mdast-util-directive": "^3.1.0",
64
64
  "mdast-util-mdx-jsx": "^3.2.0",
65
+ "unified": "^11.0.5",
65
66
  "vike": "^0.4.255",
66
67
  "vite": "^8.0.8"
67
68
  },
package/types/Config.ts CHANGED
@@ -63,6 +63,6 @@ type Category =
63
63
  }
64
64
 
65
65
  type Choice = {
66
- choices: string[]
66
+ choices: { name: string; icon: string; iconStyle?: React.CSSProperties }[]
67
67
  default: string
68
68
  }
package/vite.config.ts CHANGED
@@ -14,9 +14,7 @@ import { transformerNotationDiff, transformerNotationWordHighlight } from '@shik
14
14
  // https://github.com/shikijs/shiki/compare/main...brillout:shiki:brillout/highlight-color-param
15
15
  import { transformerNotationHighlight } from '@brillout/shiki-transformers'
16
16
  import { rehypeMetaToProps } from './code-blocks/rehypeMetaToProps.js'
17
- import { remarkDetype } from './code-blocks/remarkDetype.js'
18
17
  import { shikiTransformerAutoLinks } from './code-blocks/shikiTransformerAutoLinks.js'
19
- import { remarkPkgManager } from './code-blocks/remarkPkgManager.js'
20
18
  import { remarkChoiceGroup } from './code-blocks/remarkChoiceGroup.js'
21
19
 
22
20
  const root = process.cwd()
@@ -34,7 +32,7 @@ const prettyCode = [
34
32
  },
35
33
  ]
36
34
  const rehypePlugins: any = [prettyCode, [rehypeMetaToProps]]
37
- const remarkPlugins = [remarkGfm, remarkDirective, remarkChoiceGroup, remarkDetype, remarkPkgManager]
35
+ const remarkPlugins = [remarkGfm, remarkDirective, remarkChoiceGroup]
38
36
 
39
37
  const config: UserConfig = {
40
38
  root,