@redocly/theme 0.48.0 → 0.48.1

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 (88) hide show
  1. package/lib/components/Feedback/Mood.js +14 -9
  2. package/lib/components/Search/SearchDialog.js +9 -3
  3. package/lib/components/Search/variables.js +4 -0
  4. package/lib/components/Segmented/Segmented.d.ts +4 -4
  5. package/lib/components/Segmented/Segmented.js +4 -7
  6. package/lib/components/Tag/Tag.d.ts +1 -0
  7. package/lib/components/Tag/Tag.js +3 -2
  8. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +1 -1
  9. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +10 -5
  10. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +1 -2
  11. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.js +20 -15
  12. package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +2 -7
  13. package/lib/core/hooks/code-walkthrough/use-code-walkthrough.js +10 -3
  14. package/lib/core/hooks/code-walkthrough/use-renderable-files.d.ts +9 -0
  15. package/lib/core/hooks/code-walkthrough/use-renderable-files.js +28 -0
  16. package/lib/core/hooks/index.d.ts +1 -0
  17. package/lib/core/hooks/index.js +1 -0
  18. package/lib/core/types/l10n.d.ts +1 -1
  19. package/lib/core/utils/download-code-walkthrough.js +9 -1
  20. package/lib/core/utils/find-closest-common-directory.d.ts +6 -0
  21. package/lib/core/utils/find-closest-common-directory.js +51 -0
  22. package/lib/core/utils/get-file-icon.js +6 -0
  23. package/lib/core/utils/index.d.ts +1 -0
  24. package/lib/core/utils/index.js +1 -0
  25. package/lib/core/utils/replace-inputs-with-value.d.ts +1 -1
  26. package/lib/core/utils/replace-inputs-with-value.js +9 -10
  27. package/lib/icons/DocumentJavaIcon/DocumentJavaIcon.d.ts +9 -0
  28. package/lib/icons/DocumentJavaIcon/DocumentJavaIcon.js +22 -0
  29. package/lib/icons/DocumentJavaIcon/index.d.ts +1 -0
  30. package/lib/icons/DocumentJavaIcon/index.js +6 -0
  31. package/lib/icons/DocumentPythonIcon/DocumentPythonIcon.d.ts +9 -0
  32. package/lib/icons/DocumentPythonIcon/DocumentPythonIcon.js +23 -0
  33. package/lib/icons/DocumentPythonIcon/index.d.ts +1 -0
  34. package/lib/icons/DocumentPythonIcon/index.js +6 -0
  35. package/lib/icons/DocumentShellIcon/DocumentShellIcon.d.ts +9 -0
  36. package/lib/icons/DocumentShellIcon/DocumentShellIcon.js +22 -0
  37. package/lib/icons/DocumentShellIcon/index.d.ts +1 -0
  38. package/lib/icons/DocumentShellIcon/index.js +6 -0
  39. package/lib/icons/__tests__/IconTestUtils.d.ts +7 -0
  40. package/lib/icons/__tests__/IconTestUtils.js +33 -0
  41. package/lib/layouts/CodeWalkthroughLayout.js +4 -1
  42. package/lib/markdoc/components/CodeWalkthrough/CodeContainer.js +1 -1
  43. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +15 -2
  44. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +1 -1
  45. package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.js +29 -23
  46. package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.js +1 -1
  47. package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.js +1 -1
  48. package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +6 -3
  49. package/lib/markdoc/components/CodeWalkthrough/CodeToggle.js +1 -1
  50. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +1 -1
  51. package/lib/markdoc/components/CodeWalkthrough/Input.js +4 -2
  52. package/lib/markdoc/tags/code-walkthrough.js +5 -0
  53. package/package.json +3 -3
  54. package/src/components/Feedback/Mood.tsx +16 -7
  55. package/src/components/Search/SearchDialog.tsx +52 -36
  56. package/src/components/Search/variables.ts +4 -0
  57. package/src/components/Segmented/Segmented.tsx +10 -10
  58. package/src/components/Tag/Tag.tsx +1 -1
  59. package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +9 -3
  60. package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +30 -18
  61. package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +13 -13
  62. package/src/core/hooks/code-walkthrough/use-renderable-files.ts +51 -0
  63. package/src/core/hooks/index.ts +1 -0
  64. package/src/core/types/l10n.ts +3 -1
  65. package/src/core/utils/download-code-walkthrough.ts +14 -2
  66. package/src/core/utils/find-closest-common-directory.ts +51 -0
  67. package/src/core/utils/get-file-icon.ts +7 -0
  68. package/src/core/utils/index.ts +1 -0
  69. package/src/core/utils/replace-inputs-with-value.ts +12 -9
  70. package/src/icons/DocumentJavaIcon/DocumentJavaIcon.tsx +33 -0
  71. package/src/icons/DocumentJavaIcon/index.ts +1 -0
  72. package/src/icons/DocumentPythonIcon/DocumentPythonIcon.tsx +37 -0
  73. package/src/icons/DocumentPythonIcon/index.ts +1 -0
  74. package/src/icons/DocumentShellIcon/DocumentShellIcon.tsx +33 -0
  75. package/src/icons/DocumentShellIcon/index.ts +1 -0
  76. package/src/icons/__tests__/IconTestUtils.tsx +31 -0
  77. package/src/layouts/CodeWalkthroughLayout.tsx +5 -1
  78. package/src/markdoc/components/CodeWalkthrough/CodeContainer.tsx +1 -0
  79. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +19 -3
  80. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -1
  81. package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +64 -47
  82. package/src/markdoc/components/CodeWalkthrough/CodePanelPreview.tsx +1 -1
  83. package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +1 -1
  84. package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +6 -2
  85. package/src/markdoc/components/CodeWalkthrough/CodeToggle.tsx +1 -1
  86. package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +4 -1
  87. package/src/markdoc/components/CodeWalkthrough/Input.tsx +4 -2
  88. package/src/markdoc/tags/code-walkthrough.ts +5 -0
@@ -22,15 +22,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.MOOD_STATES = void 0;
30
27
  exports.Mood = Mood;
31
28
  const React = __importStar(require("react"));
32
29
  const react_1 = require("react");
