@redocly/theme 0.68.0-next.4 → 0.68.0-next.6

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 (66) hide show
  1. package/lib/components/Button/ShowMoreToggleButton.d.ts +11 -0
  2. package/lib/components/Button/ShowMoreToggleButton.js +21 -0
  3. package/lib/components/CodeBlock/CodeBlock.d.ts +7 -1
  4. package/lib/components/CodeBlock/CodeBlock.js +30 -7
  5. package/lib/components/Dropdown/Dropdown.d.ts +2 -0
  6. package/lib/components/Dropdown/Dropdown.js +59 -14
  7. package/lib/components/Dropdown/variables.js +3 -1
  8. package/lib/components/Feedback/Feedback.js +1 -3
  9. package/lib/components/Feedback/Stars.js +1 -1
  10. package/lib/components/Footer/FooterItem.js +1 -1
  11. package/lib/components/JsonViewer/Helpers.d.ts +1 -0
  12. package/lib/components/JsonViewer/Helpers.js +20 -7
  13. package/lib/components/JsonViewer/JsonViewer.d.ts +2 -0
  14. package/lib/components/JsonViewer/JsonViewer.js +2 -2
  15. package/lib/components/LanguagePicker/LanguagePicker.js +3 -2
  16. package/lib/components/Markdown/Markdown.js +13 -6
  17. package/lib/components/Markdown/styles/links.d.ts +1 -0
  18. package/lib/components/Markdown/styles/links.js +19 -16
  19. package/lib/components/Menu/MenuItem.d.ts +7 -1
  20. package/lib/components/Menu/MenuItem.js +43 -2
  21. package/lib/components/Navbar/NavbarItem.js +8 -3
  22. package/lib/components/PageActions/PageActions.js +1 -4
  23. package/lib/components/Panel/variables.js +1 -0
  24. package/lib/components/ReplayGate/ReplayGate.d.ts +12 -0
  25. package/lib/components/ReplayGate/ReplayGate.js +11 -0
  26. package/lib/components/ReplayTopBarActions/ReplayTopBarActions.d.ts +13 -0
  27. package/lib/components/ReplayTopBarActions/ReplayTopBarActions.js +7 -0
  28. package/lib/components/Search/SearchDialog.js +4 -4
  29. package/lib/core/hooks/use-active-section-id.d.ts +2 -0
  30. package/lib/core/hooks/use-active-section-id.js +11 -1
  31. package/lib/core/hooks/use-page-actions.js +10 -9
  32. package/lib/core/hooks/use-theme-hooks.js +1 -0
  33. package/lib/core/openapi/index.d.ts +1 -1
  34. package/lib/core/openapi/index.js +2 -1
  35. package/lib/core/styles/global.js +8 -0
  36. package/lib/core/types/hooks.d.ts +1 -0
  37. package/lib/core/types/l10n.d.ts +1 -1
  38. package/lib/layouts/ThreePanelLayout.d.ts +5 -2
  39. package/package.json +3 -3
  40. package/src/components/Button/ShowMoreToggleButton.tsx +33 -0
  41. package/src/components/CodeBlock/CodeBlock.tsx +56 -12
  42. package/src/components/Dropdown/Dropdown.tsx +93 -21
  43. package/src/components/Dropdown/variables.ts +3 -1
  44. package/src/components/Feedback/Feedback.tsx +1 -3
  45. package/src/components/Feedback/Stars.tsx +1 -0
  46. package/src/components/Footer/FooterItem.tsx +3 -0
  47. package/src/components/JsonViewer/Helpers.tsx +41 -3
  48. package/src/components/JsonViewer/JsonViewer.tsx +4 -0
  49. package/src/components/LanguagePicker/LanguagePicker.tsx +3 -1
  50. package/src/components/Markdown/Markdown.tsx +13 -6
  51. package/src/components/Markdown/styles/links.ts +19 -15
  52. package/src/components/Menu/MenuItem.tsx +47 -2
  53. package/src/components/Navbar/NavbarItem.tsx +10 -4
  54. package/src/components/PageActions/PageActions.tsx +3 -6
  55. package/src/components/Panel/variables.ts +1 -0
  56. package/src/components/ReplayGate/ReplayGate.tsx +18 -0
  57. package/src/components/ReplayTopBarActions/ReplayTopBarActions.tsx +14 -0
  58. package/src/components/Search/SearchDialog.tsx +4 -4
  59. package/src/core/hooks/use-active-section-id.ts +13 -1
  60. package/src/core/hooks/use-page-actions.ts +13 -11
  61. package/src/core/hooks/use-theme-hooks.ts +1 -0
  62. package/src/core/openapi/index.ts +1 -1
  63. package/src/core/styles/global.ts +8 -0
  64. package/src/core/types/hooks.ts +1 -0
  65. package/src/core/types/l10n.ts +39 -1
  66. package/src/layouts/ThreePanelLayout.tsx +1 -0
