@redocly/theme 0.70.0-next.4 → 0.70.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 (113) hide show
  1. package/lib/components/Buttons/ConnectMCPButton.js +8 -13
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.d.ts +1 -1
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +1 -1
  4. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +30 -11
  5. package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.js +2 -1
  6. package/lib/components/Dropdown/Dropdown.d.ts +4 -2
  7. package/lib/components/Dropdown/Dropdown.js +28 -8
  8. package/lib/components/Dropdown/DropdownMenu.d.ts +1 -0
  9. package/lib/components/Dropdown/DropdownMenu.js +1 -1
  10. package/lib/components/Feedback/Reasons.js +3 -2
  11. package/lib/components/Filter/FilterCheckboxes.js +30 -11
  12. package/lib/components/Filter/FilterDateRange.js +36 -2
  13. package/lib/components/Image/Image.js +24 -4
  14. package/lib/components/Search/SearchAiActivity.d.ts +10 -0
  15. package/lib/components/Search/SearchAiActivity.js +278 -0
  16. package/lib/components/Search/SearchAiDialog.js +5 -1
  17. package/lib/components/Search/SearchAiMessage.d.ts +2 -1
  18. package/lib/components/Search/SearchAiMessage.js +20 -108
  19. package/lib/components/Search/SearchItem.js +1 -8
  20. package/lib/components/Search/variables.js +15 -2
  21. package/lib/components/Segmented/Segmented.js +23 -3
  22. package/lib/components/Select/Select.js +10 -3
  23. package/lib/components/Select/SelectInput.d.ts +1 -0
  24. package/lib/components/Select/SelectInput.js +5 -11
  25. package/lib/components/SplitButton/SplitButton.js +37 -3
  26. package/lib/core/constants/mcp.d.ts +2 -2
  27. package/lib/core/constants/mcp.js +3 -8
  28. package/lib/core/constants/search.js +5 -1
  29. package/lib/core/hooks/index.d.ts +2 -0
  30. package/lib/core/hooks/index.js +2 -0
  31. package/lib/core/hooks/menu/use-collapse.js +1 -1
  32. package/lib/core/hooks/search/use-search-ai-activity.d.ts +11 -0
  33. package/lib/core/hooks/search/use-search-ai-activity.js +15 -0
  34. package/lib/core/hooks/use-connect-mcp-button.js +2 -1
  35. package/lib/core/hooks/use-full-height.d.ts +1 -1
  36. package/lib/core/hooks/use-full-height.js +8 -8
  37. package/lib/core/hooks/use-tab-list.d.ts +31 -0
  38. package/lib/core/hooks/use-tab-list.js +49 -0
  39. package/lib/core/styles/global.d.ts +2 -0
  40. package/lib/core/styles/global.js +80 -76
  41. package/lib/core/styles/index.d.ts +1 -0
  42. package/lib/core/styles/index.js +3 -1
  43. package/lib/core/styles/search-ai-appear.d.ts +1 -0
  44. package/lib/core/styles/search-ai-appear.js +18 -0
  45. package/lib/core/types/dropdown.d.ts +1 -0
  46. package/lib/core/types/dropdown.js +3 -0
  47. package/lib/core/types/index.d.ts +1 -0
  48. package/lib/core/types/l10n.d.ts +1 -1
  49. package/lib/core/types/mcp.d.ts +2 -1
  50. package/lib/core/types/search.d.ts +23 -0
  51. package/lib/core/utils/Dynamic.d.ts +8 -1
  52. package/lib/core/utils/Dynamic.js +34 -3
  53. package/lib/core/utils/assign-ref.d.ts +2 -0
  54. package/lib/core/utils/assign-ref.js +12 -0
  55. package/lib/core/utils/content-segments.d.ts +12 -1
  56. package/lib/core/utils/content-segments.js +90 -5
  57. package/lib/core/utils/dropdown.d.ts +2 -0
  58. package/lib/core/utils/dropdown.js +12 -0
  59. package/lib/core/utils/index.d.ts +2 -0
  60. package/lib/core/utils/index.js +2 -0
  61. package/lib/core/utils/mcp.d.ts +2 -1
  62. package/lib/core/utils/mcp.js +5 -0
  63. package/lib/core/utils/search-ai-activity.d.ts +4 -0
  64. package/lib/core/utils/search-ai-activity.js +83 -0
  65. package/lib/markdoc/tags/connect-mcp.js +15 -0
  66. package/package.json +2 -2
  67. package/src/components/Buttons/ConnectMCPButton.tsx +8 -14
  68. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.tsx +3 -1
  69. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +37 -22
  70. package/src/components/Catalog/CatalogFilter/CatalogFilterDateRange.tsx +3 -2
  71. package/src/components/Dropdown/Dropdown.tsx +28 -6
  72. package/src/components/Dropdown/DropdownMenu.tsx +7 -1
  73. package/src/components/Feedback/Reasons.tsx +3 -2
  74. package/src/components/Filter/FilterCheckboxes.tsx +33 -18
  75. package/src/components/Filter/FilterDateRange.tsx +3 -2
  76. package/src/components/Image/Image.tsx +26 -5
  77. package/src/components/Search/SearchAiActivity.tsx +318 -0
  78. package/src/components/Search/SearchAiDialog.tsx +4 -3
  79. package/src/components/Search/SearchAiMessage.tsx +27 -135
  80. package/src/components/Search/SearchItem.tsx +2 -9
  81. package/src/components/Search/variables.ts +15 -2
  82. package/src/components/Segmented/Segmented.tsx +25 -16
  83. package/src/components/Select/Select.tsx +12 -6
  84. package/src/components/Select/SelectInput.tsx +10 -18
  85. package/src/components/SplitButton/SplitButton.tsx +8 -2
  86. package/src/core/constants/mcp.ts +3 -9
  87. package/src/core/constants/search.ts +5 -1
  88. package/src/core/hooks/__mocks__/index.ts +1 -0
  89. package/src/core/hooks/__mocks__/use-theme-hooks.ts +1 -0
  90. package/src/core/hooks/index.ts +2 -0
  91. package/src/core/hooks/menu/use-collapse.ts +1 -1
  92. package/src/core/hooks/search/use-search-ai-activity.ts +31 -0
  93. package/src/core/hooks/use-connect-mcp-button.ts +7 -2
  94. package/src/core/hooks/use-full-height.ts +8 -8
  95. package/src/core/hooks/use-tab-list.ts +63 -0
  96. package/src/core/styles/global.ts +80 -75
  97. package/src/core/styles/index.ts +2 -1
  98. package/src/core/styles/search-ai-appear.ts +16 -0
  99. package/src/core/types/dropdown.ts +1 -0
  100. package/src/core/types/index.ts +1 -0
  101. package/src/core/types/l10n.ts +1 -1
  102. package/src/core/types/mcp.ts +3 -1
  103. package/src/core/types/search.ts +21 -0
  104. package/src/core/utils/Dynamic.tsx +67 -35
  105. package/src/core/utils/assign-ref.ts +9 -0
  106. package/src/core/utils/content-segments.ts +98 -6
  107. package/src/core/utils/dropdown.ts +14 -0
  108. package/src/core/utils/index.ts +2 -0
  109. package/src/core/utils/mcp.ts +7 -1
  110. package/src/core/utils/search-ai-activity.ts +110 -0
  111. package/src/icons/CheckboxIcon/CheckboxIcon.tsx +1 -0
  112. package/src/icons/ChevronSortIcon/ChevronSortIcon.tsx +1 -0
  113. package/src/markdoc/tags/connect-mcp.ts +16 -1
