@redocly/theme 0.69.0-next.1 → 0.69.0-next.11
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/lib/components/Accordion/Accordion.js +5 -1
- package/lib/components/Accordion/variables.js +1 -1
- package/lib/components/Admonition/Admonition.d.ts +1 -1
- package/lib/components/Admonition/Admonition.js +1 -1
- package/lib/components/Admonition/variables.dark.js +2 -2
- package/lib/components/Admonition/variables.js +10 -10
- package/lib/components/Badge/Badge.d.ts +3 -1
- package/lib/components/Badge/Badge.js +7 -2
- package/lib/components/Banner/variables.dark.js +2 -0
- package/lib/components/Banner/variables.js +3 -1
- package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
- package/lib/components/Breadcrumbs/variables.js +1 -1
- package/lib/components/Button/ButtonGroup.d.ts +3 -5
- package/lib/components/Button/ButtonGroup.js +25 -5
- package/lib/components/Button/variables.js +27 -4
- package/lib/components/Buttons/ConnectMCPButton.js +39 -123
- package/lib/components/Buttons/CopyButton.js +12 -1
- package/lib/components/Buttons/variables.d.ts +0 -1
- package/lib/components/Buttons/variables.js +3 -44
- package/lib/components/Catalog/CatalogEntities.js +1 -0
- package/lib/components/Catalog/CatalogEntity/CatalogEntityLinks.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +5 -3
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +1 -1
- package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.js +1 -0
- package/lib/components/Catalog/CatalogViewModeToggle.d.ts +1 -1
- package/lib/components/Catalog/CatalogViewModeToggle.js +2 -43
- package/lib/components/Catalog/variables.js +5 -5
- package/lib/components/CatalogClassic/variables.js +2 -2
- package/lib/components/CodeBlock/CodeBlock.js +2 -1
- package/lib/components/CodeBlock/CodeBlockContainer.js +1 -0
- package/lib/components/Dropdown/Dropdown.d.ts +10 -20
- package/lib/components/Dropdown/Dropdown.js +13 -2
- package/lib/components/Dropdown/DropdownMenuItemContent.d.ts +9 -0
- package/lib/components/Dropdown/DropdownMenuItemContent.js +56 -0
- package/lib/components/Dropdown/variables.js +19 -2
- package/lib/components/Feedback/Mood.js +18 -14
- package/lib/components/Feedback/Rating.js +18 -13
- package/lib/components/Feedback/Scale.js +27 -22
- package/lib/components/Feedback/Sentiment.js +17 -13
- package/lib/components/Filter/FilterInput.js +4 -2
- package/lib/components/Filter/FilterSelect.js +1 -0
- package/lib/components/Filter/variables.js +2 -2
- package/lib/components/Image/variables.js +5 -3
- package/lib/components/JsonViewer/Helpers.js +12 -42
- package/lib/components/LanguagePicker/variables.js +1 -1
- package/lib/components/MCP/McpConnectionTabs.d.ts +7 -0
- package/lib/components/MCP/McpConnectionTabs.js +161 -0
- package/lib/components/Markdown/styles/base-table.js +8 -0
- package/lib/components/Markdown/variables.js +1 -1
- package/lib/components/Menu/MenuItem.js +1 -1
- package/lib/components/Menu/variables.js +1 -1
- package/lib/components/Navbar/variables.js +1 -1
- package/lib/components/PageActions/PageActions.js +4 -6
- package/lib/components/PageActions/PageActionsMenuItem.d.ts +4 -4
- package/lib/components/PageActions/PageActionsMenuItem.js +27 -43
- package/lib/components/Panel/Panel.js +5 -1
- package/lib/components/Panel/variables.js +1 -1
- package/lib/components/Product/variables.js +2 -1
- package/lib/components/ReplayGate/ReplayGate.d.ts +1 -0
- package/lib/components/Search/FilterFields/SearchFilterFieldSelect.js +22 -32
- package/lib/components/Search/SearchAiDialog.js +4 -1
- package/lib/components/Search/SearchAiMessage.js +1 -1
- package/lib/components/Search/SearchAiNegativeFeedbackForm.js +2 -2
- package/lib/components/Search/SearchDialog.js +2 -2
- package/lib/components/Search/SearchItem.js +6 -3
- package/lib/components/Search/SearchRecent.js +1 -0
- package/lib/components/Search/SearchSuggestedPages.js +1 -0
- package/lib/components/Search/variables.js +9 -5
- package/lib/components/Segmented/Segmented.js +3 -3
- package/lib/components/Select/Select.js +30 -23
- package/lib/components/Select/variables.js +3 -3
- package/lib/components/Sidebar/Sidebar.js +2 -38
- package/lib/components/SplitButton/SplitButton.d.ts +21 -0
- package/lib/components/SplitButton/SplitButton.js +37 -0
- package/lib/components/Switch/variables.dark.js +2 -2
- package/lib/components/Switch/variables.js +2 -2
- package/lib/components/Tag/variables.js +2 -2
- package/lib/components/Tags/variables.js +1 -1
- package/lib/components/Toast/variables.js +1 -1
- package/lib/components/Tooltip/AnchorTooltip.js +2 -2
- package/lib/components/Tooltip/JsTooltip.js +2 -2
- package/lib/components/UserMenu/variables.js +1 -1
- package/lib/core/constants/mcp.d.ts +4 -0
- package/lib/core/constants/mcp.js +10 -1
- package/lib/core/constants/search.js +2 -2
- package/lib/core/contexts/AccordionGroupContext.d.ts +1 -0
- package/lib/core/contexts/AccordionGroupContext.js +6 -0
- package/lib/core/contexts/PageActionsContext.d.ts +5 -0
- package/lib/core/contexts/PageActionsContext.js +10 -0
- package/lib/core/contexts/index.d.ts +2 -0
- package/lib/core/contexts/index.js +2 -0
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +5 -17
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.js +2 -0
- package/lib/core/hooks/menu/use-menu-item-expanded.js +1 -0
- package/lib/core/hooks/use-active-heading.js +63 -15
- package/lib/core/hooks/use-active-section-id.js +3 -1
- package/lib/core/hooks/use-connect-mcp-button.d.ts +1 -1
- package/lib/core/hooks/use-connect-mcp-button.js +23 -15
- package/lib/core/hooks/use-control.js +3 -0
- package/lib/core/hooks/use-local-state.js +1 -0
- package/lib/core/hooks/use-mcp-config.d.ts +2 -0
- package/lib/core/hooks/use-mcp-config.js +14 -4
- package/lib/core/hooks/use-mobile-menu.js +10 -2
- package/lib/core/hooks/use-tabs.js +4 -2
- package/lib/core/hooks/use-telemetry-fallback.d.ts +2 -0
- package/lib/core/hooks/use-telemetry-fallback.js +2 -0
- package/lib/core/styles/global.js +16 -11
- package/lib/core/styles/palette.js +2 -0
- package/lib/core/types/button-group.d.ts +2 -0
- package/lib/core/types/button-group.js +3 -0
- package/lib/core/types/catalog.d.ts +2 -4
- package/lib/core/types/common.d.ts +2 -0
- package/lib/core/types/hooks.d.ts +1 -0
- package/lib/core/types/index.d.ts +1 -0
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/mcp.d.ts +1 -1
- package/lib/core/utils/RenderWithLink.d.ts +2 -0
- package/lib/core/utils/RenderWithLink.js +20 -0
- package/lib/core/utils/index.d.ts +1 -0
- package/lib/core/utils/index.js +1 -0
- package/lib/core/utils/mcp.d.ts +5 -0
- package/lib/core/utils/mcp.js +35 -0
- package/lib/icons/CodexIcon/CodexIcon.d.ts +25 -0
- package/lib/icons/CodexIcon/CodexIcon.js +22 -0
- package/lib/icons/LinkIcon/LinkIcon.js +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/layouts/McpNotAllowed.js +10 -10
- package/lib/markdoc/components/Accordion/Accordion.js +6 -6
- package/lib/markdoc/components/Accordion/AccordionGroup.d.ts +2 -1
- package/lib/markdoc/components/Accordion/AccordionGroup.js +39 -3
- package/lib/markdoc/components/Cards/Card.d.ts +8 -1
- package/lib/markdoc/components/Cards/Card.js +55 -16
- package/lib/markdoc/components/Cards/CardBadge.d.ts +9 -0
- package/lib/markdoc/components/Cards/CardBadge.js +30 -0
- package/lib/markdoc/components/Cards/CardIcon.d.ts +5 -4
- package/lib/markdoc/components/Cards/CardIcon.js +6 -3
- package/lib/markdoc/components/Cards/variables.dark.js +32 -0
- package/lib/markdoc/components/Cards/variables.js +81 -7
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +1 -0
- package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/variables.js +2 -1
- package/lib/markdoc/components/Heading/Heading.js +5 -2
- package/lib/markdoc/components/Tabs/TabList.js +6 -2
- package/lib/markdoc/components/Tabs/Tabs.js +4 -2
- package/lib/markdoc/components/Tabs/variables.js +4 -4
- package/lib/markdoc/tags/accordion-group.js +3 -0
- package/lib/markdoc/tags/admonition.js +1 -1
- package/lib/markdoc/tags/card.js +14 -0
- package/lib/markdoc/tags/connect-mcp.js +2 -1
- package/package.json +19 -10
- package/src/components/Accordion/Accordion.tsx +7 -3
- package/src/components/Accordion/variables.ts +1 -1
- package/src/components/Admonition/Admonition.tsx +2 -2
- package/src/components/Admonition/variables.dark.ts +2 -2
- package/src/components/Admonition/variables.ts +10 -10
- package/src/components/Badge/Badge.tsx +16 -2
- package/src/components/Banner/variables.dark.ts +2 -0
- package/src/components/Banner/variables.ts +3 -1
- package/src/components/Breadcrumbs/Breadcrumb.tsx +1 -1
- package/src/components/Breadcrumbs/variables.ts +1 -1
- package/src/components/Button/ButtonGroup.tsx +28 -10
- package/src/components/Button/variables.ts +27 -4
- package/src/components/Buttons/ConnectMCPButton.tsx +88 -145
- package/src/components/Buttons/CopyButton.tsx +14 -2
- package/src/components/Buttons/variables.ts +2 -44
- package/src/components/Catalog/CatalogEntities.tsx +1 -0
- package/src/components/Catalog/CatalogEntity/CatalogEntityLinks.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.tsx +6 -4
- package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +1 -1
- package/src/components/Catalog/CatalogFilter/CatalogFilterSelect.tsx +1 -0
- package/src/components/Catalog/CatalogViewModeToggle.tsx +2 -17
- package/src/components/Catalog/variables.ts +5 -5
- package/src/components/CatalogClassic/variables.ts +2 -2
- package/src/components/CodeBlock/CodeBlock.tsx +2 -1
- package/src/components/CodeBlock/CodeBlockContainer.tsx +1 -0
- package/src/components/Dropdown/Dropdown.tsx +25 -4
- package/src/components/Dropdown/DropdownMenuItemContent.tsx +72 -0
- package/src/components/Dropdown/variables.ts +19 -2
- package/src/components/Feedback/Mood.tsx +22 -15
- package/src/components/Feedback/Rating.tsx +22 -14
- package/src/components/Feedback/Scale.tsx +40 -32
- package/src/components/Feedback/Sentiment.tsx +21 -14
- package/src/components/Filter/FilterInput.tsx +5 -3
- package/src/components/Filter/FilterSelect.tsx +1 -0
- package/src/components/Filter/variables.ts +2 -2
- package/src/components/Image/variables.ts +5 -3
- package/src/components/JsonViewer/Helpers.tsx +13 -9
- package/src/components/LanguagePicker/variables.ts +1 -1
- package/src/components/MCP/McpConnectionTabs.tsx +285 -0
- package/src/components/Markdown/styles/base-table.ts +8 -0
- package/src/components/Markdown/variables.ts +1 -1
- package/src/components/Menu/MenuItem.tsx +2 -2
- package/src/components/Menu/variables.ts +1 -1
- package/src/components/Navbar/variables.ts +1 -1
- package/src/components/PageActions/PageActions.tsx +22 -23
- package/src/components/PageActions/PageActionsMenuItem.tsx +41 -55
- package/src/components/Panel/Panel.tsx +7 -3
- package/src/components/Panel/variables.ts +1 -1
- package/src/components/Product/variables.ts +2 -1
- package/src/components/ReplayGate/ReplayGate.tsx +3 -0
- package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +32 -40
- package/src/components/Search/SearchAiDialog.tsx +4 -1
- package/src/components/Search/SearchAiMessage.tsx +1 -1
- package/src/components/Search/SearchAiNegativeFeedbackForm.tsx +2 -2
- package/src/components/Search/SearchDialog.tsx +2 -2
- package/src/components/Search/SearchItem.tsx +7 -1
- package/src/components/Search/SearchRecent.tsx +1 -0
- package/src/components/Search/SearchSuggestedPages.tsx +1 -0
- package/src/components/Search/variables.ts +9 -5
- package/src/components/Segmented/Segmented.tsx +6 -3
- package/src/components/Select/Select.tsx +36 -22
- package/src/components/Select/variables.ts +3 -3
- package/src/components/Sidebar/Sidebar.tsx +2 -6
- package/src/components/SplitButton/SplitButton.tsx +95 -0
- package/src/components/Switch/variables.dark.ts +2 -2
- package/src/components/Switch/variables.ts +2 -2
- package/src/components/Tag/variables.ts +2 -2
- package/src/components/Tags/variables.ts +1 -1
- package/src/components/Toast/variables.ts +1 -1
- package/src/components/Tooltip/AnchorTooltip.tsx +2 -2
- package/src/components/Tooltip/JsTooltip.tsx +2 -2
- package/src/components/UserMenu/variables.ts +1 -1
- package/src/core/constants/mcp.ts +14 -0
- package/src/core/constants/search.ts +2 -2
- package/src/core/contexts/AccordionGroupContext.tsx +3 -0
- package/src/core/contexts/PageActionsContext.tsx +7 -0
- package/src/core/contexts/index.ts +2 -0
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +2 -0
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +6 -20
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +2 -0
- package/src/core/hooks/menu/use-menu-item-expanded.ts +1 -0
- package/src/core/hooks/use-active-heading.ts +83 -15
- package/src/core/hooks/use-active-section-id.ts +3 -1
- package/src/core/hooks/use-connect-mcp-button.ts +31 -17
- package/src/core/hooks/use-control.ts +5 -1
- package/src/core/hooks/use-local-state.ts +1 -0
- package/src/core/hooks/use-mcp-config.ts +15 -4
- package/src/core/hooks/use-mobile-menu.ts +11 -3
- package/src/core/hooks/use-tabs.ts +4 -2
- package/src/core/hooks/use-telemetry-fallback.ts +2 -0
- package/src/core/openapi/index.ts +1 -1
- package/src/core/styles/global.ts +17 -12
- package/src/core/styles/palette.ts +2 -0
- package/src/core/types/button-group.ts +2 -0
- package/src/core/types/catalog.ts +2 -4
- package/src/core/types/common.ts +3 -0
- package/src/core/types/hooks.ts +1 -0
- package/src/core/types/index.ts +1 -0
- package/src/core/types/l10n.ts +29 -1
- package/src/core/types/mcp.ts +1 -1
- package/src/core/utils/RenderWithLink.tsx +19 -0
- package/src/core/utils/index.ts +1 -0
- package/src/core/utils/mcp.ts +39 -0
- package/src/icons/CodexIcon/CodexIcon.tsx +23 -0
- package/src/icons/LinkIcon/LinkIcon.tsx +1 -1
- package/src/index.ts +2 -0
- package/src/layouts/McpNotAllowed.tsx +37 -11
- package/src/markdoc/components/Accordion/Accordion.tsx +8 -2
- package/src/markdoc/components/Accordion/AccordionGroup.tsx +9 -2
- package/src/markdoc/components/Cards/Card.tsx +79 -14
- package/src/markdoc/components/Cards/CardBadge.tsx +39 -0
- package/src/markdoc/components/Cards/CardIcon.tsx +16 -5
- package/src/markdoc/components/Cards/variables.dark.ts +32 -0
- package/src/markdoc/components/Cards/variables.ts +81 -7
- package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -0
- package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/variables.ts +2 -1
- package/src/markdoc/components/Heading/Heading.tsx +7 -4
- package/src/markdoc/components/Tabs/TabList.tsx +6 -2
- package/src/markdoc/components/Tabs/Tabs.tsx +4 -2
- package/src/markdoc/components/Tabs/variables.ts +4 -4
- package/src/markdoc/tags/accordion-group.ts +3 -0
- package/src/markdoc/tags/admonition.ts +1 -1
- package/src/markdoc/tags/card.ts +14 -0
- package/src/markdoc/tags/connect-mcp.ts +3 -1
|
@@ -254,7 +254,7 @@ const TooltipBody = styled.span<{
|
|
|
254
254
|
word-break: normal;
|
|
255
255
|
overflow-wrap: break-word;
|
|
256
256
|
|
|
257
|
-
border-radius: var(--border-radius-
|
|
257
|
+
border-radius: var(--border-radius-lg);
|
|
258
258
|
transition: opacity 0.3s ease-out;
|
|
259
259
|
|
|
260
260
|
font-size: var(--font-size-base);
|
|
@@ -274,7 +274,7 @@ const TooltipBody = styled.span<{
|
|
|
274
274
|
|
|
275
275
|
background: var(--tooltip-bg-color);
|
|
276
276
|
color: var(--tooltip-text-color);
|
|
277
|
-
border: var(--tooltip-border-width,
|
|
277
|
+
border: var(--tooltip-border-width, 2px) var(--tooltip-border-style, solid)
|
|
278
278
|
var(--tooltip-border-color, transparent);
|
|
279
279
|
box-shadow: var(--bg-raised-shadow);
|
|
280
280
|
|
|
@@ -49,7 +49,7 @@ export const userMenu = css`
|
|
|
49
49
|
--user-menu-dropdown-item-padding-vertical: var(--dropdown-menu-item-padding-vertical); // @presenter Spacing
|
|
50
50
|
--user-menu-dropdown-item-separator-padding-top: var(--dropdown-menu-item-separator-padding-top ); // @presenter Spacing
|
|
51
51
|
--user-menu-dropdown-item-separator-padding-bottom: var(--dropdown-menu-item-separator-padding-bottom ); // @presenter Spacing
|
|
52
|
-
--user-menu-dropdown-item-border-radius: var(--dropdown-menu-item-border-radius
|
|
52
|
+
--user-menu-dropdown-item-border-radius: var(--dropdown-menu-item-border-radius); // @presenter BorderRadius
|
|
53
53
|
--user-menu-dropdown-item-bg-color-active: var(--dropdown-menu-item-bg-color-active); // @presenter Color
|
|
54
54
|
--user-menu-dropdown-item-bg-color-hover: var(--dropdown-menu-item-bg-color-hover); // @presenter Color
|
|
55
55
|
--user-menu-dropdown-item-bg-color-disabled: var(--dropdown-menu-item-bg-color-disabled); // @presenter Color
|
|
@@ -1 +1,15 @@
|
|
|
1
|
+
import type { MCPOption } from '../types/mcp';
|
|
2
|
+
|
|
1
3
|
export const DEFAULT_MCP_SERVER_NAME = 'mcp-server';
|
|
4
|
+
|
|
5
|
+
export const MCP_ROUTE = '/mcp';
|
|
6
|
+
|
|
7
|
+
export const PUBLIC_MCP_ROUTE = '/mcp-public';
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_MCP_OPTIONS: MCPOption[] = [
|
|
10
|
+
'cursor',
|
|
11
|
+
'vscode',
|
|
12
|
+
'claude-code',
|
|
13
|
+
'codex',
|
|
14
|
+
'copy',
|
|
15
|
+
];
|
|
@@ -29,13 +29,13 @@ export const AI_SEARCH_ERROR_CONFIG: Record<AiSearchError, AiSearchErrorConfig>
|
|
|
29
29
|
headerKey: 'search.ai.error.header.forbidden',
|
|
30
30
|
headerDefault: 'Feature Unavailable',
|
|
31
31
|
messageKey: 'search.ai.error.description.forbidden',
|
|
32
|
-
messageDefault: 'AI
|
|
32
|
+
messageDefault: 'AI assistant is currently unavailable.',
|
|
33
33
|
},
|
|
34
34
|
[AiSearchError.Unauthorized]: {
|
|
35
35
|
headerKey: 'search.ai.error.header.unauthorized',
|
|
36
36
|
headerDefault: 'Authentication Required',
|
|
37
37
|
messageKey: 'search.ai.error.description.unauthorized',
|
|
38
|
-
messageDefault: 'You are not authorized to use AI
|
|
38
|
+
messageDefault: 'You are not authorized to use AI assistant.',
|
|
39
39
|
},
|
|
40
40
|
[AiSearchError.HttpRequestFailed]: defaultErrorConfig,
|
|
41
41
|
[AiSearchError.EmptyResponse]: defaultErrorConfig,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether the first heading inside the enclosing `Markdown` mounts the page actions.
|
|
5
|
+
* Without a provider `Heading` falls back to the page type in the page metadata.
|
|
6
|
+
*/
|
|
7
|
+
export const PageActionsContext = createContext<boolean | null>(null);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './ThemeDataContext';
|
|
2
2
|
export * from './MarkdownLinkContext';
|
|
3
|
+
export * from './PageActionsContext';
|
|
3
4
|
export * from './CodeWalkthrough/CodeWalkthroughControlsContext';
|
|
4
5
|
export * from './CodeWalkthrough/CodeWalkthroughStepsContext';
|
|
6
|
+
export * from './AccordionGroupContext';
|
|
5
7
|
export * from './CodeSnippetContext';
|
|
6
8
|
export * from './SearchContext';
|
|
7
9
|
export * from './Toast/ToastContext';
|
|
@@ -18,6 +18,8 @@ export const useThemeHooks = vi.fn(() => ({
|
|
|
18
18
|
useTelemetry: vi.fn(() => ({
|
|
19
19
|
send: vi.fn(),
|
|
20
20
|
sendCodeSnippetReportedMessage: vi.fn(),
|
|
21
|
+
sendConnectMcpClickedMessage: vi.fn(),
|
|
22
|
+
sendMcpConnectionSnippetCopiedMessage: vi.fn(),
|
|
21
23
|
sendPageActionsButtonClickedMessage: vi.fn(),
|
|
22
24
|
sendColorModeSwitchedMessage: vi.fn(),
|
|
23
25
|
})),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, useMemo
|
|
1
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
2
2
|
import { useLocation, useNavigate } from 'react-router';
|
|
3
3
|
|
|
4
4
|
import type {
|
|
@@ -50,10 +50,6 @@ export function useCodeWalkthroughControls(
|
|
|
50
50
|
const navigate = useNavigate();
|
|
51
51
|
const searchParams = useMemo(() => new URLSearchParams(location.search), [location.search]);
|
|
52
52
|
|
|
53
|
-
const filtersRef = useRef(filters);
|
|
54
|
-
const inputsRef = useRef(inputs);
|
|
55
|
-
const togglesRef = useRef(toggles);
|
|
56
|
-
|
|
57
53
|
const getInitialState = () => {
|
|
58
54
|
const state: CodeWalkthroughControlsState = {};
|
|
59
55
|
|
|
@@ -90,20 +86,11 @@ export function useCodeWalkthroughControls(
|
|
|
90
86
|
|
|
91
87
|
const [controlsState, setControlsState] = useState(getInitialState);
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
JSON.stringify(filters) === JSON.stringify(filtersRef.current),
|
|
96
|
-
JSON.stringify(inputs) === JSON.stringify(inputsRef.current),
|
|
97
|
-
JSON.stringify(toggles) === JSON.stringify(togglesRef.current),
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
if (sameProps.every(Boolean)) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
89
|
+
const controlsKey = JSON.stringify([filters, inputs, toggles]);
|
|
90
|
+
const [prevControlsKey, setPrevControlsKey] = useState(controlsKey);
|
|
103
91
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
togglesRef.current = toggles;
|
|
92
|
+
if (prevControlsKey !== controlsKey) {
|
|
93
|
+
setPrevControlsKey(controlsKey);
|
|
107
94
|
|
|
108
95
|
const newState = getInitialState();
|
|
109
96
|
|
|
@@ -120,8 +107,7 @@ export function useCodeWalkthroughControls(
|
|
|
120
107
|
});
|
|
121
108
|
|
|
122
109
|
setControlsState(newState);
|
|
123
|
-
|
|
124
|
-
}, [filters, inputs, toggles, enableDeepLink]);
|
|
110
|
+
}
|
|
125
111
|
|
|
126
112
|
const changeControlState = (id: string, value: string | boolean) => {
|
|
127
113
|
setControlsState((prev) => {
|
|
@@ -95,6 +95,7 @@ export function useCodeWalkthroughSteps({
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates -- marker geometry is derived from post-layout measurements (offsetTop, clientHeight, window.innerHeight)
|
|
98
99
|
setMarkers(
|
|
99
100
|
markers.reduce(
|
|
100
101
|
(acc, marker, index) => {
|
|
@@ -252,6 +253,7 @@ export function useCodeWalkthroughSteps({
|
|
|
252
253
|
|
|
253
254
|
const rootTopOffset = root.current?.offsetTop ?? 0;
|
|
254
255
|
if (!activeStep && rootTopOffset <= options.navbarHeight) {
|
|
256
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-derived-state -- seeded from root.current.offsetTop, a post-layout measurement
|
|
255
257
|
setActiveStep(visibleSteps[0]?.id || null);
|
|
256
258
|
}
|
|
257
259
|
|
|
@@ -16,6 +16,7 @@ export function useMenuItemExpanded(item: ItemState): [boolean, Dispatch<SetStat
|
|
|
16
16
|
const [controlledValue, setControlledValue] = useState(isItemExpanded(item));
|
|
17
17
|
|
|
18
18
|
useEffect(() => {
|
|
19
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-derived-state -- deferred a commit on purpose so CSS transitions still run
|
|
19
20
|
setIsExpanded(controlledValue);
|
|
20
21
|
}, [controlledValue]);
|
|
21
22
|
|
|
@@ -8,6 +8,15 @@ type HeadingEntry = {
|
|
|
8
8
|
[key: string]: IntersectionObserverEntry;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
type ClickScroll = {
|
|
12
|
+
target: HTMLElement;
|
|
13
|
+
scrollMargin: number;
|
|
14
|
+
closestDistance: number;
|
|
15
|
+
reached: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const TARGET_TOLERANCE = 2;
|
|
19
|
+
|
|
11
20
|
export function useActiveHeading(
|
|
12
21
|
contentElement: HTMLDivElement | null,
|
|
13
22
|
displayedHeadings?: Array<{ id: string; depth: number } | null>,
|
|
@@ -17,11 +26,14 @@ export function useActiveHeading(
|
|
|
17
26
|
const headingElementsRef = useRef<HeadingEntry>({});
|
|
18
27
|
const displayedHeadingsRef = useRef(displayedHeadings);
|
|
19
28
|
const lockObserver = useRef<boolean>(false);
|
|
29
|
+
const clickScroll = useRef<ClickScroll | null>(null);
|
|
20
30
|
const location = useLocation();
|
|
21
31
|
|
|
22
32
|
useEffect(() => {
|
|
23
33
|
setHeading(undefined);
|
|
24
34
|
headingElementsRef.current = {};
|
|
35
|
+
clickScroll.current = null;
|
|
36
|
+
lockObserver.current = false;
|
|
25
37
|
}, [location.pathname]);
|
|
26
38
|
|
|
27
39
|
useEffect(() => {
|
|
@@ -133,10 +145,6 @@ export function useActiveHeading(
|
|
|
133
145
|
|
|
134
146
|
const intersectionCallback = useCallback(
|
|
135
147
|
(entries: IntersectionObserverEntry[]) => {
|
|
136
|
-
if (lockObserver.current) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
148
|
headingElementsRef.current = entries.reduce(
|
|
141
149
|
(map: HeadingEntry, entry: IntersectionObserverEntry) => {
|
|
142
150
|
map[entry.target.id] = entry;
|
|
@@ -145,6 +153,10 @@ export function useActiveHeading(
|
|
|
145
153
|
headingElementsRef.current,
|
|
146
154
|
);
|
|
147
155
|
|
|
156
|
+
if (lockObserver.current) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
if (isTopOfPage()) {
|
|
149
161
|
const newHeading = headingElements[0]?.id || undefined;
|
|
150
162
|
setHeading(newHeading);
|
|
@@ -202,22 +214,71 @@ export function useActiveHeading(
|
|
|
202
214
|
[getIndexFromId, headingElements, getTriggerOffset, findActiveHeaderByVirtualPosition],
|
|
203
215
|
);
|
|
204
216
|
|
|
217
|
+
const releaseClickScroll = useCallback(() => {
|
|
218
|
+
clickScroll.current = null;
|
|
219
|
+
lockObserver.current = false;
|
|
220
|
+
}, []);
|
|
221
|
+
|
|
222
|
+
const trackClickScroll = useCallback(() => {
|
|
223
|
+
const clickScrollState = clickScroll.current;
|
|
224
|
+
if (!clickScrollState) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const { top } = clickScrollState.target.getBoundingClientRect();
|
|
229
|
+
|
|
230
|
+
if (clickScrollState.reached) {
|
|
231
|
+
if (top >= 0 && top <= getTriggerOffset()) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
const distance = Math.abs(top - clickScrollState.scrollMargin);
|
|
236
|
+
|
|
237
|
+
if (distance <= TARGET_TOLERANCE) {
|
|
238
|
+
clickScrollState.reached = true;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (distance <= clickScrollState.closestDistance + TARGET_TOLERANCE) {
|
|
243
|
+
clickScrollState.closestDistance = Math.min(clickScrollState.closestDistance, distance);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
releaseClickScroll();
|
|
249
|
+
intersectionCallback([]);
|
|
250
|
+
}, [releaseClickScroll, intersectionCallback, getTriggerOffset]);
|
|
251
|
+
|
|
205
252
|
const handleHeadingClick = useCallback(
|
|
206
253
|
(headingId: string) => {
|
|
207
|
-
|
|
254
|
+
releaseClickScroll();
|
|
208
255
|
setHeading(headingId);
|
|
209
256
|
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
257
|
+
const target =
|
|
258
|
+
document.getElementById(headingId) || headingElements.find((el) => el.id === headingId);
|
|
259
|
+
|
|
260
|
+
if (!target?.scrollIntoView) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
265
|
+
|
|
266
|
+
if (!target.getClientRects().length) {
|
|
267
|
+
return;
|
|
213
268
|
}
|
|
214
269
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
270
|
+
const scrollMargin = parseFloat(getComputedStyle(target).scrollMarginTop) || 0;
|
|
271
|
+
const distance = Math.abs(target.getBoundingClientRect().top - scrollMargin);
|
|
272
|
+
|
|
273
|
+
lockObserver.current = true;
|
|
274
|
+
clickScroll.current = {
|
|
275
|
+
target,
|
|
276
|
+
scrollMargin,
|
|
277
|
+
closestDistance: distance,
|
|
278
|
+
reached: distance <= TARGET_TOLERANCE,
|
|
279
|
+
};
|
|
219
280
|
},
|
|
220
|
-
[headingElements],
|
|
281
|
+
[headingElements, releaseClickScroll],
|
|
221
282
|
);
|
|
222
283
|
|
|
223
284
|
useEffect(() => {
|
|
@@ -225,18 +286,22 @@ export function useActiveHeading(
|
|
|
225
286
|
return;
|
|
226
287
|
}
|
|
227
288
|
const headers = findHeaders(contentElement);
|
|
289
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates -- headings and the initial active heading come from DOM queries and scroll measurement, available only after layout
|
|
228
290
|
setHeadingElements(headers);
|
|
229
291
|
|
|
230
292
|
if (headers.length > 0 && !heading) {
|
|
231
293
|
if (isTopOfPage()) {
|
|
294
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates -- see above
|
|
232
295
|
setHeading(headers[0].id);
|
|
233
296
|
} else {
|
|
234
297
|
const totalHeight = scrollY + window.innerHeight;
|
|
235
298
|
if (totalHeight >= document.body.scrollHeight - 10) {
|
|
299
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates -- see above
|
|
236
300
|
setHeading(headers[headers.length - 1]?.id || undefined);
|
|
237
301
|
} else {
|
|
238
302
|
const triggerOffset = getTriggerOffset();
|
|
239
303
|
const activeHeader = findActiveHeaderByVirtualPosition(headers, scrollY, triggerOffset);
|
|
304
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates -- see above
|
|
240
305
|
setHeading(activeHeader.id);
|
|
241
306
|
}
|
|
242
307
|
}
|
|
@@ -268,7 +333,10 @@ export function useActiveHeading(
|
|
|
268
333
|
});
|
|
269
334
|
|
|
270
335
|
const handleScroll = () => {
|
|
271
|
-
if (
|
|
336
|
+
if (clickScroll.current) {
|
|
337
|
+
trackClickScroll();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
272
340
|
|
|
273
341
|
if (isTopOfPage()) {
|
|
274
342
|
setHeading(headingElements[0]?.id || undefined);
|
|
@@ -281,7 +349,7 @@ export function useActiveHeading(
|
|
|
281
349
|
observer.disconnect();
|
|
282
350
|
window.removeEventListener('scroll', handleScroll);
|
|
283
351
|
};
|
|
284
|
-
}, [headingElements, intersectionCallback, getTriggerOffset]);
|
|
352
|
+
}, [headingElements, intersectionCallback, getTriggerOffset, trackClickScroll]);
|
|
285
353
|
|
|
286
354
|
return { heading, handleHeadingClick };
|
|
287
355
|
}
|
|
@@ -60,11 +60,13 @@ export function useActiveSectionId(
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
window.addEventListener('scroll', scrollListener, { capture: false });
|
|
63
|
-
setTimeout(() => {
|
|
63
|
+
const initialRead = setTimeout(() => {
|
|
64
64
|
scrollListener();
|
|
65
65
|
}, 10);
|
|
66
66
|
|
|
67
67
|
return () => {
|
|
68
|
+
clearTimeout(initialRead);
|
|
69
|
+
scrollListener.cancel();
|
|
68
70
|
window.removeEventListener('scroll', scrollListener);
|
|
69
71
|
};
|
|
70
72
|
}, [location, heightOffset, scrollListener]);
|
|
@@ -6,13 +6,16 @@ import type { MCPOption } from '../types';
|
|
|
6
6
|
import { useThemeHooks } from './use-theme-hooks';
|
|
7
7
|
import { useMCPConfig } from './use-mcp-config';
|
|
8
8
|
import { ClipboardService } from '../utils/clipboard-service';
|
|
9
|
+
import { DEFAULT_MCP_OPTIONS } from '../constants/mcp';
|
|
10
|
+
import { generateClaudeCodeCommand, generateCodexCommand } from '../utils/mcp';
|
|
11
|
+
import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
|
|
9
12
|
|
|
10
13
|
export type McpButtonOptions = {
|
|
11
14
|
options?: MCPOption[];
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export type McpButtonSettings = {
|
|
15
|
-
|
|
18
|
+
copiedOption: MCPOption | null;
|
|
16
19
|
cursorUrl: string;
|
|
17
20
|
vscodeUrl: string;
|
|
18
21
|
triggerButtonText: string;
|
|
@@ -23,42 +26,53 @@ export type McpButtonSettings = {
|
|
|
23
26
|
const COPIED_RESET_TIMEOUT = 1000;
|
|
24
27
|
|
|
25
28
|
export function useConnectMCPButton({
|
|
26
|
-
options =
|
|
29
|
+
options = DEFAULT_MCP_OPTIONS,
|
|
27
30
|
}: McpButtonOptions = {}): McpButtonSettings {
|
|
28
|
-
const { useTranslate } = useThemeHooks();
|
|
31
|
+
const { useTranslate, useTelemetry } = useThemeHooks();
|
|
29
32
|
const { translate } = useTranslate();
|
|
33
|
+
const telemetry = useTelemetry();
|
|
30
34
|
const { serverName, serverUrl, cursorUrl, vscodeUrl } = useMCPConfig();
|
|
31
|
-
const [
|
|
35
|
+
const [copiedOption, setCopiedOption] = useState<MCPOption | null>(null);
|
|
32
36
|
|
|
33
37
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
38
|
const resetCopied = useCallback(
|
|
35
|
-
debounce(() =>
|
|
39
|
+
debounce(() => setCopiedOption(null), COPIED_RESET_TIMEOUT),
|
|
36
40
|
[],
|
|
37
41
|
);
|
|
38
42
|
|
|
39
43
|
const handleAction = useCallback(
|
|
40
44
|
(action: MCPOption) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
telemetry.sendConnectMcpClickedMessage([
|
|
46
|
+
{ ...getBaseDataAttributes('connectMcp', 'button'), option: action },
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const connection = { serverName, url: serverUrl };
|
|
50
|
+
const copyTextMap: Partial<Record<MCPOption, string>> = {
|
|
51
|
+
copy: JSON.stringify(
|
|
52
|
+
{ [serverName]: { url: serverUrl, description: 'MCP Server' } },
|
|
53
|
+
null,
|
|
54
|
+
2,
|
|
55
|
+
),
|
|
56
|
+
'claude-code': generateClaudeCodeCommand(connection),
|
|
57
|
+
codex: generateCodexCommand(connection),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const copyText = copyTextMap[action];
|
|
61
|
+
if (copyText !== undefined) {
|
|
62
|
+
ClipboardService.copyCustom(copyText);
|
|
63
|
+
setCopiedOption(action);
|
|
50
64
|
resetCopied();
|
|
51
65
|
return;
|
|
52
66
|
}
|
|
53
67
|
|
|
54
|
-
const urlMap: Record<
|
|
68
|
+
const urlMap: Partial<Record<MCPOption, string>> = {
|
|
55
69
|
cursor: cursorUrl,
|
|
56
70
|
vscode: vscodeUrl,
|
|
57
71
|
};
|
|
58
72
|
|
|
59
73
|
window.open(urlMap[action], '_blank');
|
|
60
74
|
},
|
|
61
|
-
[cursorUrl, vscodeUrl, serverUrl, serverName, resetCopied],
|
|
75
|
+
[cursorUrl, vscodeUrl, serverUrl, serverName, resetCopied, telemetry],
|
|
62
76
|
);
|
|
63
77
|
|
|
64
78
|
const triggerButtonText = useMemo(
|
|
@@ -69,7 +83,7 @@ export function useConnectMCPButton({
|
|
|
69
83
|
const visibleOptions = useMemo(() => options.filter(Boolean), [options]);
|
|
70
84
|
|
|
71
85
|
return {
|
|
72
|
-
|
|
86
|
+
copiedOption,
|
|
73
87
|
cursorUrl,
|
|
74
88
|
vscodeUrl,
|
|
75
89
|
triggerButtonText,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from 'react';
|
|
1
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
|
|
3
3
|
const DEFAULT_CONTROL_OPEN_DELAY = 300;
|
|
4
4
|
|
|
@@ -18,6 +18,10 @@ export const useControl = (initialVal = false): UseControlReturnType => {
|
|
|
18
18
|
}
|
|
19
19
|
}, []);
|
|
20
20
|
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
return clearOpenTimer;
|
|
23
|
+
}, [clearOpenTimer]);
|
|
24
|
+
|
|
21
25
|
const handleOpen = useCallback(() => {
|
|
22
26
|
clearOpenTimer();
|
|
23
27
|
timeoutRef.current = setTimeout(() => {
|
|
@@ -21,6 +21,7 @@ export function useLocalState<T>(key: string, initialValue: T): [T, (value: T) =
|
|
|
21
21
|
// then client loads the actual stored value without hydration mismatch
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
if (!isBrowser()) return;
|
|
24
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-derived-state -- localStorage is read after mount so SSR and client hydrate from the same value
|
|
24
25
|
setValue(getStoredValue(key, initialValue));
|
|
25
26
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
27
|
}, [key]);
|
|
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { useThemeHooks } from './use-theme-hooks';
|
|
4
4
|
import { IS_BROWSER } from '../utils/dom';
|
|
5
|
-
import { DEFAULT_MCP_SERVER_NAME } from '../constants';
|
|
5
|
+
import { DEFAULT_MCP_SERVER_NAME, MCP_ROUTE, PUBLIC_MCP_ROUTE } from '../constants';
|
|
6
6
|
import { generateMCPDeepLink } from '../utils/mcp';
|
|
7
7
|
import { withPathPrefix } from '../utils/urls';
|
|
8
8
|
|
|
@@ -13,20 +13,29 @@ export type McpConfig = {
|
|
|
13
13
|
cursorUrl: string;
|
|
14
14
|
vscodeUrl: string;
|
|
15
15
|
isMcpDisabled: boolean;
|
|
16
|
+
isPublicEndpointPage: boolean;
|
|
17
|
+
alternateServerUrl?: string;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
export function useMCPConfig(): McpConfig {
|
|
19
|
-
const { useMcpData } = useThemeHooks();
|
|
21
|
+
const { useMcpData, usePageData } = useThemeHooks();
|
|
20
22
|
|
|
21
23
|
const {
|
|
22
|
-
docs: { enabled, name },
|
|
24
|
+
docs: { enabled, name, publicEndpoint },
|
|
23
25
|
} = useMcpData();
|
|
26
|
+
const pageSlug = usePageData()?.slug;
|
|
24
27
|
|
|
25
28
|
const origin = IS_BROWSER
|
|
26
29
|
? window.location.origin
|
|
27
30
|
: ((globalThis as { SSR_HOSTNAME?: string })['SSR_HOSTNAME'] ?? '');
|
|
28
31
|
const serverName = name || DEFAULT_MCP_SERVER_NAME;
|
|
29
|
-
const
|
|
32
|
+
const isPublicEndpointPage = pageSlug === withPathPrefix(PUBLIC_MCP_ROUTE);
|
|
33
|
+
const serverUrl = `${origin}${withPathPrefix(isPublicEndpointPage ? PUBLIC_MCP_ROUTE : MCP_ROUTE)}`;
|
|
34
|
+
const alternateServerUrl = isPublicEndpointPage
|
|
35
|
+
? `${origin}${withPathPrefix(MCP_ROUTE)}`
|
|
36
|
+
: publicEndpoint
|
|
37
|
+
? `${origin}${withPathPrefix(PUBLIC_MCP_ROUTE)}`
|
|
38
|
+
: undefined;
|
|
30
39
|
const isMcpDisabled = !enabled || false;
|
|
31
40
|
|
|
32
41
|
const cursorUrl = useMemo(
|
|
@@ -46,5 +55,7 @@ export function useMCPConfig(): McpConfig {
|
|
|
46
55
|
cursorUrl,
|
|
47
56
|
vscodeUrl,
|
|
48
57
|
isMcpDisabled,
|
|
58
|
+
isPublicEndpointPage,
|
|
59
|
+
alternateServerUrl,
|
|
49
60
|
};
|
|
50
61
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react';
|
|
2
2
|
import { useLocation } from 'react-router';
|
|
3
3
|
|
|
4
4
|
import { useModalScrollLock } from './use-modal-scroll-lock';
|
|
@@ -6,11 +6,19 @@ import { useModalScrollLock } from './use-modal-scroll-lock';
|
|
|
6
6
|
export function useMobileMenu(initialState = false) {
|
|
7
7
|
const location = useLocation();
|
|
8
8
|
const [isOpen, setIsOpen] = useState(initialState);
|
|
9
|
+
const locationKey = `${location.pathname}${location.hash}`;
|
|
10
|
+
const [prevLocationKey, setPrevLocationKey] = useState(locationKey);
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
if (isOpen && prevLocationKey !== locationKey) {
|
|
13
|
+
setPrevLocationKey(locationKey);
|
|
14
|
+
setIsOpen(false);
|
|
15
|
+
}
|
|
11
16
|
useModalScrollLock(isOpen);
|
|
12
17
|
|
|
13
|
-
const openMobileMenu = () =>
|
|
18
|
+
const openMobileMenu = () => {
|
|
19
|
+
setPrevLocationKey(locationKey);
|
|
20
|
+
setIsOpen(true);
|
|
21
|
+
};
|
|
14
22
|
const closeMobileMenu = () => setIsOpen(false);
|
|
15
23
|
|
|
16
24
|
return { isOpen, openMobileMenu, closeMobileMenu };
|
|
@@ -289,14 +289,16 @@ export const useActiveTab = ({ initialTab, tabsId }: UseActiveTabProps) => {
|
|
|
289
289
|
const [activeTab, setActiveTab] = useState<string | undefined>(undefined);
|
|
290
290
|
const resolvedActiveTab = activeTab ?? initialTab;
|
|
291
291
|
const prevActiveTabRef = useRef(resolvedActiveTab);
|
|
292
|
+
const isTabResolvedFromHashRef = useRef(false);
|
|
292
293
|
|
|
293
294
|
useEffect(() => {
|
|
294
|
-
if (
|
|
295
|
+
if (isTabResolvedFromHashRef.current) {
|
|
295
296
|
return;
|
|
296
297
|
}
|
|
298
|
+
isTabResolvedFromHashRef.current = true;
|
|
297
299
|
|
|
298
300
|
setActiveTab(getInitialTab({ initialTab, hash: location.hash, tabsId }));
|
|
299
|
-
}, [
|
|
301
|
+
}, [initialTab, location.hash, tabsId]);
|
|
300
302
|
|
|
301
303
|
useEffect(() => {
|
|
302
304
|
const hasActiveTabChanged = prevActiveTabRef.current !== resolvedActiveTab;
|
|
@@ -36,6 +36,8 @@ export const useTelemetryFallback = () => ({
|
|
|
36
36
|
sendProductPickerChangedMessage: () => {},
|
|
37
37
|
sendLogoClickedMessage: () => {},
|
|
38
38
|
sendCodeSnippetReportedMessage: () => {},
|
|
39
|
+
sendConnectMcpClickedMessage: () => {},
|
|
40
|
+
sendMcpConnectionSnippetCopiedMessage: () => {},
|
|
39
41
|
sendMobileMenuClosedMessage: () => {},
|
|
40
42
|
sendMobileMenuOpenedMessage: () => {},
|
|
41
43
|
sendPageViewedMessage: () => {},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This file is intended to provide selective imports from @redocly/theme/core
|
|
2
|
-
// to reduce bundle size by exporting only functionality used in the @redocly/
|
|
2
|
+
// to reduce bundle size by exporting only functionality used in the @redocly/api-docs package.
|
|
3
3
|
//
|
|
4
4
|
// This selective import approach will help with tree shaking and reduce
|
|
5
5
|
// the overall bundle size by avoiding importing the entire theme package
|