@@ -0,0 +1,11 @@
1
+ import type { JSX } from 'react';
2
+ export type ShowMoreToggleButtonProps = {
3
+ isExpanded: boolean;
4
+ onToggle: () => void;
5
+ className?: string;
6
+ };
7
+ /**
8
+ * "Show more" / "Show less" toggle used by truncated-value renderers
9
+ * (JsonViewer oversized strings, CodeBlock `maxDisplayLength`).
10
+ */
11
+ export declare function ShowMoreToggleButton({ isExpanded, onToggle, className, }: ShowMoreToggleButtonProps): JSX.Element;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ShowMoreToggleButton = ShowMoreToggleButton;
7
+ const react_1 = __importDefault(require("react"));
8
+ const hooks_1 = require("../../core/hooks");
9
+ const Button_1 = require("../../components/Button/Button");
10
+ /**
11
+ * "Show more" / "Show less" toggle used by truncated-value renderers
12
+ * (JsonViewer oversized strings, CodeBlock `maxDisplayLength`).
13
+ */
14
+ function ShowMoreToggleButton({ isExpanded, onToggle, className, }) {
15
+ const { useTranslate } = (0, hooks_1.useThemeHooks)();
16
+ const { translate } = useTranslate();
17
+ return (react_1.default.createElement(Button_1.Button, { className: className, size: "small", variant: "link", onClick: onToggle }, isExpanded
18
+ ? translate('jsonViewer.showLess', 'Show less')
19
+ : translate('jsonViewer.showMore', 'Show more')));
20
+ }
21
+ //# sourceMappingURL=ShowMoreToggleButton.js.map
@@ -13,6 +13,12 @@ export type CodeBlockProps = {
13
13
  withLineNumbers?: boolean;
14
14
  startLineNumber?: number;
15
15
  highlightedHtml?: string;
16
+ /**
17
+ * Display at most this many characters of `source`, with a "Show more" toggle for the rest.
18
+ * Copy and report controls always receive the full source. Ignored when `highlightedHtml`
19
+ * or `children` are provided.
20
+ */
21
+ maxDisplayLength?: number;
16
22
  skipHighlight?: boolean;
17
23
  codeBlockRef?: (instance: HTMLPreElement | null) => void;
18
24
  codeBlockMaxHeight?: string;
@@ -41,5 +47,5 @@ type ExternalSource = {
41
47
  properties?: any;
42
48
  operation?: any;
43
49
  };
44
- export declare function CodeBlock({ lang, source, externalSource, header, dataTestId, codeBlockRef, highlightedHtml, withLineNumbers, startLineNumber, className, codeBlockMaxHeight, tabs, dropdown, hideCodeColors, wrapContents, children, ...rest }: React.PropsWithChildren<CodeBlockProps>): JSX.Element;
50
+ export declare function CodeBlock({ lang, source, externalSource, header, dataTestId, codeBlockRef, highlightedHtml, maxDisplayLength, withLineNumbers, startLineNumber, className, codeBlockMaxHeight, tabs, dropdown, hideCodeColors, wrapContents, children, ...rest }: React.PropsWithChildren<CodeBlockProps>): JSX.Element;
45
51
  export {};
@@ -55,24 +55,42 @@ const hooks_1 = require("../../core/hooks");
55
55
  const ReportDialog_1 = require("../../components/Feedback/ReportDialog");
56
56
  const CodeBlockContainer_1 = require("../../components/CodeBlock/CodeBlockContainer");
57
57
  const CodeBlockControls_1 = require("../../components/CodeBlock/CodeBlockControls");
58
+ const ShowMoreToggleButton_1 = require("../../components/Button/ShowMoreToggleButton");
58
59
  function CodeBlock(_a) {
59
60
  var _b, _c, _d, _e, _f;
60
61
  var _g;
61
- var { lang, source, externalSource, header, dataTestId = 'source-code', codeBlockRef, highlightedHtml, withLineNumbers, startLineNumber, className, codeBlockMaxHeight, tabs, dropdown, hideCodeColors, wrapContents = false, children } = _a, rest = __rest(_a, ["lang", "source", "externalSource", "header", "dataTestId", "codeBlockRef", "highlightedHtml", "withLineNumbers", "startLineNumber", "className", "codeBlockMaxHeight", "tabs", "dropdown", "hideCodeColors", "wrapContents", "children"]);
62
+ var { lang, source, externalSource, header, dataTestId = 'source-code', codeBlockRef, highlightedHtml, maxDisplayLength, withLineNumbers, startLineNumber, className, codeBlockMaxHeight, tabs, dropdown, hideCodeColors, wrapContents = false, children } = _a, rest = __rest(_a, ["lang", "source", "externalSource", "header", "dataTestId", "codeBlockRef", "highlightedHtml", "maxDisplayLength", "withLineNumbers", "startLineNumber", "className", "codeBlockMaxHeight", "tabs", "dropdown", "hideCodeColors", "wrapContents", "children"]);
62
63
  const [sourceCode, setSourceCode] = (0, react_1.useState)((_g = (source || ((_c = (_b = externalSource === null || externalSource === void 0 ? void 0 : externalSource.sample) === null || _b === void 0 ? void 0 : _b.get) === null || _c === void 0 ? void 0 : _c.call(_b, externalSource)))) !== null && _g !== void 0 ? _g : '');
63
64
  const { useCodeHighlight } = (0, hooks_1.useThemeHooks)();
64
65
  const { highlight } = useCodeHighlight() || {};
65
- const highlightedCode = highlightedHtml
66
+ const dataHighlight = rest['data-highlight'];
67
+ const hasChildren = Boolean(children);
68
+ const [isSourceExpanded, setIsSourceExpanded] = (0, react_1.useState)(false);
69
+ const isTruncatable = maxDisplayLength !== undefined &&
70
+ sourceCode.length > maxDisplayLength &&
71
+ !highlightedHtml &&
72
+ !hasChildren;
73
+ const displayedSource = isTruncatable && !isSourceExpanded ? `${sourceCode.slice(0, maxDisplayLength)}…` : sourceCode;
74
+ const highlightedCode = (0, react_1.useMemo)(() => highlightedHtml
66
75
  ? withLineNumbers
67
76
  ? (0, utils_1.addLineNumbers)(highlightedHtml, startLineNumber)
68
77
  : highlightedHtml
69
- : children
78
+ : hasChildren
70
79
  ? null
71
- : highlight === null || highlight === void 0 ? void 0 : highlight(sourceCode, lang, {
80
+ : highlight === null || highlight === void 0 ? void 0 : highlight(displayedSource, lang, {
72
81
  withLineNumbers,
73
82
  startLineNumber,
74
- highlight: rest['data-highlight'],
75
- });
83
+ highlight: dataHighlight,
84
+ }), [
85
+ highlightedHtml,
86
+ withLineNumbers,
87
+ startLineNumber,
88
+ hasChildren,
89
+ highlight,
90
+ displayedSource,
91
+ lang,
92
+ dataHighlight,
93
+ ]);
76
94
  // The same initial value should be returned for ssr and frontend to avoid issues
77
95
  // Because we don't have session storage in ssr and can't get the security details there
78
96
  // Issue for more details https://github.com/Redocly/reference-docs/issues/888
@@ -97,8 +115,13 @@ function CodeBlock(_a) {
97
115
  /* eslint-disable-next-line no-warning-comments */
98
116
  suppressHydrationWarning // TODO: investigate issue
99
117
  : true, "data-testid": dataTestId, hideCodeColors: hideCodeColors, maxHeight: codeBlockMaxHeight, wrapContents: wrapContents, tabIndex: 0 }, children),
100
- reportDialog.visible && (react_1.default.createElement(ReportDialog_1.ReportDialog, Object.assign({}, reportDialog.props, { location: sourceCode, lang: lang }))))));
118
+ reportDialog.visible && (react_1.default.createElement(ReportDialog_1.ReportDialog, Object.assign({}, reportDialog.props, { location: sourceCode, lang: lang })))),
119
+ isTruncatable ? (react_1.default.createElement(TruncationToggleButton, { isExpanded: isSourceExpanded, onToggle: () => setIsSourceExpanded((expanded) => !expanded) })) : null));
101
120
  }