33
- const styled_components_1 = __importDefault(require("styled-components"));
30
+ const styled_components_1 = __importStar(require("styled-components"));
34
31
  const Reasons_1 = require("../../components/Feedback/Reasons");
35
32
  const hooks_1 = require("../../core/hooks");
36
33
  const RadioCheckButtonIcon_1 = require("../../icons/RadioCheckButtonIcon/RadioCheckButtonIcon");
@@ -134,14 +131,14 @@ function Mood({ settings, onSubmit, className }) {
134
131
  if (isSubmitted) {
135
132
  return (React.createElement(MoodWrapper, { "data-component-name": "Feedback/Mood" },
136
133
  React.createElement(StyledFormMandatoryFields, null,
137
- React.createElement(Label, { "data-translation-key": "feedback.settings.submitText" }, submitText ||
134
+ React.createElement(Label, { standAlone: true, "data-translation-key": "feedback.settings.submitText" }, submitText ||
138
135
  translate('feedback.settings.submitText', 'Thank you for helping improve our documentation!')),
139
136
  React.createElement(RadioCheckButtonIcon_1.RadioCheckButtonIcon, null))));
140
137
  }
141
138
  return (React.createElement(MoodWrapper, { "data-component-name": "Feedback/Mood", className: className },
142
139
  React.createElement(StyledForm, { onSubmit: onSubmitMoodForm },
143
140
  React.createElement(StyledFormMandatoryFields, null,
144
- React.createElement(Label, { "data-translation-key": "feedback.settings.label" }, label || translate('feedback.settings.label', 'Was this helpful?')),
141
+ React.createElement(Label, { standAlone: true, "data-translation-key": "feedback.settings.label" }, label || translate('feedback.settings.label', 'Was this helpful?')),
145
142
  React.createElement(StyledMandatoryFieldContainer, null,
146
143
  React.createElement(Button_1.Button, { "aria-label": MOOD_STATES.DISSATISFIED, type: "button", size: "medium", variant: score === MOOD_STATES.DISSATISFIED ? 'primary' : 'secondary', tone: score === MOOD_STATES.DISSATISFIED ? 'danger' : 'default', onClick: () => {
147
144
  setScore(MOOD_STATES.DISSATISFIED);
@@ -189,9 +186,17 @@ const MoodWrapper = styled_components_1.default.div `
189
186
  const Label = styled_components_1.default.h4 `
190
187
  font-family: var(--feedback-font-family);
191
188
  font-weight: var(--font-weight-regular);
192
- font-size: var(--feedback-header-font-size);
193
- line-height: var(--feedback-header-line-height);
194
- color: var(--feedback-header-text-color);
189
+ font-size: var(--feedback-font-size);
190
+ line-height: var(--feedback-line-height);
191
+ color: var(--feedback-text-color);
192
+
193
+ ${({ standAlone = false }) => standAlone &&
194
+ (0, styled_components_1.css) `
195
+ font-size: var(--feedback-header-font-size);
196
+ line-height: var(--feedback-header-line-height);
197
+ color: var(--feedback-header-text-color);
198
+ `}
199
+
195
200
  margin: 0;
196
201
  `;
197
202
  const ButtonsContainer = styled_components_1.default.div `
@@ -120,7 +120,7 @@ function SearchDialog({ onClose, className }) {
120
120
  setQuery('');
121
121
  aiSearch.askQuestion(query);
122
122
  }
123
- } }, translate('search.aiButton', 'Search with AI'))) : null,
123
+ } }, translate('search.ai.button', 'Search with AI'))) : null,
124
124
  showSearchFilterButton && (react_1.default.createElement(SearchFilterToggleButton, { icon: react_1.default.createElement(SettingsIcon_1.SettingsIcon, null), onClick: onFilterToggle }))))),
125
125
  react_1.default.createElement(SearchDialogBody, null, mode === 'search' ? (react_1.default.createElement(react_1.default.Fragment, null,
126
126
  react_1.default.createElement(SearchDialogBodyMainView, null,
@@ -139,7 +139,7 @@ function SearchDialog({ onClose, className }) {
139
139
  react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))),
140
140
  advancedSearch && mode === 'search' && isFilterOpen && (react_1.default.createElement(SearchDialogBodyFilterView, null,
141
141
  react_1.default.createElement(SearchFilter_1.SearchFilter, { facets: facets, filter: filter, query: query, quickFilterFields: [groupField], onFilterChange: onFilterChange, onFilterReset: onFilterReset, onFacetReset: onFacetReset }))))) : (react_1.default.createElement(SearchAiResponse_1.SearchAiResponse, { question: aiSearch.question, isGeneratingResponse: aiSearch.isGeneratingResponse, response: aiSearch.response, resources: aiSearch.resources }))),
142
- mode === 'search' && (react_1.default.createElement(SearchDialogFooter, null,
142
+ react_1.default.createElement(SearchDialogFooter, null, mode === 'ai-dialog' ? (react_1.default.createElement(AiDisclaimer, null, translate('search.ai.disclaimer', 'AI search might provide incomplete or incorrect results. Verify important information.'))) : (react_1.default.createElement(react_1.default.Fragment, null,
143
143
  react_1.default.createElement(SearchShortcuts, null,
144
144
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "search.keys.navigate", combination: "Tab", text: translate('search.keys.navigate', 'to navigate') }),
145
145
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "search.keys.select", combination: "\u23CE", text: translate('search.keys.select', 'to select') }),
@@ -147,7 +147,7 @@ function SearchDialog({ onClose, className }) {
147
147
  isSearchLoading && (react_1.default.createElement(SearchLoading, null,
148
148
  react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "16px", color: "var(--search-input-icon-color)" }),
149
149
  translate('search.loading', 'Loading...'))),
150
- react_1.default.createElement(SearchCancelButton, { "data-translation-key": "search.cancel", variant: "secondary", size: "small", onClick: onClose }, translate('search.cancel', 'Cancel')))))));
150
+ react_1.default.createElement(SearchCancelButton, { "data-translation-key": "search.cancel", variant: "secondary", size: "small", onClick: onClose }, translate('search.cancel', 'Cancel'))))))));
151
151
  }
