@redocly/theme 0.69.0-next.8 → 0.69.0

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.
Files changed (81) hide show
  1. package/lib/components/Accordion/Accordion.js +5 -1
  2. package/lib/components/Catalog/CatalogEntities.js +1 -0
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +5 -3
  4. package/lib/components/Catalog/CatalogViewModeToggle.d.ts +1 -1
  5. package/lib/components/Catalog/CatalogViewModeToggle.js +2 -43
  6. package/lib/components/Filter/FilterInput.js +4 -2
  7. package/lib/components/JsonViewer/Helpers.js +12 -42
  8. package/lib/components/MCP/McpConnectionTabs.js +21 -11
  9. package/lib/components/Markdown/Markdown.js +1 -3
  10. package/lib/components/Markdown/styles/base-table.js +8 -0
  11. package/lib/components/Markdown/variables.js +1 -2
  12. package/lib/components/Panel/Panel.js +5 -1
  13. package/lib/components/Search/FilterFields/SearchFilterFieldSelect.js +22 -32
  14. package/lib/components/Search/SearchAiDialog.js +3 -0
  15. package/lib/components/Search/SearchItem.js +5 -3
  16. package/lib/components/Search/variables.js +1 -0
  17. package/lib/components/Select/Select.js +10 -5
  18. package/lib/components/Sidebar/Sidebar.js +2 -38
  19. package/lib/core/contexts/AccordionGroupContext.d.ts +1 -0
  20. package/lib/core/contexts/AccordionGroupContext.js +6 -0
  21. package/lib/core/contexts/PageActionsContext.d.ts +5 -0
  22. package/lib/core/contexts/PageActionsContext.js +10 -0
  23. package/lib/core/contexts/index.d.ts +2 -0
  24. package/lib/core/contexts/index.js +2 -0
  25. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +5 -17
  26. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.js +2 -0
  27. package/lib/core/hooks/menu/use-menu-item-expanded.js +1 -0
  28. package/lib/core/hooks/use-active-heading.js +4 -0
  29. package/lib/core/hooks/use-connect-mcp-button.js +7 -2
  30. package/lib/core/hooks/use-local-state.js +1 -0
  31. package/lib/core/hooks/use-mobile-menu.js +10 -2
  32. package/lib/core/hooks/use-product-picker.js +1 -1
  33. package/lib/core/hooks/use-tabs.js +4 -2
  34. package/lib/core/hooks/use-telemetry-fallback.d.ts +2 -0
  35. package/lib/core/hooks/use-telemetry-fallback.js +2 -0
  36. package/lib/core/styles/global.js +1 -0
  37. package/lib/core/utils/class-names.d.ts +1 -0
  38. package/lib/core/utils/class-names.js +7 -0
  39. package/lib/markdoc/components/Accordion/Accordion.js +6 -6
  40. package/lib/markdoc/components/Accordion/AccordionGroup.d.ts +2 -1
  41. package/lib/markdoc/components/Accordion/AccordionGroup.js +39 -3
  42. package/lib/markdoc/components/Heading/Heading.js +5 -2
  43. package/lib/markdoc/tags/accordion-group.js +3 -0
  44. package/package.json +2 -2
  45. package/src/components/Accordion/Accordion.tsx +7 -3
  46. package/src/components/Catalog/CatalogEntities.tsx +1 -0
  47. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.tsx +6 -4
  48. package/src/components/Catalog/CatalogViewModeToggle.tsx +2 -17
  49. package/src/components/Filter/FilterInput.tsx +5 -3
  50. package/src/components/JsonViewer/Helpers.tsx +13 -9
  51. package/src/components/MCP/McpConnectionTabs.tsx +32 -10
  52. package/src/components/Markdown/Markdown.tsx +1 -3
  53. package/src/components/Markdown/styles/base-table.ts +8 -0
  54. package/src/components/Markdown/variables.ts +1 -2
  55. package/src/components/Panel/Panel.tsx +7 -3
  56. package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +32 -40
  57. package/src/components/Search/SearchAiDialog.tsx +3 -0
  58. package/src/components/Search/SearchItem.tsx +6 -1
  59. package/src/components/Search/variables.ts +1 -0
  60. package/src/components/Select/Select.tsx +12 -6
  61. package/src/components/Sidebar/Sidebar.tsx +2 -6
  62. package/src/core/contexts/AccordionGroupContext.tsx +3 -0
  63. package/src/core/contexts/PageActionsContext.tsx +7 -0
  64. package/src/core/contexts/index.ts +2 -0
  65. package/src/core/hooks/__mocks__/use-theme-hooks.ts +2 -0
  66. package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +6 -20
  67. package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +2 -0
  68. package/src/core/hooks/menu/use-menu-item-expanded.ts +1 -0
  69. package/src/core/hooks/use-active-heading.ts +4 -0
  70. package/src/core/hooks/use-connect-mcp-button.ts +8 -2
  71. package/src/core/hooks/use-local-state.ts +1 -0
  72. package/src/core/hooks/use-mobile-menu.ts +11 -3
  73. package/src/core/hooks/use-product-picker.ts +2 -2
  74. package/src/core/hooks/use-tabs.ts +4 -2
  75. package/src/core/hooks/use-telemetry-fallback.ts +2 -0
  76. package/src/core/styles/global.ts +1 -0
  77. package/src/core/utils/class-names.ts +8 -0
  78. package/src/markdoc/components/Accordion/Accordion.tsx +8 -2
  79. package/src/markdoc/components/Accordion/AccordionGroup.tsx +9 -2
  80. package/src/markdoc/components/Heading/Heading.tsx +7 -4
  81. package/src/markdoc/tags/accordion-group.ts +3 -0
