@brillout/docpress 0.16.43 → 0.16.44
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/code-blocks/components/ChoiceGroup.tsx +4 -4
- package/code-blocks/components/Tabs.tsx +2 -2
- package/code-blocks/types.ts +3 -2
- package/code-blocks/utils/generateChoiceGroupCode.ts +5 -5
- package/code-blocks/utils/resolveChoices.ts +15 -0
- package/dist/code-blocks/components/Tabs.js +2 -2
- package/dist/code-blocks/types.d.ts +3 -2
- package/dist/code-blocks/utils/generateChoiceGroupCode.js +5 -3
- package/dist/code-blocks/utils/resolveChoices.d.ts +7 -0
- package/dist/code-blocks/utils/resolveChoices.js +7 -0
- package/dist/renderer/usePageContext.d.ts +1 -0
- package/dist/resolvePageContext.d.ts +1 -0
- package/dist/resolvePageContext.js +3 -0
- package/dist/types/Config.d.ts +8 -6
- package/package.json +1 -1
- package/resolvePageContext.ts +4 -0
- package/types/Config.ts +4 -2
|
@@ -12,7 +12,7 @@ function ChoiceGroupContainer({
|
|
|
12
12
|
children,
|
|
13
13
|
choiceGroupAll,
|
|
14
14
|
}: { children: React.ReactNode; choiceGroupAll: ChoiceGroupWithParent[] }) {
|
|
15
|
-
const renderCustomSelect = choiceGroupAll.some((choiceGroup) => choiceGroup.lvl === 0 && !choiceGroup.hidden)
|
|
15
|
+
const renderCustomSelect = (choiceGroupAll ?? []).some((choiceGroup) => choiceGroup.lvl === 0 && !choiceGroup.hidden)
|
|
16
16
|
return (
|
|
17
17
|
<div className="choice-group-container">
|
|
18
18
|
{children}
|
|
@@ -49,7 +49,7 @@ function ChoiceGroup({ children, choiceGroup }: { children: React.ReactNode; cho
|
|
|
49
49
|
const OPTION_HEIGHT = 25
|
|
50
50
|
function CustomSelect({ choiceGroup }: { choiceGroup: ChoiceGroupWithParent }) {
|
|
51
51
|
const radioId = useId()
|
|
52
|
-
const choicesAll = usePageContext().
|
|
52
|
+
const choicesAll = usePageContext().resolved.choices
|
|
53
53
|
const { name: groupName, emptyChoices, default: defaultChoice, hidden, parentChoiceGroup, isBuiltIn } = choiceGroup
|
|
54
54
|
const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice)
|
|
55
55
|
const [expanded, setExpanded] = useState(false)
|
|
@@ -57,7 +57,7 @@ function CustomSelect({ choiceGroup }: { choiceGroup: ChoiceGroupWithParent }) {
|
|
|
57
57
|
const [parentSelectedChoice] = useCurrentSelection(parentChoiceGroup?.name || '', parentChoiceGroup?.default || '')
|
|
58
58
|
const setPrevPosition = useRestoreScroll([selectedChoice])
|
|
59
59
|
|
|
60
|
-
const
|
|
60
|
+
const choices = (isBuiltIn ? choiceGroup : choicesAll![groupName]!).choices
|
|
61
61
|
const isHidden = parentChoiceGroup ? !parentChoiceGroup.choices.includes(parentSelectedChoice) : hidden
|
|
62
62
|
const isEmptyChoice = (choice: string) => emptyChoices.includes(choice)
|
|
63
63
|
const filteredChoices = choices.filter((choice) => !isEmptyChoice(choice.name))
|
|
@@ -104,7 +104,7 @@ function CustomSelect({ choiceGroup }: { choiceGroup: ChoiceGroupWithParent }) {
|
|
|
104
104
|
readOnly
|
|
105
105
|
/>
|
|
106
106
|
<span className="choice-select__option-content">
|
|
107
|
-
<img src={icon} alt="" aria-hidden="true" style={iconStyle} />
|
|
107
|
+
{icon && <img src={icon} alt="" aria-hidden="true" style={iconStyle} />}
|
|
108
108
|
{choice}
|
|
109
109
|
</span>
|
|
110
110
|
</label>
|
|
@@ -11,7 +11,7 @@ function Tabs({ choice, hide = [] }: { choice: string; hide: string[] }) {
|
|
|
11
11
|
const radioId = useId()
|
|
12
12
|
const groupName = choice
|
|
13
13
|
const pageContext = usePageContext()
|
|
14
|
-
const choicesAll = pageContext.
|
|
14
|
+
const choicesAll = pageContext.resolved.choices
|
|
15
15
|
assertUsage(choicesAll && choicesAll[groupName], `${groupName} is unknown`)
|
|
16
16
|
const { choices, default: defaultChoice } = choicesAll[groupName]
|
|
17
17
|
const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice)
|
|
@@ -40,7 +40,7 @@ function Tabs({ choice, hide = [] }: { choice: string; hide: string[] }) {
|
|
|
40
40
|
}}
|
|
41
41
|
/>
|
|
42
42
|
<span className="choice-tabs__tab-content">
|
|
43
|
-
<img src={icon} alt="" aria-hidden="true" style={iconStyle} />
|
|
43
|
+
{icon && <img src={icon} alt="" aria-hidden="true" style={iconStyle} />}
|
|
44
44
|
{choice}
|
|
45
45
|
</span>
|
|
46
46
|
</label>
|
package/code-blocks/types.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type { ChoiceGroup, ChoiceGroupWithParent, ParentChoiceGroup }
|
|
2
2
|
|
|
3
|
-
import type { Config } from '../types/Config.js'
|
|
3
|
+
import type { Config, ChoiceItem } from '../types/Config.js'
|
|
4
4
|
|
|
5
|
-
type ChoiceGroup = NonNullable<Config['choices']>[string] & {
|
|
5
|
+
type ChoiceGroup = Omit<NonNullable<Config['choices']>[string], 'choices'> & {
|
|
6
6
|
name: string
|
|
7
|
+
choices: ChoiceItem[]
|
|
7
8
|
emptyChoices: string[]
|
|
8
9
|
hidden: boolean
|
|
9
10
|
lvl: number
|
|
@@ -8,6 +8,7 @@ import type { MdxJsxAttribute, MdxJsxFlowElement, MdxJsxFlowElementData } from '
|
|
|
8
8
|
import { getVikeConfig } from 'vike/plugin'
|
|
9
9
|
import { assertUsage } from '../../utils/assert.js'
|
|
10
10
|
import { valueToEstree } from 'estree-util-value-to-estree'
|
|
11
|
+
import { resolveChoices } from './resolveChoices.js'
|
|
11
12
|
|
|
12
13
|
type ChoiceNode = {
|
|
13
14
|
choiceValue: string
|
|
@@ -143,7 +144,7 @@ function resolveChoiceGroupNodes(choiceNodes: ChoiceNode[]) {
|
|
|
143
144
|
const vikeConfig = getVikeConfig()
|
|
144
145
|
const choices = choiceNodes.map((choiceNode) => choiceNode.choiceValue)
|
|
145
146
|
const { choices: choicesConfig } = vikeConfig.config.docpress
|
|
146
|
-
const choicesAll = { ...CHOICES_BUILT_IN, ...choicesConfig }
|
|
147
|
+
const choicesAll = resolveChoices({ ...CHOICES_BUILT_IN, ...choicesConfig })
|
|
147
148
|
|
|
148
149
|
// Resolve to the group that defines ALL of the block's values. Matching a group that merely
|
|
149
150
|
// shares ANY value would mis-resolve a custom group that collides with a built-in on a single
|
|
@@ -153,13 +154,12 @@ function resolveChoiceGroupNodes(choiceNodes: ChoiceNode[]) {
|
|
|
153
154
|
)
|
|
154
155
|
assertUsage(groupName, `Missing group name for [${choices}]. Define it in +docpress.choices.`)
|
|
155
156
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
)
|
|
157
|
+
const group = choicesAll[groupName]!
|
|
158
|
+
const emptyChoices = group.choices.filter((choice) => !choices.includes(choice.name)).map((choice) => choice.name)
|
|
159
159
|
|
|
160
160
|
const choiceGroup = {
|
|
161
161
|
name: groupName,
|
|
162
|
-
...
|
|
162
|
+
...group,
|
|
163
163
|
emptyChoices,
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { resolveChoices }
|
|
2
|
+
export type { ResolvedChoices }
|
|
3
|
+
|
|
4
|
+
import type { Choice, ChoiceItem } from '../../types/Config.js'
|
|
5
|
+
|
|
6
|
+
type ResolvedChoices = Record<string, Omit<Choice, 'choices'> & { choices: ChoiceItem[] }>
|
|
7
|
+
|
|
8
|
+
function resolveChoices(choicesConfig: Record<string, Choice>): ResolvedChoices {
|
|
9
|
+
return Object.fromEntries(
|
|
10
|
+
Object.entries(choicesConfig).map(([name, group]) => [name, { ...group, choices: group.choices.map(resolveChoice) }]),
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
function resolveChoice(choice: string | ChoiceItem): ChoiceItem {
|
|
14
|
+
return typeof choice === 'string' ? { name: choice } : choice
|
|
15
|
+
}
|
|
@@ -9,7 +9,7 @@ function Tabs({ choice, hide = [] }) {
|
|
|
9
9
|
const radioId = useId();
|
|
10
10
|
const groupName = choice;
|
|
11
11
|
const pageContext = usePageContext();
|
|
12
|
-
const choicesAll = pageContext.
|
|
12
|
+
const choicesAll = pageContext.resolved.choices;
|
|
13
13
|
assertUsage(choicesAll && choicesAll[groupName], `${groupName} is unknown`);
|
|
14
14
|
const { choices, default: defaultChoice } = choicesAll[groupName];
|
|
15
15
|
const [selectedChoice, setSelectedChoice] = useCurrentSelection(groupName, defaultChoice);
|
|
@@ -22,6 +22,6 @@ function Tabs({ choice, hide = [] }) {
|
|
|
22
22
|
setSelectedChoice(choice);
|
|
23
23
|
} }),
|
|
24
24
|
React.createElement("span", { className: "choice-tabs__tab-content" },
|
|
25
|
-
React.createElement("img", { src: icon, alt: "", "aria-hidden": "true", style: iconStyle }),
|
|
25
|
+
icon && React.createElement("img", { src: icon, alt: "", "aria-hidden": "true", style: iconStyle }),
|
|
26
26
|
choice)))))));
|
|
27
27
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type { ChoiceGroup, ChoiceGroupWithParent, ParentChoiceGroup };
|
|
2
|
-
import type { Config } from '../types/Config.js';
|
|
3
|
-
type ChoiceGroup = NonNullable<Config['choices']>[string] & {
|
|
2
|
+
import type { Config, ChoiceItem } from '../types/Config.js';
|
|
3
|
+
type ChoiceGroup = Omit<NonNullable<Config['choices']>[string], 'choices'> & {
|
|
4
4
|
name: string;
|
|
5
|
+
choices: ChoiceItem[];
|
|
5
6
|
emptyChoices: string[];
|
|
6
7
|
hidden: boolean;
|
|
7
8
|
lvl: number;
|
|
@@ -2,6 +2,7 @@ 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
|
+
import { resolveChoices } from './resolveChoices.js';
|
|
5
6
|
// TODO: determine icon representation for CHOICES_BUILT_IN given lack of SVG/file import support
|
|
6
7
|
// use SVG URLs for now
|
|
7
8
|
const CHOICES_BUILT_IN = {
|
|
@@ -118,16 +119,17 @@ function resolveChoiceGroupNodes(choiceNodes) {
|
|
|
118
119
|
const vikeConfig = getVikeConfig();
|
|
119
120
|
const choices = choiceNodes.map((choiceNode) => choiceNode.choiceValue);
|
|
120
121
|
const { choices: choicesConfig } = vikeConfig.config.docpress;
|
|
121
|
-
const choicesAll = { ...CHOICES_BUILT_IN, ...choicesConfig };
|
|
122
|
+
const choicesAll = resolveChoices({ ...CHOICES_BUILT_IN, ...choicesConfig });
|
|
122
123
|
// Resolve to the group that defines ALL of the block's values. Matching a group that merely
|
|
123
124
|
// shares ANY value would mis-resolve a custom group that collides with a built-in on a single
|
|
124
125
|
// value — e.g. a `runtime` group [Node, Bun, Deno, Cloudflare] sharing `Bun` with `pkgManager`.
|
|
125
126
|
const groupName = Object.keys(choicesAll).find((key) => choices.every((choice) => choicesAll[key].choices.some(({ name }) => name === choice)));
|
|
126
127
|
assertUsage(groupName, `Missing group name for [${choices}]. Define it in +docpress.choices.`);
|
|
127
|
-
const
|
|
128
|
+
const group = choicesAll[groupName];
|
|
129
|
+
const emptyChoices = group.choices.filter((choice) => !choices.includes(choice.name)).map((choice) => choice.name);
|
|
128
130
|
const choiceGroup = {
|
|
129
131
|
name: groupName,
|
|
130
|
-
...
|
|
132
|
+
...group,
|
|
131
133
|
emptyChoices,
|
|
132
134
|
};
|
|
133
135
|
const mergedChoiceNodes = choiceGroup.choices.map((choice) => {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { resolveChoices };
|
|
2
|
+
export type { ResolvedChoices };
|
|
3
|
+
import type { Choice, ChoiceItem } from '../../types/Config.js';
|
|
4
|
+
type ResolvedChoices = Record<string, Omit<Choice, 'choices'> & {
|
|
5
|
+
choices: ChoiceItem[];
|
|
6
|
+
}>;
|
|
7
|
+
declare function resolveChoices(choicesConfig: Record<string, Choice>): ResolvedChoices;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { resolveChoices };
|
|
2
|
+
function resolveChoices(choicesConfig) {
|
|
3
|
+
return Object.fromEntries(Object.entries(choicesConfig).map(([name, group]) => [name, { ...group, choices: group.choices.map(resolveChoice) }]));
|
|
4
|
+
}
|
|
5
|
+
function resolveChoice(choice) {
|
|
6
|
+
return typeof choice === 'string' ? { name: choice } : choice;
|
|
7
|
+
}
|
|
@@ -16,6 +16,7 @@ declare function usePageContextLegacy(): {
|
|
|
16
16
|
pageTitle: string | null;
|
|
17
17
|
documentTitle: string;
|
|
18
18
|
activeCategoryName: string;
|
|
19
|
+
choices: import("../code-blocks/utils/resolveChoices.js").ResolvedChoices | undefined;
|
|
19
20
|
};
|
|
20
21
|
declare function usePageContext(): PageContext;
|
|
21
22
|
declare function PageContextProvider({ pageContext, children, }: {
|
|
@@ -4,6 +4,7 @@ import { jsxToTextContent } from './utils/jsxToTextContent.js';
|
|
|
4
4
|
import pc from '@brillout/picocolors';
|
|
5
5
|
import { parseMarkdownMini } from './parseMarkdownMini.js';
|
|
6
6
|
import { determineNavItemsColumnLayout } from './determineNavItemsColumnLayout.js';
|
|
7
|
+
import { resolveChoices } from './code-blocks/utils/resolveChoices.js';
|
|
7
8
|
function resolvePageContext(pageContext) {
|
|
8
9
|
const config = pageContext.globalContext.config.docpress;
|
|
9
10
|
const { urlPathname } = pageContext;
|
|
@@ -45,6 +46,7 @@ function resolvePageContext(pageContext) {
|
|
|
45
46
|
}
|
|
46
47
|
// Don't show landing page in navigation
|
|
47
48
|
navItemsAll = navItemsAll.filter((navItem) => navItem.url !== '/');
|
|
49
|
+
const choices = config.choices && resolveChoices(config.choices);
|
|
48
50
|
const resolved = {
|
|
49
51
|
navItemsAll,
|
|
50
52
|
navItemsDetached,
|
|
@@ -54,6 +56,7 @@ function resolvePageContext(pageContext) {
|
|
|
54
56
|
pageTitle,
|
|
55
57
|
documentTitle,
|
|
56
58
|
activeCategoryName,
|
|
59
|
+
choices,
|
|
57
60
|
};
|
|
58
61
|
return resolved;
|
|
59
62
|
}
|
package/dist/types/Config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { Config };
|
|
1
|
+
export type { Config, Choice, ChoiceItem };
|
|
2
2
|
import type { HeadingDefinition, HeadingDetachedDefinition } from './Heading.js';
|
|
3
3
|
import type React from 'react';
|
|
4
4
|
type Config = {
|
|
@@ -47,11 +47,13 @@ type Category = string | {
|
|
|
47
47
|
/** Hide from Algolia search */
|
|
48
48
|
hide?: boolean;
|
|
49
49
|
};
|
|
50
|
+
/** A choice. A plain `string` is shorthand for `{ name: string }` (no icon). */
|
|
51
|
+
type ChoiceItem = {
|
|
52
|
+
name: string;
|
|
53
|
+
icon?: string;
|
|
54
|
+
iconStyle?: React.CSSProperties;
|
|
55
|
+
};
|
|
50
56
|
type Choice = {
|
|
51
|
-
choices:
|
|
52
|
-
name: string;
|
|
53
|
-
icon: string;
|
|
54
|
-
iconStyle?: React.CSSProperties;
|
|
55
|
-
}[];
|
|
57
|
+
choices: (string | ChoiceItem)[];
|
|
56
58
|
default: string;
|
|
57
59
|
};
|
package/package.json
CHANGED
package/resolvePageContext.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { jsxToTextContent } from './utils/jsxToTextContent.js'
|
|
|
18
18
|
import pc from '@brillout/picocolors'
|
|
19
19
|
import { parseMarkdownMini } from './parseMarkdownMini.js'
|
|
20
20
|
import { determineNavItemsColumnLayout } from './determineNavItemsColumnLayout.js'
|
|
21
|
+
import { resolveChoices } from './code-blocks/utils/resolveChoices.js'
|
|
21
22
|
|
|
22
23
|
type PageSectionResolved = {
|
|
23
24
|
url: string | null
|
|
@@ -80,6 +81,8 @@ function resolvePageContext(pageContext: PageContextServer) {
|
|
|
80
81
|
// Don't show landing page in navigation
|
|
81
82
|
navItemsAll = navItemsAll.filter((navItem) => navItem.url !== '/')
|
|
82
83
|
|
|
84
|
+
const choices = config.choices && resolveChoices(config.choices)
|
|
85
|
+
|
|
83
86
|
const resolved = {
|
|
84
87
|
navItemsAll,
|
|
85
88
|
navItemsDetached,
|
|
@@ -89,6 +92,7 @@ function resolvePageContext(pageContext: PageContextServer) {
|
|
|
89
92
|
pageTitle,
|
|
90
93
|
documentTitle,
|
|
91
94
|
activeCategoryName,
|
|
95
|
+
choices,
|
|
92
96
|
}
|
|
93
97
|
return resolved
|
|
94
98
|
}
|
package/types/Config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { Config }
|
|
1
|
+
export type { Config, Choice, ChoiceItem }
|
|
2
2
|
|
|
3
3
|
import type { HeadingDefinition, HeadingDetachedDefinition } from './Heading.js'
|
|
4
4
|
import type React from 'react'
|
|
@@ -62,7 +62,9 @@ type Category =
|
|
|
62
62
|
hide?: boolean
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/** A choice. A plain `string` is shorthand for `{ name: string }` (no icon). */
|
|
66
|
+
type ChoiceItem = { name: string; icon?: string; iconStyle?: React.CSSProperties }
|
|
65
67
|
type Choice = {
|
|
66
|
-
choices:
|
|
68
|
+
choices: (string | ChoiceItem)[]
|
|
67
69
|
default: string
|
|
68
70
|
}
|