121
+ const TruncationToggleButton = (0, styled_components_1.default)(ShowMoreToggleButton_1.ShowMoreToggleButton) `
122
+ margin: 0 var(--spacing-sm) var(--spacing-xs);
123
+ user-select: none;
124
+ `;
102
125
  const ContainerWrapper = styled_components_1.default.div `
103
126
  display: grid; // prevents content to overstretch
104
127
  position: relative;
@@ -10,6 +10,7 @@ export type DropdownProps = PropsWithChildren<{
10
10
  dataAttributes?: Record<string, string>;
11
11
  className?: string;
12
12
  withArrow?: boolean;
13
+ portalled?: boolean;
13
14
  onClick?: (event: React.UIEvent) => void;
14
15
  onClose?: () => void;
15
16
  onOpen?: () => void;
@@ -24,6 +25,7 @@ export declare const Dropdown: React.ForwardRefExoticComponent<{
24
25
  dataAttributes?: Record<string, string>;
25
26
  className?: string;
26
27
  withArrow?: boolean;
28
+ portalled?: boolean;
27
29
  onClick?: (event: React.UIEvent) => void;
28
30
  onClose?: () => void;
29
31
  onOpen?: () => void;
@@ -32,19 +32,21 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.Dropdown = void 0;
40
37
  const react_1 = __importStar(require("react"));
41
- const styled_components_1 = __importDefault(require("styled-components"));
38
+ const react_dom_1 = require("react-dom");
39
+ const styled_components_1 = __importStar(require("styled-components"));
42
40
  const hooks_1 = require("../../core/hooks");
43
41
  const ChevronDownIcon_1 = require("../../icons/ChevronDownIcon/ChevronDownIcon");
44
42
  const ChevronUpIcon_1 = require("../../icons/ChevronUpIcon/ChevronUpIcon");
45
- exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigger, triggerEvent = 'click', closeOnClick = true, withArrow, dataAttributes, placement, alignment, onClick, onClose, onOpen, }, ref) => {
43
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? react_1.useLayoutEffect : react_1.useEffect;
44
+ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigger, triggerEvent = 'click', closeOnClick = true, withArrow, dataAttributes, placement, alignment, portalled = false, onClick, onClose, onOpen, }, ref) => {
46
45
  const dropdownRef = (0, react_1.useRef)(null);
46
+ const menuRef = (0, react_1.useRef)(null);
47
47
  const [isOpen, setIsOpen] = (0, hooks_1.useControlledState)(false, active);
48
+ const [menuStyle, setMenuStyle] = (0, react_1.useState)({});
49
+ const wrapperRef = ref || dropdownRef;
48
50
  const handleOpen = () => {
49
51
  setIsOpen(true);
50
52
  onOpen === null || onOpen === void 0 ? void 0 : onOpen();
@@ -71,12 +73,49 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
71
73
  handleToggle(event);
72
74
  }
73
75
  };
74
- (0, hooks_1.useOutsideClick)(ref || dropdownRef, handleClose);
76
+ const updateMenuPosition = (0, react_1.useCallback)(() => {
77
+ const wrapper = wrapperRef.current;
78
+ if (!wrapper)
79
+ return;
80
+ const rect = wrapper.getBoundingClientRect();
81
+ const style = { minWidth: rect.width };
82
+ if (placement === 'top') {
83
+ style.bottom = window.innerHeight - rect.top;
84
+ }
85
+ else {
86
+ style.top = rect.bottom;
87
+ }
88
+ if (alignment === 'end') {
89
+ style.right = window.innerWidth - rect.right;
90
+ }
91
+ else {
92
+ style.left = rect.left;
93
+ }
94
+ const zIndex = getComputedStyle(wrapper).getPropertyValue('--dropdown-menu-z-index').trim();
95
+ if (zIndex) {
96
+ style.zIndex = zIndex;
97
+ }
98
+ setMenuStyle(style);
99
+ }, [placement, alignment, wrapperRef]);
100
+ useIsomorphicLayoutEffect(() => {
101
+ if (!portalled || !isOpen)
102
+ return;
103
+ updateMenuPosition();
104
+ window.addEventListener('scroll', updateMenuPosition, true);
105
+ window.addEventListener('resize', updateMenuPosition);
106
+ return () => {
107
+ window.removeEventListener('scroll', updateMenuPosition, true);
108
+ window.removeEventListener('resize', updateMenuPosition);
109
+ };
110
+ }, [portalled, isOpen, updateMenuPosition]);
111
+ (0, hooks_1.useOutsideClick)(portalled ? [wrapperRef, menuRef] : wrapperRef, handleClose);
75
112
  const triggerChild = react_1.default.Children.only(trigger);
76
113
  const dropdownTrigger = (0, react_1.cloneElement)(triggerChild, Object.assign(Object.assign(Object.assign({ onClick: triggerEvent === 'click' ? handleToggle : undefined, icon: withArrow ? isOpen ? react_1.default.createElement(ChevronUpIcon_1.ChevronUpIcon, null) : react_1.default.createElement(ChevronDownIcon_1.ChevronDownIcon, null) : undefined }, (withArrow ? { iconPosition: 'right' } : {})), triggerChild.props), { onKeyDown: triggerEvent === 'click' ? handleKeyDown : undefined }));
77
- return (react_1.default.createElement(DropdownWrapper, Object.assign({ "data-component-name": "Dropdown/Dropdown", "data-testid": "dropdown" }, dataAttributes, { className: className, ref: ref || dropdownRef, onPointerEnter: triggerEvent === 'hover' ? handleOpen : undefined, onPointerLeave: triggerEvent === 'hover' ? handleClose : undefined, onClick: onClick }),
114
+ const menu = (react_1.default.createElement(ChildrenWrapper, { ref: menuRef, $placement: placement, $alignment: alignment, $isOpen: isOpen, $portalled: portalled, style: portalled ? menuStyle : undefined, onClick: closeOnClick ? handleChildClick : undefined }, children));
115
+ const portalledMenu = isOpen && typeof document !== 'undefined' ? (0, react_dom_1.createPortal)(menu, document.body) : null;
116
+ return (react_1.default.createElement(DropdownWrapper, Object.assign({ "data-component-name": "Dropdown/Dropdown", "data-testid": "dropdown" }, dataAttributes, { className: className, ref: wrapperRef, onPointerEnter: triggerEvent === 'hover' ? handleOpen : undefined, onPointerLeave: triggerEvent === 'hover' ? handleClose : undefined, onClick: onClick }),
78
117
  dropdownTrigger,
79
- react_1.default.createElement(ChildrenWrapper, { $placement: placement, $alignment: alignment, $isOpen: isOpen, onClick: closeOnClick ? handleChildClick : undefined }, children)));
118
+ portalled ? portalledMenu : menu));
80
119
  });
81
120
  const DropdownWrapper = styled_components_1.default.div `
