@redocly/theme 0.70.0-next.1 → 0.70.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/Buttons/ConnectMCPButton.js +19 -14
- package/lib/components/Buttons/variables.d.ts +1 -0
- package/lib/components/Buttons/variables.js +4 -1
- package/lib/components/Catalog/Catalog.js +3 -3
- package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.d.ts +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +2 -2
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +1 -1
- package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +30 -11
- package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.js +2 -1
- package/lib/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanel.js +1 -1
- package/lib/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanelOverlay.js +2 -2
- package/lib/components/CodeBlock/CodeBlockControls.js +3 -5
- package/lib/components/Consent/Consent.d.ts +2 -0
- package/lib/components/Consent/Consent.js +17 -0
- package/lib/components/Consent/ConsentBanner.d.ts +2 -0
- package/lib/components/Consent/ConsentBanner.js +120 -0
- package/lib/components/Consent/ConsentDialog.d.ts +2 -0
- package/lib/components/Consent/ConsentDialog.js +128 -0
- package/lib/components/Consent/ConsentSettingsLink.d.ts +2 -0
- package/lib/components/Consent/ConsentSettingsLink.js +35 -0
- package/lib/components/Consent/variables.d.ts +1 -0
- package/lib/components/Consent/variables.js +31 -0
- package/lib/components/Dropdown/Dropdown.d.ts +4 -2
- package/lib/components/Dropdown/Dropdown.js +31 -9
- package/lib/components/Dropdown/DropdownMenu.d.ts +1 -0
- package/lib/components/Dropdown/DropdownMenu.js +1 -1
- package/lib/components/Feedback/Reasons.js +3 -2
- package/lib/components/Filter/FilterCheckboxes.js +30 -11
- package/lib/components/Filter/FilterDateRange.js +36 -2
- package/lib/components/Footer/Footer.js +4 -1
- package/lib/components/Image/Image.js +24 -4
- package/lib/components/JsonViewer/Helpers.d.ts +10 -2
- package/lib/components/JsonViewer/Helpers.js +32 -36
- package/lib/components/JsonViewer/JsonViewer.js +15 -18
- package/lib/components/LoadProgressBar/LoadProgressBar.d.ts +8 -0
- package/lib/components/LoadProgressBar/LoadProgressBar.js +122 -0
- package/lib/components/MCP/McpConnectionTabs.js +9 -2
- package/lib/components/Markdown/Markdown.js +3 -2
- package/lib/components/Markdown/styles/base-table.js +14 -1
- package/lib/components/Markdown/variables.js +1 -0
- package/lib/components/Menu/Menu.js +4 -0
- package/lib/components/Menu/MenuSelect.d.ts +7 -0
- package/lib/components/Menu/MenuSelect.js +129 -0
- package/lib/components/Menu/variables.js +43 -4
- package/lib/components/Navbar/Navbar.js +44 -5
- package/lib/components/Navbar/variables.js +3 -0
- package/lib/components/NavigationTabs/NavigationTab.d.ts +7 -0
- package/lib/components/NavigationTabs/NavigationTab.js +93 -0
- package/lib/components/NavigationTabs/NavigationTabContent.d.ts +7 -0
- package/lib/components/NavigationTabs/NavigationTabContent.js +50 -0
- package/lib/components/NavigationTabs/NavigationTabMenu.d.ts +7 -0
- package/lib/components/NavigationTabs/NavigationTabMenu.js +18 -0
- package/lib/components/NavigationTabs/NavigationTabs.d.ts +7 -0
- package/lib/components/NavigationTabs/NavigationTabs.js +97 -0
- package/lib/components/NavigationTabs/variables.d.ts +1 -0
- package/lib/components/NavigationTabs/variables.js +37 -0
- package/lib/components/Portal/Portal.js +37 -5
- package/lib/components/Product/utils.js +1 -1
- package/lib/components/Search/SearchAiActionButtons.js +8 -3
- package/lib/components/Search/SearchAiActivity.d.ts +10 -0
- package/lib/components/Search/SearchAiActivity.js +278 -0
- package/lib/components/Search/SearchAiConversationInput.js +10 -6
- package/lib/components/Search/SearchAiDialog.js +13 -2
- package/lib/components/Search/SearchAiMessage.d.ts +2 -1
- package/lib/components/Search/SearchAiMessage.js +21 -109
- package/lib/components/Search/SearchAiResponse.js +1 -0
- package/lib/components/Search/SearchDialog.js +10 -0
- package/lib/components/Search/SearchItem.js +11 -10
- package/lib/components/Search/SearchTrigger.js +37 -6
- package/lib/components/Search/variables.js +17 -2
- package/lib/components/Segmented/Segmented.js +23 -3
- package/lib/components/Select/Select.js +10 -3
- package/lib/components/Select/SelectInput.d.ts +1 -0
- package/lib/components/Select/SelectInput.js +5 -11
- package/lib/components/Sidebar/Sidebar.js +2 -2
- package/lib/components/SplitButton/SplitButton.js +37 -3
- package/lib/components/TableOfContent/TableOfContent.js +2 -2
- package/lib/core/constants/common.d.ts +1 -0
- package/lib/core/constants/common.js +1 -0
- package/lib/core/constants/consent.d.ts +2 -0
- package/lib/core/constants/consent.js +30 -0
- package/lib/core/constants/index.d.ts +2 -0
- package/lib/core/constants/index.js +2 -0
- package/lib/core/constants/mcp.d.ts +2 -2
- package/lib/core/constants/mcp.js +3 -8
- package/lib/core/constants/prompt.d.ts +9 -0
- package/lib/core/constants/prompt.js +33 -0
- package/lib/core/constants/search.d.ts +1 -1
- package/lib/core/constants/search.js +6 -2
- package/lib/core/contexts/PortalContainerContext.d.ts +2 -0
- package/lib/core/contexts/PortalContainerContext.js +7 -0
- package/lib/core/hooks/code-walkthrough/use-code-panel.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +1 -2
- package/lib/core/hooks/code-walkthrough/use-renderable-files.d.ts +1 -1
- package/lib/core/hooks/index.d.ts +9 -0
- package/lib/core/hooks/index.js +9 -0
- package/lib/core/hooks/menu/use-collapse.js +1 -1
- package/lib/core/hooks/menu/use-mobile-menu-items.js +75 -51
- package/lib/core/hooks/menu/use-mobile-menu-levels.js +12 -7
- package/lib/core/hooks/prompt/use-prompt-actions.d.ts +7 -0
- package/lib/core/hooks/prompt/use-prompt-actions.js +19 -0
- package/lib/core/hooks/prompt/use-prompt-text-limit.d.ts +19 -0
- package/lib/core/hooks/prompt/use-prompt-text-limit.js +35 -0
- package/lib/core/hooks/search/use-persisted-quick-filter.d.ts +21 -0
- package/lib/core/hooks/search/use-persisted-quick-filter.js +92 -0
- package/lib/core/hooks/search/use-search-ai-activity.d.ts +11 -0
- package/lib/core/hooks/search/use-search-ai-activity.js +15 -0
- package/lib/core/hooks/use-connect-mcp-button.js +3 -1
- package/lib/core/hooks/use-consent-dialog.d.ts +12 -0
- package/lib/core/hooks/use-consent-dialog.js +36 -0
- package/lib/core/hooks/use-consent-telemetry.d.ts +1 -0
- package/lib/core/hooks/use-consent-telemetry.js +42 -0
- package/lib/core/hooks/use-dialog-hotkeys.js +4 -2
- package/lib/core/hooks/use-full-height.d.ts +1 -1
- package/lib/core/hooks/use-full-height.js +8 -8
- package/lib/core/hooks/use-page-actions.d.ts +1 -1
- package/lib/core/hooks/use-page-actions.js +10 -8
- package/lib/core/hooks/use-pointer-border-highlight.d.ts +7 -0
- package/lib/core/hooks/use-pointer-border-highlight.js +29 -0
- package/lib/core/hooks/use-scroll-item-into-view.d.ts +2 -0
- package/lib/core/hooks/use-scroll-item-into-view.js +16 -0
- package/lib/core/hooks/use-tab-list.d.ts +31 -0
- package/lib/core/hooks/use-tab-list.js +49 -0
- package/lib/core/hooks/use-telemetry-fallback.d.ts +2 -0
- package/lib/core/hooks/use-telemetry-fallback.js +2 -0
- package/lib/core/hooks/use-theme-hooks.js +16 -0
- package/lib/core/styles/dark.js +14 -12
- package/lib/core/styles/global.d.ts +2 -0
- package/lib/core/styles/global.js +115 -136
- package/lib/core/styles/index.d.ts +1 -0
- package/lib/core/styles/index.js +3 -1
- package/lib/core/styles/search-ai-appear.d.ts +1 -0
- package/lib/core/styles/search-ai-appear.js +18 -0
- package/lib/core/types/code-walkthrough.d.ts +84 -0
- package/lib/core/types/consent.d.ts +54 -0
- package/lib/core/types/consent.js +3 -0
- package/lib/core/types/dropdown.d.ts +1 -0
- package/lib/core/types/dropdown.js +3 -0
- package/lib/core/types/hooks.d.ts +8 -1
- package/lib/core/types/index.d.ts +4 -0
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/mcp.d.ts +3 -2
- package/lib/core/types/navigation-tabs.d.ts +49 -0
- package/lib/core/types/navigation-tabs.js +3 -0
- package/lib/core/types/prompt.d.ts +9 -0
- package/lib/core/types/prompt.js +3 -0
- package/lib/core/types/search.d.ts +25 -0
- package/lib/core/utils/Dynamic.d.ts +8 -1
- package/lib/core/utils/Dynamic.js +34 -3
- package/lib/core/utils/assign-ref.d.ts +2 -0
- package/lib/core/utils/assign-ref.js +12 -0
- package/lib/core/utils/consent-settings-link-placement.d.ts +3 -0
- package/lib/core/utils/consent-settings-link-placement.js +15 -0
- package/lib/core/utils/content-segments.d.ts +12 -1
- package/lib/core/utils/content-segments.js +90 -5
- package/lib/core/utils/download-code-walkthrough.d.ts +1 -1
- package/lib/core/utils/dropdown.d.ts +2 -0
- package/lib/core/utils/dropdown.js +12 -0
- package/lib/core/utils/get-ai-prompt-link.d.ts +15 -0
- package/lib/core/utils/get-ai-prompt-link.js +29 -0
- package/lib/core/utils/get-code-walkthrough-file-text.d.ts +1 -1
- package/lib/core/utils/index.d.ts +5 -0
- package/lib/core/utils/index.js +5 -0
- package/lib/core/utils/match-code-walkthrough-conditions.d.ts +1 -1
- package/lib/core/utils/mcp.d.ts +2 -1
- package/lib/core/utils/mcp.js +13 -3
- package/lib/core/utils/menu.d.ts +4 -0
- package/lib/core/utils/menu.js +48 -8
- package/lib/core/utils/navigation-tabs.d.ts +8 -0
- package/lib/core/utils/navigation-tabs.js +71 -0
- package/lib/core/utils/search-ai-activity.d.ts +4 -0
- package/lib/core/utils/search-ai-activity.js +83 -0
- package/lib/core/utils/urls.js +3 -1
- package/lib/core/utils/with-load-progress.d.ts +3 -0
- package/lib/core/utils/with-load-progress.js +24 -19
- package/lib/ext/configure.d.ts +1 -1
- package/lib/ext/configure.js +0 -1
- package/lib/icons/ExpandCollapseIcon/ExpandCollapseIcon.d.ts +29 -0
- package/lib/icons/ExpandCollapseIcon/ExpandCollapseIcon.js +81 -0
- package/lib/icons/LinkIcon/LinkIconSymbol.d.ts +12 -0
- package/lib/icons/LinkIcon/LinkIconSymbol.js +41 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +9 -1
- package/lib/layouts/PageLayout.js +1 -1
- package/lib/layouts/RootLayout.js +2 -2
- package/lib/markdoc/components/CodeWalkthrough/CodeFilters.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +3 -3
- package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeStep.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +1 -1
- package/lib/markdoc/components/Prompt/Prompt.d.ts +15 -0
- package/lib/markdoc/components/Prompt/Prompt.js +163 -0
- package/lib/markdoc/components/Prompt/PromptActions.d.ts +13 -0
- package/lib/markdoc/components/Prompt/PromptActions.js +43 -0
- package/lib/markdoc/components/Prompt/PromptBody.d.ts +14 -0
- package/lib/markdoc/components/Prompt/PromptBody.js +99 -0
- package/lib/markdoc/components/Prompt/PromptCopyButton.d.ts +10 -0
- package/lib/markdoc/components/Prompt/PromptCopyButton.js +28 -0
- package/lib/markdoc/components/Prompt/PromptHeader.d.ts +9 -0
- package/lib/markdoc/components/Prompt/PromptHeader.js +57 -0
- package/lib/markdoc/components/Prompt/PromptShowHideButton.d.ts +7 -0
- package/lib/markdoc/components/Prompt/PromptShowHideButton.js +21 -0
- package/lib/markdoc/components/Prompt/PromptToggleLabel.d.ts +7 -0
- package/lib/markdoc/components/Prompt/PromptToggleLabel.js +28 -0
- package/lib/markdoc/components/Prompt/variables.d.ts +1 -0
- package/lib/markdoc/components/Prompt/variables.dark.d.ts +1 -0
- package/lib/markdoc/components/Prompt/variables.dark.js +8 -0
- package/lib/markdoc/components/Prompt/variables.js +44 -0
- package/lib/markdoc/components/Tabs/TabList.js +8 -6
- package/lib/markdoc/components/default.d.ts +1 -0
- package/lib/markdoc/components/default.js +1 -0
- package/lib/markdoc/default.d.ts +2 -0
- package/lib/markdoc/default.js +2 -0
- package/lib/markdoc/tags/code-walkthrough.d.ts +1 -1
- package/lib/markdoc/tags/connect-mcp.js +15 -0
- package/lib/markdoc/tags/prompt.d.ts +2 -0
- package/lib/markdoc/tags/prompt.js +56 -0
- package/package.json +4 -8
- package/src/components/Buttons/ConnectMCPButton.tsx +21 -16
- package/src/components/Buttons/variables.ts +4 -0
- package/src/components/Catalog/Catalog.tsx +6 -4
- package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.tsx +3 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +2 -2
- package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +1 -1
- package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +37 -22
- package/src/components/Catalog/CatalogFilter/CatalogFilterDateRange.tsx +3 -2
- package/src/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanel.tsx +1 -1
- package/src/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanelOverlay.tsx +2 -2
- package/src/components/CodeBlock/CodeBlockControls.tsx +4 -7
- package/src/components/Consent/Consent.tsx +18 -0
- package/src/components/Consent/ConsentBanner.tsx +110 -0
- package/src/components/Consent/ConsentDialog.tsx +210 -0
- package/src/components/Consent/ConsentSettingsLink.tsx +44 -0
- package/src/components/Consent/variables.ts +28 -0
- package/src/components/Dropdown/Dropdown.tsx +32 -7
- package/src/components/Dropdown/DropdownMenu.tsx +7 -1
- package/src/components/Feedback/Reasons.tsx +3 -2
- package/src/components/Filter/FilterCheckboxes.tsx +33 -18
- package/src/components/Filter/FilterDateRange.tsx +3 -2
- package/src/components/Footer/Footer.tsx +2 -0
- package/src/components/Image/Image.tsx +26 -5
- package/src/components/JsonViewer/Helpers.tsx +51 -54
- package/src/components/JsonViewer/JsonViewer.tsx +23 -25
- package/src/components/LoadProgressBar/LoadProgressBar.tsx +113 -0
- package/src/components/MCP/McpConnectionTabs.tsx +22 -5
- package/src/components/Markdown/Markdown.tsx +3 -2
- package/src/components/Markdown/styles/base-table.ts +14 -1
- package/src/components/Markdown/variables.ts +1 -0
- package/src/components/Menu/Menu.tsx +5 -0
- package/src/components/Menu/MenuSelect.tsx +198 -0
- package/src/components/Menu/variables.ts +43 -4
- package/src/components/Navbar/Navbar.tsx +22 -5
- package/src/components/Navbar/variables.ts +3 -0
- package/src/components/NavigationTabs/NavigationTab.tsx +148 -0
- package/src/components/NavigationTabs/NavigationTabContent.tsx +66 -0
- package/src/components/NavigationTabs/NavigationTabMenu.tsx +40 -0
- package/src/components/NavigationTabs/NavigationTabs.tsx +83 -0
- package/src/components/NavigationTabs/variables.ts +34 -0
- package/src/components/Portal/Portal.tsx +4 -2
- package/src/components/Product/utils.ts +1 -1
- package/src/components/Search/SearchAiActionButtons.tsx +31 -19
- package/src/components/Search/SearchAiActivity.tsx +318 -0
- package/src/components/Search/SearchAiConversationInput.tsx +13 -7
- package/src/components/Search/SearchAiDialog.tsx +20 -4
- package/src/components/Search/SearchAiMessage.tsx +28 -136
- package/src/components/Search/SearchAiResponse.tsx +1 -0
- package/src/components/Search/SearchDialog.tsx +11 -0
- package/src/components/Search/SearchItem.tsx +19 -10
- package/src/components/Search/SearchTrigger.tsx +47 -3
- package/src/components/Search/variables.ts +17 -2
- package/src/components/Segmented/Segmented.tsx +25 -16
- package/src/components/Select/Select.tsx +12 -6
- package/src/components/Select/SelectInput.tsx +10 -18
- package/src/components/Sidebar/Sidebar.tsx +2 -2
- package/src/components/SplitButton/SplitButton.tsx +8 -2
- package/src/components/TableOfContent/TableOfContent.tsx +2 -2
- package/src/core/constants/common.ts +1 -0
- package/src/core/constants/consent.ts +29 -0
- package/src/core/constants/index.ts +2 -0
- package/src/core/constants/mcp.ts +3 -9
- package/src/core/constants/prompt.ts +34 -0
- package/src/core/constants/search.ts +6 -2
- package/src/core/contexts/PortalContainerContext.tsx +4 -0
- package/src/core/hooks/__mocks__/index.ts +5 -0
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +20 -0
- package/src/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.ts +1 -2
- package/src/core/hooks/code-walkthrough/__mocks__/mock-intersection-observer.ts +1 -2
- package/src/core/hooks/code-walkthrough/use-code-panel.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +2 -2
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +3 -3
- package/src/core/hooks/code-walkthrough/use-renderable-files.ts +1 -1
- package/src/core/hooks/index.ts +9 -0
- package/src/core/hooks/menu/use-collapse.ts +1 -1
- package/src/core/hooks/menu/use-mobile-menu-items.ts +91 -56
- package/src/core/hooks/menu/use-mobile-menu-levels.ts +14 -6
- package/src/core/hooks/prompt/use-prompt-actions.ts +28 -0
- package/src/core/hooks/prompt/use-prompt-text-limit.ts +59 -0
- package/src/core/hooks/search/use-persisted-quick-filter.ts +125 -0
- package/src/core/hooks/search/use-search-ai-activity.ts +31 -0
- package/src/core/hooks/use-connect-mcp-button.ts +13 -2
- package/src/core/hooks/use-consent-dialog.ts +51 -0
- package/src/core/hooks/use-consent-telemetry.ts +56 -0
- package/src/core/hooks/use-dialog-hotkeys.ts +11 -5
- package/src/core/hooks/use-full-height.ts +8 -8
- package/src/core/hooks/use-page-actions.ts +21 -9
- package/src/core/hooks/use-pointer-border-highlight.ts +46 -0
- package/src/core/hooks/use-scroll-item-into-view.ts +18 -0
- package/src/core/hooks/use-tab-list.ts +63 -0
- package/src/core/hooks/use-telemetry-fallback.ts +2 -0
- package/src/core/hooks/use-theme-hooks.ts +16 -0
- package/src/core/styles/dark.ts +2 -0
- package/src/core/styles/global.ts +96 -116
- package/src/core/styles/index.ts +2 -1
- package/src/core/styles/search-ai-appear.ts +16 -0
- package/src/core/types/code-walkthrough.ts +103 -0
- package/src/core/types/consent.ts +51 -0
- package/src/core/types/dropdown.ts +1 -0
- package/src/core/types/hooks.ts +8 -0
- package/src/core/types/index.ts +4 -0
- package/src/core/types/l10n.ts +46 -2
- package/src/core/types/mcp.ts +4 -2
- package/src/core/types/navigation-tabs.ts +54 -0
- package/src/core/types/prompt.ts +11 -0
- package/src/core/types/search.ts +23 -0
- package/src/core/utils/Dynamic.tsx +67 -35
- package/src/core/utils/assign-ref.ts +9 -0
- package/src/core/utils/consent-settings-link-placement.ts +18 -0
- package/src/core/utils/content-segments.ts +98 -6
- package/src/core/utils/download-code-walkthrough.ts +1 -1
- package/src/core/utils/dropdown.ts +14 -0
- package/src/core/utils/get-ai-prompt-link.ts +30 -0
- package/src/core/utils/get-code-walkthrough-file-text.ts +1 -1
- package/src/core/utils/index.ts +5 -0
- package/src/core/utils/match-code-walkthrough-conditions.ts +1 -1
- package/src/core/utils/mcp.ts +16 -4
- package/src/core/utils/menu.ts +54 -9
- package/src/core/utils/navigation-tabs.ts +99 -0
- package/src/core/utils/search-ai-activity.ts +110 -0
- package/src/core/utils/urls.ts +3 -1
- package/src/core/utils/with-load-progress.ts +23 -18
- package/src/ext/configure.ts +1 -1
- package/src/icons/CheckboxIcon/CheckboxIcon.tsx +1 -0
- package/src/icons/ChevronSortIcon/ChevronSortIcon.tsx +1 -0
- package/src/icons/ExpandCollapseIcon/ExpandCollapseIcon.tsx +56 -0
- package/src/icons/LinkIcon/LinkIconSymbol.tsx +51 -0
- package/src/index.ts +8 -0
- package/src/layouts/PageLayout.tsx +1 -1
- package/src/layouts/RootLayout.tsx +2 -2
- package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +2 -2
- package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +4 -4
- package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +2 -2
- package/src/markdoc/components/Prompt/Prompt.tsx +219 -0
- package/src/markdoc/components/Prompt/PromptActions.tsx +104 -0
- package/src/markdoc/components/Prompt/PromptBody.tsx +107 -0
- package/src/markdoc/components/Prompt/PromptCopyButton.tsx +73 -0
- package/src/markdoc/components/Prompt/PromptHeader.tsx +81 -0
- package/src/markdoc/components/Prompt/PromptShowHideButton.tsx +43 -0
- package/src/markdoc/components/Prompt/PromptToggleLabel.tsx +41 -0
- package/src/markdoc/components/Prompt/variables.dark.ts +5 -0
- package/src/markdoc/components/Prompt/variables.ts +41 -0
- package/src/markdoc/components/Tabs/TabList.tsx +9 -12
- package/src/markdoc/components/default.ts +1 -0
- package/src/markdoc/default.ts +2 -0
- package/src/markdoc/tags/code-walkthrough.ts +1 -1
- package/src/markdoc/tags/connect-mcp.ts +16 -1
- package/src/markdoc/tags/prompt.ts +58 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
|
|
5
|
+
export type PromptTextLimit = 'none' | 'oneLine' | 'maxLines';
|
|
6
|
+
|
|
7
|
+
export type UsePromptTextLimitParams = {
|
|
8
|
+
prompt: string;
|
|
9
|
+
singleLine: boolean;
|
|
10
|
+
isPromptVisible: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type PromptTextLimitState = {
|
|
14
|
+
textRef: RefObject<HTMLDivElement | null>;
|
|
15
|
+
textLimit: PromptTextLimit;
|
|
16
|
+
isExpanded: boolean;
|
|
17
|
+
hasHiddenText: boolean;
|
|
18
|
+
toggleExpanded: () => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Tracks the line limit of the prompt text (one line or the maximum lines) and whether the
|
|
23
|
+
* reader expanded it. `hasHiddenText` is true only when the limit hides some text.
|
|
24
|
+
*/
|
|
25
|
+
export function usePromptTextLimit({
|
|
26
|
+
prompt,
|
|
27
|
+
singleLine,
|
|
28
|
+
isPromptVisible,
|
|
29
|
+
}: UsePromptTextLimitParams): PromptTextLimitState {
|
|
30
|
+
const textRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
32
|
+
const [hasHiddenText, setHasHiddenText] = useState(false);
|
|
33
|
+
|
|
34
|
+
/* The text mounts late with hidePrompt and re-wraps on resize, so the observer is
|
|
35
|
+
attached each time the text (re)appears. */
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
const text = textRef.current;
|
|
38
|
+
if (!text || isExpanded) return;
|
|
39
|
+
|
|
40
|
+
const measure = () =>
|
|
41
|
+
setHasHiddenText(
|
|
42
|
+
text.scrollHeight > text.clientHeight || text.scrollWidth > text.clientWidth,
|
|
43
|
+
);
|
|
44
|
+
measure();
|
|
45
|
+
|
|
46
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
47
|
+
const observer = new ResizeObserver(measure);
|
|
48
|
+
observer.observe(text);
|
|
49
|
+
return () => observer.disconnect();
|
|
50
|
+
}, [prompt, singleLine, isExpanded, isPromptVisible]);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
textRef,
|
|
54
|
+
textLimit: isExpanded ? 'none' : singleLine ? 'oneLine' : 'maxLines',
|
|
55
|
+
isExpanded,
|
|
56
|
+
hasHiddenText,
|
|
57
|
+
toggleExpanded: () => setIsExpanded((expanded) => !expanded),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Dispatch, SetStateAction } from 'react';
|
|
4
|
+
import type { SearchFacet, SearchFilterItem } from '../../types/search';
|
|
5
|
+
|
|
6
|
+
import { createStore, useStore } from '../use-store';
|
|
7
|
+
|
|
8
|
+
type StoredQuickFilter = Pick<SearchFilterItem, 'field' | 'values'>;
|
|
9
|
+
|
|
10
|
+
const quickFilterStore = createStore<StoredQuickFilter | null>({
|
|
11
|
+
storageKey: 'searchQuickFilter',
|
|
12
|
+
storageType: 'sessionStorage',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const findQuickFilter = (filter: SearchFilterItem[]) => filter.find((item) => item.isQuickFilter);
|
|
16
|
+
|
|
17
|
+
const withQuickFilter = (filter: SearchFilterItem[], quickFilter: StoredQuickFilter) => [
|
|
18
|
+
...filter.filter((item) => !item.isQuickFilter),
|
|
19
|
+
...(quickFilter.values.length ? [{ ...quickFilter, isQuickFilter: true }] : []),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const groupFacetValues = (facets: SearchFacet[], field: string) => {
|
|
23
|
+
const facet = facets.find((item) => item.field === field);
|
|
24
|
+
const values = facet?.values ?? [];
|
|
25
|
+
return {
|
|
26
|
+
present: facet !== undefined,
|
|
27
|
+
values: values.map((item) => (typeof item === 'string' ? item : item.value)),
|
|
28
|
+
counted: values.some((item) => typeof item !== 'string' && item.isCounterVisible),
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const isRestorable = (
|
|
33
|
+
stored: StoredQuickFilter | null,
|
|
34
|
+
groupField: string,
|
|
35
|
+
): stored is StoredQuickFilter =>
|
|
36
|
+
!!stored &&
|
|
37
|
+
stored.field === groupField &&
|
|
38
|
+
Array.isArray(stored.values) &&
|
|
39
|
+
stored.values.length > 0 &&
|
|
40
|
+
stored.values.every((value) => typeof value === 'string');
|
|
41
|
+
|
|
42
|
+
type UsePersistedQuickFilterOptions = {
|
|
43
|
+
filter: SearchFilterItem[];
|
|
44
|
+
setFilter: Dispatch<SetStateAction<SearchFilterItem[]>>;
|
|
45
|
+
facets: SearchFacet[];
|
|
46
|
+
groupField: string;
|
|
47
|
+
query: string;
|
|
48
|
+
isSearchLoading: boolean;
|
|
49
|
+
searchError: string | null;
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Remembers the quick filter on `groupField` for the browser tab and restores it on mount unless
|
|
55
|
+
* one is already selected. Restored values are dropped once known not to exist: absent from the
|
|
56
|
+
* full value list, or from the `groupField` facet left by the first search that finishes without
|
|
57
|
+
* error on an empty query (the restored value is that search's filter, so a value without
|
|
58
|
+
* documents is not counted). Does nothing while `enabled` is false.
|
|
59
|
+
*/
|
|
60
|
+
export function usePersistedQuickFilter({
|
|
61
|
+
filter,
|
|
62
|
+
setFilter,
|
|
63
|
+
facets,
|
|
64
|
+
groupField,
|
|
65
|
+
query,
|
|
66
|
+
isSearchLoading,
|
|
67
|
+
searchError,
|
|
68
|
+
enabled = true,
|
|
69
|
+
}: UsePersistedQuickFilterOptions): void {
|
|
70
|
+
const [stored, setStored] = useStore(quickFilterStore, null);
|
|
71
|
+
const [initial] = useState(() =>
|
|
72
|
+
enabled && isRestorable(stored, groupField) && !findQuickFilter(filter) ? stored.values : null,
|
|
73
|
+
);
|
|
74
|
+
const phaseRef = useRef<'restoring' | 'validating' | 'done'>(initial ? 'restoring' : 'done');
|
|
75
|
+
const searchedRef = useRef(false);
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!initial) return;
|
|
79
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- the filter state belongs to the product's `useSearch` and starts empty on every mount
|
|
80
|
+
setFilter((current) => withQuickFilter(current, { field: groupField, values: initial }));
|
|
81
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- applies only to the initial state
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!enabled) return;
|
|
86
|
+
const quickFilter = findQuickFilter(filter);
|
|
87
|
+
// The commit that starts the restore still sees the empty initial filter.
|
|
88
|
+
if (phaseRef.current === 'restoring') {
|
|
89
|
+
if (!quickFilter) return;
|
|
90
|
+
phaseRef.current = 'validating';
|
|
91
|
+
}
|
|
92
|
+
if (phaseRef.current === 'validating' && initial) {
|
|
93
|
+
if (isSearchLoading) searchedRef.current = true;
|
|
94
|
+
const settled = searchedRef.current && !isSearchLoading && !searchError && !query.trim();
|
|
95
|
+
const { present, values: known, counted } = groupFacetValues(facets, groupField);
|
|
96
|
+
if ((known.length && !counted) || (settled && present)) {
|
|
97
|
+
phaseRef.current = 'done';
|
|
98
|
+
const values = quickFilter?.values.filter(
|
|
99
|
+
(value) => known.includes(value) || !initial.includes(value),
|
|
100
|
+
);
|
|
101
|
+
if (quickFilter && values && values.length !== quickFilter.values.length) {
|
|
102
|
+
// oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- the facets arrive after the restore
|
|
103
|
+
setFilter((current) => withQuickFilter(current, { field: groupField, values }));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const next = quickFilter ? { field: quickFilter.field, values: quickFilter.values } : null;
|
|
109
|
+
if (JSON.stringify(next) !== JSON.stringify(stored)) {
|
|
110
|
+
setStored(next);
|
|
111
|
+
}
|
|
112
|
+
}, [
|
|
113
|
+
enabled,
|
|
114
|
+
filter,
|
|
115
|
+
facets,
|
|
116
|
+
groupField,
|
|
117
|
+
query,
|
|
118
|
+
isSearchLoading,
|
|
119
|
+
searchError,
|
|
120
|
+
initial,
|
|
121
|
+
stored,
|
|
122
|
+
setFilter,
|
|
123
|
+
setStored,
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SearchAiActivityStatus, SearchAiActivityStep, ToolCall } from '../../types/search';
|
|
2
|
+
|
|
3
|
+
import { useThemeHooks } from '../use-theme-hooks';
|
|
4
|
+
import { getSearchAiActivityStatus, getSearchAiActivityStep } from '../../utils/search-ai-activity';
|
|
5
|
+
|
|
6
|
+
type UseSearchAiActivityParams = {
|
|
7
|
+
toolCalls: ToolCall[];
|
|
8
|
+
isActive: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type UseSearchAiActivityReturn = {
|
|
12
|
+
status: SearchAiActivityStatus;
|
|
13
|
+
steps: SearchAiActivityStep[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function useSearchAiActivity({
|
|
17
|
+
toolCalls,
|
|
18
|
+
isActive,
|
|
19
|
+
}: UseSearchAiActivityParams): UseSearchAiActivityReturn {
|
|
20
|
+
const { useTranslate } = useThemeHooks();
|
|
21
|
+
const { translate } = useTranslate();
|
|
22
|
+
|
|
23
|
+
const runningToolCall = isActive ? toolCalls.find((toolCall) => !toolCall.result) : undefined;
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
status: getSearchAiActivityStatus(toolCalls, isActive, runningToolCall, translate),
|
|
27
|
+
steps: toolCalls.map((toolCall) =>
|
|
28
|
+
getSearchAiActivityStep(toolCall, isActive && !toolCall.result, translate),
|
|
29
|
+
),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -7,7 +7,12 @@ import { useThemeHooks } from './use-theme-hooks';
|
|
|
7
7
|
import { useMCPConfig } from './use-mcp-config';
|
|
8
8
|
import { ClipboardService } from '../utils/clipboard-service';
|
|
9
9
|
import { DEFAULT_MCP_OPTIONS } from '../constants/mcp';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
generateClaudeCodeCommand,
|
|
12
|
+
generateCodexCommand,
|
|
13
|
+
generateMCPDeepLink,
|
|
14
|
+
isMCPOption,
|
|
15
|
+
} from '../utils/mcp';
|
|
11
16
|
import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
|
|
12
17
|
|
|
13
18
|
export type McpButtonOptions = {
|
|
@@ -68,6 +73,7 @@ export function useConnectMCPButton({
|
|
|
68
73
|
const urlMap: Partial<Record<MCPOption, string>> = {
|
|
69
74
|
cursor: cursorUrl,
|
|
70
75
|
vscode: vscodeUrl,
|
|
76
|
+
claude: generateMCPDeepLink('claude', connection),
|
|
71
77
|
};
|
|
72
78
|
|
|
73
79
|
window.open(urlMap[action], '_blank');
|
|
@@ -80,7 +86,12 @@ export function useConnectMCPButton({
|
|
|
80
86
|
[translate],
|
|
81
87
|
);
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
// Markdoc reports attribute errors but still renders the tag, so `options` can be any value.
|
|
90
|
+
const visibleOptions = useMemo(
|
|
91
|
+
() =>
|
|
92
|
+
Array.isArray(options) ? [...new Set(options.filter(isMCPOption))] : [...DEFAULT_MCP_OPTIONS],
|
|
93
|
+
[options],
|
|
94
|
+
);
|
|
84
95
|
|
|
85
96
|
return {
|
|
86
97
|
copiedOption,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
import type { ConsentCategory, ConsentCategoryId, UseConsentResult } from '../types/consent';
|
|
5
|
+
|
|
6
|
+
import { CONSENT_CATEGORIES } from '../constants/consent';
|
|
7
|
+
import { useFocusTrap } from './use-focus-trap';
|
|
8
|
+
|
|
9
|
+
export type ConsentDraft = Record<Exclude<ConsentCategoryId, 'necessary'>, boolean>;
|
|
10
|
+
|
|
11
|
+
export type UseConsentDialogResult = {
|
|
12
|
+
draft: ConsentDraft;
|
|
13
|
+
setCategory: (id: keyof ConsentDraft, value: boolean) => void;
|
|
14
|
+
dialogRef: RefObject<HTMLDivElement | null>;
|
|
15
|
+
close: () => void;
|
|
16
|
+
save: () => void;
|
|
17
|
+
categories: readonly ConsentCategory[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function useConsentDialog(consent: UseConsentResult): UseConsentDialogResult {
|
|
21
|
+
const [draft, setDraft] = useState<ConsentDraft>(() => ({
|
|
22
|
+
analytics: consent.state?.analytics ?? consent.mode === 'opt-out',
|
|
23
|
+
marketing: (consent.state?.marketing ?? consent.mode === 'opt-out') && !consent.gpc,
|
|
24
|
+
}));
|
|
25
|
+
const dialogRef = useRef<HTMLDivElement | null>(null);
|
|
26
|
+
const close = consent.closeDialog;
|
|
27
|
+
const closeRef = useRef(close);
|
|
28
|
+
closeRef.current = close;
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const previous = document.activeElement as HTMLElement | null;
|
|
32
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
33
|
+
if (event.key === 'Escape') closeRef.current();
|
|
34
|
+
};
|
|
35
|
+
document.addEventListener('keydown', onKeyDown);
|
|
36
|
+
return () => {
|
|
37
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
38
|
+
previous?.focus?.();
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
useFocusTrap(dialogRef);
|
|
43
|
+
|
|
44
|
+
const setCategory = (id: keyof ConsentDraft, value: boolean) => {
|
|
45
|
+
setDraft((current) => ({ ...current, [id]: value }));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const save = () => consent.save(draft);
|
|
49
|
+
|
|
50
|
+
return { draft, setCategory, dialogRef, close, save, categories: CONSENT_CATEGORIES };
|
|
51
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ConsentRuntime } from '../types/consent';
|
|
4
|
+
|
|
5
|
+
import { useThemeHooks } from './use-theme-hooks';
|
|
6
|
+
import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
|
|
7
|
+
|
|
8
|
+
type RealmOwnedRuntime = ConsentRuntime & {
|
|
9
|
+
mode: 'opt-in' | 'opt-out';
|
|
10
|
+
configuredMode: 'auto' | 'opt-in' | 'opt-out';
|
|
11
|
+
region: { source: 'timezone' | 'config' | 'none'; timeZone: string | null };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function isRealmOwned(runtime: ConsentRuntime): runtime is RealmOwnedRuntime {
|
|
15
|
+
return runtime.region.source !== 'provider';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getConsentRuntime(): ConsentRuntime | undefined {
|
|
19
|
+
if (typeof window === 'undefined') return undefined;
|
|
20
|
+
return (window as Window & { redocly?: { consent?: ConsentRuntime } }).redocly?.consent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Sends one consent.changed event per visitor choice in the modes Realm owns.
|
|
24
|
+
export function useConsentTelemetry(): void {
|
|
25
|
+
const { useTelemetry } = useThemeHooks();
|
|
26
|
+
const telemetry = useTelemetry();
|
|
27
|
+
const telemetryRef = useRef(telemetry);
|
|
28
|
+
telemetryRef.current = telemetry;
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const found = getConsentRuntime();
|
|
32
|
+
const runtime = found && isRealmOwned(found) ? found : null;
|
|
33
|
+
if (!runtime) return;
|
|
34
|
+
return runtime.on('change', (state) => {
|
|
35
|
+
const choice =
|
|
36
|
+
state.analytics && state.marketing
|
|
37
|
+
? 'accept'
|
|
38
|
+
: !state.analytics && !state.marketing
|
|
39
|
+
? 'reject'
|
|
40
|
+
: 'partial';
|
|
41
|
+
const { origin, pathname, search, hash } = window.location;
|
|
42
|
+
const uri = `${origin}${pathname}${search}${hash}`;
|
|
43
|
+
telemetryRef.current.sendConsentChangedMessage([
|
|
44
|
+
{
|
|
45
|
+
...getBaseDataAttributes('consent', 'consent'),
|
|
46
|
+
choice,
|
|
47
|
+
mode: runtime.mode,
|
|
48
|
+
configuredMode: runtime.configuredMode,
|
|
49
|
+
regionSource: runtime.region.source,
|
|
50
|
+
gpc: runtime.gpc,
|
|
51
|
+
},
|
|
52
|
+
getBaseDataAttributes(uri, 'page', uri),
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
}
|
|
@@ -21,12 +21,18 @@ export function useDialogHotKeys(ref: RefObject<HTMLElement | null>, onClose: ()
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const onFocusableElementsHandler = () => {
|
|
24
|
-
const focusableElements =
|
|
25
|
-
|
|
24
|
+
const focusableElements = Array.from(
|
|
25
|
+
ref.current?.querySelectorAll<HTMLElement>(
|
|
26
|
+
'input, textarea, select, button, [href], [tabindex]:not([tabindex="-1"])',
|
|
27
|
+
) ?? [],
|
|
28
|
+
).filter(
|
|
29
|
+
(element) =>
|
|
30
|
+
!element.hasAttribute('disabled') &&
|
|
31
|
+
(typeof element.checkVisibility !== 'function' || element.checkVisibility()),
|
|
26
32
|
);
|
|
27
|
-
if (focusableElements
|
|
28
|
-
firstFocusableRef.current = focusableElements[0]
|
|
29
|
-
lastFocusableRef.current = focusableElements[focusableElements.length - 1]
|
|
33
|
+
if (focusableElements.length > 0) {
|
|
34
|
+
firstFocusableRef.current = focusableElements[0];
|
|
35
|
+
lastFocusableRef.current = focusableElements[focusableElements.length - 1];
|
|
30
36
|
}
|
|
31
37
|
};
|
|
32
38
|
|
|
@@ -3,9 +3,9 @@ import throttle from 'lodash.throttle';
|
|
|
3
3
|
|
|
4
4
|
import type { RefObject } from 'react';
|
|
5
5
|
|
|
6
|
-
export function useFullHeight(
|
|
6
|
+
export function useFullHeight(elementRef: RefObject<HTMLElement | null>): void {
|
|
7
7
|
const handler = useCallback(() => {
|
|
8
|
-
if (!
|
|
8
|
+
if (!elementRef.current) {
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -14,19 +14,19 @@ export function useFullHeight(element: RefObject<HTMLElement | null>): void {
|
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const elementTop =
|
|
17
|
+
const elementTop = elementRef.current.getBoundingClientRect().top;
|
|
18
18
|
const footerOffset = footer.offsetTop - window.scrollY - elementTop;
|
|
19
19
|
if (footerOffset > window.innerHeight) {
|
|
20
|
-
|
|
20
|
+
elementRef.current.style.maxHeight = `${window.innerHeight - elementTop}px`;
|
|
21
21
|
} else {
|
|
22
|
-
|
|
22
|
+
elementRef.current.style.maxHeight = `${footerOffset}px`;
|
|
23
23
|
}
|
|
24
|
-
}, [
|
|
24
|
+
}, [elementRef]);
|
|
25
25
|
|
|
26
26
|
const throttledHandler = useMemo(() => throttle(handler, 150), [handler]);
|
|
27
27
|
|
|
28
28
|
useEffect(() => {
|
|
29
|
-
if (typeof window === 'undefined' || !
|
|
29
|
+
if (typeof window === 'undefined' || !elementRef.current) {
|
|
30
30
|
return () => {
|
|
31
31
|
// nope
|
|
32
32
|
};
|
|
@@ -45,5 +45,5 @@ export function useFullHeight(element: RefObject<HTMLElement | null>): void {
|
|
|
45
45
|
window.removeEventListener('scroll', throttledHandler);
|
|
46
46
|
window.removeEventListener('resize', throttledHandler);
|
|
47
47
|
};
|
|
48
|
-
}, [throttledHandler,
|
|
48
|
+
}, [throttledHandler, elementRef, handler]);
|
|
49
49
|
}
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
withoutPathPrefix,
|
|
24
24
|
} from '../utils/urls';
|
|
25
25
|
import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
|
|
26
|
+
import { getAiPromptLink } from '../utils/get-ai-prompt-link';
|
|
26
27
|
|
|
27
28
|
const DEFAULT_ENABLED_ACTIONS = [
|
|
28
29
|
'copy',
|
|
@@ -31,6 +32,7 @@ const DEFAULT_ENABLED_ACTIONS = [
|
|
|
31
32
|
'claude',
|
|
32
33
|
'docs-mcp-cursor',
|
|
33
34
|
'docs-mcp-vscode',
|
|
35
|
+
'docs-mcp-claude',
|
|
34
36
|
] as const;
|
|
35
37
|
|
|
36
38
|
export type PageActionType =
|
|
@@ -40,6 +42,7 @@ export type PageActionType =
|
|
|
40
42
|
| 'claude'
|
|
41
43
|
| 'docs-mcp-cursor'
|
|
42
44
|
| 'docs-mcp-vscode'
|
|
45
|
+
| 'docs-mcp-claude'
|
|
43
46
|
// Used in OpenAPI docs x-mcp
|
|
44
47
|
| 'mcp-cursor'
|
|
45
48
|
| 'mcp-vscode';
|
|
@@ -110,10 +113,12 @@ export function usePageActions(
|
|
|
110
113
|
const mdPageUrl = isRoot
|
|
111
114
|
? combineUrls(origin, pathname, 'index.html.md')
|
|
112
115
|
: combineUrls(origin, removeTrailingSlash(pathname) + '.md');
|
|
116
|
+
const externalAiPrompt = `Read ${mdPageUrl} and answer questions based on the content.`;
|
|
113
117
|
|
|
114
118
|
const actionHandlers: Record<PageActionType, () => PageAction> = {
|
|
115
119
|
'docs-mcp-cursor': createMCPHandler('cursor', false),
|
|
116
120
|
'docs-mcp-vscode': createMCPHandler('vscode', false),
|
|
121
|
+
'docs-mcp-claude': createMCPHandler('claude', false),
|
|
117
122
|
'mcp-cursor': createMCPHandler('cursor', true),
|
|
118
123
|
'mcp-vscode': createMCPHandler('vscode', true),
|
|
119
124
|
|
|
@@ -159,7 +164,7 @@ export function usePageActions(
|
|
|
159
164
|
}),
|
|
160
165
|
|
|
161
166
|
chatgpt: () => {
|
|
162
|
-
const link =
|
|
167
|
+
const link = getAiPromptLink('chatgpt', externalAiPrompt);
|
|
163
168
|
return {
|
|
164
169
|
buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
|
|
165
170
|
title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
|
|
@@ -179,7 +184,7 @@ export function usePageActions(
|
|
|
179
184
|
},
|
|
180
185
|
|
|
181
186
|
claude: () => {
|
|
182
|
-
const link =
|
|
187
|
+
const link = getAiPromptLink('claude', externalAiPrompt);
|
|
183
188
|
return {
|
|
184
189
|
buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
|
|
185
190
|
title: translate('page.actions.claudeTitle', 'Open in Claude'),
|
|
@@ -220,13 +225,6 @@ export function usePageActions(
|
|
|
220
225
|
return result;
|
|
221
226
|
}
|
|
222
227
|
|
|
223
|
-
function getExternalAiPromptLink(baseUrl: string, mdPageUrl: string): string {
|
|
224
|
-
const externalAiPrompt = `Read ${mdPageUrl} and answer questions based on the content.`;
|
|
225
|
-
const url = new URL(baseUrl);
|
|
226
|
-
url.searchParams.set('q', externalAiPrompt);
|
|
227
|
-
return url.toString();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
228
|
type CreateMCPActionParams = {
|
|
231
229
|
clientType: MCPClientType;
|
|
232
230
|
mcpConfig: McpConnectionParams;
|
|
@@ -261,6 +259,19 @@ function createMCPAction({
|
|
|
261
259
|
};
|
|
262
260
|
}
|
|
263
261
|
|
|
262
|
+
if (clientType === 'claude') {
|
|
263
|
+
return {
|
|
264
|
+
...sharedProps,
|
|
265
|
+
buttonText: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
|
|
266
|
+
title: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
|
|
267
|
+
description: translate(
|
|
268
|
+
'page.actions.connectMcp.claudeDescription',
|
|
269
|
+
'Add MCP server to your Claude account',
|
|
270
|
+
),
|
|
271
|
+
iconComponent: ClaudeIcon,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
264
275
|
return {
|
|
265
276
|
...sharedProps,
|
|
266
277
|
buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'),
|
|
@@ -337,6 +348,7 @@ function shouldHideActionByType(
|
|
|
337
348
|
return !isPublic;
|
|
338
349
|
case 'docs-mcp-cursor':
|
|
339
350
|
case 'docs-mcp-vscode':
|
|
351
|
+
case 'docs-mcp-claude':
|
|
340
352
|
return Boolean(mcpUrl) || isMcpDisabled;
|
|
341
353
|
case 'mcp-cursor':
|
|
342
354
|
case 'mcp-vscode':
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { PointerEvent, RefObject } from 'react';
|
|
4
|
+
|
|
5
|
+
const EDGE_PROXIMITY_DISTANCE = 80;
|
|
6
|
+
|
|
7
|
+
export type PointerBorderHighlight<T extends HTMLElement> = {
|
|
8
|
+
ref: RefObject<T | null>;
|
|
9
|
+
onPointerMove: (event: PointerEvent<T>) => void;
|
|
10
|
+
onPointerLeave: () => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/* Writes `--pointer-x`, `--pointer-y` and `--pointer-edge-proximity` (1 at the border, 0 at
|
|
14
|
+
`distance` px inside) to the element's inline style, so the highlight moves without re-renders. */
|
|
15
|
+
export function usePointerBorderHighlight<T extends HTMLElement>(
|
|
16
|
+
distance = EDGE_PROXIMITY_DISTANCE,
|
|
17
|
+
): PointerBorderHighlight<T> {
|
|
18
|
+
const ref = useRef<T | null>(null);
|
|
19
|
+
|
|
20
|
+
const onPointerMove = useCallback(
|
|
21
|
+
(event: PointerEvent<T>) => {
|
|
22
|
+
const element = ref.current;
|
|
23
|
+
if (!element) return;
|
|
24
|
+
|
|
25
|
+
const rect = element.getBoundingClientRect();
|
|
26
|
+
const x = event.clientX - rect.left;
|
|
27
|
+
const y = event.clientY - rect.top;
|
|
28
|
+
const edgeDistance = Math.min(x, y, rect.width - x, rect.height - y);
|
|
29
|
+
const proximity = Math.min(1, Math.max(0, 1 - edgeDistance / distance));
|
|
30
|
+
|
|
31
|
+
element.style.setProperty('--pointer-x', `${x}px`);
|
|
32
|
+
element.style.setProperty('--pointer-y', `${y}px`);
|
|
33
|
+
element.style.setProperty(
|
|
34
|
+
'--pointer-edge-proximity',
|
|
35
|
+
String(Math.round(proximity * 100) / 100),
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
[distance],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const onPointerLeave = useCallback(() => {
|
|
42
|
+
ref.current?.style.setProperty('--pointer-edge-proximity', '0');
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
return { ref, onPointerMove, onPointerLeave };
|
|
46
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
|
|
5
|
+
export function useScrollItemIntoView(
|
|
6
|
+
listRef: RefObject<HTMLElement | null>,
|
|
7
|
+
activeIndex: number,
|
|
8
|
+
): void {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const list = listRef.current;
|
|
11
|
+
const activeItem = activeIndex === -1 ? undefined : list?.children[activeIndex];
|
|
12
|
+
if (!list || !activeItem) return;
|
|
13
|
+
|
|
14
|
+
const listRect = list.getBoundingClientRect();
|
|
15
|
+
const itemRect = activeItem.getBoundingClientRect();
|
|
16
|
+
list.scrollLeft += itemRect.left - listRect.left - (listRect.width - itemRect.width) / 2;
|
|
17
|
+
}, [listRef, activeIndex]);
|
|
18
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useCallback, useId, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { KeyboardEvent } from 'react';
|
|
4
|
+
|
|
5
|
+
type UseTabListProps = {
|
|
6
|
+
count: number;
|
|
7
|
+
activeIndex: number;
|
|
8
|
+
onChange: (index: number) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Props for a WAI-ARIA tab list with automatic activation: only the active tab is a tab stop,
|
|
13
|
+
* and Left/Right/Home/End select and focus another tab.
|
|
14
|
+
*/
|
|
15
|
+
export function useTabList({ count, activeIndex, onChange }: UseTabListProps) {
|
|
16
|
+
const idPrefix = useId();
|
|
17
|
+
const focusableIndex = activeIndex >= 0 ? activeIndex : 0;
|
|
18
|
+
const tabRefs = useRef<(HTMLElement | null)[]>([]);
|
|
19
|
+
|
|
20
|
+
const select = useCallback(
|
|
21
|
+
(index: number) => {
|
|
22
|
+
onChange(index);
|
|
23
|
+
tabRefs.current[index]?.focus();
|
|
24
|
+
},
|
|
25
|
+
[onChange],
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const onKeyDown = useCallback(
|
|
29
|
+
(event: KeyboardEvent, index: number) => {
|
|
30
|
+
const target = (<Record<string, number>>{
|
|
31
|
+
ArrowRight: (index + 1) % count,
|
|
32
|
+
ArrowLeft: (index - 1 + count) % count,
|
|
33
|
+
Home: 0,
|
|
34
|
+
End: count - 1,
|
|
35
|
+
})[event.key];
|
|
36
|
+
if (target === undefined) return;
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
select(target);
|
|
39
|
+
},
|
|
40
|
+
[count, select],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const getTabProps = (index: number) => ({
|
|
44
|
+
id: `${idPrefix}-tab-${index}`,
|
|
45
|
+
role: 'tab',
|
|
46
|
+
'aria-selected': index === activeIndex,
|
|
47
|
+
'aria-controls': `${idPrefix}-panel-${index}`,
|
|
48
|
+
tabIndex: index === focusableIndex ? 0 : -1,
|
|
49
|
+
ref: (element: HTMLElement | null) => {
|
|
50
|
+
tabRefs.current[index] = element;
|
|
51
|
+
},
|
|
52
|
+
onClick: () => select(index),
|
|
53
|
+
onKeyDown: (event: KeyboardEvent) => onKeyDown(event, index),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const getTabPanelProps = (index: number) => ({
|
|
57
|
+
id: `${idPrefix}-panel-${index}`,
|
|
58
|
+
role: 'tabpanel',
|
|
59
|
+
'aria-labelledby': `${idPrefix}-tab-${index}`,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return { tabListProps: { role: 'tablist' }, getTabProps, getTabPanelProps };
|
|
63
|
+
}
|
|
@@ -38,6 +38,8 @@ export const useTelemetryFallback = () => ({
|
|
|
38
38
|
sendCodeSnippetReportedMessage: () => {},
|
|
39
39
|
sendConnectMcpClickedMessage: () => {},
|
|
40
40
|
sendMcpConnectionSnippetCopiedMessage: () => {},
|
|
41
|
+
sendPromptTagCopiedMessage: () => {},
|
|
42
|
+
sendPromptTagOpenedMessage: () => {},
|
|
41
43
|
sendMobileMenuClosedMessage: () => {},
|
|
42
44
|
sendMobileMenuOpenedMessage: () => {},
|
|
43
45
|
sendPageViewedMessage: () => {},
|