152
152
  const SearchOverlay = styled_components_1.default.div `
153
153
  position: fixed;
@@ -296,4 +296,10 @@ const SearchHeaderButtons = styled_components_1.default.div `
296
296
  padding-left: var(--search-header-buttons-padding-left);
297
297
  border-left: var(--search-header-buttons-border-left);
298
298
  `;
299
+ const AiDisclaimer = styled_components_1.default.div `
300
+ font-size: var(--search-ai-disclaimer-font-size);
301
+ line-height: var(--search-ai-disclaimer-line-height);
302
+ color: var(--search-ai-disclaimer-text-color);
303
+ margin: 0 auto;
304
+ `;
299
305
  //# sourceMappingURL=SearchDialog.js.map
@@ -178,6 +178,10 @@ exports.search = (0, styled_components_1.css) `
178
178
  --search-ai-resource-tag-text-color: var(--text-color-secondary);
179
179
  --search-ai-resource-tag-icon-color: var(--text-color-secondary);
180
180
 
181
+ --search-ai-disclaimer-font-size: var(--font-size-sm);
182
+ --search-ai-disclaimer-line-height: var(--line-height-sm);
183
+ --search-ai-disclaimer-text-color: var(--text-color-secondary);
184
+
181
185
  // @tokens End
182
186
  `;
183
187
  //# sourceMappingURL=variables.js.map
@@ -1,4 +1,4 @@
1
- import type { ReactElement } from 'react';
1
+ import type { ForwardedRef, ReactElement } from 'react';
2
2
  import type { SelectOption } from '../../core/types/select';
3
3
  export type SegmentedProps<T> = {
4
4
  options: SelectOption<T>[];
@@ -7,6 +7,6 @@ export type SegmentedProps<T> = {
7
7
  className?: string;
8
8
  size?: 'regular' | 'small';
9
9
  };
10
- declare function SegmentedComponent<T>({ options, onChange, value, className, size, }: SegmentedProps<T>): ReactElement;
11
- export declare const Segmented: typeof SegmentedComponent;
12
- export {};
10
+ export declare const Segmented: <T>(props: SegmentedProps<T> & {
11
+ ref?: ForwardedRef<HTMLDivElement>;
12
+ }) => ReactElement;
@@ -22,18 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.Segmented = void 0;
30
- const react_1 = __importDefault(require("react"));
27
+ const react_1 = __importStar(require("react"));
31
28
  const styled_components_1 = __importStar(require("styled-components"));
32
29
  const typedMemo_1 = require("../../core/hoc/typedMemo");
33
- function SegmentedComponent({ options, onChange, value, className = '', size = 'regular', }) {
34
- return (react_1.default.createElement(SegmentedGroup, { "data-component-name": "Segmented/Segmented", className: `tag-grey ${size} ${className}`, role: "tablist" }, options.map((opt) => (react_1.default.createElement(SegmentedItem, { key: opt.label, role: "tab", title: opt.label, onClick: () => onChange(opt), "$isActive": value == opt.value, "$size": size }, opt.label)))));
30
+ function SegmentedComponent({ options, onChange, value, className = '', size = 'regular' }, ref) {
31
+ return (react_1.default.createElement(SegmentedGroup, { ref: ref, "data-component-name": "Segmented/Segmented", className: `tag-grey ${size} ${className}`, role: "tablist" }, options.map((opt) => (react_1.default.createElement(SegmentedItem, { key: opt.label, role: "tab", title: opt.label, onClick: () => onChange(opt), "$isActive": value == opt.value, "$size": size }, opt.label)))));
35
32
  }
36
- exports.Segmented = (0, typedMemo_1.typedMemo)(SegmentedComponent);
33
+ exports.Segmented = (0, typedMemo_1.typedMemo)((0, react_1.forwardRef)(SegmentedComponent));
37
34
  const SegmentedGroup = styled_components_1.default.div `
38
35
  display: flex;
39
36
  background: var(--segmented-buttons-bg-color-main);
@@ -21,4 +21,5 @@ export type TagProps = {
21
21
  onClose?: (event: React.MouseEvent) => void;
22
22
  };
23
23
  export declare function Tag({ children, color, icon, active, closable, onClick, onClose, size, borderless, withStatusDot, statusDotColor, ...otherProps }: TagProps): JSX.Element;
24
+ export declare const ContentWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
24
25
  export {};
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ContentWrapper = void 0;
17
18
  exports.Tag = Tag;
18
19
  const react_1 = __importDefault(require("react"));
19
20
  const styled_components_1 = __importDefault(require("styled-components"));
@@ -23,14 +24,14 @@ function Tag(_a) {
23
24
  var { children, color, icon, active, closable, onClick, onClose, size, borderless, withStatusDot, statusDotColor = 'var(--tag-status-dot-color-default)' } = _a, otherProps = __rest(_a, ["children", "color", "icon", "active", "closable", "onClick", "onClose", "size", "borderless", "withStatusDot", "statusDotColor"]);
24
25
  return (react_1.default.createElement(TagWrapper, Object.assign({ "data-component-name": "Tag/Tag", borderless: borderless, color: color, size: size, onClick: onClick, hasCloseButton: closable }, otherProps),
25
26
  withStatusDot ? react_1.default.createElement(StatusDot, { color: statusDotColor }) : icon ? icon : null,
26
- react_1.default.createElement(ContentWrapper, null, children),
27
+ react_1.default.createElement(exports.ContentWrapper, null, children),
27
28
  closable && (react_1.default.createElement(CloseButton, { onClick: (event) => {
28
29
  onClose === null || onClose === void 0 ? void 0 : onClose(event);
29
30
  } },
30
31
  react_1.default.createElement(CloseIcon_1.CloseIcon, null))),
31
32
  active && react_1.default.createElement(ActiveIcon, null)));
32
33
  }
33
- const ContentWrapper = styled_components_1.default.div `
34
+ exports.ContentWrapper = styled_components_1.default.div `
34
35
  display: inline-flex;
35
36
  align-items: center;
36
37
  justify-content: center;
@@ -19,4 +19,4 @@ export type WalkthroughControlsState = {
19
19
  getFileText: (file: CodeWalkthroughFile) => string;
20
20
  populateInputsWithValue: (node: string) => string;
21
21
  };