@@ -19,55 +19,50 @@ const CopyIcon_1 = require("../../icons/CopyIcon/CopyIcon");
19
19
  const CheckmarkFilledIcon_1 = require("../../icons/CheckmarkFilledIcon/CheckmarkFilledIcon");
20
20
  const hooks_1 = require("../../core/hooks");
21
21
  const constants_1 = require("../../core/constants");
22
- const MENU_OPTIONS = [
23
- {
24
- key: 'cursor',
22
+ const MENU_OPTIONS = {
23
+ cursor: {
25
24
  icon: CursorIcon_1.CursorIcon,
26
25
  titleTranslationKey: 'page.actions.connectMcp.cursor',
27
26
  titleDefault: 'Connect to Cursor',
28
27
  descriptionTranslationKey: 'page.actions.connectMcp.cursorDescription',
29
28
  descriptionDefault: 'Install MCP server on Cursor',
30
29
  },
31
- {
32
- key: 'vscode',
30
+ vscode: {
33
31
  icon: VSCodeIcon_1.VSCodeIcon,
34
32
  titleTranslationKey: 'page.actions.connectMcp.vscode',
35
33
  titleDefault: 'Connect to VS Code',
36
34
  descriptionTranslationKey: 'page.actions.connectMcp.vscodeDescription',
37
35
  descriptionDefault: 'Install MCP server on VS Code',
38
36
  },
39
- {
40
- key: 'claude-code',
37
+ 'claude-code': {
41
38
  icon: ClaudeIcon_1.ClaudeIcon,
42
39
  titleTranslationKey: 'page.actions.connectMcp.claudeCode',
43
40
  titleDefault: 'Connect to Claude Code',
44
41
  descriptionTranslationKey: 'page.actions.connectMcp.claudeCodeDescription',
45
42
  descriptionDefault: 'Copy the Claude Code CLI command',
46
43
  },
47
- {
48
- key: 'codex',
44
+ codex: {
49
45
  icon: CodexIcon_1.CodexIcon,
50
46
  titleTranslationKey: 'page.actions.connectMcp.codex',
51
47
  titleDefault: 'Connect to Codex CLI',
52
48
  descriptionTranslationKey: 'page.actions.connectMcp.codexDescription',
53
49
  descriptionDefault: 'Copy the Codex CLI command',
54
50
  },
55
- {
56
- key: 'copy',
51
+ copy: {
57
52
  icon: CopyIcon_1.CopyIcon,
58
53
  titleTranslationKey: 'page.actions.connectMcp.copyConfig',
59
54
  titleDefault: 'Copy MCP Configuration',
60
55
  descriptionTranslationKey: 'page.actions.connectMcp.copyConfigDescription',
61
56
  descriptionDefault: 'Copy MCP JSON Configuration',
62
57
  },
63
- ];
58
+ };
64
59
  // Copy actions keep the dropdown open so the copied checkmark is visible.
65
60
  const COPY_OPTIONS = ['claude-code', 'codex', 'copy'];
66
61
  function ConnectMCPButton({ placement = 'bottom', alignment = 'end', options = constants_1.DEFAULT_MCP_OPTIONS, }) {
67
62
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
68
63
  const { translate } = useTranslate();
69
64
  const { copiedOption, visibleOptions, handleAction } = (0, hooks_1.useConnectMCPButton)({ options });
70
- const menuOptions = MENU_OPTIONS.filter((option) => visibleOptions.includes(option.key));
65
+ const menuOptions = visibleOptions.map((key) => (Object.assign({ key }, MENU_OPTIONS[key])));
71
66
  const primaryOption = menuOptions[0];
72
67
  const dropdownOptions = menuOptions.slice(1);
73
68
  if (!primaryOption)
@@ -1,2 +1,2 @@
1
1
  import type { CatalogEntityRelationsGraphProps } from '../../../../components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph';
2
- export declare const CatalogEntityRelationsGraph: import("react").ComponentType<CatalogEntityRelationsGraphProps>;
2
+ export declare const CatalogEntityRelationsGraph: import("../../../../core/utils").DynamicComponent<CatalogEntityRelationsGraphProps>;
@@ -35,5 +35,5 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.CatalogEntityRelationsGraph = void 0;
37
37
  const utils_1 = require("../../../../core/utils");
38
- exports.CatalogEntityRelationsGraph = (0, utils_1.dynamic)(() => Promise.resolve().then(() => __importStar(require('./CatalogEntityRelationsGraph'))).then((mod) => mod.CatalogEntityRelationsGraph));
38
+ exports.CatalogEntityRelationsGraph = (0, utils_1.dynamic)(() => Promise.resolve().then(() => __importStar(require('../../../../components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph'))).then((mod) => mod.CatalogEntityRelationsGraph));
39
39
  //# sourceMappingURL=CatalogEntityRelationsGraph.lazy.js.map
@@ -101,17 +101,20 @@ function CatalogFilterCheckboxes({ filter, filterValuesCasing, showCounter = tru
101
101
  react_1.default.createElement(FilterInput_1.FilterInput, { value: searchTerm, onChange: setSearchTerm })),
102
102
  react_1.default.createElement(FilterOptions_1.FilterOptions, null, filteredOptions.map(({ value, count }) => {
103
103
  const id = 'filter--' + filter.property + '--' + value;
104
- return (react_1.default.createElement(FilterCheckboxOption, { key: id, role: "link", onClick: () => {
105
- filter.toggleOption(value);
106
- telemetry.sendCatalogEntitiesFilterCheckboxToggledMessage([
107
- Object.assign(Object.assign({}, (0, utils_1.getBaseDataAttributes)('catalogEntitiesFilterCheckboxId', 'checkbox')), { category: filter.property, value: value }),
108
- ]);
109
- } },
110
- react_1.default.createElement(CheckboxIcon_1.CheckboxIcon, { checked: filter.selectedOptions instanceof Set
111
- ? filter.selectedOptions.has(value) ||
112
- filter.selectedOptions.has(value === null || value === void 0 ? void 0 : value.toLowerCase())
113
- : false }),
114
- react_1.default.createElement(FilterOptionLabel_1.FilterOptionLabel, { "data-translation-key": value }, highlightText((0, utils_1.changeTextCasing)(translate(value), filterValuesCasing) || '')),
104
+ const checked = filter.selectedOptions instanceof Set
105
+ ? filter.selectedOptions.has(value) ||
106
+ filter.selectedOptions.has(value === null || value === void 0 ? void 0 : value.toLowerCase())
107
+ : false;
108
+ return (react_1.default.createElement(FilterCheckboxOption, { key: id },
109
+ react_1.default.createElement(CheckboxIcon_1.CheckboxIcon, { checked: checked }),
110
+ react_1.default.createElement(FilterOptionLabel_1.FilterOptionLabel, { "data-translation-key": value },
111
+ react_1.default.createElement(FilterCheckboxInput, { checked: checked, onChange: () => {
112
+ filter.toggleOption(value);
113
+ telemetry.sendCatalogEntitiesFilterCheckboxToggledMessage([
114
+ Object.assign(Object.assign({}, (0, utils_1.getBaseDataAttributes)('catalogEntitiesFilterCheckboxId', 'checkbox')), { category: filter.property, value: value }),
115
+ ]);
116
+ } }),
117
+ highlightText((0, utils_1.changeTextCasing)(translate(value), filterValuesCasing) || '')),
115
118
  showCounter && react_1.default.createElement(CounterTag_1.CounterTag, { borderless: true }, count)));
116
119
  })))));
117
120
  }
@@ -147,6 +150,22 @@ const HighlightedText = styled_components_1.default.span `
147
150
  `;
148
151
  const FilterCheckboxOption = (0, styled_components_1.default)(FilterOption_1.FilterOption) `
149
152
  padding-left: var(--filter-option-checkbox-padding-left);
153
+
154
+ &:has(input:focus-visible) {
155
+ outline: 1px solid var(--button-border-color-focused);
156
+ outline-offset: -1px;
157
+ }
158
+ `;
159
+ const FilterCheckboxInput = styled_components_1.default.input.attrs({ type: 'checkbox' }) `
160
+ position: absolute;
161
+ width: 1px;
162
+ height: 1px;
163
+ margin: -1px;
164
+ padding: 0;
165
+ overflow: hidden;
166
+ clip: rect(0 0 0 0);
167
+ white-space: nowrap;
168
+ border: 0;
150
169
  `;
151
170
  const FilterSearchWrapper = styled_components_1.default.div `
152
171
  padding-bottom: var(--spacing-xs);
@@ -46,6 +46,7 @@ const hooks_1 = require("../../../core/hooks");
46
46
  const utils_1 = require("../../../core/utils");
47
47
  const Accordion_1 = require("../../../components/Accordion/Accordion");
48
48
  function CatalogFilterDateRange({ filter, className, }) {
49
+ const [today] = (0, react_1.useState)(() => new Date());
49
50
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
50
51
  const { translate } = useTranslate();
51
52
  const from = (0, react_1.useMemo)(() => (filter.selectedOptions.from ? new Date(filter.selectedOptions.from) : undefined), [filter.selectedOptions.from]);
@@ -62,7 +63,7 @@ function CatalogFilterDateRange({ filter, className, }) {
62
63
  react_1.default.createElement(DateRangeWrapper, null,
63
64
  react_1.default.createElement(DateRangeRow, null,
64
65
  react_1.default.createElement("span", null, translate('filter.dateRange.from', 'From:')),
65
- react_1.default.createElement(DatePicker_1.DatePicker, { closeCalendar: true, format: "y-MM-dd", dayPlaceholder: "DD", monthPlaceholder: "MM", yearPlaceholder: "YYYY", value: from, maxDate: new Date(), onChange: (from) => {
66
+ react_1.default.createElement(DatePicker_1.DatePicker, { closeCalendar: true, format: "y-MM-dd", dayPlaceholder: "DD", monthPlaceholder: "MM", yearPlaceholder: "YYYY", value: from, maxDate: today, onChange: (from) => {
66
67
  if (Array.isArray(from))
67
68
  return;
68
69
  filter.selectOption(Object.assign(Object.assign({}, filter.selectedOptions), { from: (0, utils_1.formatDateWithoutTimeZone)(from), to: (0, utils_1.formatDateWithoutTimeZone)(to) }));
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { RenderableChildren } from '../../core/types';
2
+ import type { DropdownAlignment, RenderableChildren } from '../../core/types';
3
3
  type DropdownMenuContext = {
4
4
  close: () => void;
5
5
  isOpen: boolean;
@@ -9,13 +9,15 @@ export type DropdownProps = {
9
9
  children: RenderableChildren<DropdownMenuContext>;
10
10
  triggerEvent?: 'click' | 'hover';
11
11
  placement?: 'top' | 'bottom';
12
- alignment?: 'start' | 'end';
12
+ alignment?: DropdownAlignment;
13
13
  active?: boolean;
14
14
  closeOnClick?: boolean;
15
15
  dataAttributes?: Record<string, string>;
16
16
  className?: string;
17
17
  withArrow?: boolean;
18
18
  portalled?: boolean;
19
+ /** Element the menu lines up with when it is not the dropdown itself, e.g. a whole split button. */
20
+ alignmentAnchorRef?: React.RefObject<HTMLElement | null>;
19
21
  onClick?: (event: React.UIEvent) => void;
20
22
  onClose?: () => void;
21
23
  onOpen?: () => void;
@@ -38,15 +38,17 @@ const react_1 = __importStar(require("react"));
38
38
  const react_dom_1 = require("react-dom");
39
39
  const styled_components_1 = __importStar(require("styled-components"));
40
40
  const hooks_1 = require("../../core/hooks");
41
+ const utils_1 = require("../../core/utils");
41
42
  const ChevronDownIcon_1 = require("../../icons/ChevronDownIcon/ChevronDownIcon");
42
43
  const ChevronUpIcon_1 = require("../../icons/ChevronUpIcon/ChevronUpIcon");
43
44
  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) => {
45
+ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigger, triggerEvent = 'click', closeOnClick = true, withArrow, dataAttributes, placement, alignment, portalled = false, alignmentAnchorRef, onClick, onClose, onOpen, }, ref) => {
45
46
  var _a, _b;
46
47
  const dropdownRef = (0, react_1.useRef)(null);
47
48
  const menuRef = (0, react_1.useRef)(null);
48
49
  const [isOpen, setIsOpen] = (0, hooks_1.useControlledState)(false, active);
49
50
  const [menuStyle, setMenuStyle] = (0, react_1.useState)({});
51
+ const [fittedAlignment, setFittedAlignment] = (0, react_1.useState)(alignment);
50
52
  const wrapperRef = ref || dropdownRef;
51
53
  const handleOpen = () => {
52
54
  setIsOpen(true);
@@ -78,13 +80,13 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
78
80
  }
79
81
  };
80
82
  const updateMenuPosition = (0, react_1.useCallback)(() => {
81
- var _a;
82
- var _b;
83
+ var _a, _b;
84
+ var _c, _d, _e;
83
85
  const wrapper = wrapperRef.current;
84
86
  if (!wrapper)
85
87
  return;
86
- const rect = wrapper.getBoundingClientRect();
87
- const menuHeight = (_b = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0;
88
+ const rect = ((_c = alignmentAnchorRef === null || alignmentAnchorRef === void 0 ? void 0 : alignmentAnchorRef.current) !== null && _c !== void 0 ? _c : wrapper).getBoundingClientRect();
89
+ const menuHeight = (_d = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _d !== void 0 ? _d : 0;
88
90
  const fitsBelow = rect.bottom + menuHeight <= window.innerHeight;
89
91
  const fitsAbove = rect.top - menuHeight >= 0;
90
92
  const openUpward = placement === 'top' ? fitsAbove || !fitsBelow : !fitsBelow && fitsAbove;
@@ -95,7 +97,7 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
95
97
  else {
96
98
  style.top = rect.bottom;
97
99
  }
98
- if (alignment === 'end') {
100
+ if ((0, utils_1.fitDropdownAlignment)(rect, (_e = (_b = menuRef.current) === null || _b === void 0 ? void 0 : _b.offsetWidth) !== null && _e !== void 0 ? _e : 0, alignment) === 'end') {
99
101
  style.right = window.innerWidth - rect.right;
100
102
  }
101
103
  else {
@@ -106,7 +108,25 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
106
108
  style.zIndex = zIndex;
107
109
  }
108
110
  setMenuStyle(style);
109
- }, [placement, alignment, wrapperRef]);
111
+ }, [placement, alignment, wrapperRef, alignmentAnchorRef]);
112
+ /* The absolute-positioned menu is placed by CSS, so the side is measured once it is
113
+ shown and again on resize; a side that runs off the viewport flips to the other one. */
114
+ const updateFittedAlignment = (0, react_1.useCallback)(() => {
115
+ var _a;
116
+ const wrapper = wrapperRef.current;
117
+ const menu = menuRef.current;
118
+ if (!wrapper || !menu)
119
+ return;
120
+ const rect = ((_a = alignmentAnchorRef === null || alignmentAnchorRef === void 0 ? void 0 : alignmentAnchorRef.current) !== null && _a !== void 0 ? _a : wrapper).getBoundingClientRect();
121
+ setFittedAlignment((0, utils_1.fitDropdownAlignment)(rect, menu.offsetWidth, alignment));
122
+ }, [alignment, wrapperRef, alignmentAnchorRef]);
123
+ useIsomorphicLayoutEffect(() => {
124
+ if (portalled || !isOpen)
125
+ return;
126
+ updateFittedAlignment();
127
+ window.addEventListener('resize', updateFittedAlignment);
128
+ return () => window.removeEventListener('resize', updateFittedAlignment);
129
+ }, [portalled, isOpen, updateFittedAlignment]);
110
130
  useIsomorphicLayoutEffect(() => {
111
131
  if (!portalled || !isOpen)
112
132
  return;
@@ -123,7 +143,7 @@ exports.Dropdown = (0, react_1.forwardRef)(({ children, className, active, trigg
123
143
  const triggerChild = react_1.default.Children.only(trigger);
124
144
  const isLinkTrigger = Boolean(((_a = triggerChild.props) === null || _a === void 0 ? void 0 : _a.to) || ((_b = triggerChild.props) === null || _b === void 0 ? void 0 : _b.href));
125
145
  const dropdownTrigger = (0, react_1.cloneElement)(triggerChild, Object.assign(Object.assign(Object.assign({ onClick: triggerEvent === 'click' ? handleToggle : undefined, 'aria-haspopup': 'menu', 'aria-expanded': isOpen, 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' || !isLinkTrigger ? handleKeyDown : undefined }));
126
- 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 }, menuContent));
146
+ const menu = (react_1.default.createElement(ChildrenWrapper, { ref: menuRef, $placement: placement, $alignment: fittedAlignment, $isOpen: isOpen, $portalled: portalled, style: portalled ? menuStyle : undefined, onClick: closeOnClick ? handleChildClick : undefined }, menuContent));
127
147
  const portalledMenu = isOpen && typeof document !== 'undefined' ? (0, react_dom_1.createPortal)(menu, document.body) : null;
128
148
  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 }),
129
149
  dropdownTrigger,
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import type { ReactNode, JSX } from 'react';
3
3
  import type { DropdownMenuItemProps } from '../../components/Dropdown/DropdownMenuItem';
4
4
  export type DropdownMenuProps = {
5
+ id?: string;
5
6
  className?: string;
6
7
  role?: string;
7
8
  footer?: React.ReactNode;
@@ -15,7 +15,7 @@ function DropdownMenu(props) {
15
15
  if ('items' in props) {
16
16
  content = props.items.map((item, idx) => (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, Object.assign({ key: idx }, item), item.content)));
17
17
  }
18
- return (react_1.default.createElement(DropdownMenuWrapper, { "data-component-name": "Dropdown/DropdownMenu", "data-testid": "dropdown-menu", className: props.className, role: props.role || 'menu' },
18
+ return (react_1.default.createElement(DropdownMenuWrapper, { "data-component-name": "Dropdown/DropdownMenu", "data-testid": "dropdown-menu", id: props.id, className: props.className, role: props.role || 'menu' },
19
19
  content,
20
20
  props.footer || null));
21
21
  }
@@ -43,6 +43,7 @@ const hooks_1 = require("../../core/hooks");
43
43
  function Reasons({ settings, onChange, className }) {
44
44
  const { label, component = 'checkbox', items = [] } = settings;
45
45
  const [checkedState, setCheckedState] = React.useState(new Array(items.length).fill(false));
46
+ const idPrefix = React.useId();
46
47
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
47
48
  const { translate } = useTranslate();
48
49
  if (!items.length) {
@@ -59,8 +60,8 @@ function Reasons({ settings, onChange, className }) {
59
60
  React.createElement(Label, null, label ||
60
61
  translate('feedback.settings.reasons.label', 'Which statement describes your thoughts about this page?')),
61
62
  items.map((reason, idx) => (React.createElement(OptionWrapper, { key: reason },
62
- React.createElement("input", { type: component, value: reason, checked: checkedState[idx], name: "reasons", onChange: () => handleOptionChange(idx) }),
63
- React.createElement("label", { "data-translation-key": `feedback.settings.reasons.items.${idx + 1}`, id: reason, onClick: () => handleOptionChange(idx) }, translate(`feedback.settings.reasons.items.${idx + 1}`, reason)))))));
63
+ React.createElement("input", { id: `${idPrefix}-${idx}`, type: component, value: reason, checked: checkedState[idx], name: "reasons", onChange: () => handleOptionChange(idx) }),
64
+ React.createElement("label", { "data-translation-key": `feedback.settings.reasons.items.${idx + 1}`, htmlFor: `${idPrefix}-${idx}` }, translate(`feedback.settings.reasons.items.${idx + 1}`, reason)))))));
64
65
  }
65
66
  const ReasonsWrapper = styled_components_1.default.div `
66
67
  font-family: var(--feedback-font-family);
@@ -22,22 +22,41 @@ function FilterCheckboxes({ filter, filterValuesCasing, showCounter = true, }) {
22
22
  react_1.default.createElement(FilterTitle_1.FilterTitle, { "data-translation-key": filter.titleTranslationKey }, translate(filter.titleTranslationKey, filter.title)),
23
23
  react_1.default.createElement(FilterOptions_1.FilterOptions, null, (filter.filteredOptions || filter.options).map(({ value, count }) => {
24
24
  const id = 'filter--' + filter.property + '--' + value;
25
- return (react_1.default.createElement(FilterCheckboxOption, { key: id, role: "link", onClick: () => {
26
- filter.toggleOption(value);
27
- telemetry.sendFilterCheckboxToggledMessage([
28
- (0, utils_1.getBaseDataAttributes)('filterId', 'checkbox'),
29
- ]);
30
- } },
31
- react_1.default.createElement(CheckboxIcon_1.CheckboxIcon, { checked: filter.selectedOptions instanceof Set
32
- ? filter.selectedOptions.has(value) ||
33
- filter.selectedOptions.has(value === null || value === void 0 ? void 0 : value.toLowerCase())
34
- : false }),
35
- react_1.default.createElement(FilterOptionLabel_1.FilterOptionLabel, { "data-translation-key": value }, (0, utils_1.changeTextCasing)(translate(value), filterValuesCasing)),
25
+ const checked = filter.selectedOptions instanceof Set
26
+ ? filter.selectedOptions.has(value) ||
27
+ filter.selectedOptions.has(value === null || value === void 0 ? void 0 : value.toLowerCase())
28
+ : false;
29
+ return (react_1.default.createElement(FilterCheckboxOption, { key: id },
30
+ react_1.default.createElement(CheckboxIcon_1.CheckboxIcon, { checked: checked }),
31
+ react_1.default.createElement(FilterOptionLabel_1.FilterOptionLabel, { "data-translation-key": value },
32
+ react_1.default.createElement(FilterCheckboxInput, { checked: checked, onChange: () => {
33
+ filter.toggleOption(value);
34
+ telemetry.sendFilterCheckboxToggledMessage([
35
+ (0, utils_1.getBaseDataAttributes)('filterId', 'checkbox'),
36
+ ]);
37
+ } }),
38
+ (0, utils_1.changeTextCasing)(translate(value), filterValuesCasing)),
36
39
  showCounter && react_1.default.createElement(CounterTag_1.CounterTag, { borderless: true }, count)));
37
40
  }))));
38
41
  }
39
42
  const FilterCheckboxOption = (0, styled_components_1.default)(FilterOption_1.FilterOption) `
40
43
  padding-left: var(--filter-option-checkbox-padding-left);
44
+
45
+ &:has(input:focus-visible) {
46
+ outline: 1px solid var(--button-border-color-focused);
47
+ outline-offset: -1px;
48
+ }
49
+ `;
50
+ const FilterCheckboxInput = styled_components_1.default.input.attrs({ type: 'checkbox' }) `
51
+ position: absolute;
52
+ width: 1px;
53
+ height: 1px;
54
+ margin: -1px;
55
+ padding: 0;
56
+ overflow: hidden;
57
+ clip: rect(0 0 0 0);
58
+ white-space: nowrap;
59
+ border: 0;
41
60
  `;
42
61
  const FilterCheckboxesWrapper = styled_components_1.default.div `
43
62
  display: flex;
@@ -1,10 +1,43 @@
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
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.FilterDateRange = FilterDateRange;
7
- const react_1 = __importDefault(require("react"));
40
+ const react_1 = __importStar(require("react"));
8
41
  const styled_components_1 = __importDefault(require("styled-components"));
9
42
  const FilterOptions_1 = require("../../components/Filter/FilterOptions");
10
43
  const FilterTitle_1 = require("../../components/Filter/FilterTitle");
@@ -12,6 +45,7 @@ const DatePicker_1 = require("../../components/DatePicker/DatePicker");
12
45
  const hooks_1 = require("../../core/hooks");
13
46
  const utils_1 = require("../../core/utils");
14
47
  function FilterDateRange({ filter }) {
48
+ const [today] = (0, react_1.useState)(() => new Date());
15
49
  const { useTranslate } = (0, hooks_1.useThemeHooks)();
16
50
  const { translate } = useTranslate();
17
51
  const from = filter.selectedOptions.from ? new Date(filter.selectedOptions.from) : undefined;
@@ -22,7 +56,7 @@ function FilterDateRange({ filter }) {
22
56
  react_1.default.createElement(DateRangeWrapper, null,
23
57
  react_1.default.createElement(DateRangeRow, null,
24
58
  react_1.default.createElement("span", null, translate('filter.dateRange.from', 'From:')),
25
- react_1.default.createElement(DatePicker_1.DatePicker, { closeCalendar: true, format: "y-MM-dd", dayPlaceholder: "DD", monthPlaceholder: "MM", yearPlaceholder: "YYYY", value: from, maxDate: new Date(), onChange: (from) => {
59
+ react_1.default.createElement(DatePicker_1.DatePicker, { closeCalendar: true, format: "y-MM-dd", dayPlaceholder: "DD", monthPlaceholder: "MM", yearPlaceholder: "YYYY", value: from, maxDate: today, onChange: (from) => {
26
60
  if (Array.isArray(from))
27
61
  return;
28
62
  filter.selectOption(Object.assign(Object.assign({}, filter.selectedOptions), { from: (0, utils_1.formatDateWithoutTimeZone)(from), to: (0, utils_1.formatDateWithoutTimeZone)(to) }));
@@ -43,6 +43,7 @@ const Button_1 = require("../../components/Button/Button");
43
43
  function Image(props) {
44
44
  const { src, srcSet, images: galleryImages, alt, className, width, height, border, caption, framed, style, withLightbox, lightboxStyle, } = props;
45
45
  const lightboxContainerRef = (0, react_1.useRef)(null);
46
+ const lightboxTriggerRef = (0, react_1.useRef)(null);
46
47
  const [lightboxImage, setLightboxImage] = (0, react_1.useState)(undefined);
47
48
  const parsedSourceSetMap = (0, react_1.useMemo)(() => {
48
49
  return srcSet ? (0, utils_1.parseSrcSet)(srcSet) : new Map();
@@ -53,28 +54,47 @@ function Image(props) {
53
54
  setLightboxImage(undefined);
54
55
  }
55
56
  }, []);
56
- const handleImageClick = (0, react_1.useCallback)((src) => {
57
+ const handleImageClick = (0, react_1.useCallback)((src, trigger) => {
57
58
  if (!withLightbox || lightboxImage) {
58
59
  return;
59
60
  }
61
+ lightboxTriggerRef.current = trigger;
60
62
  setLightboxImage(src);
61
63
  }, [withLightbox, lightboxImage]);
64
+ const getLightboxTriggerProps = (imageSrc) => withLightbox
65
+ ? {
66
+ role: 'button',
67
+ tabIndex: 0,
68
+ 'aria-label': alt ? undefined : 'Open image',
69
+ onClick: (e) => handleImageClick(imageSrc, e.currentTarget),
70
+ onKeyDown: (e) => {
71
+ if (e.key === 'Enter' || e.key === ' ') {
72
+ e.preventDefault();
73
+ handleImageClick(imageSrc, e.currentTarget);
74
+ }
75
+ },
76
+ }
77
+ : {};
62
78
  const handleCloseLightbox = (0, react_1.useCallback)(() => {
63
79
  setLightboxImage(undefined);
64
80
  }, []);
65
81
  (0, hooks_1.useModalScrollLock)(!!lightboxImage);
66
82
  (0, react_1.useEffect)(() => {
67
- var _a;
83
+ var _a, _b;
68
84
  if (lightboxImage) {
69
85
  (_a = lightboxContainerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
70
86
  }
87
+ else {
88
+ (_b = lightboxTriggerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
89
+ lightboxTriggerRef.current = null;
90
+ }
71
91
  }, [lightboxImage]);
72
92
  const combinedStyles = Object.assign(Object.assign(Object.assign({}, (withLightbox && { cursor: 'pointer' })), (border && { border })), (typeof style === 'string' ? (0, utils_1.parseStyleString)(style) : style));
73
93
  const lightboxOverlayStyles = typeof lightboxStyle === 'string' ? (0, utils_1.parseStyleString)(lightboxStyle) : lightboxStyle;
74
- const images = src ? (react_1.default.createElement("img", { src: src, alt: alt, className: className, width: width, height: height, style: combinedStyles, onClick: () => handleImageClick(src) })) : (Array.from(parsedSourceSetMap).map(([key, value]) => (react_1.default.createElement(ColorModeAwareImage, { key: key, $colorMode: key, src: value, alt: alt, className: className, width: width, height: height, $withLightbox: withLightbox, style: combinedStyles, onClick: () => handleImageClick(value) }))));
94
+ const images = src ? (react_1.default.createElement("img", Object.assign({ src: src, alt: alt, className: className, width: width, height: height, style: combinedStyles }, getLightboxTriggerProps(src)))) : (Array.from(parsedSourceSetMap).map(([key, value]) => (react_1.default.createElement(ColorModeAwareImage, Object.assign({ key: key, $colorMode: key, src: value, alt: alt, className: className, width: width, height: height, $withLightbox: withLightbox, style: combinedStyles }, getLightboxTriggerProps(value))))));
75
95
  const hasGallery = Array.isArray(galleryImages) && galleryImages.length > 0;
76
96
  const visibleGalleryImages = hasGallery ? galleryImages.slice(0, 3) : [];
77
- const gallery = hasGallery ? (react_1.default.createElement(GalleryRow, null, visibleGalleryImages.map((galleryImageSrc, index) => (react_1.default.createElement("img", { key: `${galleryImageSrc}-${index}`, src: galleryImageSrc, alt: alt, style: withLightbox ? { cursor: 'pointer' } : undefined, onClick: () => handleImageClick(galleryImageSrc) }))))) : null;
97
+ const gallery = hasGallery ? (react_1.default.createElement(GalleryRow, null, visibleGalleryImages.map((galleryImageSrc, index) => (react_1.default.createElement("img", Object.assign({ key: `${galleryImageSrc}-${index}`, src: galleryImageSrc, alt: alt, style: withLightbox ? { cursor: 'pointer' } : undefined }, getLightboxTriggerProps(galleryImageSrc))))))) : null;
78
98
  const hasCaption = Boolean(caption);
79
99
  const hasWrapper = Boolean(framed || hasCaption || hasGallery);
80
100
  const wrapperContent = hasGallery ? gallery : images;
@@ -0,0 +1,10 @@
1
+ import { type JSX } from 'react';
2
+ import type { ToolCall } from '../../core/types';
3
+ export type SearchAiActivityProps = {
4
+ /** One run of consecutive tool calls; an empty list means the assistant has not called a tool yet. */
5
+ toolCalls: ToolCall[];
6
+ /** The assistant works on this group now; once it moves on, a call without a result counts as finished. */
7
+ isActive: boolean;
8
+ className?: string;
9
+ };
10
+ export declare function SearchAiActivity({ toolCalls, isActive, className, }: SearchAiActivityProps): JSX.Element;