82
121
  --button-gap: var(--spacing-xxs);
@@ -96,13 +135,19 @@ const DropdownWrapper = styled_components_1.default.div `
96
135
  `;
97
136
  const ChildrenWrapper = styled_components_1.default.div `
98
137
  padding-top: var(--dropdown-menu-padding-top);
99
- position: absolute;
100
- top: ${({ $placement }) => ($placement === 'top' ? 'auto' : '100%')};
101
- bottom: ${({ $placement }) => ($placement === 'top' ? '100%' : 'auto')};
102
- left: ${({ $alignment }) => ($alignment === 'start' ? '0' : 'auto')};
103
- right: ${({ $alignment }) => ($alignment === 'end' ? '0' : 'auto')};
104
138
  display: ${({ $isOpen }) => ($isOpen ? 'block' : 'none')};
105
-
106
139
  z-index: var(--dropdown-menu-z-index);
140
+
141
+ ${({ $portalled, $placement, $alignment }) => $portalled
142
+ ? (0, styled_components_1.css) `
143
+ position: fixed;
144
+ `
145
+ : (0, styled_components_1.css) `
146
+ position: absolute;
147
+ top: ${$placement === 'top' ? 'auto' : '100%'};
148
+ bottom: ${$placement === 'top' ? '100%' : 'auto'};
149
+ left: ${$alignment === 'start' ? '0' : 'auto'};
150
+ right: ${$alignment === 'end' ? '0' : 'auto'};
151
+ `}
107
152
  `;
108
153
  //# sourceMappingURL=Dropdown.js.map
@@ -10,7 +10,9 @@ exports.dropdown = (0, styled_components_1.css) `
10
10
  --dropdown-menu-font-weight: var(--font-weight-regular); // @presenter FontWeight
11
11
  --dropdown-menu-line-height: var(--line-height-base); // @presenter LineHeight
12
12
  --dropdown-menu-text-color: var(--text-color-secondary); // @presenter Color
13
- --dropdown-menu-z-index: var(--z-index-raised); // @presenter ZIndex
13
+ /* One below --z-index-raised (the sticky Navbar) so a portaled menu, which is
14
+ appended to <body> after the navbar, never paints over it on a z-index tie. */
15
+ --dropdown-menu-z-index: calc(var(--z-index-raised) - 1); // @presenter ZIndex
14
16
 
15
17
  --dropdown-menu-padding-top: var(--spacing-xxs);
16
18
  --dropdown-menu-min-width: 100px;
@@ -38,7 +38,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.Feedback = Feedback;
40
40
  const React = __importStar(require("react"));
41
- const react_router_dom_1 = require("react-router-dom");
42
41
  const styled_components_1 = __importDefault(require("styled-components"));
43
42
  const hooks_1 = require("../../core/hooks");
44
43
  const Rating_1 = require("../../components/Feedback/Rating");
@@ -60,7 +59,6 @@ function Feedback(props) {
60
59
  const { useSubmitFeedback, useTelemetry } = (0, hooks_1.useThemeHooks)();
61
60
  const { submitFeedback } = useSubmitFeedback();
62
61
  const telemetry = useTelemetry();
63
- const { pathname } = (0, react_router_dom_1.useLocation)();
64
62
  const { feedback: themeFeedbackConf } = (0, hooks_1.useThemeConfig)();
65
63
  const feedbackConf = Object.assign(Object.assign({}, themeFeedbackConf), { path: props === null || props === void 0 ? void 0 : props.path, type: (props === null || props === void 0 ? void 0 : props.type) || (themeFeedbackConf === null || themeFeedbackConf === void 0 ? void 0 : themeFeedbackConf.type) || constants_1.DEFAULT_FEEDBACK_TYPE, settings: (props === null || props === void 0 ? void 0 : props.settings) || (themeFeedbackConf === null || themeFeedbackConf === void 0 ? void 0 : themeFeedbackConf.settings) || {}, hide: (_a = props.hide) !== null && _a !== void 0 ? _a : themeFeedbackConf === null || themeFeedbackConf === void 0 ? void 0 : themeFeedbackConf.hide });
66
64
  if (feedbackConf.hide) {
@@ -80,7 +78,7 @@ function Feedback(props) {
80
78
  ]);
81
79
  } })));
82
80
  };
83
- return React.createElement(React.Fragment, { key: pathname }, renderFeedbackComponent());
81
+ return React.createElement(React.Fragment, { key: feedbackConf.path }, renderFeedbackComponent());
84
82
  }
85
83
  const FeedbackWrapper = styled_components_1.default.div `
