@redocly/theme 0.71.0-next.0 → 0.71.0-next.2

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.
@@ -1,4 +1,4 @@
1
- import type { CSSProperties, ReactNode, PropsWithChildren, JSX } from 'react';
1
+ import type { KeyboardEvent, MouseEvent, CSSProperties, ReactNode, PropsWithChildren, JSX } from 'react';
2
2
  import type { LinkProps } from '../../core/types';
3
3
  export type DropdownMenuItemProps = Partial<Pick<LinkProps, 'to' | 'target' | 'external'>> & {
4
4
  prefix?: ReactNode;
@@ -12,7 +12,7 @@ export type DropdownMenuItemProps = Partial<Pick<LinkProps, 'to' | 'target' | 'e
12
12
  separator?: boolean;
13
13
  disabled?: boolean;
14
14
  dangerous?: boolean;
15
- onAction?: () => void;
15
+ onAction?: (event: KeyboardEvent | MouseEvent) => void;
16
16
  active?: boolean;
17
17
  };
18
18
  export declare function DropdownMenuItem({ children, content, active, onAction, to, dangerous, prefix, suffix, disabled, separator, dataAttributes, className, separatorLine, style, role, ...otherProps }: PropsWithChildren<DropdownMenuItemProps>): JSX.Element;
@@ -53,12 +53,12 @@ const styled_components_1 = __importStar(require("styled-components"));
53
53
  const Link_1 = require("../../components/Link/Link");
