@redocly/theme 0.47.1 → 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.
- package/lib/components/Feedback/Mood.d.ts +2 -2
- package/lib/components/Feedback/Mood.js +20 -15
- package/lib/components/Feedback/Rating.d.ts +2 -2
- package/lib/components/Feedback/Rating.js +6 -6
- package/lib/components/Feedback/Scale.d.ts +2 -2
- package/lib/components/Feedback/Scale.js +6 -6
- package/lib/components/Feedback/Sentiment.d.ts +2 -2
- package/lib/components/Feedback/Sentiment.js +6 -6
- package/lib/components/Search/SearchDialog.js +17 -11
- package/lib/components/Search/SearchFilter.d.ts +3 -2
- package/lib/components/Search/SearchFilter.js +2 -2
- package/lib/components/Search/SearchFilterField.d.ts +3 -2
- package/lib/components/Search/SearchFilterField.js +2 -2
- package/lib/components/Search/SearchGroups.d.ts +5 -4
- package/lib/components/Search/SearchGroups.js +3 -3
- package/lib/components/Search/variables.js +4 -0
- package/lib/components/Segmented/Segmented.d.ts +4 -4
- package/lib/components/Segmented/Segmented.js +4 -7
- package/lib/components/Tag/Tag.d.ts +1 -0
- package/lib/components/Tag/Tag.js +3 -2
- package/lib/core/hooks/__mocks__/search/use-search-filter.d.ts +1 -1
- package/lib/core/hooks/__mocks__/search/use-search-filter.js +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +10 -5
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +1 -2
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.js +20 -15
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +2 -7
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough.js +10 -3
- package/lib/core/hooks/code-walkthrough/use-renderable-files.d.ts +9 -0
- package/lib/core/hooks/code-walkthrough/use-renderable-files.js +28 -0
- package/lib/core/hooks/index.d.ts +1 -0
- package/lib/core/hooks/index.js +1 -0
- package/lib/core/hooks/search/use-search-filter.d.ts +2 -2
- package/lib/core/hooks/search/use-search-filter.js +5 -5
- package/lib/core/types/hooks.d.ts +1 -0
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/search.d.ts +1 -2
- package/lib/core/utils/download-code-walkthrough.js +9 -1
- package/lib/core/utils/find-closest-common-directory.d.ts +6 -0
- package/lib/core/utils/find-closest-common-directory.js +51 -0
- package/lib/core/utils/get-file-icon.js +6 -0
- package/lib/core/utils/index.d.ts +1 -0
- package/lib/core/utils/index.js +1 -0
- package/lib/core/utils/replace-inputs-with-value.d.ts +1 -1
- package/lib/core/utils/replace-inputs-with-value.js +9 -10
- package/lib/icons/DocumentJavaIcon/DocumentJavaIcon.d.ts +9 -0
- package/lib/icons/DocumentJavaIcon/DocumentJavaIcon.js +22 -0
- package/lib/icons/DocumentJavaIcon/index.d.ts +1 -0
- package/lib/icons/DocumentJavaIcon/index.js +6 -0
- package/lib/icons/DocumentPythonIcon/DocumentPythonIcon.d.ts +9 -0
- package/lib/icons/DocumentPythonIcon/DocumentPythonIcon.js +23 -0
- package/lib/icons/DocumentPythonIcon/index.d.ts +1 -0
- package/lib/icons/DocumentPythonIcon/index.js +6 -0
- package/lib/icons/DocumentShellIcon/DocumentShellIcon.d.ts +9 -0
- package/lib/icons/DocumentShellIcon/DocumentShellIcon.js +22 -0
- package/lib/icons/DocumentShellIcon/index.d.ts +1 -0
- package/lib/icons/DocumentShellIcon/index.js +6 -0
- package/lib/icons/__tests__/IconTestUtils.d.ts +7 -0
- package/lib/icons/__tests__/IconTestUtils.js +33 -0
- package/lib/layouts/CodeWalkthroughLayout.js +4 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeContainer.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +15 -2
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.js +29 -23
- package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +6 -3
- package/lib/markdoc/components/CodeWalkthrough/CodeToggle.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +1 -1
- package/lib/markdoc/components/CodeWalkthrough/Input.js +4 -2
- package/lib/markdoc/tags/code-walkthrough.js +5 -0
- package/package.json +3 -3
- package/src/components/Feedback/Mood.tsx +25 -17
- package/src/components/Feedback/Rating.tsx +9 -10
- package/src/components/Feedback/Scale.tsx +9 -10
- package/src/components/Feedback/Sentiment.tsx +9 -10
- package/src/components/Search/SearchDialog.tsx +63 -42
- package/src/components/Search/SearchFilter.tsx +6 -3
- package/src/components/Search/SearchFilterField.tsx +4 -2
- package/src/components/Search/SearchGroups.tsx +13 -8
- package/src/components/Search/variables.ts +4 -0
- package/src/components/Segmented/Segmented.tsx +10 -10
- package/src/components/Tag/Tag.tsx +1 -1
- package/src/core/hooks/__mocks__/search/use-search-filter.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +9 -3
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +30 -18
- package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +13 -13
- package/src/core/hooks/code-walkthrough/use-renderable-files.ts +51 -0
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/search/use-search-filter.ts +9 -5
- package/src/core/types/hooks.ts +1 -0
- package/src/core/types/l10n.ts +5 -3
- package/src/core/types/search.ts +1 -2
- package/src/core/utils/download-code-walkthrough.ts +14 -2
- package/src/core/utils/find-closest-common-directory.ts +51 -0
- package/src/core/utils/get-file-icon.ts +7 -0
- package/src/core/utils/index.ts +1 -0
- package/src/core/utils/replace-inputs-with-value.ts +12 -9
- package/src/icons/DocumentJavaIcon/DocumentJavaIcon.tsx +33 -0
- package/src/icons/DocumentJavaIcon/index.ts +1 -0
- package/src/icons/DocumentPythonIcon/DocumentPythonIcon.tsx +37 -0
- package/src/icons/DocumentPythonIcon/index.ts +1 -0
- package/src/icons/DocumentShellIcon/DocumentShellIcon.tsx +33 -0
- package/src/icons/DocumentShellIcon/index.ts +1 -0
- package/src/icons/__tests__/IconTestUtils.tsx +31 -0
- package/src/layouts/CodeWalkthroughLayout.tsx +5 -1
- package/src/markdoc/components/CodeWalkthrough/CodeContainer.tsx +1 -0
- package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +19 -3
- package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +64 -47
- package/src/markdoc/components/CodeWalkthrough/CodePanelPreview.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +6 -2
- package/src/markdoc/components/CodeWalkthrough/CodeToggle.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +4 -1
- package/src/markdoc/components/CodeWalkthrough/Input.tsx +4 -2
- package/src/markdoc/tags/code-walkthrough.ts +5 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.testIconComponent = testIconComponent;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const react_2 = require("@testing-library/react");
|
|
9
|
+
require("@testing-library/jest-dom");
|
|
10
|
+
function testIconComponent(IconComponent, componentName) {
|
|
11
|
+
const dataName = `icons/${componentName}/${componentName}`;
|
|
12
|
+
return {
|
|
13
|
+
rendersCorrectlyWithDefaultProps: () => {
|
|
14
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(IconComponent, null));
|
|
15
|
+
const svgElement = container.querySelector('svg');
|
|
16
|
+
expect(svgElement).toBeInTheDocument();
|
|
17
|
+
expect(container.firstChild).toHaveStyle('height: 16px; width: 16px;');
|
|
18
|
+
},
|
|
19
|
+
appliesCustomSizeAndColor: () => {
|
|
20
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(IconComponent, { size: "24px", color: "--color-primary" }));
|
|
21
|
+
const svgElement = container.querySelector('svg');
|
|
22
|
+
expect(svgElement).toBeInTheDocument();
|
|
23
|
+
expect(container.firstChild).toHaveStyle('height: 24px; width: 24px;');
|
|
24
|
+
const pathElement = container.querySelector('path');
|
|
25
|
+
expect(pathElement).toHaveStyle('fill: var(--color-primary);');
|
|
26
|
+
},
|
|
27
|
+
hasCorrectDataComponentName: () => {
|
|
28
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(IconComponent, null));
|
|
29
|
+
expect(container.firstChild).toHaveAttribute('data-component-name', dataName);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=IconTestUtils.js.map
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.CodeWalkthroughLayout = CodeWalkthroughLayout;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
|
+
const core_1 = require("../core");
|
|
9
10
|
function CodeWalkthroughLayout({ className, children, }) {
|
|
10
11
|
return (react_1.default.createElement(LayoutWrapper, { "data-component-name": "Layout/CodeWalkthroughLayout", className: className },
|
|
11
12
|
react_1.default.createElement(ContentWrapper, null, children)));
|
|
@@ -59,8 +60,10 @@ const ContentWrapper = styled_components_1.default.section `
|
|
|
59
60
|
|
|
60
61
|
/* Full-width styling for all .code-walkthroughs */
|
|
61
62
|
.code-walkthrough {
|
|
62
|
-
max-width: none;
|
|
63
63
|
width: 100%;
|
|
64
|
+
max-width: ${core_1.breakpoints.max};
|
|
65
|
+
margin-left: auto;
|
|
66
|
+
margin-right: auto;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
&:first-child > h1:first-child {
|
|
@@ -43,7 +43,7 @@ function CodeContainer({ highlightedCode, toolbar, }) {
|
|
|
43
43
|
}
|
|
44
44
|
}, 200);
|
|
45
45
|
}, [activeStep]);
|
|
46
|
-
return (react_1.default.createElement(CodeContainerWrapper, { ref: compRef, hideCodeColors: !isHovered, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) },
|
|
46
|
+
return (react_1.default.createElement(CodeContainerWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodeContainer", ref: compRef, hideCodeColors: !isHovered, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) },
|
|
47
47
|
react_1.default.createElement(CodeBlockContainer_1.CodeBlockContainer, { dangerouslySetInnerHTML: { __html: highlightedCode } }),
|
|
48
48
|
toolbar));
|
|
49
49
|
}
|
|
@@ -11,7 +11,7 @@ function CodeFilters({ filters, getFilterState, handleFilterSelect, filtersEleme
|
|
|
11
11
|
if (filters.length === 0) {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
|
-
return (react_1.default.createElement(FilterWrapper, { ref: filtersElementRef }, filters.map(({ label, items, id }) => {
|
|
14
|
+
return (react_1.default.createElement(FilterWrapper, { ref: filtersElementRef, "data-component-name": "Markdoc/CodeWalkthrough/CodeFilters" }, filters.map(({ label, items, id }) => {
|
|
15
15
|
return (react_1.default.createElement(Filter, { key: id },
|
|
16
16
|
label && react_1.default.createElement(FilterName, null,
|
|
17
17
|
label,
|
|
@@ -24,8 +24,9 @@ function CodeFilters({ filters, getFilterState, handleFilterSelect, filtersEleme
|
|
|
24
24
|
}
|
|
25
25
|
const Filter = styled_components_1.default.div `
|
|
26
26
|
display: flex;
|
|
27
|
-
align-items:
|
|
27
|
+
align-items: flex-start;
|
|
28
28
|
gap: var(--spacing-xs);
|
|
29
|
+
max-width: 100%;
|
|
29
30
|
`;
|
|
30
31
|
const FilterName = styled_components_1.default.div `
|
|
31
32
|
color: var(--color-text-primary);
|
|
@@ -46,13 +47,25 @@ const FilterWrapper = styled_components_1.default.div `
|
|
|
46
47
|
top: calc(var(--navbar-height));
|
|
47
48
|
background-color: var(--bg-color);
|
|
48
49
|
z-index: 1;
|
|
50
|
+
max-width: var(--md-content-max-width);
|
|
49
51
|
`;
|
|
50
52
|
const ButtonsWrapper = styled_components_1.default.div `
|
|
51
53
|
display: flex;
|
|
54
|
+
min-width: 0;
|
|
55
|
+
flex-wrap: wrap;
|
|
52
56
|
`;
|
|
53
57
|
const TagButton = (0, styled_components_1.default)(Tag_1.Tag) `
|
|
54
58
|
cursor: pointer;
|
|
55
59
|
padding: 0px var(--spacing-xs);
|
|
56
60
|
margin-right: var(--spacing-xs);
|
|
61
|
+
max-width: 100%;
|
|
62
|
+
margin-bottom: var(--spacing-xs);
|
|
63
|
+
|
|
64
|
+
${Tag_1.ContentWrapper} {
|
|
65
|
+
display: inline-block;
|
|
66
|
+
text-overflow: ellipsis;
|
|
67
|
+
white-space: nowrap;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
}
|
|
57
70
|
`;
|
|
58
71
|
//# sourceMappingURL=CodeFilters.js.map
|
|
@@ -38,7 +38,7 @@ const CodePanelToolbar_1 = require("../../../markdoc/components/CodeWalkthrough/
|
|
|
38
38
|
function CodePanel({ files, downloadAssociatedFiles, preview, }) {
|
|
39
39
|
const { activeFile, handleTabSwitch, highlightedCode } = (0, hooks_1.useCodePanel)(files);
|
|
40
40
|
const { handleDownloadCode } = (0, react_1.useContext)(contexts_1.CodeWalkthroughControlsStateContext);
|
|
41
|
-
return (react_1.default.createElement(CodePanelWrapper,
|
|
41
|
+
return (react_1.default.createElement(CodePanelWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodePanel" },
|
|
42
42
|
preview ? (react_1.default.createElement(CodePanelPreview_1.CodePanelPreview, null, preview.map((element, idx) => (react_1.default.createElement(react_1.default.Fragment, { key: idx }, element))))) : null,
|
|
43
43
|
react_1.default.createElement(CodePanelHeader_1.CodePanelHeader, { files: files, activeTabName: (activeFile === null || activeFile === void 0 ? void 0 : activeFile.path) || '', handleTabSwitch: handleTabSwitch, onDownloadCode: () => handleDownloadCode([...files, ...downloadAssociatedFiles]) }),
|
|
44
44
|
react_1.default.createElement(CodeContainer_1.CodeContainer, { key: (activeFile === null || activeFile === void 0 ? void 0 : activeFile.path) || '', highlightedCode: highlightedCode, toolbar: react_1.default.createElement(CodePanelToolbar_1.CodePanelToolbar, { file: activeFile }) })));
|
|
@@ -27,7 +27,6 @@ exports.CodePanelHeader = CodePanelHeader;
|
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
const styled_components_1 = __importStar(require("styled-components"));
|
|
29
29
|
const hooks_1 = require("../../../core/hooks");
|
|
30
|
-
const utils_1 = require("../../../core/utils");
|
|
31
30
|
const OverflowMenuVerticalIcon_1 = require("../../../icons/OverflowMenuVerticalIcon/OverflowMenuVerticalIcon");
|
|
32
31
|
const Dropdown_1 = require("../../../components/Dropdown/Dropdown");
|
|
33
32
|
const DropdownMenu_1 = require("../../../components/Dropdown/DropdownMenu");
|
|
@@ -35,6 +34,7 @@ const DropdownMenuItem_1 = require("../../../components/Dropdown/DropdownMenuIte
|
|
|
35
34
|
const DownloadIcon_1 = require("../../../icons/DownloadIcon/DownloadIcon");
|
|
36
35
|
const Button_1 = require("../../../components/Button/Button");
|
|
37
36
|
function CodePanelHeader({ files, handleTabSwitch, activeTabName, onDownloadCode, }) {
|
|
37
|
+
const renderableFiles = (0, hooks_1.useRenderableFiles)(files);
|
|
38
38
|
const { useTranslate } = (0, hooks_1.useThemeHooks)();
|
|
39
39
|
const { translate } = useTranslate();
|
|
40
40
|
const tabRefs = (0, react_1.useRef)([]);
|
|
@@ -42,47 +42,49 @@ function CodePanelHeader({ files, handleTabSwitch, activeTabName, onDownloadCode
|
|
|
42
42
|
const [hiddenFiles, setHiddenFiles] = (0, react_1.useState)([]);
|
|
43
43
|
(0, react_1.useEffect)(() => {
|
|
44
44
|
const activeTab = tabRefs.current.find((tab) => (tab === null || tab === void 0 ? void 0 : tab.dataset.name) === activeTabName);
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const tabsWrapper = tabsWrapperRef.current;
|
|
46
|
+
if (activeTab && tabsWrapper) {
|
|
47
|
+
const { left: wrapperLeft, right: wrapperRight } = tabsWrapper.getBoundingClientRect();
|
|
48
|
+
const { left: tabLeft, right: tabRight } = activeTab.getBoundingClientRect();
|
|
49
|
+
const tabHidden = tabLeft < wrapperLeft || tabRight > wrapperRight;
|
|
50
|
+
if (tabHidden) {
|
|
51
|
+
activeTab.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
52
|
+
}
|
|
47
53
|
}
|
|
48
|
-
}, [activeTabName]);
|
|
49
|
-
(0, react_1.useEffect)(() => {
|
|
50
54
|
const calculateHiddenFiles = () => {
|
|
51
55
|
if (!tabsWrapperRef.current)
|
|
52
56
|
return;
|
|
53
57
|
const { left: wrapperLeft, right: wrapperRight } = tabsWrapperRef.current.getBoundingClientRect();
|
|
54
|
-
const hidden =
|
|
58
|
+
const hidden = [];
|
|
59
|
+
for (let i = 0; i < renderableFiles.length; i++) {
|
|
55
60
|
const tab = tabRefs.current[i];
|
|
56
61
|
if (!tab)
|
|
57
|
-
|
|
62
|
+
continue;
|
|
58
63
|
const { left: tabLeft, right: tabRight } = tab.getBoundingClientRect();
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
const visible = tabLeft > wrapperLeft && tabRight < wrapperRight;
|
|
65
|
+
if (!visible) {
|
|
66
|
+
hidden.push(renderableFiles[i]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
61
69
|
setHiddenFiles(hidden);
|
|
62
70
|
};
|
|
63
71
|
calculateHiddenFiles();
|
|
64
72
|
window.addEventListener('resize', calculateHiddenFiles);
|
|
65
73
|
return () => window.removeEventListener('resize', calculateHiddenFiles);
|
|
66
|
-
}, [files]);
|
|
67
|
-
const getFileTypeIcon = (0, react_1.useCallback)((basename) => {
|
|
68
|
-
var _a;
|
|
69
|
-
const extension = ((_a = basename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
|
|
70
|
-
return (0, utils_1.getFileIconByExt)(extension);
|
|
71
|
-
}, []);
|
|
74
|
+
}, [activeTabName, files, renderableFiles]);
|
|
72
75
|
return (react_1.default.createElement(CodePanelHeaderWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodePanelHeader" },
|
|
73
76
|
react_1.default.createElement(TabsWrapper, { ref: tabsWrapperRef },
|
|
74
|
-
react_1.default.createElement(Tabs, null,
|
|
75
|
-
const FileIcon = getFileTypeIcon(basename);
|
|
77
|
+
react_1.default.createElement(Tabs, null, renderableFiles.map(({ path, basename, FileIcon, parentFolder, isNameDuplicate, inRootDir }, i) => {
|
|
76
78
|
return (react_1.default.createElement(Tab, { ref: (el) => (tabRefs.current[i] = el), "data-name": path, active: path === activeTabName, key: i, onClick: () => handleTabSwitch(path) },
|
|
77
79
|
react_1.default.createElement(FileIcon, null),
|
|
78
|
-
basename
|
|
80
|
+
basename,
|
|
81
|
+
isNameDuplicate && !inRootDir ? react_1.default.createElement(Dirname, null, parentFolder) : null));
|
|
79
82
|
})),
|
|
80
83
|
react_1.default.createElement(Gradient, null)),
|
|
81
84
|
react_1.default.createElement(ActionBar, null,
|
|
82
85
|
hiddenFiles.length ? (react_1.default.createElement(Dropdown_1.Dropdown, { trigger: react_1.default.createElement(StyledOverflowMenuVerticalIcon, { size: "14px" }), alignment: "end" },
|
|
83
|
-
react_1.default.createElement(StyledDropdownMenu, null, hiddenFiles.map(({ path, basename }, i) => {
|
|
84
|
-
|
|
85
|
-
return (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { active: path === activeTabName, key: i, onAction: () => handleTabSwitch(path), prefix: react_1.default.createElement(FileIcon, null), content: basename }));
|
|
86
|
+
react_1.default.createElement(StyledDropdownMenu, null, hiddenFiles.map(({ path, basename, FileIcon, isNameDuplicate, inRootDir, parentFolder }, i) => {
|
|
87
|
+
return (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { active: path === activeTabName, key: i, onAction: () => handleTabSwitch(path), prefix: react_1.default.createElement(FileIcon, null), content: isNameDuplicate && !inRootDir ? `${parentFolder}/${basename}` : basename }));
|
|
86
88
|
})))) : null,
|
|
87
89
|
react_1.default.createElement(Button_1.Button, { variant: "text", icon: react_1.default.createElement(DownloadIcon_1.DownloadIcon, null), onClick: onDownloadCode, size: "small" }, translate('codeWalkthrough.download', 'Download')))));
|
|
88
90
|
}
|
|
@@ -108,13 +110,17 @@ const Gradient = styled_components_1.default.div `
|
|
|
108
110
|
`;
|
|
109
111
|
const Tabs = styled_components_1.default.div `
|
|
110
112
|
display: flex;
|
|
111
|
-
overflow-x:
|
|
113
|
+
overflow-x: hidden;
|
|
112
114
|
padding-right: var(--spacing-base);
|
|
113
115
|
|
|
114
116
|
&::-webkit-scrollbar {
|
|
115
117
|
display: none;
|
|
116
118
|
}
|
|
117
119
|
`;
|
|
120
|
+
const Dirname = styled_components_1.default.span `
|
|
121
|
+
font-size: var(--font-size-sm);
|
|
122
|
+
color: var(--text-color-description);
|
|
123
|
+
`;
|
|
118
124
|
const ActionBar = styled_components_1.default.div `
|
|
119
125
|
display: flex;
|
|
120
126
|
`;
|
|
@@ -129,7 +135,7 @@ const Tab = styled_components_1.default.button `
|
|
|
129
135
|
gap: var(--spacing-xs);
|
|
130
136
|
color: var(--text-color-secondary);
|
|
131
137
|
white-space: nowrap;
|
|
132
|
-
|
|
138
|
+
scroll-margin-right: var(--spacing-base);
|
|
133
139
|
${({ active }) => active
|
|
134
140
|
? (0, styled_components_1.css) `
|
|
135
141
|
color: var(--text-color-primary);
|
|
@@ -36,7 +36,7 @@ function CodePanelPreview({ children }) {
|
|
|
36
36
|
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
37
37
|
const { useTranslate } = (0, hooks_1.useThemeHooks)();
|
|
38
38
|
const { translate } = useTranslate();
|
|
39
|
-
return (react_1.default.createElement(CodePanelPreviewWrapper,
|
|
39
|
+
return (react_1.default.createElement(CodePanelPreviewWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodePanelPreview" },
|
|
40
40
|
react_1.default.createElement(PreviewDropdown, { onClick: () => setIsOpen(!isOpen) },
|
|
41
41
|
translate('codeWalkthrough.preview', 'Preview'),
|
|
42
42
|
isOpen ? react_1.default.createElement(ChevronUpIcon_1.ChevronUpIcon, null) : react_1.default.createElement(ChevronDownIcon_1.ChevronDownIcon, null)),
|
|
@@ -34,7 +34,7 @@ const CopyButton_1 = require("../../../components/Buttons/CopyButton");
|
|
|
34
34
|
function CodePanelToolbar({ file }) {
|
|
35
35
|
const { getFileText } = (0, react_1.useContext)(contexts_1.CodeWalkthroughControlsStateContext);
|
|
36
36
|
const fileContent = getFileText(file);
|
|
37
|
-
return (react_1.default.createElement(CodeToolbarWrapper,
|
|
37
|
+
return (react_1.default.createElement(CodeToolbarWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodePanelToolbar" },
|
|
38
38
|
react_1.default.createElement(CopyButton_1.CopyButton, { data: fileContent, type: "compound", variant: "secondary", size: "medium" })));
|
|
39
39
|
}
|
|
40
40
|
const CodeToolbarWrapper = styled_components_1.default.div `
|
|
@@ -41,7 +41,7 @@ function CodeStep({ id, heading, stepKey, when, unless, children, }) {
|
|
|
41
41
|
if (lockObserver) {
|
|
42
42
|
lockObserver.current = true;
|
|
43
43
|
if (compRef.current) {
|
|
44
|
-
compRef.current.scrollIntoView({ behavior: 'smooth', block: '
|
|
44
|
+
compRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
45
45
|
}
|
|
46
46
|
setActiveStep(id);
|
|
47
47
|
setTimeout(() => {
|
|
@@ -71,7 +71,7 @@ function CodeStep({ id, heading, stepKey, when, unless, children, }) {
|
|
|
71
71
|
}
|
|
72
72
|
const filtersElementHeight = ((_a = filtersElementRef === null || filtersElementRef === void 0 ? void 0 : filtersElementRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0;
|
|
73
73
|
const navbarHeight = ((_b = document.querySelector('nav')) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;
|
|
74
|
-
setScrollMarginTop(filtersElementHeight + navbarHeight);
|
|
74
|
+
setScrollMarginTop(filtersElementHeight + navbarHeight + 10);
|
|
75
75
|
return () => {
|
|
76
76
|
if (currentCompRef) {
|
|
77
77
|
unregister(currentCompRef);
|
|
@@ -79,9 +79,12 @@ function CodeStep({ id, heading, stepKey, when, unless, children, }) {
|
|
|
79
79
|
};
|
|
80
80
|
}, [activeStep, register, unregister, filtersElementRef]);
|
|
81
81
|
if (!areConditionsMet({ when, unless })) {
|
|
82
|
+
if (isActive) {
|
|
83
|
+
setActiveStep(null);
|
|
84
|
+
}
|
|
82
85
|
return null;
|
|
83
86
|
}
|
|
84
|
-
return (react_1.default.createElement(exports.StepWrapper, { ref: compRef, isActive: isActive, scrollMarginTop: scrollMarginTop, "data-step-key": stepKey, "data-step-active": isActive, onClick: handleActivateStep, onFocus: handleActivateStep, tabIndex: 0 },
|
|
87
|
+
return (react_1.default.createElement(exports.StepWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodeStep", ref: compRef, isActive: isActive, scrollMarginTop: scrollMarginTop, "data-step-key": stepKey, "data-step-active": isActive, onClick: handleActivateStep, onFocus: handleActivateStep, tabIndex: 0 },
|
|
85
88
|
react_1.default.createElement(StepContent, { isActive: isActive },
|
|
86
89
|
heading ? react_1.default.createElement(StepHeading, null, heading) : null,
|
|
87
90
|
children)));
|
|
@@ -41,7 +41,7 @@ function CodeToggle(props) {
|
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
43
|
const checked = toggleState.value;
|
|
44
|
-
return (react_1.default.createElement(exports.ToggleWrapper,
|
|
44
|
+
return (react_1.default.createElement(exports.ToggleWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/CodeToggle" },
|
|
45
45
|
react_1.default.createElement(ToggleContentWrapper, null,
|
|
46
46
|
react_1.default.createElement(exports.ToggleSubtitle, null,
|
|
47
47
|
react_1.default.createElement(Switch_1.Switch, { value: checked, onChange: (newValue) => changeToggleState(id, newValue) }),
|
|
@@ -55,7 +55,7 @@ function CodeWalkthrough(_a) {
|
|
|
55
55
|
const { filtersElementRef } = stepsState;
|
|
56
56
|
return (react_1.default.createElement(contexts_1.CodeWalkthroughStepsContext.Provider, { value: stepsState },
|
|
57
57
|
react_1.default.createElement(contexts_1.CodeWalkthroughControlsStateContext.Provider, { value: controlsState },
|
|
58
|
-
react_1.default.createElement(CodeWalkthroughWrapper, { className: "code-walkthrough" },
|
|
58
|
+
react_1.default.createElement(CodeWalkthroughWrapper, { className: "code-walkthrough", "data-component-name": "Markdoc/CodeWalkthrough/CodeWalkthrough" },
|
|
59
59
|
react_1.default.createElement(DocsPanel, null,
|
|
60
60
|
react_1.default.createElement(CodeFilters_1.CodeFilters, { filters: activeFilters, getFilterState: getFilterState, handleFilterSelect: changeFilterState, filtersElementRef: filtersElementRef }),
|
|
61
61
|
react_1.default.createElement(ContentWrapper, null, children)),
|
|
@@ -49,14 +49,15 @@ function Input(props) {
|
|
|
49
49
|
setValue(inputValue);
|
|
50
50
|
debouncedSave(id, inputValue);
|
|
51
51
|
};
|
|
52
|
-
return (react_1.default.createElement(InputWrapper,
|
|
52
|
+
return (react_1.default.createElement(InputWrapper, { "data-component-name": "Markdoc/CodeWalkthrough/Input" },
|
|
53
53
|
label && react_1.default.createElement(Label, null, label),
|
|
54
54
|
react_1.default.createElement(StyledInput, { id: id, value: value, onChange: handleChange, "aria-label": label, placeholder: placeholder })));
|
|
55
55
|
}
|
|
56
56
|
const InputWrapper = styled_components_1.default.div `
|
|
57
57
|
display: flex;
|
|
58
58
|
flex-direction: column;
|
|
59
|
-
margin: var(--
|
|
59
|
+
margin-top: var(--spacing-base);
|
|
60
|
+
margin-bottom: var(--spacing-base);
|
|
60
61
|
`;
|
|
61
62
|
const Label = styled_components_1.default.p `
|
|
62
63
|
color: var(--text-color-secondary);
|
|
@@ -64,6 +65,7 @@ const Label = styled_components_1.default.p `
|
|
|
64
65
|
line-height: var(--line-height-base);
|
|
65
66
|
font-family: var(--font-family-base);
|
|
66
67
|
font-weight: var(--font-weight-medium);
|
|
68
|
+
margin-bottom: var(--spacing-xxs) !important;
|
|
67
69
|
`;
|
|
68
70
|
const StyledInput = styled_components_1.default.input `
|
|
69
71
|
border: 1px solid var(--border-color-primary);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.1",
|
|
4
4
|
"description": "Shared UI components lib",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"theme",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/jest-when": "3.5.5",
|
|
47
47
|
"@types/lodash.debounce": "4.0.9",
|
|
48
48
|
"@types/lodash.throttle": "4.1.9",
|
|
49
|
-
"@types/node": "
|
|
49
|
+
"@types/node": "22.10.5",
|
|
50
50
|
"@types/react": "18.3.9",
|
|
51
51
|
"@types/react-dom": "18.3.5",
|
|
52
52
|
"@types/styled-components": "5.1.34",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"timeago.js": "4.0.2",
|
|
87
87
|
"i18next": "22.4.15",
|
|
88
88
|
"nprogress": "0.2.0",
|
|
89
|
-
"@redocly/config": "0.
|
|
89
|
+
"@redocly/config": "0.20.1"
|
|
90
90
|
},
|
|
91
91
|
"scripts": {
|
|
92
92
|
"watch": "tsc -p tsconfig.build.json && (concurrently \"tsc -w -p tsconfig.build.json\" \"tsc-alias -w -p tsconfig.build.json\")",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
|
-
import styled from 'styled-components';
|
|
3
|
+
import styled, { css } from 'styled-components';
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { OptionalEmailSettings, ReasonsSettingsSchema } from '@redocly/config';
|
|
6
6
|
import type { ReasonsProps } from '@redocly/theme/components/Feedback/Reasons';
|
|
7
7
|
|
|
8
8
|
import { Reasons } from '@redocly/theme/components/Feedback/Reasons';
|
|
@@ -41,7 +41,7 @@ export type MoodProps = {
|
|
|
41
41
|
neutral?: ReasonsSettingsSchema;
|
|
42
42
|
dissatisfied?: ReasonsSettingsSchema;
|
|
43
43
|
};
|
|
44
|
-
|
|
44
|
+
optionalEmail?: OptionalEmailSettings;
|
|
45
45
|
};
|
|
46
46
|
className?: string;
|
|
47
47
|
};
|
|
@@ -52,7 +52,7 @@ export function Mood({ settings, onSubmit, className }: MoodProps): JSX.Element
|
|
|
52
52
|
submitText,
|
|
53
53
|
comment: commentSettings,
|
|
54
54
|
reasons: reasonsSettings,
|
|
55
|
-
|
|
55
|
+
optionalEmail: optionalEmailSettings,
|
|
56
56
|
} = settings || {};
|
|
57
57
|
const [score, setScore] = React.useState('');
|
|
58
58
|
const [isSubmitted, setIsSubmitted] = React.useState(false);
|
|
@@ -131,8 +131,7 @@ export function Mood({ settings, onSubmit, className }: MoodProps): JSX.Element
|
|
|
131
131
|
const displayReasons = checkIfShouldDisplayReasons(score);
|
|
132
132
|
const displayComment = !!(score && !commentSettings?.hide);
|
|
133
133
|
const displaySubmitBnt = !!(score && (displayReasons || displayComment));
|
|
134
|
-
const displayFeedbackEmail =
|
|
135
|
-
!!score && anonymousUserEmailSettings?.enabled && !userData.isAuthenticated;
|
|
134
|
+
const displayFeedbackEmail = !!score && !optionalEmailSettings?.hide && !userData.isAuthenticated;
|
|
136
135
|
|
|
137
136
|
const onSubmitMoodForm = () => {
|
|
138
137
|
onSubmit({
|
|
@@ -162,7 +161,7 @@ export function Mood({ settings, onSubmit, className }: MoodProps): JSX.Element
|
|
|
162
161
|
return (
|
|
163
162
|
<MoodWrapper data-component-name="Feedback/Mood">
|
|
164
163
|
<StyledFormMandatoryFields>
|
|
165
|
-
<Label data-translation-key="feedback.settings.submitText">
|
|
164
|
+
<Label standAlone={true} data-translation-key="feedback.settings.submitText">
|
|
166
165
|
{submitText ||
|
|
167
166
|
translate(
|
|
168
167
|
'feedback.settings.submitText',
|
|
@@ -179,7 +178,7 @@ export function Mood({ settings, onSubmit, className }: MoodProps): JSX.Element
|
|
|
179
178
|
<MoodWrapper data-component-name="Feedback/Mood" className={className}>
|
|
180
179
|
<StyledForm onSubmit={onSubmitMoodForm}>
|
|
181
180
|
<StyledFormMandatoryFields>
|
|
182
|
-
<Label data-translation-key="feedback.settings.label">
|
|
181
|
+
<Label standAlone={true} data-translation-key="feedback.settings.label">
|
|
183
182
|
{label || translate('feedback.settings.label', 'Was this helpful?')}
|
|
184
183
|
</Label>
|
|
185
184
|
<StyledMandatoryFieldContainer>
|
|
@@ -241,18 +240,18 @@ export function Mood({ settings, onSubmit, className }: MoodProps): JSX.Element
|
|
|
241
240
|
|
|
242
241
|
{displayFeedbackEmail && (
|
|
243
242
|
<StyledFormOptionalFields>
|
|
244
|
-
<Label data-translation-key="feedback.settings.
|
|
245
|
-
{
|
|
243
|
+
<Label data-translation-key="feedback.settings.optionalEmail.label">
|
|
244
|
+
{optionalEmailSettings?.label ||
|
|
246
245
|
translate(
|
|
247
|
-
'feedback.settings.
|
|
246
|
+
'feedback.settings.optionalEmail.label',
|
|
248
247
|
'Your email (optional, for follow-up)',
|
|
249
248
|
)}
|
|
250
249
|
</Label>
|
|
251
250
|
<EmailInput
|
|
252
251
|
onChange={onEmailChange}
|
|
253
252
|
placeholder={
|
|
254
|
-
|
|
255
|
-
translate('feedback.settings.
|
|
253
|
+
optionalEmailSettings?.placeholder ||
|
|
254
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com')
|
|
256
255
|
}
|
|
257
256
|
type="email"
|
|
258
257
|
required={!!email}
|
|
@@ -295,12 +294,21 @@ const MoodWrapper = styled.div`
|
|
|
295
294
|
align-items: center;
|
|
296
295
|
`;
|
|
297
296
|
|
|
298
|
-
const Label = styled.h4
|
|
297
|
+
const Label = styled.h4<{ standAlone?: boolean }>`
|
|
299
298
|
font-family: var(--feedback-font-family);
|
|
300
299
|
font-weight: var(--font-weight-regular);
|
|
301
|
-
font-size: var(--feedback-
|
|
302
|
-
line-height: var(--feedback-
|
|
303
|
-
color: var(--feedback-
|
|
300
|
+
font-size: var(--feedback-font-size);
|
|
301
|
+
line-height: var(--feedback-line-height);
|
|
302
|
+
color: var(--feedback-text-color);
|
|
303
|
+
|
|
304
|
+
${({ standAlone = false }) =>
|
|
305
|
+
standAlone &&
|
|
306
|
+
css`
|
|
307
|
+
font-size: var(--feedback-header-font-size);
|
|
308
|
+
line-height: var(--feedback-header-line-height);
|
|
309
|
+
color: var(--feedback-header-text-color);
|
|
310
|
+
`}
|
|
311
|
+
|
|
304
312
|
margin: 0;
|
|
305
313
|
`;
|
|
306
314
|
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { OptionalEmailSettings } from '@redocly/config';
|
|
6
6
|
import type { ReasonsProps } from '@redocly/theme/components/Feedback/Reasons';
|
|
7
7
|
|
|
8
8
|
import { Reasons } from '@redocly/theme/components/Feedback/Reasons';
|
|
@@ -35,7 +35,7 @@ export type RatingProps = {
|
|
|
35
35
|
component?: string;
|
|
36
36
|
items: string[];
|
|
37
37
|
};
|
|
38
|
-
|
|
38
|
+
optionalEmail?: OptionalEmailSettings;
|
|
39
39
|
};
|
|
40
40
|
className?: string;
|
|
41
41
|
};
|
|
@@ -46,7 +46,7 @@ export function Rating({ settings, onSubmit, className }: RatingProps): JSX.Elem
|
|
|
46
46
|
submitText,
|
|
47
47
|
comment: commentSettings,
|
|
48
48
|
reasons: reasonsSettings,
|
|
49
|
-
|
|
49
|
+
optionalEmail: optionalEmailSettings,
|
|
50
50
|
} = settings || {};
|
|
51
51
|
const [isSubmitted, setIsSubmitted] = React.useState(false);
|
|
52
52
|
const [score, setScore] = React.useState(0);
|
|
@@ -83,8 +83,7 @@ export function Rating({ settings, onSubmit, className }: RatingProps): JSX.Elem
|
|
|
83
83
|
const displayReasons = !!(score && reasonsSettings && !reasonsSettings.hide);
|
|
84
84
|
const displayComment = !!(score && !commentSettings?.hide);
|
|
85
85
|
const displaySubmitBnt = !!(score && (displayReasons || displayComment));
|
|
86
|
-
const displayFeedbackEmail =
|
|
87
|
-
!!score && anonymousUserEmailSettings?.enabled && !userData.isAuthenticated;
|
|
86
|
+
const displayFeedbackEmail = !!score && !optionalEmailSettings?.hide && !userData.isAuthenticated;
|
|
88
87
|
|
|
89
88
|
useEffect(() => {
|
|
90
89
|
if (score && !displayComment && !displayReasons && !displayFeedbackEmail) {
|
|
@@ -154,18 +153,18 @@ export function Rating({ settings, onSubmit, className }: RatingProps): JSX.Elem
|
|
|
154
153
|
|
|
155
154
|
{displayFeedbackEmail && (
|
|
156
155
|
<StyledFormOptionalFields>
|
|
157
|
-
<Label data-translation-key="feedback.settings.
|
|
158
|
-
{
|
|
156
|
+
<Label data-translation-key="feedback.settings.optionalEmail.label">
|
|
157
|
+
{optionalEmailSettings?.label ||
|
|
159
158
|
translate(
|
|
160
|
-
'feedback.settings.
|
|
159
|
+
'feedback.settings.optionalEmail.label',
|
|
161
160
|
'Your email (optional, for follow-up)',
|
|
162
161
|
)}
|
|
163
162
|
</Label>
|
|
164
163
|
<EmailInput
|
|
165
164
|
onChange={onEmailChange}
|
|
166
165
|
placeholder={
|
|
167
|
-
|
|
168
|
-
translate('feedback.settings.
|
|
166
|
+
optionalEmailSettings?.placeholder ||
|
|
167
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com')
|
|
169
168
|
}
|
|
170
169
|
type="email"
|
|
171
170
|
required={!!email}
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { OptionalEmailSettings } from '@redocly/config';
|
|
6
6
|
import type { ReasonsProps } from '@redocly/theme/components/Feedback/Reasons';
|
|
7
7
|
|
|
8
8
|
import { breakpoints } from '@redocly/theme/core/utils';
|
|
@@ -37,7 +37,7 @@ export type ScaleProps = {
|
|
|
37
37
|
component?: string;
|
|
38
38
|
items: string[];
|
|
39
39
|
};
|
|
40
|
-
|
|
40
|
+
optionalEmail?: OptionalEmailSettings;
|
|
41
41
|
};
|
|
42
42
|
className?: string;
|
|
43
43
|
};
|
|
@@ -50,7 +50,7 @@ export function Scale({ settings, onSubmit, className }: ScaleProps): JSX.Elemen
|
|
|
50
50
|
rightScaleLabel,
|
|
51
51
|
comment: commentSettings,
|
|
52
52
|
reasons: reasonsSettings,
|
|
53
|
-
|
|
53
|
+
optionalEmail: optionalEmailSettings,
|
|
54
54
|
} = settings || {};
|
|
55
55
|
const [score, setScore] = React.useState(0);
|
|
56
56
|
const [isSubmitted, setIsSubmitted] = React.useState(false);
|
|
@@ -85,8 +85,7 @@ export function Scale({ settings, onSubmit, className }: ScaleProps): JSX.Elemen
|
|
|
85
85
|
const displayReasons = !!score && reasonsSettings && !reasonsSettings.hide;
|
|
86
86
|
const displayComment = !!(score && !commentSettings?.hide);
|
|
87
87
|
const displaySubmitBnt = !!score && (displayReasons || displayComment);
|
|
88
|
-
const displayFeedbackEmail =
|
|
89
|
-
!!score && anonymousUserEmailSettings?.enabled && !userData.isAuthenticated;
|
|
88
|
+
const displayFeedbackEmail = !!score && !optionalEmailSettings?.hide && !userData.isAuthenticated;
|
|
90
89
|
|
|
91
90
|
const handleCancel = () => {
|
|
92
91
|
setScore(0);
|
|
@@ -179,18 +178,18 @@ export function Scale({ settings, onSubmit, className }: ScaleProps): JSX.Elemen
|
|
|
179
178
|
|
|
180
179
|
{displayFeedbackEmail && (
|
|
181
180
|
<StyledFormOptionalFields>
|
|
182
|
-
<Label data-translation-key="feedback.settings.
|
|
183
|
-
{
|
|
181
|
+
<Label data-translation-key="feedback.settings.optionalEmail.label">
|
|
182
|
+
{optionalEmailSettings?.label ||
|
|
184
183
|
translate(
|
|
185
|
-
'feedback.settings.
|
|
184
|
+
'feedback.settings.optionalEmail.label',
|
|
186
185
|
'Your email (optional, for follow-up)',
|
|
187
186
|
)}
|
|
188
187
|
</Label>
|
|
189
188
|
<EmailInput
|
|
190
189
|
onChange={onEmailChange}
|
|
191
190
|
placeholder={
|
|
192
|
-
|
|
193
|
-
translate('feedback.settings.
|
|
191
|
+
optionalEmailSettings?.placeholder ||
|
|
192
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com')
|
|
194
193
|
}
|
|
195
194
|
type="email"
|
|
196
195
|
required={!!email}
|