86
84
  padding: var(--feedback-padding);
@@ -45,7 +45,7 @@ function Stars({ max = 5, onChange, value }) {
45
45
  const [hovered, setHovered] = React.useState(value || 0);
46
46
  const stars = [];
47
47
  for (let index = 1; index <= max; index++) {
48
- stars.push(React.createElement(Star, { "data-testid": `star-${index}`, key: index, onClick: () => onChange(index), onMouseOver: () => setHovered(index), onMouseLeave: () => !value && setHovered(0) }, hovered < index ? (React.createElement(StarIcon_1.StarIcon, { color: "var(--feedback-star-color)" })) : (React.createElement(StarFilledIcon_1.StarFilledIcon, { color: "var(--feedback-star-color)" }))));
48
+ stars.push(React.createElement(Star, { "data-testid": `star-${index}`, key: index, "aria-label": `${index} ${index === 1 ? 'star' : 'stars'}`, onClick: () => onChange(index), onMouseOver: () => setHovered(index), onMouseLeave: () => !value && setHovered(0) }, hovered < index ? (React.createElement(StarIcon_1.StarIcon, { color: "var(--feedback-star-color)" })) : (React.createElement(StarFilledIcon_1.StarFilledIcon, { color: "var(--feedback-star-color)" }))));
49
49
  }
50
50
  return React.createElement(StarsWrapper, { "data-component-name": "Feedback/Stars" }, stars);
51
51
  }
@@ -20,7 +20,7 @@ function FooterItem({ item, iconsOnly, className }) {
20
20
  }
21
21
  const hasIcon = Boolean(item.icon || item.srcSet);
22
22
  const iconWithoutLabel = Boolean(item.label === item.link && hasIcon);