@@ -47,6 +47,11 @@ const ChevronRightIcon_1 = require("../../icons/ChevronRightIcon/ChevronRightIco
47
47
  function Accordion({ expanded = true, isExpandable = true, renderChildrenHidden = false, header, className, children, onToggle, dataTestId, }) {
48
48
  const [isExpanded, setExpanded] = (0, react_1.useState)(expanded);
49
49
  const [animate, setAnimate] = (0, react_1.useState)(false);
50
+ const [prevExpanded, setPrevExpanded] = (0, react_1.useState)(expanded);
51
+ if (prevExpanded !== expanded) {
52
+ setPrevExpanded(expanded);
53
+ setExpanded(expanded);
54
+ }
50
55
  const toggle = ({ target }) => {
51
56
  if (target instanceof HTMLAnchorElement || !isExpandable)
52
57
  return;
@@ -54,7 +59,6 @@ function Accordion({ expanded = true, isExpandable = true, renderChildrenHidden
54
59
  setExpanded(!isExpanded);
55
60
  onToggle === null || onToggle === void 0 ? void 0 : onToggle(!isExpanded);
56
61
  };
57
- (0, react_1.useEffect)(() => setExpanded(expanded), [expanded]);
58
62
  return (react_1.default.createElement(AccordionWrapper, { className: className, "data-testid": dataTestId, "data-component-name": "Accordion/Accordion" },
59
63
  header &&
60
64
  (typeof header === 'function' ? (header({ expanded: isExpanded })) : (react_1.default.createElement(AccordionHeader_1.AccordionHeader, { "data-testid": "accordion-header", onClick: toggle, expanded: isExpanded, isExpandable: isExpandable },
@@ -70,6 +70,7 @@ function CatalogEntities(props) {
70
70
  const shouldShowLoadMore = query.hasNextPage ||
71
71
  (query.isPlaceholderData && entities && entities.length >= LOAD_MORE_THRESHOLD);
72
72
  (0, react_1.useEffect)(() => {
73
+ // oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- the entities query lives in this ejectable component; the fetched total is mirrored up so the portal page header can show the count
73
74
  setEntitiesCounter(total || 0);
74
75
  }, [total, setEntitiesCounter]);
75
76
  if (!query.isPending && (!entities || entities.length === 0)) {
@@ -48,9 +48,11 @@ function CatalogEntityRelations({ entity, entitiesCatalogConfig, initialRelation
48
48
  const { useCatalogSort, useFetchCatalogEntitiesRelations } = (0, hooks_1.useThemeHooks)();
49
49
  const { sortOption, setSortOption, handleSortClick, isColumnSorted } = useCatalogSort();
50
50
  const [filter, setFilter] = (0, react_1.useState)(ENTITY_DEFAULT_FILTERS[entity.type]);
51
- (0, react_1.useEffect)(() => {
52
- setFilter(ENTITY_DEFAULT_FILTERS[entity.key]);
53
- }, [entity.key]);
51
+ const [prevEntityKey, setPrevEntityKey] = (0, react_1.useState)(entity.key);
52
+ if (prevEntityKey !== entity.key) {
53
+ setPrevEntityKey(entity.key);
54
+ setFilter(ENTITY_DEFAULT_FILTERS[entity.type]);
55
+ }
54
56
  const combinedFilter = (0, react_1.useMemo)(() => {
55
57
  const baseFilter = filter !== null && filter !== void 0 ? filter : ENTITY_DEFAULT_FILTERS[entity.type];
56
58
  if (entity.version && entity.revision) {
@@ -4,4 +4,4 @@ export type CatalogViewModeToggleProps = {
4
4
  viewMode: CatalogViewMode;
5
5
  onViewModeChange: (mode: CatalogViewMode) => void;
6
6
  };
7
- export declare function CatalogViewModeToggle({ viewMode: initialViewMode, onViewModeChange, }: CatalogViewModeToggleProps): React.JSX.Element;
7
+ export declare function CatalogViewModeToggle({ viewMode, onViewModeChange }: CatalogViewModeToggleProps): React.JSX.Element;
@@ -1,55 +1,14 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
38
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.CatalogViewModeToggle = CatalogViewModeToggle;
40
- const react_1 = __importStar(require("react"));
7
+ const react_1 = __importDefault(require("react"));
41
8
  const styled_components_1 = __importDefault(require("styled-components"));
42
9
  const TableIcon_1 = require("../../icons/TableIcon/TableIcon");
43
10
  const CardsIcon_1 = require("../../icons/CardsIcon/CardsIcon");
44
- function useViewMode(initialViewMode) {
45
- const [viewMode, setViewMode] = (0, react_1.useState)(null);
46
- (0, react_1.useEffect)(() => {
47
- setViewMode(initialViewMode);
48
- }, [initialViewMode]);
49
- return viewMode;
50
- }
51
- function CatalogViewModeToggle({ viewMode: initialViewMode, onViewModeChange, }) {
52
- const viewMode = useViewMode(initialViewMode);
11
+ function CatalogViewModeToggle({ viewMode, onViewModeChange }) {
53
12
  return (react_1.default.createElement(ViewModeToggleWrapper, { "data-component-name": "Catalog/CatalogViewModeToggle" },
54
13
  react_1.default.createElement(ViewModeButton, { className: viewMode === 'table' ? 'active' : '', onClick: () => onViewModeChange('table') },
55
14
  react_1.default.createElement(TableIcon_1.TableIcon, { size: "var(--catalog-view-mode-table-icon-size)" })),
@@ -44,9 +44,11 @@ const SearchIcon_1 = require("../../icons/SearchIcon/SearchIcon");
44
44
  function FilterInput(props) {
45
45
  const { value: initialValue, onChange, dataTestId } = props;
46
46
  const [value, setValue] = (0, react_1.useState)(initialValue);
47
- (0, react_1.useEffect)(() => {
47
+ const [prevInitialValue, setPrevInitialValue] = (0, react_1.useState)(initialValue);
48
+ if (prevInitialValue !== initialValue) {
49
+ setPrevInitialValue(initialValue);
48
50
  setValue(initialValue);
49
- }, [initialValue]);
51
+ }
50
52
  const handleChange = (e) => {
51
53
  const newValue = e.target.value;
52
54
  setValue(newValue);
@@ -1,43 +1,10 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
38
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.JsonValue = JsonValue;
40
- const react_1 = __importStar(require("react"));
7
+ const react_1 = __importDefault(require("react"));
41
8
  const styled_components_1 = __importDefault(require("styled-components"));
42
9
  const Button_1 = require("../../components/Button/Button");
43
10
  const ShowMoreToggleButton_1 = require("../../components/Button/ShowMoreToggleButton");
@@ -47,14 +14,15 @@ function JsonValue(props) {
47
14
  const indent = ' '.repeat(level * 2);
48
15
  const [isExpandedState, setExpanded] = react_1.default.useState(expandAllSignal !== null && expandAllSignal !== void 0 ? expandAllSignal : level < defaultExpandLevel);
49
16
  const isExpanded = expandAllSignal !== undefined && level > 0 ? expandAllSignal : isExpandedState;
50
- (0, react_1.useEffect)(() => {
51
- if (expandAllSignal !== undefined) {
52
- if (expandAllSignal === false && level === 0) {
53
- return;
54
- }
17
+ const [prevExpandAllSignal, setPrevExpandAllSignal] = react_1.default.useState(expandAllSignal);
18
+ const [prevLevel, setPrevLevel] = react_1.default.useState(level);
19
+ if (prevExpandAllSignal !== expandAllSignal || prevLevel !== level) {
20
+ setPrevExpandAllSignal(expandAllSignal);
21
+ setPrevLevel(level);
22
+ if (expandAllSignal !== undefined && !(expandAllSignal === false && level === 0)) {
55
23
  setExpanded(expandAllSignal);
56
24
  }
57
- }, [expandAllSignal, level]);
25
+ }
58
26
  const keys = (value && Object.keys(value).filter((key) => value[key] !== undefined)) || []; // filter out undefined properties
59
27
  const valueType = typeof value;
60
28
  const isPrimitive = (valueType !== 'object' && value !== null) || keys.length === 0;
@@ -94,11 +62,13 @@ function JsonKeyValue(props) {
94
62
  const isCollapsible = typeof value === 'object' && value !== null && keys.length > 0;
95
63
  const [isExpandedState, setExpanded] = react_1.default.useState(expandAllSignal !== null && expandAllSignal !== void 0 ? expandAllSignal : level < defaultExpandLevel);
96
64
  const isExpanded = expandAllSignal !== undefined ? expandAllSignal : isExpandedState;
97
- (0, react_1.useEffect)(() => {
65
+ const [prevExpandAllSignal, setPrevExpandAllSignal] = react_1.default.useState(expandAllSignal);
66
+ if (prevExpandAllSignal !== expandAllSignal) {
67
+ setPrevExpandAllSignal(expandAllSignal);
98
68
  if (expandAllSignal !== undefined) {
99
69
  setExpanded(expandAllSignal);
100
70
  }
101
- }, [expandAllSignal]);
71
+ }
102
72
  const openingPunctuation = Array.isArray(value) ? '[' : '{';
103
73
  const closingPunctuation = Array.isArray(value) ? ']' : '}';
104
74
  const valueElement = isCollapsible ? (react_1.default.createElement(react_1.default.Fragment, null,
@@ -62,11 +62,10 @@ const TAB_LABELS = {
62
62
  },
63
63
  json: { translationKey: 'page.mcpNotAllowed.tabs.json', defaultLabel: 'JSON' },
64
64
  };
65
- // The report control is docs feedback, not useful on the connection page.
66
- const CODE_BLOCK_HEADER = { controls: { copy: {}, report: { hidden: true } } };
67
65
  function McpConnectionTabs({ options = DEFAULT_TAB_OPTIONS, className, }) {
68
- const { useTranslate } = (0, hooks_1.useThemeHooks)();
66
+ const { useTranslate, useTelemetry } = (0, hooks_1.useThemeHooks)();
69
67
  const { translate } = useTranslate();
68
+ const telemetry = useTelemetry();
70
69
  const { serverName, serverUrl, isMcpDisabled } = (0, hooks_1.useMCPConfig)();
71
70
  // The SSR markup of error pages is cached with the build-time origin, so the
72
71
  // tabs remount after hydration to pick up the real browser origin.
@@ -76,20 +75,31 @@ function McpConnectionTabs({ options = DEFAULT_TAB_OPTIONS, className, }) {
76
75
  return null;
77
76
  }
78
77
  const connection = { serverName, url: serverUrl };
78
+ const snippetHeader = (client, snippet) => ({
79
+ controls: {
80
+ copy: {
81
+ onClick: () => telemetry.sendMcpConnectionSnippetCopiedMessage([
82
+ Object.assign(Object.assign({}, (0, utils_1.getBaseDataAttributes)('mcpConnectionSnippet', 'button')), { client, snippet }),
83
+ ]),
84
+ },
85
+ // The report control is docs feedback, not useful on the connection page.
86
+ report: { hidden: true },
87
+ },
88
+ });
79
89
  return (react_1.default.createElement(McpConnectionTabsWrapper, { key: hydrated ? 'client' : 'ssr', "data-component-name": "MCP/McpConnectionTabs", "data-testid": "mcp-connection-tabs", className: className },
80
90
  react_1.default.createElement(Tabs_1.Tabs, { size: Tabs_1.TabsSize.SMALL }, options.map((option) => {
81
91
  const { translationKey, defaultLabel, icon: TabIcon } = TAB_LABELS[option];
82
- return (react_1.default.createElement(TabItemFragment_1.TabItemFragment, { key: option, label: translate(translationKey, defaultLabel), icon: TabIcon ? react_1.default.createElement(TabIcon, null) : undefined }, renderTabContent(option, connection, translate)));
92
+ return (react_1.default.createElement(TabItemFragment_1.TabItemFragment, { key: option, label: translate(translationKey, defaultLabel), icon: TabIcon ? react_1.default.createElement(TabIcon, null) : undefined }, renderTabContent(option, connection, translate, snippetHeader)));
83
93
  }))));
84
94
  }
85
- function renderTabContent(option, connection, translate) {
95
+ function renderTabContent(option, connection, translate, snippetHeader) {
86
96
  const terminalHint = (react_1.default.createElement(TabHint, null, translate('page.mcpNotAllowed.snippets.terminal.hint', 'Run this command in your terminal:')));
87
- const urlBlock = react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "text", source: connection.url, header: CODE_BLOCK_HEADER });
97
+ const urlBlock = (react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "text", source: connection.url, header: snippetHeader(option, 'chatgpt-app') }));
88
98
  const assistantPromptClient = {
89
99
  headline: translate('page.mcpNotAllowed.snippets.prompt.headline', 'Prompt'),
90
100
  content: (react_1.default.createElement(react_1.default.Fragment, null,
91
101
  react_1.default.createElement(TabHint, null, translate('page.mcpNotAllowed.snippets.prompt.hint', 'Or paste this prompt into the chat to have it add the server for you:')),
92
- react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "text", source: (0, utils_1.generateMcpInstallPrompt)(connection), header: CODE_BLOCK_HEADER, wrapContents: true }))),
102
+ react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "text", source: (0, utils_1.generateMcpInstallPrompt)(connection), header: snippetHeader(option, 'prompt'), wrapContents: true }))),
93
103
  };
94
104
  switch (option) {
95
105
  case 'claude':
@@ -98,13 +108,13 @@ function renderTabContent(option, connection, translate) {
98
108
  headline: translate('page.mcpNotAllowed.snippets.claudeCode.headline', 'Claude Code'),
99
109
  content: (react_1.default.createElement(react_1.default.Fragment, null,
100
110
  terminalHint,
101
- react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "shell", source: (0, utils_1.generateClaudeCodeCommand)(connection), header: CODE_BLOCK_HEADER, wrapContents: true }))),
111
+ react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "shell", source: (0, utils_1.generateClaudeCodeCommand)(connection), header: snippetHeader(option, 'claude-code'), wrapContents: true }))),
102
112
  },
103
113
  {
104
114
  headline: translate('page.mcpNotAllowed.snippets.claudeDesktop.headline', 'Claude Desktop'),
105
115
  content: (react_1.default.createElement(react_1.default.Fragment, null,
106
116
  react_1.default.createElement(TabHint, null, translate('page.mcpNotAllowed.snippets.claudeDesktop.instruction', 'In Claude Desktop, open Settings → Developer → Edit Config, add this to the configuration file, and restart Claude Desktop:')),
107
- react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "json", source: (0, utils_1.generateClaudeDesktopConfig)(connection), header: CODE_BLOCK_HEADER }))),
117
+ react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "json", source: (0, utils_1.generateClaudeDesktopConfig)(connection), header: snippetHeader(option, 'claude-desktop') }))),
108
118
  },
109
119
  ]);
110
120
  case 'chatgpt':
@@ -113,7 +123,7 @@ function renderTabContent(option, connection, translate) {
113
123
  headline: translate('page.mcpNotAllowed.snippets.codexCli.headline', 'Codex CLI'),
114
124
  content: (react_1.default.createElement(react_1.default.Fragment, null,
115
125
  terminalHint,
116
- react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "shell", source: (0, utils_1.generateCodexCommand)(connection), header: CODE_BLOCK_HEADER, wrapContents: true }))),
126
+ react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "shell", source: (0, utils_1.generateCodexCommand)(connection), header: snippetHeader(option, 'codex'), wrapContents: true }))),
117
127
  },