22
- export declare function useCodeWalkthroughControls(filters: Record<string, CodeWalkthroughFilter>, inputs: InputsMarkdocAttr, toggles: TogglesMarkdocAttr): WalkthroughControlsState;
22
+ export declare function useCodeWalkthroughControls(filters: Record<string, CodeWalkthroughFilter>, inputs: InputsMarkdocAttr, toggles: TogglesMarkdocAttr, enableDeepLink: boolean): WalkthroughControlsState;
@@ -9,14 +9,14 @@ const defaultControlsValues = {
9
9
  toggle: false,
10
10
  filter: '',
11
11
  };
12
- function useCodeWalkthroughControls(filters, inputs, toggles) {
12
+ function useCodeWalkthroughControls(filters, inputs, toggles, enableDeepLink) {
13
13
  const location = (0, react_router_dom_1.useLocation)();
14
14
  const navigate = (0, react_router_dom_1.useNavigate)();
15
15
  const searchParams = (0, react_1.useMemo)(() => new URLSearchParams(location.search), [location.search]);
16
16
  const [togglesState, setTogglesState] = (0, react_1.useState)(() => {
17
17
  const initialState = {};
18
18
  for (const [id, toggle] of Object.entries(toggles)) {
19
- initialState[id] = Object.assign(Object.assign({}, toggle), { render: true, type: 'toggle', value: searchParams.get(id) === 'true' });
19
+ initialState[id] = Object.assign(Object.assign({}, toggle), { render: true, type: 'toggle', value: enableDeepLink ? searchParams.get(id) === 'true' : false });
20
20
  }
21
21
  return initialState;
22
22
  });
@@ -44,9 +44,10 @@ function useCodeWalkthroughControls(filters, inputs, toggles) {
44
44
  }
45
45
  };
46
46
  const [inputsState, setInputsState] = (0, react_1.useState)(() => {
47
+ var _a;
47
48
  const initialState = {};
48
49
  for (const [id, input] of Object.entries(inputs)) {
49
- initialState[id] = Object.assign(Object.assign({}, input), { render: true, type: 'input', value: searchParams.get(id) || input.value });
50
+ initialState[id] = Object.assign(Object.assign({}, input), { render: true, type: 'input', value: enableDeepLink ? ((_a = searchParams.get(id)) !== null && _a !== void 0 ? _a : input.value) : input.value });
50
51
  }
51
52
  return initialState;
52
53
  });
@@ -74,10 +75,11 @@ function useCodeWalkthroughControls(filters, inputs, toggles) {
74
75
  }
75
76
  };