23
- return (react_1.default.createElement(FooterItemWrapper, { className: className, "data-component-name": "Footer/FooterItem", $iconsOnly: iconsOnly, $item: item }, item.type === 'separator' ? (react_1.default.createElement(FooterSeparator, { "data-translation-key": item.labelTranslationKey }, translate(item.labelTranslationKey, item.label))) : (react_1.default.createElement(FooterLink, { to: item.link, external: item.external, target: item.target, "data-testid": item.label, onClick: () => telemetry.sendFooterItemClickedMessage([(0, utils_1.getBaseDataAttributes)('footerItem', 'footer')]), "data-translation-key": item.labelTranslationKey },
23
+ return (react_1.default.createElement(FooterItemWrapper, { className: className, "data-component-name": "Footer/FooterItem", $iconsOnly: iconsOnly, $item: item }, item.type === 'separator' ? (react_1.default.createElement(FooterSeparator, { "data-translation-key": item.labelTranslationKey }, translate(item.labelTranslationKey, item.label))) : (react_1.default.createElement(FooterLink, { to: item.link, external: item.external, target: item.target, "data-testid": item.label, onClick: () => telemetry.sendFooterItemClickedMessage([(0, utils_1.getBaseDataAttributes)('footerItem', 'footer')]), "data-translation-key": item.labelTranslationKey, "aria-label": iconWithoutLabel ? translate(item.labelTranslationKey, item.label) : undefined },
24
24
  hasIcon ? (react_1.default.createElement(FooterLinkIcon, { $iconsOnly: iconsOnly },
25
25
  react_1.default.createElement(GenericIcon_1.GenericIcon, { icon: item.icon, srcSet: item.srcSet }))) : null,
26
26
  !iconWithoutLabel ? translate(item.labelTranslationKey, item.label) : null,
@@ -5,4 +5,5 @@ export declare function JsonValue(props: {
5
5
  standalone?: boolean;
6
6
  defaultExpandLevel: number;
7
7
  expandAllSignal: boolean | undefined;
8
+ maxStringLength?: number;
8
9
  }): React.ReactNode;
@@ -40,9 +40,10 @@ exports.JsonValue = JsonValue;
40
40
  const react_1 = __importStar(require("react"));
41
41
  const styled_components_1 = __importDefault(require("styled-components"));
42
42
  const Button_1 = require("../../components/Button/Button");
43
+ const ShowMoreToggleButton_1 = require("../../components/Button/ShowMoreToggleButton");
43
44
  const ChevronDownIcon_1 = require("../../icons/ChevronDownIcon/ChevronDownIcon");
44
45
  function JsonValue(props) {
45
- const { standalone, defaultExpandLevel, level, value, expandAllSignal } = props;
46
+ const { standalone, defaultExpandLevel, level, value, expandAllSignal, maxStringLength } = props;
46
47
  const indent = ' '.repeat(level * 2);
47
48
  const [isExpandedState, setExpanded] = react_1.default.useState(expandAllSignal !== null && expandAllSignal !== void 0 ? expandAllSignal : level < defaultExpandLevel);
48
49
  const isExpanded = expandAllSignal !== undefined && level > 0 ? expandAllSignal : isExpandedState;
@@ -58,18 +59,19 @@ function JsonValue(props) {
58
59
  const valueType = typeof value;
59
60
  const isPrimitive = (valueType !== 'object' && value !== null) || keys.length === 0;
60
61
  if (isPrimitive) {
62
+ const isOversizedString = typeof value === 'string' && maxStringLength !== undefined && value.length > maxStringLength;
61
63
  return (react_1.default.createElement(react_1.default.Fragment, null,
62
64
  standalone ? indent : null,
63
- react_1.default.createElement("span", { className: 'token ' + valueType }, JSON.stringify(value))));
65
+ isOversizedString ? (react_1.default.createElement(TruncatedStringValue, { value: value, maxStringLength: maxStringLength })) : (react_1.default.createElement("span", { className: 'token ' + valueType }, JSON.stringify(value)))));
64
66
  }
65
67
  const openingPunctuation = Array.isArray(value) ? '[' : '{';
66
68
  const closingPunctuation = Array.isArray(value) ? ']' : '}';
67
69
  const valueElement = Array.isArray(value)
68
70
  ? value.map((item, index) => (react_1.default.createElement(react_1.default.Fragment, { key: index },
69
- react_1.default.createElement(JsonValue, { value: item, level: level + 1, standalone: true, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal }),
71
+ react_1.default.createElement(JsonValue, { value: item, level: level + 1, standalone: true, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal, maxStringLength: maxStringLength }),
70
72
  index < value.length - 1 ? ',\n' : null)))
71
73
  : keys.map((key, index) => (react_1.default.createElement(react_1.default.Fragment, { key: key },
72
- react_1.default.createElement(JsonKeyValue, { name: key, value: value[key], level: level + 1, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal }),
74
+ react_1.default.createElement(JsonKeyValue, { name: key, value: value[key], level: level + 1, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal, maxStringLength: maxStringLength }),
73
75
  index < keys.length - 1 ? ',\n' : null)));
74
76
  const openingPunctuationElement = standalone ? (react_1.default.createElement(react_1.default.Fragment, null,
75
77
  indent,
@@ -86,7 +88,7 @@ function JsonValue(props) {
86
88
  closingPunctuationElement));
87
89
  }
88
90
  function JsonKeyValue(props) {
89
- const { defaultExpandLevel, level, name, value, expandAllSignal } = props;
91
+ const { defaultExpandLevel, level, name, value, expandAllSignal, maxStringLength } = props;
90
92
  const indent = ' '.repeat(level * 2);
91
93
  const keys = (value && Object.keys(value).filter((key) => value[key] !== undefined)) || []; // filter out undefined properties
92
94
  const isCollapsible = typeof value === 'object' && value !== null && keys.length > 0;
@@ -103,10 +105,10 @@ function JsonKeyValue(props) {
103
105
  openingPunctuation,
104
106
  isExpanded ? (react_1.default.createElement(react_1.default.Fragment, null,
105
107
  '\n',
106
- react_1.default.createElement(JsonValue, { value: value, level: level, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal }),
108
+ react_1.default.createElement(JsonValue, { value: value, level: level, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal, maxStringLength: maxStringLength }),
107
109
  '\n')) : (' … '),
108
110
  isExpanded ? indent : null,
109
- closingPunctuation)) : (react_1.default.createElement(JsonValue, { value: value, level: level, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal }));
111
+ closingPunctuation)) : (react_1.default.createElement(JsonValue, { value: value, level: level, defaultExpandLevel: defaultExpandLevel, expandAllSignal: expandAllSignal, maxStringLength: maxStringLength }));
110
112
  return (react_1.default.createElement(react_1.default.Fragment, null,
111
113
  indent,
112
114
  isCollapsible ? (react_1.default.createElement(ExpandIcon, { onClick: () => setExpanded((v) => !v), isExpanded: isExpanded })) : null,
@@ -114,9 +116,20 @@ function JsonKeyValue(props) {
114
116
  ": ",
115
117
  valueElement));
116
118
  }
119
+ function TruncatedStringValue({ value, maxStringLength, }) {
120
+ const [isExpanded, setExpanded] = react_1.default.useState(false);
121
+ const shownValue = react_1.default.useMemo(() => JSON.stringify(isExpanded ? value : `${value.slice(0, maxStringLength)}…`), [isExpanded, value, maxStringLength]);
122
+ return (react_1.default.createElement(react_1.default.Fragment, null,
123
+ react_1.default.createElement("span", { className: "token string" }, shownValue),
124
+ ' ',
125
+ react_1.default.createElement(ShowMoreButton, { isExpanded: isExpanded, onToggle: () => setExpanded((v) => !v) })));
126
+ }
117
127
  function ExpandIcon({ isExpanded, onClick, }) {
118
128
  return (react_1.default.createElement(ExpandButton, { "aria-label": "collapse", className: isExpanded ? 'expanded' : '', size: "small", variant: "text", onClick: onClick, icon: react_1.default.createElement(ChevronDownIcon_1.ChevronDownIcon, { color: "var(--text-color-helper)" }) }));
119
129
  }
130
+ const ShowMoreButton = (0, styled_components_1.default)(ShowMoreToggleButton_1.ShowMoreToggleButton) `
131
+ user-select: none;
132
+ `;
120
133
  const ExpandButton = (0, styled_components_1.default)(Button_1.Button) `
121
134
  position: absolute;
122
135
  left: -10px;
@@ -8,6 +8,8 @@ export type JsonProps = {
8
8
  className?: string;
9
9
  expandLevel: number;
10
10
  startLineNumber?: number;
11
+ /** Truncate string values longer than this at render time (full value stays available for copy). */
12
+ maxStringLength?: number;
11
13
  onCopyClick?: () => void;
12
14
  onPanelToggle?: (isExpanded: boolean, panelType?: PanelType) => void;
13
15
  };
@@ -41,7 +41,7 @@ const react_1 = __importStar(require("react"));
41
41
  const styled_components_1 = __importDefault(require("styled-components"));
42
42
  const CodeBlock_1 = require("../../components/CodeBlock/CodeBlock");
43
43
  const Helpers_1 = require("../../components/JsonViewer/Helpers");
44
- function JsonComponent({ data, expandLevel = 1, className, onCopyClick, onPanelToggle, title, controls = {}, }) {
44
+ function JsonComponent({ data, expandLevel = 1, className, onCopyClick, onPanelToggle, title, controls = {}, maxStringLength, }) {
45
45
  const showFoldingButtons = data && Object.values(data).some((value) => typeof value === 'object' && value !== null);
46
46
  const [expandAllSignal, setExpandAllSignal] = react_1.default.useState(undefined);
47
47
  const expandAll = () => {
@@ -71,7 +71,7 @@ function JsonComponent({ data, expandLevel = 1, className, onCopyClick, onPanelT
71
71
  }
72
72
  : undefined, source: source },
73
73
  react_1.default.createElement(FoldingWrap, null,
74
- react_1.default.createElement(Helpers_1.JsonValue, { value: data, level: 0, standalone: true, expandAllSignal: expandAllSignal, defaultExpandLevel: Math.max(1, expandLevel) })))));
74
+ react_1.default.createElement(Helpers_1.JsonValue, { value: data, level: 0, standalone: true, expandAllSignal: expandAllSignal, defaultExpandLevel: Math.max(1, expandLevel), maxStringLength: maxStringLength })))));
75
75
  }
76
76
  exports.JsonViewer = (0, react_1.memo)(JsonComponent);
77
77
  const FoldingWrap = styled_components_1.default.div `
@@ -15,12 +15,13 @@ const Dropdown_1 = require("../../components/Dropdown/Dropdown");
15
15
  const CheckmarkIcon_1 = require("../../icons/CheckmarkIcon/CheckmarkIcon");
16
16
  function LanguagePicker(props) {
17
17
  const { currentLocale, locales, getLocaleUrl } = (0, hooks_1.useLanguagePicker)();
18
- const { useTelemetry } = (0, hooks_1.useThemeHooks)();
18
+ const { useTelemetry, useTranslate } = (0, hooks_1.useThemeHooks)();
19
19
  const telemetry = useTelemetry();
20
+ const { translate } = useTranslate();
20
21
  if (locales.length < 2 || !currentLocale) {
21
22
  return null;
22
23
  }
23
- const languagePickerButton = (react_1.default.createElement(Button_1.Button, { icon: react_1.default.createElement(GlobalOutlinedIcon_1.GlobalOutlinedIcon, { color: "--button-content-color" }), variant: "secondary", size: "medium" }));
24
+ const languagePickerButton = (react_1.default.createElement(Button_1.Button, { icon: react_1.default.createElement(GlobalOutlinedIcon_1.GlobalOutlinedIcon, { color: "--button-content-color" }), variant: "secondary", size: "medium", "aria-label": translate('languagePicker.label', 'Select language') }));
24
25
  const languageItems = locales.map((locale) => ({
25
26
  content: locale.name || locale.code || '',
26
27
  to: getLocaleUrl(locale.code),
@@ -53,6 +53,7 @@ exports.Markdown = styled_components_1.default.main
53
53
  line-height: var(--md-content-line-height);
54
54
  color: var(--md-content-text-color);
55
55
  padding: 0;
56
+ overflow-wrap: break-word;
56
57
 
57
58
  ${({ compact }) => compact &&
58
59
  (0, styled_components_1.css) `
@@ -97,7 +98,12 @@ exports.Markdown = styled_components_1.default.main
97
98
  scroll-margin-top: calc(var(--navbar-height) + var(--banner-height));
98
99
  ${(0, heading_anchor_1.headingAnchorCss)(constants_1.ANCHOR_CLASS)};
99
100
 
100
- h1, h2, h3, h4, h5, h6 {
101
+ h1,
102
+ h2,
103
+ h3,
104
+ h4,
105
+ h5,
106
+ h6 {
101
107
  display: flex;
102
108
  align-items: flex-start;
103
109
  gap: var(--spacing-sm);
@@ -306,8 +312,10 @@ exports.Markdown = styled_components_1.default.main
306
312
  }
307
313
 
308
314
  blockquote {
309
- margin: var(--md-blockquote-margin-vertical) var(--md-blockquote-margin-horizontal);
310
- padding: var(--md-blockquote-padding-vertical) var(--md-blockquote-padding-horizontal);
315
+ margin: var(--md-blockquote-margin-vertical)
316
+ var(--md-blockquote-margin-horizontal);
317
+ padding: var(--md-blockquote-padding-vertical)
318
+ var(--md-blockquote-padding-horizontal);
311
319
  border-left: var(--md-blockquote-border-left);
312
320
  background-color: var(--md-blockquote-bg-color);
313
321
  color: var(--md-blockquote-text-color);
@@ -335,8 +343,7 @@ exports.Markdown = styled_components_1.default.main
335
343
  }
336
344
  }
337
345
 
338
- ul.${constants_1.MARKDOWN_CLASS_NAME},
339
- ol.${constants_1.MARKDOWN_CLASS_NAME} {
346
+ ul.${constants_1.MARKDOWN_CLASS_NAME}, ol.${constants_1.MARKDOWN_CLASS_NAME} {
340
347
  padding-left: var(--md-list-left-padding);
341
348
  margin: var(--md-list-margin);
342
349
 
@@ -359,7 +366,7 @@ exports.Markdown = styled_components_1.default.main
359
366
  }
360
367
  }
361
368
 
362
- ul > li:has(input[type='checkbox']) {
369
+ ul > li:has(input[type="checkbox"]) {
363
370
  list-style: var(--md-checkbox-list-item-style);
364
371
  }
365
372
 
@@ -1 +1,2 @@
1
+ export declare const linkCss: import("styled-components").RuleSet<object>;
1
2
  export declare const markdownLinksCss: import("styled-components").RuleSet<object>;
@@ -1,24 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.markdownLinksCss = void 0;
3
+ exports.markdownLinksCss = exports.linkCss = void 0;
4
4
  const styled_components_1 = require("styled-components");
5
- exports.markdownLinksCss = (0, styled_components_1.css) `
6
- a:not([role='button']) {
7
- text-decoration: var(--link-decoration);
8
- text-underline-offset: var(--link-underline-offset);
9
- color: var(--link-color-primary);
10
- font-weight: var(--link-font-weight);
5
+ exports.linkCss = (0, styled_components_1.css) `
6
+ text-decoration: var(--link-decoration);
7
+ text-underline-offset: var(--link-underline-offset);
8
+ color: var(--link-color-primary);
9
+ font-weight: var(--link-font-weight);
11
10
 
12
- &:visited {
13
- color: var(--link-color-visited);
14
- text-decoration: var(--link-decoration-visited);
15
- }
11
+ &:visited {
12
+ color: var(--link-color-visited);
13
+ text-decoration: var(--link-decoration-visited);
14
+ }
16
15
 
17
- &:hover,
18
- &:focus {
19
- text-decoration: var(--link-decoration-hover);
20
- color: var(--link-color-primary-hover);
21
- }
16
+ &:hover,
17
+ &:focus {
18
+ text-decoration: var(--link-decoration-hover);
19
+ color: var(--link-color-primary-hover);
20
+ }
21
+ `;
22
+ exports.markdownLinksCss = (0, styled_components_1.css) `
23
+ a:not([role='button']) {
24
+ ${exports.linkCss}
22
25
  }
23
26
  `;
24
27
  //# sourceMappingURL=links.js.map
@@ -1,4 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { MenuItemProps } from '../../core/types';
3
3
  import type { JSX } from 'react';
4
- export declare function MenuItem(props: React.PropsWithChildren<MenuItemProps>): JSX.Element;
4
+ declare function MenuItemImpl(props: React.PropsWithChildren<MenuItemProps>): JSX.Element;
5
+ /** Compares only the props that actually affect this row. `item` is expected
6
+ * to be reference-stable from the producer (e.g. `useMenuItems`) when the
7
+ * row's state hasn't changed; `onClick` and `children` are fresh JSX from
8
+ * the parent's `.map()` every render and would defeat the memo. */
9
+ export declare const MenuItem: React.MemoExoticComponent<typeof MenuItemImpl>;
10
+ export {};
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.MenuItem = MenuItem;
36
+ exports.MenuItem = void 0;
37
37
  const react_1 = __importStar(require("react"));
38
38
  const styled_components_1 = __importStar(require("styled-components"));
39
39
  const hooks_1 = require("../../core/hooks");
@@ -47,7 +47,19 @@ const utils_1 = require("../../core/utils");
47
47
  const ArrowRightIcon_1 = require("../../icons/ArrowRightIcon/ArrowRightIcon");
48
48
  const GenericIcon_1 = require("../../icons/GenericIcon/GenericIcon");
49
49
  const Tag_1 = require("../../components/Tag/Tag");
50
- function MenuItem(props) {
50
+ /** Nearest scrollable ancestor, stopping before <body> so only the sidebar scrolls — never the page. */
51
+ function getScrollParent(el) {
52
+ let node = el.parentElement;
53
+ while (node && node !== document.body) {
54
+ const { overflowY } = getComputedStyle(node);
55
+ if ((overflowY === 'auto' || overflowY === 'scroll') && node.scrollHeight > node.clientHeight) {
56
+ return node;
57
+ }
58
+ node = node.parentElement;
59
+ }
60
+ return null;
61
+ }
62
+ function MenuItemImpl(props) {
51
63
  var _a, _b;
52
64
  var _c;
53
65
  const { item, depth, className, onClick } = props;
@@ -65,6 +77,25 @@ function MenuItem(props) {
65
77
  const isNested = type === constants_1.MenuItemType.Group;
66
78
  const hasChevron = isNested && !isDrilldown;
67
79
  const hasHttpTag = !!item.httpVerb || type === constants_1.MenuItemType.Operation;
80
+ // When this item becomes the active one (via navigation or scroll-spy), keep
81
+ // it visible by scrolling only the sidebar's own scroll container.
82
+ (0, react_1.useEffect)(() => {
83
+ const el = labelRef.current;
84
+ if (!item.active || !el)
85
+ return;
86
+ const scroller = getScrollParent(el);
87
+ if (!scroller)
88
+ return;
89
+ const scrollerRect = scroller.getBoundingClientRect();
90
+ const elRect = el.getBoundingClientRect();
91
+ const margin = elRect.height;
92
+ if (elRect.top < scrollerRect.top + margin) {
93
+ scroller.scrollTop -= scrollerRect.top + margin - elRect.top;
94
+ }
95
+ else if (elRect.bottom > scrollerRect.bottom - margin) {
96
+ scroller.scrollTop += elRect.bottom - (scrollerRect.bottom - margin);
97
+ }
98
+ }, [item.active]);
68
99
  const handleOnClick = () => {
69
100
  telemetry.sendSidebarItemClickedMessage([
70
101
  Object.assign(Object.assign({}, (0, utils_1.getBaseDataAttributes)('sidebarItem', 'sidebar')), { label: item.label, type: item.type === 'link' || item.type === 'group' ? item.type : undefined }),
@@ -323,4 +354,14 @@ const BadgeIcon = (0, styled_components_1.default)(GenericIcon_1.GenericIcon) `
323
354
  margin-right: var(--spacing-xxs);
324
355
  flex-shrink: 0;
325
356
  `;
357
+ /** Compares only the props that actually affect this row. `item` is expected
358
+ * to be reference-stable from the producer (e.g. `useMenuItems`) when the
359
+ * row's state hasn't changed; `onClick` and `children` are fresh JSX from
360
+ * the parent's `.map()` every render and would defeat the memo. */
361
+ exports.MenuItem = react_1.default.memo(MenuItemImpl, (prev, next) => {
362
+ return (prev.item === next.item &&
363
+ prev.depth === next.depth &&
364
+ prev.isMobile === next.isMobile &&
365
+ prev.className === next.className);
366
+ });
326
367
  //# sourceMappingURL=MenuItem.js.map