118
128
  {
119
129
  headline: translate('page.mcpNotAllowed.snippets.chatgptApp.headline', 'ChatGPT desktop app'),
@@ -126,7 +136,7 @@ function renderTabContent(option, connection, translate) {
126
136
  case 'json':
127
137
  return (react_1.default.createElement(react_1.default.Fragment, null,
128
138
  react_1.default.createElement(TabHint, null, translate('page.mcpNotAllowed.snippets.json.hint', 'Add this server entry to your MCP client configuration file:')),
129
- react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "json", source: JSON.stringify({ [connection.serverName]: { url: connection.url, description: 'MCP Server' } }, null, 2), header: CODE_BLOCK_HEADER })));
139
+ react_1.default.createElement(CodeBlock_1.CodeBlock, { lang: "json", source: JSON.stringify({ [connection.serverName]: { url: connection.url, description: 'MCP Server' } }, null, 2), header: snippetHeader(option, 'json') })));
130
140
  }
131
141
  }
132
142
  function renderClientList(clients) {
@@ -178,10 +178,8 @@ exports.Markdown = styled_components_1.default.main
178
178
  }
179
179
 
180
180
  hr {
181
- border-top: 1px solid var(--md-hr-border-color);
182
- background-color: var(--md-hr-bg-color);
183
- height: var(--md-hr-height);
184
181
  margin: var(--md-hr-margin-vertical) 0;
182
+ border: var(--md-hr-border);
185
183
  }