76
77
  const [filtersState, setFiltersState] = (0, react_1.useState)(() => {
77
- var _a, _b;
78
+ var _a, _b, _c;
78
79
  const initialState = {};
79
80
  for (const [id, filter] of Object.entries(filters)) {
80
- initialState[id] = Object.assign(Object.assign({}, filter), { render: true, type: 'filter', value: searchParams.get(id) || ((_b = (_a = filter === null || filter === void 0 ? void 0 : filter.items) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value) || '' });
81
+ const defaultValue = ((_b = (_a = filter === null || filter === void 0 ? void 0 : filter.items) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value) || '';
82
+ initialState[id] = Object.assign(Object.assign({}, filter), { render: true, type: 'filter', value: enableDeepLink ? ((_c = searchParams.get(id)) !== null && _c !== void 0 ? _c : defaultValue) : defaultValue });
81
83
  }
82
84
  return initialState;
83
85
  });
@@ -157,6 +159,9 @@ function useCodeWalkthroughControls(filters, inputs, toggles) {
157
159
  * Update the URL search params with the current state of the filters and inputs
158
160
  */
159
161
  (0, react_1.useEffect)(() => {
162
+ if (!enableDeepLink) {
163
+ return;
164
+ }
160
165
  const newSearchParams = new URLSearchParams(Array.from(searchParams.entries()));
161
166
  for (const [id, { value }] of Object.entries(state)) {
162
167
  if (value) {
@@ -1,7 +1,6 @@
1
1
  import type { CodeWalkthroughStepAttr } from '@redocly/config';
2
2
  type ActiveStep = string | null;
3
3
  type CodeWalkthroughStep = CodeWalkthroughStepAttr & {
4
- active?: boolean;
5
4
  compRef?: HTMLElement;
6
5
  };
7
6
  export type WalkthroughStepsState = {
@@ -12,5 +11,5 @@ export type WalkthroughStepsState = {
12
11
  lockObserver?: React.MutableRefObject<boolean>;
13
12
  filtersElementRef?: React.RefObject<HTMLDivElement>;
14
13
  };
15
- export declare function useCodeWalkthroughSteps(steps: CodeWalkthroughStep[]): WalkthroughStepsState;
14
+ export declare function useCodeWalkthroughSteps(steps: CodeWalkthroughStep[], enableDeepLink: boolean): WalkthroughStepsState;
16
15
  export {};
@@ -5,7 +5,7 @@ const react_1 = require("react");
5
5
  const react_router_dom_1 = require("react-router-dom");
6
6
  const utils_1 = require("../../../core/utils");
7
7
  const constants_1 = require("../../../core/constants");
8
- function useCodeWalkthroughSteps(steps) {
8
+ function useCodeWalkthroughSteps(steps, enableDeepLink) {
9
9
  const location = (0, react_router_dom_1.useLocation)();
10
10
  const navigate = (0, react_router_dom_1.useNavigate)();
11
11
  const searchParams = (0, react_1.useMemo)(() => new URLSearchParams(location.search), [location.search]);
@@ -14,7 +14,7 @@ function useCodeWalkthroughSteps(steps) {
14
14
  const lockObserver = (0, react_1.useRef)(false);
15
15
  // Track observed elements in case new observer needs to be created
16
16
  const observedElementsRef = (0, react_1.useRef)(new Set());
17
- const [activeStep, setActiveStep] = (0, react_1.useState)(searchParams.get(constants_1.ACTIVE_STEP_QUERY_PARAM));
17
+ const [activeStep, setActiveStep] = (0, react_1.useState)(enableDeepLink ? searchParams.get(constants_1.ACTIVE_STEP_QUERY_PARAM) : null);
18
18
  const register = (0, react_1.useCallback)((element) => {
19
19
  // for some reason, the observer is not ready immediately
20
20
  setTimeout(() => {
@@ -43,27 +43,29 @@ function useCodeWalkthroughSteps(steps) {
43
43
  if (lockObserver.current) {
44
44
  return;
45
45
  }
46
- const stepsEntries = [];
46
+ const renderedSteps = steps.filter((step) => Boolean(step.compRef));
47
+ if (renderedSteps.length < 2) {
48
+ setActiveStep(((_a = renderedSteps[0]) === null || _a === void 0 ? void 0 : _a.id) || null);
49
+ return;
50
+ }
47
51
  for (const entry of entries) {
48
- const { target } = entry;
49
- const stepKey = Number((_a = target === null || target === void 0 ? void 0 : target.dataset) === null || _a === void 0 ? void 0 : _a.stepKey);
50
- const stepActive = ((_b = target === null || target === void 0 ? void 0 : target.dataset) === null || _b === void 0 ? void 0 : _b.stepActive) === 'true';
52
+ const stepKey = Number((_c = (_b = entry.target) === null || _b === void 0 ? void 0 : _b.dataset) === null || _c === void 0 ? void 0 : _c.stepKey);
51
53
  if (!Number.isInteger(stepKey) || stepKey < 0) {
52
54
  continue;
53
55
  }
56
+ const { intersectionRatio, boundingClientRect, rootBounds, isIntersecting } = entry;
54
57
  const step = steps[stepKey];
55
- step.active = stepActive;
56
- stepsEntries.push(entry);
57
- }
58
- for (const stepEntry of stepsEntries) {
59
- const { target, intersectionRatio, boundingClientRect, rootBounds, isIntersecting } = stepEntry;
60
- const stepKey = Number((_c = target === null || target === void 0 ? void 0 : target.dataset) === null || _c === void 0 ? void 0 : _c.stepKey);
61
- const step = steps[stepKey];
62
- const renderedSteps = steps.filter((step) => Boolean(step.compRef));
63
58
  const stepIndex = renderedSteps.findIndex((renderedStep) => renderedStep.stepKey === step.stepKey);
64
59
  const { next } = (0, utils_1.getAdjacentValues)(renderedSteps, stepIndex);
65
60
  const intersectionAtTop = (rootBounds === null || rootBounds === void 0 ? void 0 : rootBounds.bottom) !== undefined && boundingClientRect.top < rootBounds.top;
66
61
  const stepGoesIn = isIntersecting;
62
+ if (intersectionRatio > 0.8 &&
63
+ intersectionRatio < 1 &&
64
+ intersectionAtTop &&
65
+ activeStep === null) {
66
+ setActiveStep(step.id);
67
+ break;
68
+ }
67
69
  if (intersectionRatio < 1 && intersectionRatio !== 0 && intersectionAtTop) {
68
70
  let newStep = null;
69
71
  if (stepGoesIn) {
@@ -84,7 +86,7 @@ function useCodeWalkthroughSteps(steps) {
84
86
  const filtersElementHeight = ((_a = filtersElementRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0;
85
87
  const navbarHeight = ((_b = document.querySelector('nav')) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;
86
88
  const newObserver = new IntersectionObserver(observerCallback, {
87
- threshold: [0.8],
89
+ threshold: [0.8, 0.85, 0.9, 0.95],
88
90
  rootMargin: `-${filtersElementHeight + navbarHeight}px 0px 0px 0px`,
89
91
  });
90
92
  for (const observedElement of observedElementsRef.current) {
@@ -98,6 +100,9 @@ function useCodeWalkthroughSteps(steps) {
98
100
  * Update the URL search params with the current state of the filters and inputs
99
101
  */
100
102
  (0, react_1.useEffect)(() => {
103
+ if (!enableDeepLink) {
104
+ return;
105
+ }
101
106
  const newSearchParams = new URLSearchParams(Array.from(searchParams.entries()));
102
107
  if (activeStep) {
103
108
  newSearchParams.set(constants_1.ACTIVE_STEP_QUERY_PARAM, activeStep);
@@ -1,4 +1,4 @@
1
- import type { CodeWalkthroughFileset, CodeWalkthroughFile, CodeWalkthroughStepAttr, CodeWalkthroughFilter, InputsMarkdocAttr, TogglesMarkdocAttr } from '@redocly/config';
1
+ import type { CodeWalkthroughFile, CodeWalkthroughStepAttr, CodeWalkthroughAttr } from '@redocly/config';
2
2
  import { type WalkthroughControlsState, type WalkthroughStepsState } from '../../../core/hooks';
3
3
  export type WalkthroughState = {
4
4
  stepsState: WalkthroughStepsState;
@@ -6,9 +6,4 @@ export type WalkthroughState = {
6
6
  downloadAssociatedFiles: CodeWalkthroughFile[];
7
7
  files: CodeWalkthroughFile[];
8
8
  };
9
- export declare function useCodeWalkthrough(steps: CodeWalkthroughStepAttr[], attributes: {
10
- filters: Record<string, CodeWalkthroughFilter>;
11
- filesets: CodeWalkthroughFileset[];
12
- inputs: InputsMarkdocAttr;
13
- toggles: TogglesMarkdocAttr;
14
- }): WalkthroughState;
9
+ export declare function useCodeWalkthrough(steps: CodeWalkthroughStepAttr[], attributes: Omit<CodeWalkthroughAttr, 'steps' | 'preview'>): WalkthroughState;
@@ -3,9 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useCodeWalkthrough = useCodeWalkthrough;
4
4
  const hooks_1 = require("../../../core/hooks");
5
5
  function useCodeWalkthrough(steps, attributes) {
6
- const { filters, filesets, inputs, toggles } = attributes;
7
- const stepsState = (0, hooks_1.useCodeWalkthroughSteps)(steps);
8
- const controlsState = (0, hooks_1.useCodeWalkthroughControls)(filters, inputs, toggles);
6
+ const { filters, filesets, inputs, toggles, __idx } = attributes;
7
+ /*
8
+ We only enable deep linking for the first CodeWalkthrough,
9
+ because we don't expect more than one on the same page.
10
+ Any subsequent walkthroughs have it disabled to avoid
11
+ collisions/conflicts in the URL.
12
+ */
13
+ const enableDeepLink = __idx === 1;
14
+ const stepsState = (0, hooks_1.useCodeWalkthroughSteps)(steps, enableDeepLink);
15
+ const controlsState = (0, hooks_1.useCodeWalkthroughControls)(filters, inputs, toggles, enableDeepLink);
9
16
  const files = filesets
10
17
  .filter((fileset) => controlsState.areConditionsMet(fileset))
11
18
  .flatMap((fileset) => fileset.files || []);
@@ -0,0 +1,9 @@
1
+ import type { CodeWalkthroughFile } from '@redocly/config';
2
+ import type { IconProps } from '../../../icons/types';
3
+ export type RenderableFile = CodeWalkthroughFile & {
4
+ FileIcon: React.FunctionComponent<IconProps>;
5
+ parentFolder: string;
6
+ isNameDuplicate: boolean;
7
+ inRootDir: boolean;
8
+ };
9
+ export declare function useRenderableFiles(files: CodeWalkthroughFile[]): RenderableFile[];
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useRenderableFiles = useRenderableFiles;
4
+ const react_1 = require("react");
5
+ const utils_1 = require("../../../core/utils");
6
+ function useRenderableFiles(files) {
7
+ return (0, react_1.useMemo)(function () {
8
+ const filePaths = files.map(({ path }) => path);
9
+ const rootDir = (0, utils_1.findClosestCommonDirectory)(filePaths);
10
+ const renderableFiles = files.map((file) => {
11
+ const FileIcon = getFileTypeIcon(file.basename);
12
+ const parentFolder = file.path.split('/').slice(-2, -1)[0];
13
+ const isNameDuplicate = files.some((_file) => file.basename === _file.basename && file.path !== _file.path);
14
+ const inRootDir = file.path === `${(0, utils_1.removeLeadingSlash)(rootDir)}/${file.basename}`;
15
+ return Object.assign(Object.assign({}, file), { FileIcon,
16
+ inRootDir,
17
+ parentFolder,
18
+ isNameDuplicate });
19
+ });
20
+ return renderableFiles;
21
+ }, [files]);
22
+ }
23
+ function getFileTypeIcon(basename) {
24
+ var _a;
25
+ const extension = ((_a = basename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
26
+ return (0, utils_1.getFileIconByExt)(extension);
27
+ }
28
+ //# sourceMappingURL=use-renderable-files.js.map
@@ -32,3 +32,4 @@ export * from '../../core/hooks/code-walkthrough/use-code-walkthrough';
32
32
  export * from '../../core/hooks/code-walkthrough/use-code-walkthrough-steps';
33
33
  export * from '../../core/hooks/code-walkthrough/use-code-walkthrough-controls';
34
34
  export * from '../../core/hooks/code-walkthrough/use-code-panel';
35
+ export * from '../../core/hooks/code-walkthrough/use-renderable-files';
@@ -48,4 +48,5 @@ __exportStar(require("../../core/hooks/code-walkthrough/use-code-walkthrough"),
48
48
  __exportStar(require("../../core/hooks/code-walkthrough/use-code-walkthrough-steps"), exports);
49
49
  __exportStar(require("../../core/hooks/code-walkthrough/use-code-walkthrough-controls"), exports);
50
50
  __exportStar(require("../../core/hooks/code-walkthrough/use-code-panel"), exports);
51
+ __exportStar(require("../../core/hooks/code-walkthrough/use-renderable-files"), exports);
51
52
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
1
  import type { TOptions } from 'i18next';
2
- export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.aiButton' | 'search.ai.label' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeLayout' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.settings.reasons.send' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'page.nextButton' | 'page.previousButton' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.deprecated' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.noResponseExample' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.scopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'codeWalkthrough.download' | 'codeWalkthrough.preview';
2
+ export type TranslationKey = 'dev.newApp' | 'dev.newApp.text' | 'dev.sidebar.header' | 'dev.sidebar.footer.text' | 'dev.create.app.dialog.appName.placeholder' | 'dev.create.app.dialog.appName.error' | 'dev.create.app.dialog.selectAPIs' | 'dev.create.app.dialog.description' | 'dev.create.app.dialog.description.placeholder' | 'dev.create.app.dialog.create' | 'dev.create.app.dialog.cancel' | 'dev.main.tab.appKeys' | 'dev.main.tab.logs' | 'dev.app.description.title' | 'dev.edit.description.dialog.title' | 'dev.edit.description.dialog.save' | 'dev.edit.description.dialog.cancel' | 'dev.edit.apis.dialog.selectedAPIs' | 'dev.app.key.create' | 'dev.create.key.dialog.title' | 'dev.create.key.dialog.create' | 'dev.create.key.dialog.cancel' | 'dev.app.edit' | 'dev.app.delete' | 'dev.edit.app.dialog.title' | 'dev.edit.app.dialog.save' | 'dev.edit.app.dialog.cancel' | 'dev.delete.app.dialog.title' | 'dev.delete.app.dialog.confirmation' | 'dev.delete.app.dialog.delete' | 'dev.delete.app.dialog.cancel' | 'dev.app.key.roll' | 'dev.roll.key.dialog.title' | 'dev.roll.key.dialog.apiKey' | 'dev.roll.key.dialog.expires' | 'dev.roll.key.dialog.confirmation' | 'dev.roll.key.dialog.cancel' | 'dev.roll.key.dialog.roll' | 'dev.update.key.dialog.title' | 'dev.update.key.dialog.update' | 'dev.update.key.dialog.cancel' | 'dev.app.key.api.name' | 'dev.app.key.api.status' | 'dev.app.key.api.edit' | 'dev.edit.apis.dialog.title' | 'dev.edit.apis.dialog.apiKey' | 'dev.edit.apis.dialog.save' | 'dev.edit.apis.dialog.cancel' | 'dev.select.placeholder' | 'dev.app.overview.status.pending' | 'dev.app.overview.status.approved' | 'dev.app.overview.status.revoked' | 'dev.app.overview.status' | 'dev.app.overview.non-production' | 'dev.app.overview.production' | 'dev.app.overview.clientId' | 'dev.app.overview.apiKey' | 'dev.app.key.revoke' | 'dev.revoke.key.dialog.title' | 'dev.revoke.key.dialog.apiKey' | 'dev.revoke.key.dialog.expires' | 'dev.revoke.key.dialog.confirmation' | 'dev.revoke.key.dialog.revoke' | 'dev.revoke.key.dialog.cancel' | 'dev.app.overview.expires' | 'dev.app.overview.created' | 'dev.app.overview.visibilityToggle.hide' | 'dev.app.overview.visibilityToggle.show' | 'search.loading' | 'search.noResults.title' | 'search.keys.navigate' | 'search.keys.select' | 'search.keys.exit' | 'search.label' | 'search.cancel' | 'search.recent' | 'search.navbar.label' | 'search.suggested' | 'search.showMore' | 'search.filter.title' | 'search.filter.reset' | 'search.filter.field.reset' | 'search.ai.thinkingText' | 'search.ai.resourcesFound' | 'search.ai.button' | 'search.ai.label' | 'search.ai.disclaimer' | 'toc.header' | 'footer.copyrightText' | 'page.homeButton' | 'page.forbidden.title' | 'page.notFound.title' | 'page.notFound.description' | 'page.lastUpdated.timeago' | 'page.lastUpdated.on' | 'catalog.filters.placeholder' | 'catalog.filters.title' | 'catalog.filters.clearAll' | 'catalog.filters.select.addFilter' | 'catalog.filters.select.all' | 'catalog.filters.done' | 'sidebar.menu.backLabel' | 'sidebar.menu.backToLabel' | 'sidebar.actions.show' | 'sidebar.actions.hide' | 'sidebar.actions.changeLayout' | 'versionPicker.label' | 'versionPicker.unversioned' | 'codeSnippet.copy.buttonText' | 'codeSnippet.copy.tooltipText' | 'codeSnippet.copy.toasterText' | 'markdown.editPage.text' | 'feedback.settings.comment.submitText' | 'feedback.settings.comment.label' | 'feedback.settings.comment.send' | 'feedback.settings.comment.cancel' | 'feedback.settings.comment.satisfiedLabel' | 'feedback.settings.comment.neutralLabel' | 'feedback.settings.comment.dissatisfiedLabel' | 'feedback.settings.submitText' | 'feedback.settings.label' | 'feedback.settings.reasons.label' | 'feedback.settings.reasons.send' | 'feedback.settings.comment.likeLabel' | 'feedback.settings.comment.dislikeLabel' | 'feedback.sentiment.thumbUp' | 'feedback.sentiment.thumbDown' | 'feedback.settings.leftScaleLabel' | 'feedback.settings.rightScaleLabel' | 'feedback.settings.optionalEmail.placeholder' | 'feedback.settings.optionalEmail.label' | 'codeSnippet.report.buttonText' | 'codeSnippet.report.tooltipText' | 'codeSnippet.report.label' | 'userMenu.login' | 'userMenu.logout' | 'userMenu.devOnboardingLabel' | 'mobileMenu.mainMenu' | 'mobileMenu.previous' | 'mobileMenu.products' | 'page.nextButton' | 'page.previousButton' | 'openapi.download.description.title' | 'openapi.info.title' | 'openapi.info.contact.url' | 'openapi.info.contact.name' | 'openapi.info.license' | 'openapi.info.termsOfService' | 'openapi.info.metadata.title' | 'openapi.key' | 'openapi.value' | 'openapi.enum' | 'openapi.items' | 'openapi.default' | 'openapi.variable' | 'openapi.variables' | 'openapi.actions.show' | 'openapi.actions.hide' | 'openapi.actions.more' | 'openapi.languages.title' | 'openapi.servers.title' | 'openapi.operations' | 'openapi.webhooks' | 'openapi.description' | 'openapi.badges.deprecated' | 'openapi.badges.required' | 'openapi.badges.webhook' | 'openapi.request' | 'openapi.path' | 'openapi.query' | 'openapi.cookie' | 'openapi.header' | 'openapi.body' | 'openapi.responses' | 'openapi.response' | 'openapi.callbacks' | 'openapi.callbackRequest' | 'openapi.callbackResponse' | 'openapi.payload' | 'openapi.discriminator' | 'openapi.contentType' | 'openapi.tryIt' | 'openapi.loading' | 'openapi.example' | 'openapi.examples' | 'openapi.additionalProperties' | 'openapi.patternProperties' | 'openapi.required' | 'openapi.recursive' | 'openapi.complex' | 'openapi.deprecated' | 'openapi.hideExample' | 'openapi.showExample' | 'openapi.expandAll' | 'openapi.collapseAll' | 'openapi.noResponseExample' | 'openapi.noResponseContent' | 'openapi.noRequestPayload' | 'openapi.hidePattern' | 'openapi.showPattern' | 'openapi.authorizationUrl' | 'openapi.tokenUrl' | 'openapi.refreshUrl' | 'openapi.scopes' | 'openapi.security' | 'openapi.httpAuthorizationScheme' | 'openapi.bearerFormat' | 'openapi.parameterName' | 'openapi.flowType' | 'openapi.connectUrl' | 'openapi.requiredScopes' | 'openapi.unsupportedLanguage' | 'openapi.failedToGenerateCodeSample' | 'graphql.queries' | 'graphql.mutations' | 'graphql.subscriptions' | 'graphql.directives' | 'graphql.objects' | 'graphql.interfaces' | 'graphql.unions' | 'graphql.enums' | 'graphql.inputs' | 'graphql.scalars' | 'graphql.arguments.label' | 'graphql.arguments.show' | 'graphql.arguments.hide' | 'graphql.arguments.here' | 'graphql.returnTypes.label' | 'graphql.returnTypes.show' | 'graphql.returnTypes.hide' | 'graphql.possibleTypes' | 'graphql.defaultValue' | 'graphql.deprecationReason' | 'graphql.implementedInterfaces' | 'graphql.nonNull' | 'graphql.required' | 'graphql.deprecated' | 'graphql.variables' | 'graphql.querySample' | 'graphql.mutationSample' | 'graphql.subscriptionSample' | 'graphql.responseSample' | 'graphql.locations' | 'graphql.sample' | 'graphql.referenced' | 'codeWalkthrough.download' | 'codeWalkthrough.preview';
3
3
  export type Locale = {
4
4
  code: string;
5
5
  name: string;
@@ -21,9 +21,17 @@ jszip_1.default.support.nodebuffer = false;
21
21
  function downloadCodeWalkthrough(files, state, inputsState) {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
23
  const zip = new jszip_1.default();
24
+ const filePaths = files.map(({ path }) => path);
25
+ const commonClosestDirectory = (0, utils_1.findClosestCommonDirectory)(filePaths);
24
26
  for (const file of files) {
25
27
  const fileContent = (0, utils_1.getCodeWalkthroughFileText)(file, state, inputsState);
26
- zip.file(file.basename, fileContent);
28
+ if (commonClosestDirectory === '/') {
29
+ zip.file(file.path, fileContent);
30
+ }
31
+ else {
32
+ const filePath = file.path.replace((0, utils_1.removeLeadingSlash)(`${commonClosestDirectory}/`), '');
33
+ zip.file(filePath, fileContent);
34
+ }
27
35
  }
28
36
  const zipContent = yield zip.generateAsync({ type: 'blob' });
29
37
  (0, file_saver_1.saveAs)(zipContent, 'sample-code.zip');
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Finds the closest common directory for a set of file paths.
3
+ * @param paths - An array of absolute file paths.
4
+ * @returns The closest common directory as a string.
5
+ */
6
+ export declare function findClosestCommonDirectory(paths: string[]): string;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findClosestCommonDirectory = findClosestCommonDirectory;
4
+ /**
5
+ * Splits a file path into its directory components, removing the file name.
6
+ * @param path - The full file path.
7
+ * @returns An array of directories.
8
+ */
9
+ function splitPath(path) {
10
+ const parts = path.split('/').filter(Boolean);
11
+ parts.pop();
12
+ return parts;
13
+ }
14
+ /**
15
+ * Finds the longest common prefix between two paths.
16
+ * @param path1 - The first path as an array of directories.
17
+ * @param path2 - The second path as an array of directories.
18
+ * @returns An array representing the common prefix.
19
+ */
20
+ function findCommonPrefix(path1, path2) {
21
+ const common = [];
22
+ for (let i = 0; i < Math.min(path1.length, path2.length); i++) {
23
+ if (path1[i] === path2[i]) {
24
+ common.push(path1[i]);
25
+ }
26
+ else {
27
+ break;
28
+ }
29
+ }
30
+ return common;
31
+ }
32
+ /**
33
+ * Finds the closest common directory for a set of file paths.
34
+ * @param paths - An array of absolute file paths.
35
+ * @returns The closest common directory as a string.
36
+ */
37
+ function findClosestCommonDirectory(paths) {
38
+ if (paths.length === 0) {
39
+ return '/';
40
+ }
41
+ const splitPaths = paths.map(splitPath);
42
+ let commonPrefix = splitPaths[0];
43
+ for (let i = 1; i < splitPaths.length; i++) {
44
+ commonPrefix = findCommonPrefix(commonPrefix, splitPaths[i]);
45
+ if (commonPrefix.length === 0) {
46
+ return '/';
47
+ }
48
+ }
49
+ return '/' + commonPrefix.join('/');
50
+ }
51
+ //# sourceMappingURL=find-closest-common-directory.js.map
@@ -11,6 +11,9 @@ const DocumentHtmlIcon_1 = require("../../icons/DocumentHtmlIcon/DocumentHtmlIco
11
11
  const DocumentReactIcon_1 = require("../../icons/DocumentReactIcon/DocumentReactIcon");
12
12
  const DocumentMarkdownIcon_1 = require("../../icons/DocumentMarkdownIcon/DocumentMarkdownIcon");
13
13
  const DocumentGraphqlIcon_1 = require("../../icons/DocumentGraphqlIcon/DocumentGraphqlIcon");
14
+ const DocumentPythonIcon_1 = require("../../icons/DocumentPythonIcon/DocumentPythonIcon");
15
+ const DocumentShellIcon_1 = require("../../icons/DocumentShellIcon/DocumentShellIcon");
16
+ const DocumentJavaIcon_1 = require("../../icons/DocumentJavaIcon/DocumentJavaIcon");
14
17
  const fileIconMap = {
15
18
  yaml: DocumentYamlIcon_1.DocumentYamlIcon,
16
19
  yml: DocumentYamlIcon_1.DocumentYamlIcon,
@@ -24,6 +27,9 @@ const fileIconMap = {
24
27
  md: DocumentMarkdownIcon_1.DocumentMarkdownIcon,
25
28
  graphql: DocumentGraphqlIcon_1.DocumentGraphqlIcon,
26
29
  gql: DocumentGraphqlIcon_1.DocumentGraphqlIcon,
30
+ py: DocumentPythonIcon_1.DocumentPythonIcon,
31
+ sh: DocumentShellIcon_1.DocumentShellIcon,
32
+ java: DocumentJavaIcon_1.DocumentJavaIcon,
27
33
  };
28
34
  function getFileIconByExt(ext) {
29
35
  return fileIconMap[ext] || DocumentBlankIcon_1.DocumentBlankIcon;
@@ -30,3 +30,4 @@ export * from '../../core/utils/download-code-walkthrough';
30
30
  export * from '../../core/utils/get-file-icon';
31
31
  export * from '../../core/utils/match-code-walkthrough-conditions';
32
32
  export * from '../../core/utils/replace-inputs-with-value';
33
+ export * from '../../core/utils/find-closest-common-directory';
@@ -46,4 +46,5 @@ __exportStar(require("../../core/utils/download-code-walkthrough"), exports);
46
46
  __exportStar(require("../../core/utils/get-file-icon"), exports);
47
47
  __exportStar(require("../../core/utils/match-code-walkthrough-conditions"), exports);
48
48
  __exportStar(require("../../core/utils/replace-inputs-with-value"), exports);
49
+ __exportStar(require("../../core/utils/find-closest-common-directory"), exports);
49
50
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,3 @@
1
1
  export declare function replaceInputsWithValue(node: string, inputs: Record<string, {
2
- value: string;
2
+ value?: string;
3
3
  }>): string;