diff --git a/znai-docs/znai/release-notes/1.88/fix-2026-04-06-tabs-switch-wrong-content.md b/znai-docs/znai/release-notes/1.88/fix-2026-04-06-tabs-switch-wrong-content.md new file mode 100644 index 000000000..18004de38 --- /dev/null +++ b/znai-docs/znai/release-notes/1.88/fix-2026-04-06-tabs-switch-wrong-content.md @@ -0,0 +1 @@ +* Fix: Tab properly displays selected content (instead of previously selected content) \ No newline at end of file diff --git a/znai-docs/znai/snippets/file-name.js b/znai-docs/znai/snippets/file-name.js index baf15538d..a7ee6e8ea 100644 --- a/znai-docs/znai/snippets/file-name.js +++ b/znai-docs/znai/snippets/file-name.js @@ -1,7 +1,7 @@ class JsClass { - constructor() { - usefulAction() - } + constructor() { + usefulAction(); + } } -export default JsClass \ No newline at end of file +export default JsClass; diff --git a/znai-reactjs/src/doc-elements/code-snippets/SimpleCodeSnippet.jsx b/znai-reactjs/src/doc-elements/code-snippets/SimpleCodeSnippet.jsx index c5010559e..e5fc13661 100644 --- a/znai-reactjs/src/doc-elements/code-snippets/SimpleCodeSnippet.jsx +++ b/znai-reactjs/src/doc-elements/code-snippets/SimpleCodeSnippet.jsx @@ -38,34 +38,12 @@ class SimpleCodeSnippet extends React.Component { constructor(props) { super(props); - this.processProps(props); this.state = { clickedReadMore: false, hasHighlightedText: false, }; } - // handles changes during preview - componentDidUpdate(prevProps) { - // Only process props if they actually changed - if ( - prevProps.tokens !== this.props.tokens || - prevProps.linesOfCode !== this.props.linesOfCode || - prevProps.highlight !== this.props.highlight - ) { - this.processProps(this.props); - // If you need to update state based on props changes, you can do it here - // but be careful to avoid infinite loops - } - } - - processProps({ tokens, linesOfCode, highlight }) { - this.linesOfTokens = !linesOfCode ? splitTokensIntoLines(tokens) : linesOfCode; - - // highlight is either a single line index/substring or a collection of line indexes and substrings - this.highlight = convertToList(highlight); - } - componentDidMount() { addHighlightedTextListener(this); } @@ -99,14 +77,16 @@ class SimpleCodeSnippet extends React.Component { render() { this.hiddenLinesContainerRef = React.createRef(); const { clickedReadMore } = this.state; - const { wrap, isPresentation, slideIdx, references } = this.props; + const { wrap, isPresentation, slideIdx, references, tokens, linesOfCode, highlight } = this.props; // slideIdx === 0 means no highlights, 1 - first highlight, etc const highlightIsVisible = !isPresentation || slideIdx > 0; - const linesOfTokens = this.linesOfTokens; + const linesOfTokens = !linesOfCode ? splitTokensIntoLines(tokens) : linesOfCode; + const highlightList = convertToList(highlight); + const visibleLines = - this.limitLines(this.props) && !clickedReadMore && !isPresentation + this.limitLines(linesOfTokens, this.props) && !clickedReadMore && !isPresentation ? linesOfTokens.slice(0, this.readMoreVisibleLines(this.props)) : linesOfTokens; @@ -115,7 +95,7 @@ class SimpleCodeSnippet extends React.Component { const linesToRender = this.processLinesToRender(visibleLines); const mergedReferences = mergeWithGlobalDocReferences(references); - const isHighlightedByIdx = highlightIsVisible ? linesToRender.map((_, lineIdx) => this.isHighlighted(lineIdx)) : []; + const isHighlightedByIdx = highlightIsVisible ? linesToRender.map((_, lineIdx) => this.isHighlighted(highlightList, lineIdx)) : []; return (
@@ -157,9 +137,11 @@ class SimpleCodeSnippet extends React.Component {
renderReadMore() {
const { clickedReadMore } = this.state;
- const { isPresentation } = this.props;
+ const { isPresentation, tokens, linesOfCode } = this.props;
+
+ const linesOfTokens = !linesOfCode ? splitTokensIntoLines(tokens) : linesOfCode;
- if (isPresentation || !this.limitLines(this.props)) {
+ if (isPresentation || !this.limitLines(linesOfTokens, this.props)) {
return null;
}
@@ -208,20 +190,20 @@ class SimpleCodeSnippet extends React.Component {
);
};
- limitLines(props) {
- return this.linesOfTokens.length >= this.readMoreVisibleLines(props) && props.readMore;
+ limitLines(linesOfTokens, props) {
+ return linesOfTokens.length >= this.readMoreVisibleLines(props) && props.readMore;
}
readMoreVisibleLines(props) {
return props.readMoreVisibleLines || 8;
}
- isHighlighted(lineIdx) {
+ isHighlighted(highlightList, lineIdx) {
const { meta, isPresentation, slideIdx, revealLineStop } = this.props;
- const highlightSliceIdx = calcHighlightSliceIdx(this.highlight);
+ const highlightSliceIdx = calcHighlightSliceIdx(highlightList);
- const highlight = !isPresentation ? this.highlight : this.highlight.slice(0, highlightSliceIdx);
+ const highlight = !isPresentation ? highlightList : highlightList.slice(0, highlightSliceIdx);
if (!highlight) {
return false;
diff --git a/znai-tests/src/test/groovy/pages/DocContent.groovy b/znai-tests/src/test/groovy/pages/DocContent.groovy
index cba260ad0..41617f335 100644
--- a/znai-tests/src/test/groovy/pages/DocContent.groovy
+++ b/znai-tests/src/test/groovy/pages/DocContent.groovy
@@ -26,6 +26,10 @@ class DocContent {
def mainPanelScrollTop = mainPanel.scrollTop
def mermaidClickableNodes = $(".znai-mermaid .clickable")
+ def tabNames = $(".tabs-area .tab-name")
+ def activeTabName = $(".tabs-area .tab-name.active")
+ def tabsSnippet = $(".tabs-area .snippet")
+
void clickMermaidNode() {
// GeckoDriver can't click elements inside SVG (even HTML inside foreignObject),
// use DOM .click() which creates a trusted event
diff --git a/znai-tests/src/test/groovy/sampledoc/chapter-one/tabs.md b/znai-tests/src/test/groovy/sampledoc/chapter-one/tabs.md
new file mode 100644
index 000000000..e5a50eae4
--- /dev/null
+++ b/znai-tests/src/test/groovy/sampledoc/chapter-one/tabs.md
@@ -0,0 +1,20 @@
+# Tabs Switching
+
+Tabs with code snippets for e2e testing of tab switching.
+
+````tabs
+Java:
+```java
+System.out.println("hello from java");
+```
+
+Python:
+```python
+print("hello from python")
+```
+
+Ruby:
+```ruby
+puts "hello from ruby"
+```
+````
diff --git a/znai-tests/src/test/groovy/sampledoc/toc b/znai-tests/src/test/groovy/sampledoc/toc
index 74b7a75df..82c3c4895 100644
--- a/znai-tests/src/test/groovy/sampledoc/toc
+++ b/znai-tests/src/test/groovy/sampledoc/toc
@@ -2,6 +2,7 @@ outside-chapter-file.md
chapter-one
links
target
+ tabs
chapter-two
doxygen-from-zip
chapter-three
diff --git a/znai-tests/src/test/groovy/scenarios/sampleDoc.groovy b/znai-tests/src/test/groovy/scenarios/sampleDoc.groovy
index 4ae784ead..c53444ab9 100644
--- a/znai-tests/src/test/groovy/scenarios/sampleDoc.groovy
+++ b/znai-tests/src/test/groovy/scenarios/sampleDoc.groovy
@@ -45,6 +45,29 @@ scenario("check redirect page") {
docContent.title.waitToBe == "Links"
}
+scenario("switch tabs and validate snippet content") {
+ def snippets = [
+ Java : 'System.out.println("hello from java");',
+ Python: 'print("hello from python")',
+ Ruby : 'puts "hello from ruby"',
+ ]
+
+ def assertActiveTab = { String name ->
+ docContent.activeTabName.waitTo == name
+ docContent.tabsSnippet.waitTo == snippets[name]
+ }
+
+ standardView.tocItems.get("Tabs").click()
+ docContent.title.waitTo == "Tabs"
+
+ assertActiveTab("Java")
+
+ ["Python", "Ruby", "Java"].each { name ->
+ docContent.tabNames.get(name).click()
+ assertActiveTab(name)
+ }
+}
+
scenario("validate uploads files") {
def baseUrl = "http://localhost:$port/preview"