186
184
 
187
185
  details:not(${constants_1.ACCORDION_SELECTOR}) {
@@ -46,6 +46,14 @@ exports.markdownBaseTableCss = (0, styled_components_1.css) `
46
46
  background-color: var(--md-table-header-bg-color);
47
47
  }
48
48
 
49
+ /* hide the header row when every cell is empty; one labelled cell keeps it visible */
50
+ thead:has(th:empty) {
51
+ display: none;
52
+ }
53
+ thead:has(th:not(:empty)) {
54
+ display: table-header-group;
55
+ }
56
+
49
57
  tr {
50
58
  background-color: var(--md-table-stripe-bg-color);
51
59
  }
@@ -62,9 +62,8 @@ exports.markdown = (0, styled_components_1.css) `
62
62
  * @tokens Markdown Horizontal Rule
63
63
  */
64
64
 
65
- --md-hr-bg-color: transparent; // @presenter Color
66
65
  --md-hr-border-color: var(--border-color-secondary); // @presenter Color
67
- --md-hr-height: unset;
66
+ --md-hr-border: 0.5px solid var(--md-hr-border-color); // @presenter Border
68
67
  --md-hr-margin-vertical: 20px; // @presenter Spacing
69
68
 
70
69
  /**
@@ -47,6 +47,11 @@ const ChevronRightIcon_1 = require("../../icons/ChevronRightIcon/ChevronRightIco
47
47
  function Panel({ expanded = true, isExpandable = true, renderChildrenHidden = false, header, footer, className = 'panel-default', children, onToggle, description, }) {
48
48
  const [isExpanded, setExpanded] = (0, react_1.useState)(expanded);
49
49
  const [animate, setAnimate] = (0, react_1.useState)(false);
50
+ const [prevExpanded, setPrevExpanded] = (0, react_1.useState)(expanded);
51
+ if (prevExpanded !== expanded) {
52
+ setPrevExpanded(expanded);
53
+ setExpanded(expanded);
54
+ }
50
55
  const toggle = ({ target }) => {
51
56
  if (target instanceof HTMLAnchorElement || !isExpandable)
52
57
  return;
@@ -54,7 +59,6 @@ function Panel({ expanded = true, isExpandable = true, renderChildrenHidden = fa
54
59
  setExpanded(!isExpanded);
55
60
  onToggle === null || onToggle === void 0 ? void 0 : onToggle(!isExpanded);
56
61
  };
57
- (0, react_1.useEffect)(() => setExpanded(expanded), [expanded]);
58
62
  return (react_1.default.createElement(PanelWrapper, { className: className, "data-testid": typeof header === 'string' ? ('panel-' + header).replace(/ /g, '-').toLowerCase() : null, "data-component-name": "Panel/Panel" },
59
63
  header &&
60
64
  (typeof header === 'function' ? (header({ expanded: isExpanded, toggle })) : (react_1.default.createElement(PanelHeader_1.PanelHeader, { "data-testid": "panel-header", toggle: toggle, expanded: isExpanded, isExpandable: isExpandable },
@@ -47,13 +47,7 @@ function SearchFilterFieldSelect({ facet, filter, query, selectedValues, onChang
47
47
  const { useFacetQuery, useTranslate } = (0, hooks_1.useThemeHooks)();
48
48
  const { translate } = useTranslate();
49
49
  const { searchFacet, setSearchFacet, setSearchFacetQuery } = useFacetQuery(facet.field);
50
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
51
- const [selectOptions, setSelectOptions] = (0, react_1.useState)([]);
52
50
  const isMultiple = facet.type === 'multi-select';
53
- (0, react_1.useEffect)(() => {
54
- setSelectOptions(getSelectOptions());
55
- // eslint-disable-next-line react-hooks/exhaustive-deps
56
- }, [searchFacet, facet]);
57
51
  const onSearch = (value) => {
58
52
  if (value === null) {
59
53
  setSearchFacet(null);
@@ -67,38 +61,34 @@ function SearchFilterFieldSelect({ facet, filter, query, selectedValues, onChang
67
61
  });
68
62
  }
69
63
  };
70
- const getSelectOptions = () => {
71
- return searchFacet
72
- ? searchFacet.values.map(facetValueToSelectOption)
73
- : facet.values.map(facetValueToSelectOption);
74
- };
75
- const facetValueToSelectOption = (facetValue) => {
76
- if (!facetValue) {
77
- return { element: null, value: '' };
78
- }
79
- if (typeof facetValue === 'string') {
80
- return {
81
- element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
82
- react_1.default.createElement(FilterSelectOptionText, null, facetValue))),
83
- value: facetValue,
84
- };
85
- }
86
- else {
87
- const { value, count, isCounterVisible } = facetValue;
88
- return {
89
- element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
90
- react_1.default.createElement(FilterSelectOptionText, null, value),
91
- isCounterVisible && react_1.default.createElement(CounterTag_1.CounterTag, null, count))),
92
- value: value,
93
- };
94
- }
95
- };
64
+ const selectOptions = (0, react_1.useMemo)(() => (searchFacet ? searchFacet.values : facet.values).map(facetValueToSelectOption), [searchFacet, facet]);
96
65
  return (react_1.default.createElement(Select_1.Select, { value: selectedValues.length
97
66
  ? isMultiple
98
67
  ? selectedValues.map((value) => facetValueToSelectOption(value))
99
68
  : facetValueToSelectOption(selectedValues[0])
100
69
  : undefined, options: selectOptions, onChange: onChange, placeholder: `${translate('search.filter.field.placeholder', 'Search')} ${facet.name.toLowerCase()}...`, alignment: "start", multiple: isMultiple, searchable: true, footer: selectOptions.length === MAX_SELECT_OPTIONS ? (react_1.default.createElement(FilterSelectFooter, null, translate('search.filter.field.footer', 'Search to show more items...'))) : null, onSearch: onSearch, checkmarkIconPosition: "start" }));
101
70
  }
71
+ function facetValueToSelectOption(facetValue) {
72
+ if (!facetValue) {
73
+ return { element: null, value: '' };
74
+ }
75
+ if (typeof facetValue === 'string') {
76
+ return {
77
+ element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
78
+ react_1.default.createElement(FilterSelectOptionText, null, facetValue))),
79
+ value: facetValue,
80
+ };
81
+ }
82
+ else {
83
+ const { value, count, isCounterVisible } = facetValue;
84
+ return {
85
+ element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
86
+ react_1.default.createElement(FilterSelectOptionText, null, value),
87
+ isCounterVisible && react_1.default.createElement(CounterTag_1.CounterTag, null, count))),
88
+ value: value,
89
+ };
90
+ }
91
+ }
102
92
  const FilterSelectOptionWrapper = styled_components_1.default.div `
103
93
  width: 100%;
104
94
  display: flex;
@@ -80,6 +80,7 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
80
80
  if (!(initialMessage === null || initialMessage === void 0 ? void 0 : initialMessage.trim().length)) {
81
81
  return;
82
82
  }
83
+ // oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- appends the initial message into the conversation state lifted to the search root once the dialog mounts
83
84
  setConversation((prev) => [
84
85
  ...prev,
85
86
  { role: constants_1.AiSearchConversationRole.USER, content: initialMessage },
@@ -89,6 +90,7 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
89
90
  if (response === undefined || conversation.length === 0 || error) {
90
91
  return;
91
92
  }
93
+ // oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- merges the streamed assistant response into the lifted conversation state as chunks arrive
92
94
  setConversation((prev) => {
93
95
  const lastMessage = prev[prev.length - 1];
94
96
  const content = response || '';
@@ -127,6 +129,7 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
127
129
  ]);
128
130
  (0, react_1.useEffect)(() => {
129
131
  if (error) {
132
+ // oxlint-disable-next-line react-you-might-not-need-an-effect/no-pass-data-to-parent -- drops the pending message from the lifted conversation state once the request errors
130
133
  setConversation((prev) => prev.slice(0, -1));
131
134
  }
132
135
  }, [error, setConversation]);
@@ -48,7 +48,7 @@ const utils_1 = require("../../core/utils");
48
48
  const ReturnKeyIcon_1 = require("../../icons/ReturnKeyIcon/ReturnKeyIcon");
49
49
  const hooks_1 = require("../../core/hooks");
50
50
  function SearchItem({ onClick, item, className, product, innerRef, }) {
51
- var _a, _b, _c, _d;
51
+ var _a, _b, _c;
52
52
  const ref = (0, react_1.useRef)(null);
53
53
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
54
54
  const { translate } = useTranslate();
@@ -95,11 +95,13 @@ function SearchItem({ onClick, item, className, product, innerRef, }) {
95
95
  react_1.default.createElement("div", null,
96
96
  (0, SearchHighlight_1.searchHighlight)(parameter.place),
97
97
  ` → `,
98
- ((_b = parameter.path) === null || _b === void 0 ? void 0 : _b.length) ? (0, SearchHighlight_1.searchHighlight)((_c = parameter.path) === null || _c === void 0 ? void 0 : _c.join(' → ')) + ' → ' : '',
98
+ ((_b = parameter.path) === null || _b === void 0 ? void 0 : _b.length) ? (react_1.default.createElement(react_1.default.Fragment, null,
99
+ (0, SearchHighlight_1.searchHighlight)(parameter.path.join(' → ')),
100
+ ` → `)) : null,
99
101
  (0, SearchHighlight_1.searchHighlight)(parameter.name)),
100
102
  react_1.default.createElement("div", null, (0, SearchHighlight_1.searchHighlight)(parameter.description)))) : (shouldShowPath && (react_1.default.createElement(SearchItemPath, null, highlight.path && highlight.path.length
101
103
  ? (0, SearchHighlight_1.searchHighlight)(highlight.path.join(' → '))
102
- : (_d = document.path) === null || _d === void 0 ? void 0 : _d.join(' → '))))),
104
+ : (_c = document.path) === null || _c === void 0 ? void 0 : _c.join(' → '))))),
103
105
  react_1.default.createElement(ReturnKeyIcon_1.ReturnKeyIcon, { color: "var(--search-item-text-color)" })));
104
106
  }
105
107
  const SearchItemWrapper = (0, styled_components_1.default)(Link_1.Link) `
@@ -98,6 +98,7 @@ exports.search = (0, styled_components_1.css) `
98
98
  --search-message-line-height: var(--line-height-lg); // @presenter LineHeight
99
99
  --search-message-text-color: var(--text-color-secondary); // @presenter Color
100
100
  --search-message-gap: var(--spacing-md);
101
+ --search-message-padding: var(--spacing-md);
101
102
 
102
103
  --search-header-buttons-gap: var(--spacing-sm);
103
104
  --search-header-buttons-padding-left: var(--spacing-sm);
@@ -71,13 +71,18 @@ function Select(props) {
71
71
  (0, hooks_1.useOutsideClick)(selectRef, () => {
72
72
  setDropdownActive(false);
73
73
  });
74
- (0, react_1.useEffect)(() => {
74
+ const [prevOptions, setPrevOptions] = (0, react_1.useState)(options);
75
+ const [prevValue, setPrevValue] = (0, react_1.useState)(value);
76
+ const [prevMultiple, setPrevMultiple] = (0, react_1.useState)(multiple);
77
+ if (prevOptions !== options) {
78
+ setPrevOptions(options);
75
79
  setFilteredOptions(options);
76
- }, [options]);
77
- (0, react_1.useEffect)(() => {
80
+ }
81
+ if (prevValue !== value || prevMultiple !== multiple) {
82
+ setPrevValue(value);
83
+ setPrevMultiple(multiple);
78
84
  setSelectedOptions(getSelectedOptionsFromPropsValue());
79
- // eslint-disable-next-line react-hooks/exhaustive-deps
80
- }, [multiple, value]);
85
+ }
81
86
  const changeSearchValue = (newSearchValue) => {
82
87
  if (newSearchValue === searchValue) {
83
88
  return;
@@ -1,54 +1,18 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
38
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.SidebarHeader = void 0;
40
7
  exports.Sidebar = Sidebar;
41
- const react_1 = __importStar(require("react"));
8
+ const react_1 = __importDefault(require("react"));
42
9
  const styled_components_1 = __importDefault(require("styled-components"));
43
10
  const utils_1 = require("../../core/utils");
44
11
  const hooks_1 = require("../../core/hooks");
45
12
  const MenuContainer_1 = require("../../components/Menu/MenuContainer");
46
13
  function Sidebar({ versions, menu, footer, header, growContent, collapsed, className, menuItemsAnimation, }) {
47
14
  const { isOpen } = (0, hooks_1.useMobileMenu)();
48
- const [mappedCollapsed, setMappedCollapsed] = react_1.default.useState(collapsed);
49
- (0, react_1.useEffect)(() => {
50
- setMappedCollapsed(collapsed && !isOpen);
51
- }, [isOpen, collapsed, setMappedCollapsed]);
15
+ const mappedCollapsed = collapsed && !isOpen;
52
16
  const { sidebar } = (0, hooks_1.useThemeConfig)();
53
17
  if (sidebar === null || sidebar === void 0 ? void 0 : sidebar.hide) {
54
18
  return null;
@@ -0,0 +1 @@
1
+ export declare const AccordionGroupContext: import("react").Context<string | null>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccordionGroupContext = void 0;
4
+ const react_1 = require("react");
5
+ exports.AccordionGroupContext = (0, react_1.createContext)(null);
6
+ //# sourceMappingURL=AccordionGroupContext.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Whether the first heading inside the enclosing `Markdown` mounts the page actions.
3
+ * Without a provider `Heading` falls back to the page type in the page metadata.
4
+ */
5
+ export declare const PageActionsContext: import("react").Context<boolean | null>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PageActionsContext = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Whether the first heading inside the enclosing `Markdown` mounts the page actions.
7
+ * Without a provider `Heading` falls back to the page type in the page metadata.
8
+ */
9
+ exports.PageActionsContext = (0, react_1.createContext)(null);
10
+ //# sourceMappingURL=PageActionsContext.js.map
@@ -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';
@@ -16,8 +16,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./ThemeDataContext"), exports);
18
18
  __exportStar(require("./MarkdownLinkContext"), exports);
19
+ __exportStar(require("./PageActionsContext"), exports);
19
20
  __exportStar(require("./CodeWalkthrough/CodeWalkthroughControlsContext"), exports);
20
21
  __exportStar(require("./CodeWalkthrough/CodeWalkthroughStepsContext"), exports);
22
+ __exportStar(require("./AccordionGroupContext"), exports);
21
23
  __exportStar(require("./CodeSnippetContext"), exports);
22
24
  __exportStar(require("./SearchContext"), exports);
23
25
  __exportStar(require("./Toast/ToastContext"), exports);