54
54
  function DropdownMenuItem(_a) {
55
55
  var { children, content, active, onAction, to, dangerous, prefix, suffix, disabled, separator, dataAttributes, className, separatorLine, style, role = 'menuitem' } = _a, otherProps = __rest(_a, ["children", "content", "active", "onAction", "to", "dangerous", "prefix", "suffix", "disabled", "separator", "dataAttributes", "className", "separatorLine", "style", "role"]);
56
- const handleClick = () => {
57
- onAction === null || onAction === void 0 ? void 0 : onAction();
56
+ const handleClick = (event) => {
57
+ onAction === null || onAction === void 0 ? void 0 : onAction(event);
58
58
  };
59
59
  const handleKeyDown = (event) => {
60
60
  if (event.key === 'Enter' || event.key === ' ') {
61
- onAction === null || onAction === void 0 ? void 0 : onAction();
61
+ onAction === null || onAction === void 0 ? void 0 : onAction(event);
62
62
  }
63
63
  };
64
64
  className = className || '' + (active ? ' active' : '');
@@ -40,6 +40,10 @@ exports.AI_SEARCH_ERROR_CONFIG = {
40
40
  exports.AI_SEARCH_MAX_MESSAGE_LENGTH = 45000;
41
41
  exports.SEARCH_DEBOUNCE_TIME_MS = 500;
42
42
  exports.DEFAULT_KEYBOARD_SHORTCUTS = '⌘+K,CTRL+K';
43
+ const discoverToolsDisplayText = {
44
+ inProgressText: 'Discovering available tools...',
45
+ completedText: 'Discovered available tools',
46
+ };
43
47
  exports.TOOL_CALL_DISPLAY_TEXT = {
44
48
  [search_1.ToolCallName.SearchDocumentation]: {
45
49
  inProgressText: 'Searching documentation...',
@@ -69,10 +73,8 @@ exports.TOOL_CALL_DISPLAY_TEXT = {
69
73
  inProgressText: 'Running code...',
70
74
  completedText: 'Ran code',
71
75
  },
72
- [search_1.ToolCallName.DescribeTools]: {
73
- inProgressText: 'Discovering available tools...',
74
- completedText: 'Discovered available tools',
75
- },
76
+ [search_1.ToolCallName.DescribeTools]: discoverToolsDisplayText,
77
+ [search_1.ToolCallName.Discover]: discoverToolsDisplayText,
76
78
  [search_1.ToolCallName.ContactSupport]: {
77
79
  inProgressText: 'Opening the contact support option...',
78
80
  completedText: 'Offered to contact support',
@@ -153,5 +153,6 @@ export declare enum ToolCallName {
153
153
  GetFullApiDescription = "get-full-api-description",
154
154
  Execute = "execute",
155
155
  DescribeTools = "describe-tools",
156
+ Discover = "discover",
156
157
  ContactSupport = "contact-support"
157
158
  }
@@ -16,6 +16,7 @@ var ToolCallName;
16
16
  ToolCallName["GetFullApiDescription"] = "get-full-api-description";
17
17
  ToolCallName["Execute"] = "execute";
18
18
  ToolCallName["DescribeTools"] = "describe-tools";
19
+ ToolCallName["Discover"] = "discover";
19
20
  ToolCallName["ContactSupport"] = "contact-support";
20
21
  })(ToolCallName || (exports.ToolCallName = ToolCallName = {}));
21
22
  //# sourceMappingURL=search.js.map
@@ -1 +1,6 @@
1
1
  export declare function extendDetailsBehaviour(): () => void;
2
+ /**
3
+ * The id a `<details>` element without one gets from its summary text; a URL hash with that id
4
+ * opens it. Empty for an empty summary.
5
+ */
6
+ export declare function detailsAnchorId(summaryText: string): string;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extendDetailsBehaviour = extendDetailsBehaviour;
4
+ exports.detailsAnchorId = detailsAnchorId;
4
5
  function extendDetailsBehaviour() {
5
6
  enhanceDetails();
6
7
  openDetailsFromHash();
@@ -9,6 +10,13 @@ function extendDetailsBehaviour() {
9
10
  window.removeEventListener('hashchange', openDetailsFromHash);
10
11
  };
11
12
  }
13
+ /**
14
+ * The id a `<details>` element without one gets from its summary text; a URL hash with that id
15
+ * opens it. Empty for an empty summary.
16
+ */
17
+ function detailsAnchorId(summaryText) {
18
+ return summaryText.replace(/\s+/g, '-').toLowerCase();
19
+ }
12
20
  function openDetailsAndScroll(detailsElement) {
13
21
  detailsElement.setAttribute('open', '');
14
22
  setTimeout(() => {
@@ -21,11 +29,12 @@ function openDetailsAndScroll(detailsElement) {
21
29
  function enhanceDetails() {
22
30
  const existingIds = [];
23
31
  Array.from(document.getElementsByTagName('details')).forEach((detailsElement, index) => {
24
- var _a, _b;
32
+ var _a;
33
+ var _b;
25
34
  if (detailsElement.id) {
26
35
  return;
27
36
  }
28
- const generatedId = ((_b = (_a = detailsElement.querySelector('summary')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.replace(/\s+/g, '-').toLowerCase()) ||
37
+ const generatedId = detailsAnchorId((_b = (_a = detailsElement.querySelector('summary')) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : '') ||
29
38
  `details-${index}`;
30
39
  detailsElement.id = existingIds.includes(generatedId) ? `${generatedId}-${index}` : generatedId;
31
40
  existingIds.push(detailsElement.id);
@@ -40,10 +40,10 @@ function getSearchAiActivityStep(toolCall, isRunning, translate) {
40
40
  }
41
41
  function getToolCallLabel(toolCall, isCompleted, translate) {
42
42
  const detail = getToolCallDetail(toolCall);
43
- if (toolCall.name === search_1.ToolCallName.Execute && detail) {
43
+ const builtInText = search_2.TOOL_CALL_DISPLAY_TEXT[toolCall.name];
44
+ if ((toolCall.name === search_1.ToolCallName.Execute || !builtInText) && detail) {
44
45
  return { label: detail };
45
46
  }
46
- const builtInText = search_2.TOOL_CALL_DISPLAY_TEXT[toolCall.name];
47
47
  if (builtInText) {
48
48
  const text = isCompleted ? builtInText.completedText : builtInText.inProgressText;
49
49
  return detail ? { label: stripEllipsis(text), detail } : { label: text };
@@ -67,7 +67,9 @@ function getToolCallDetail(toolCall) {
67
67
  case search_1.ToolCallName.Execute:
68
68
  return getStringArg(toolCall.args, 'description');
69
69
  default:
70
- return undefined;
70
+ return search_2.TOOL_CALL_DISPLAY_TEXT[toolCall.name]
71
+ ? undefined
72
+ : getStringArg(toolCall.args, 'description');
71
73
  }
72
74
  }
73
75
  function getStringArg(args, name) {
@@ -0,0 +1,15 @@
1
+ import type { MarkdocSchemaWrapper } from '../../markdoc/tags/types';
2
+ /** The part of a node the check reads; a stored plain-JSON AST node satisfies it too. */
3
+ type VisibilityNodeLike = {
4
+ tag?: string;
5
+ attributes?: Record<string, unknown>;
6
+ };
7
+ /** True for a node whose content must never reach the rendered page. */
8
+ export declare function isForAgentsOnly(node: VisibilityNodeLike): boolean;
9
+ /**
10
+ * A `renderTag` that empties nodes hidden from the page and leaves every other tag to the
11
+ * caller's own walk. Used by the text extractors that read a raw AST, which no tag schema runs on.
12
+ */
13
+ export declare function skipAgentsOnlyContent(node: VisibilityNodeLike): string | undefined;
14
+ export declare const visibility: MarkdocSchemaWrapper;
15
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.visibility = void 0;
4
+ exports.isForAgentsOnly = isForAgentsOnly;
5
+ exports.skipAgentsOnlyContent = skipAgentsOnlyContent;
6
+ /** True for a node whose content must never reach the rendered page. */
7
+ function isForAgentsOnly(node) {
8
+ var _a;
9
+ return node.tag === 'visibility' && ((_a = node.attributes) === null || _a === void 0 ? void 0 : _a.for) === 'agents';
10
+ }
11
+ /**
12
+ * A `renderTag` that empties nodes hidden from the page and leaves every other tag to the
13
+ * caller's own walk. Used by the text extractors that read a raw AST, which no tag schema runs on.
14
+ */
15
+ function skipAgentsOnlyContent(node) {
16
+ return isForAgentsOnly(node) ? '' : undefined;
17
+ }
18
+ exports.visibility = {
19
+ schema: {
20
+ attributes: {
21
+ for: { type: String, required: true, matches: ['humans', 'agents'] },
22
+ },
23
+ transform(node, config) {
24
+ return isForAgentsOnly(node) ? [] : node.transformChildren(config);
25
+ },
26
+ renderForLlms(node, { getBody }) {
27
+ return node.attributes.for === 'humans' ? '' : getBody();
28
+ },
29
+ },
30
+ tagName: 'visibility',
31
+ };
32
+ //# sourceMappingURL=visibility.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.71.0-next.0",
3
+ "version": "0.71.0-next.2",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -22,6 +22,7 @@
22
22
  "./core/templates/*": "./lib/core/templates/*.js",
23
23
  "./core/contexts/*": "./lib/core/contexts/*.js",
24
24
  "./core/hooks/*": "./lib/core/hooks/*.js",
25
+ "./core/utils/*": "./lib/core/utils/*.js",
25
26
  "./core/hoc/*": "./lib/core/hoc/*.js",
26
27
  "./core/constants/*": "./lib/core/constants/*.js",
27
28
  "./ext/*": "./lib/ext/*.js",
@@ -68,7 +69,7 @@
68
69
  "webpack": "5.105.2"
69
70
  },
70
71
  "dependencies": {
71
- "@redocly/config": "0.65.0",
72
+ "@redocly/config": "0.66.0",
72
73
  "@tanstack/react-query": "5.62.3",
73
74
  "@tanstack/react-virtual": "3.13.0",
74
75
  "@xyflow/react": "12.8.3",
@@ -1,7 +1,14 @@
1
1
  import React from 'react';
2
2
  import styled, { css } from 'styled-components';
3
3
 
4
- import type { KeyboardEvent, CSSProperties, ReactNode, PropsWithChildren, JSX } from 'react';
4
+ import type {
5
+ KeyboardEvent,
6
+ MouseEvent,
7
+ CSSProperties,
8
+ ReactNode,
9
+ PropsWithChildren,
10
+ JSX,
11
+ } from 'react';
5
12
  import type { LinkProps } from '@redocly/theme/core/types';
6
13
 
7
14
  import { Link } from '@redocly/theme/components/Link/Link';
@@ -21,7 +28,7 @@ export type DropdownMenuItemProps = Partial<Pick<LinkProps, 'to' | 'target' | 'e
21
28
  separator?: boolean;
22
29
  disabled?: boolean;
23
30
  dangerous?: boolean;
24
- onAction?: () => void;
31
+ onAction?: (event: KeyboardEvent | MouseEvent) => void;
25
32
  active?: boolean;
26
33
  };
27
34
 
@@ -43,13 +50,13 @@ export function DropdownMenuItem({
43
50
  role = 'menuitem',
44
51
  ...otherProps
45
52
  }: PropsWithChildren<DropdownMenuItemProps>): JSX.Element {
46
- const handleClick = () => {
47
- onAction?.();
53
+ const handleClick = (event: MouseEvent) => {
54
+ onAction?.(event);
48
55
  };
49
56
 
50
57
  const handleKeyDown = (event: KeyboardEvent) => {
51
58
  if (event.key === 'Enter' || event.key === ' ') {
52
- onAction?.();
59
+ onAction?.(event);
53
60
  }
54
61
  };
55
62
 
@@ -48,6 +48,11 @@ export const SEARCH_DEBOUNCE_TIME_MS = 500;
48
48
 
49
49
  export const DEFAULT_KEYBOARD_SHORTCUTS = '⌘+K,CTRL+K';
50
50
 
51
+ const discoverToolsDisplayText = {
52
+ inProgressText: 'Discovering available tools...',
53
+ completedText: 'Discovered available tools',
54
+ };
55
+
51
56
  export const TOOL_CALL_DISPLAY_TEXT: Partial<
52
57
  Record<string, { inProgressText: string; completedText: string }>
53
58
  > = {
@@ -79,10 +84,8 @@ export const TOOL_CALL_DISPLAY_TEXT: Partial<
79
84
  inProgressText: 'Running code...',
80
85
  completedText: 'Ran code',
81
86
  },
82
- [ToolCallName.DescribeTools]: {
83
- inProgressText: 'Discovering available tools...',
84
- completedText: 'Discovered available tools',
85
- },
87
+ [ToolCallName.DescribeTools]: discoverToolsDisplayText,
88
+ [ToolCallName.Discover]: discoverToolsDisplayText,
86
89
  [ToolCallName.ContactSupport]: {
87
90
  inProgressText: 'Opening the contact support option...',
88
91
  completedText: 'Offered to contact support',
@@ -158,5 +158,6 @@ export enum ToolCallName {
158
158
  GetFullApiDescription = 'get-full-api-description',
159
159
  Execute = 'execute',
160
160
  DescribeTools = 'describe-tools',
161
+ Discover = 'discover',
161
162
  ContactSupport = 'contact-support',
162
163
  }
@@ -8,6 +8,14 @@ export function extendDetailsBehaviour() {
8
8
  };
9
9
  }
10
10
 
11
+ /**
12
+ * The id a `<details>` element without one gets from its summary text; a URL hash with that id
13
+ * opens it. Empty for an empty summary.
14
+ */
15
+ export function detailsAnchorId(summaryText: string): string {
16
+ return summaryText.replace(/\s+/g, '-').toLowerCase();
17
+ }
18
+
11
19
  function openDetailsAndScroll(detailsElement: Element) {
12
20
  detailsElement.setAttribute('open', '');
13
21
  setTimeout(() => {
@@ -26,7 +34,7 @@ function enhanceDetails() {
26
34
  }
27
35
 
28
36
  const generatedId =
29
- detailsElement.querySelector('summary')?.textContent?.replace(/\s+/g, '-').toLowerCase() ||
37
+ detailsAnchorId(detailsElement.querySelector('summary')?.textContent ?? '') ||
30
38
  `details-${index}`;
31
39
 
32
40
  detailsElement.id = existingIds.includes(generatedId) ? `${generatedId}-${index}` : generatedId;
@@ -66,10 +66,10 @@ function getToolCallLabel(
66
66
  translate: TFunction,
67
67
  ): { label: string; detail?: string } {
68
68
  const detail = getToolCallDetail(toolCall);
69
- if (toolCall.name === ToolCallName.Execute && detail) {
69
+ const builtInText = TOOL_CALL_DISPLAY_TEXT[toolCall.name];
70
+ if ((toolCall.name === ToolCallName.Execute || !builtInText) && detail) {
70
71
  return { label: detail };
71
72
  }
72
- const builtInText = TOOL_CALL_DISPLAY_TEXT[toolCall.name];
73
73
  if (builtInText) {
74
74
  const text = isCompleted ? builtInText.completedText : builtInText.inProgressText;
75
75
  return detail ? { label: stripEllipsis(text), detail } : { label: text };
@@ -93,7 +93,9 @@ function getToolCallDetail(toolCall: ToolCall): string | undefined {
93
93
  case ToolCallName.Execute:
94
94
  return getStringArg(toolCall.args, 'description');
95
95
  default:
96
- return undefined;
96
+ return TOOL_CALL_DISPLAY_TEXT[toolCall.name]
97
+ ? undefined
98
+ : getStringArg(toolCall.args, 'description');
97
99
  }
98
100
  }
99
101
 
@@ -0,0 +1,33 @@
1
+ import type { Config, Node } from '@markdoc/markdoc';
2
+ import type { MarkdocSchemaWrapper } from '@redocly/theme/markdoc/tags/types';
3
+
4
+ /** The part of a node the check reads; a stored plain-JSON AST node satisfies it too. */
5
+ type VisibilityNodeLike = { tag?: string; attributes?: Record<string, unknown> };
6
+
7
+ /** True for a node whose content must never reach the rendered page. */
8
+ export function isForAgentsOnly(node: VisibilityNodeLike): boolean {
9
+ return node.tag === 'visibility' && node.attributes?.for === 'agents';
10
+ }
11
+
12
+ /**
13
+ * A `renderTag` that empties nodes hidden from the page and leaves every other tag to the
14
+ * caller's own walk. Used by the text extractors that read a raw AST, which no tag schema runs on.
15
+ */
16
+ export function skipAgentsOnlyContent(node: VisibilityNodeLike): string | undefined {
17
+ return isForAgentsOnly(node) ? '' : undefined;
18
+ }
19
+
20
+ export const visibility: MarkdocSchemaWrapper = {
21
+ schema: {
22
+ attributes: {
23
+ for: { type: String, required: true, matches: ['humans', 'agents'] },
24
+ },
25
+ transform(node: Node, config: Config) {
26
+ return isForAgentsOnly(node) ? [] : node.transformChildren(config);
27
+ },
28
+ renderForLlms(node: Node, { getBody }) {
29
+ return node.attributes.for === 'humans' ? '' : getBody();
30
+ },
31
+ },
32
+ tagName: 'visibility',
33
+ };