properties) {
+ addClassName("source-code-viewer");
+ addClassName("has-code-viewer-gutter");
+
codeViewer = new Element("code-viewer");
- getElement().appendChild(codeViewer);
- getElement().getStyle().set("overflow", "auto");
- getElement().getStyle().set("display", "flex");
- codeViewer.getStyle().set("flex-grow", "1");
+
+ Div codeViewerWrapper = new Div();
+ codeViewerWrapper.addClassName("source-code-viewer-codeviewer-wrapper");
+ codeViewerWrapper.getElement().appendChild(codeViewer);
+
+ // Non-scrolling overlay so the buttons stay pinned while the code scrolls
+ buttonsWrapper = new Div();
+ buttonsWrapper.addClassName("source-code-viewer-buttons-wrapper");
+
+ add(codeViewerWrapper, buttonsWrapper);
+
setProperties(properties);
- addAttachListener(ev -> fetchContents(url, language));
+ addAttachListener(ev -> {
+ fetchContents(url, language);
+ observeScrollbar();
+ });
+ }
+
+ /**
+ * Adds the overlay controls (show, hide, flip and rotate) pinned over the source code.
+ *
+ * The buttons do not change this viewer directly. Instead, each one dispatches a bubbling DOM
+ * event that is expected to be handled by an enclosing layout, which is what actually collapses,
+ * repositions or reorients the source panel:
+ *
+ * - show / hide dispatch {@code source-collapse-changed} (carrying {@code detail.collapsed});
+ *
- flip dispatches {@code source-flip};
+ *
- rotate dispatches {@code source-rotate}.
+ *
+ * The buttons are therefore only useful when this viewer is placed inside a layout that listens
+ * for those events and coordinates the response (see {@link TabbedDemo}); otherwise they emit
+ * events that nothing consumes.
+ *
+ * The controls are rendered by the {@code source-code-viewer-buttons} client-side web component,
+ * which dispatches the events directly on click, so no server roundtrip is involved. This method
+ * is idempotent: the component is added only once.
+ */
+ public void withButtons() {
+ if (buttonsWrapper.getElement().getChildCount() == 0) {
+ buttonsWrapper.getElement().appendChild(new Element("source-code-viewer-buttons"));
+ }
+ }
+
+ /**
+ * Observes the scrollable wrapper. Whenever the vertical scrollbar appears or disappears, sets (or
+ * clears) the {@code --code-viewer-gutter} custom property on the nearest ancestor (or self)
+ * carrying the {@code has-code-viewer-gutter} class. Whenever the wrapper collapses below 24px in
+ * either axis, sets {@code --source-code-viewer-show-button-display} so the show button becomes
+ * visible (and clears it otherwise).
+ */
+ private void observeScrollbar() {
+ getElement().executeJs(
+ """
+ const root = this;
+ const wrapper = root.querySelector('.source-code-viewer-codeviewer-wrapper');
+ if (!wrapper) return;
+ root.__scrollbarObserver?.disconnect();
+ root.__scrollbarMutation?.disconnect();
+ let hasScrollbar = null;
+ const update = () => {
+ if (wrapper.offsetWidth < 24 || wrapper.offsetHeight < 10) {
+ root.style.setProperty('--source-code-viewer-show-button-display', 'block');
+ } else {
+ root.style.removeProperty('--source-code-viewer-show-button-display');
+ }
+ const current = wrapper.scrollHeight > wrapper.clientHeight;
+ if (current === hasScrollbar) return;
+ hasScrollbar = current;
+ let target = root;
+ while (target && !target.classList.contains('has-code-viewer-gutter')) {
+ target = target.parentElement;
+ }
+ if (target) {
+ if (current) {
+ const scrollbarWidth = wrapper.offsetWidth - wrapper.clientWidth;
+ target.style.setProperty('--code-viewer-gutter', scrollbarWidth + 'px');
+ } else {
+ target.style.removeProperty('--code-viewer-gutter');
+ }
+ }
+ };
+ let frame = 0;
+ const scheduleUpdate = () => {
+ if (frame) return;
+ frame = requestAnimationFrame(() => { frame = 0; update(); });
+ };
+ const resizeObserver = new ResizeObserver(scheduleUpdate);
+ resizeObserver.observe(wrapper);
+ root.__scrollbarObserver = resizeObserver;
+ const codeViewer = root.querySelector('code-viewer');
+ if (codeViewer) {
+ const mutationObserver = new MutationObserver(scheduleUpdate);
+ mutationObserver.observe(codeViewer, {childList: true, subtree: true});
+ root.__scrollbarMutation = mutationObserver;
+ }
+ update();
+ """);
+ }
+
+ private void dispatchEvent(ComponentEvent extends Component> ev) {
+ for (Component c = this; c != null; c = c.getParent().orElse(null)) {
+ ComponentUtil.fireEvent(c, ev);
+ }
}
public void fetchContents(String url, String language) {
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
index 1f7a148..25aee66 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
@@ -48,7 +48,7 @@ public SplitLayoutDemo(Component demo, List tabs) {
properties.put("vaadin", VaadinVersion.getVaadinVersion());
properties.put("flow", Version.getFullVersion());
- code = new MultiSourceCodeViewer(tabs, properties);
+ code = new MultiSourceCodeViewer(tabs, properties).withButtons();
this.demo = demo;
setSourcePosition(code.getSourcePosition());
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
index 52dc8fa..7a12934 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
@@ -77,9 +77,6 @@ public class TabbedDemo extends VerticalLayout implements RouterLayout {
private EnhancedRouteTabs tabs;
private HorizontalLayout footer;
private SplitLayoutDemo currentLayout;
- private Checkbox orientationCB;
- private Checkbox codeCB;
- private Checkbox codePositionCB;
private Checkbox themeCB;
private Orientation splitOrientation;
private Button helperButton;
@@ -93,28 +90,14 @@ public TabbedDemo() {
tabs = new EnhancedRouteTabs();
- // Footer
- orientationCB = new Checkbox("Toggle Orientation");
- orientationCB.setValue(true);
- orientationCB.addClassName("smallcheckbox");
- orientationCB.addValueChangeListener(ev -> {
- if (ev.isFromClient()) {
- toggleSplitterOrientation(ev.isFromClient());
- }
- });
- codeCB = new Checkbox("Show Source Code");
- codeCB.setValue(true);
- codeCB.addClassName("smallcheckbox");
- codeCB.addValueChangeListener(
- ev -> fireSourceCollapseChangedEvent(!ev.getValue(), ev.isFromClient()));
+ // The source controls live inside SourceCodeViewer and signal across components
+ // via bubbling DOM events; collapse carries data, so it uses SourceCollapseChangedEvent.
addSourceCollapseListener(ev -> {
sourceCollapsed = ev.isCollapsed();
updateSplitterPosition();
});
- codePositionCB = new Checkbox("Toggle Code Position");
- codePositionCB.setValue(true);
- codePositionCB.addClassName("smallcheckbox");
- codePositionCB.addValueChangeListener(ev -> toggleSourcePosition(ev.isFromClient()));
+ getElement().addEventListener("source-flip", ev -> toggleSourcePosition(true));
+ getElement().addEventListener("source-rotate", ev -> toggleSplitterOrientation(true));
themeCB = new Checkbox("Dark Theme");
themeCB.setValue(false);
themeCB.addClassName("smallcheckbox");
@@ -126,7 +109,7 @@ public TabbedDemo() {
footer = new HorizontalLayout();
footer.setWidthFull();
footer.setJustifyContentMode(JustifyContentMode.END);
- footer.add(codeCB, codePositionCB, orientationCB, themeCB);
+ footer.add(themeCB);
footer.setClassName("demo-footer");
Package pkg = this.getClass().getPackage();
@@ -348,8 +331,6 @@ private void updateSplitterPosition() {
} else {
currentLayout.showSourceCode();
}
- orientationCB.setEnabled(!sourceCollapsed);
- codePositionCB.setEnabled(!sourceCollapsed);
}
}
@@ -359,8 +340,7 @@ private void updateSplitterPosition() {
* @param visible {@code true} to make the source code visible, {@code false} otherwise
*/
public void setSourceVisible(boolean visible) {
- codeCB.setValue(visible);
- codePositionCB.setVisible(visible);
+ fireSourceCollapseChangedEvent(!visible, false);
}
/**
@@ -428,7 +408,6 @@ private void setOrientation(Orientation orientation, boolean fromClient) {
currentLayout.setOrientation(orientation);
currentLayout.setSplitterPosition(50);
}
- orientationCB.setValue(Orientation.HORIZONTAL.equals(orientation));
fireOrientationChangedEvent(orientation, fromClient);
}
@@ -525,9 +504,6 @@ private static Stream collectThemeChangeObservers(Component
private void updateFooterButtonsVisibility() {
boolean hasSourceCode = currentLayout != null;
ComponentUtil.fireEvent(this, new TabbedDemoSourceEvent(this, hasSourceCode));
- orientationCB.setVisible(hasSourceCode);
- codeCB.setVisible(hasSourceCode);
- codePositionCB.setVisible(hasSourceCode);
}
/**
@@ -546,8 +522,7 @@ protected void onAttach(AttachEvent attachEvent) {
super.onAttach(attachEvent);
getUI().ifPresent(ui -> ui.getPage().retrieveExtendedClientDetails(receiver -> {
boolean mobile = receiver.getBodyClientWidth() <= MOBILE_DEVICE_BREAKPOINT_WIDTH;
- codeCB.setValue(!sourceCollapsed && !mobile);
- codePositionCB.setValue(!sourceCollapsed && !mobile);
+ fireSourceCollapseChangedEvent(sourceCollapsed || mobile, false);
boolean portraitOrientation = receiver.getBodyClientHeight() > receiver.getBodyClientWidth();
adjustSplitOrientation(portraitOrientation);
diff --git a/base/src/main/resources/META-INF/resources/frontend/source-code-viewer-buttons.ts b/base/src/main/resources/META-INF/resources/frontend/source-code-viewer-buttons.ts
new file mode 100644
index 0000000..f83182f
--- /dev/null
+++ b/base/src/main/resources/META-INF/resources/frontend/source-code-viewer-buttons.ts
@@ -0,0 +1,70 @@
+/*-
+ * #%L
+ * Commons Demo
+ * %%
+ * Copyright (C) 2020 - 2026 Flowing Code
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+import {
+ html,
+ LitElement
+} from "lit-element";
+
+import {customElement} from 'lit/decorators/custom-element.js';
+import '@vaadin/button/vaadin-button.js';
+import './commons-demo-iconset.js';
+
+/**
+ * Overlay controls pinned over the source code. Each button dispatches a bubbling DOM event that is
+ * handled by an enclosing layout (see TabbedDemo), which is what actually collapses, repositions or
+ * reorients the source panel. Firing the events on the client avoids a server roundtrip on click.
+ */
+@customElement("source-code-viewer-buttons")
+export class SourceCodeViewerButtons extends LitElement {
+
+ // Render in light DOM so the shared stylesheet (shared-styles.css) styles the buttons.
+ createRenderRoot() {
+ return this;
+ }
+
+ private fire(type: string, detail?: any) {
+ this.dispatchEvent(new CustomEvent(type, {bubbles: true, detail}));
+ }
+
+ render() {
+ return html`
+ this.fire('source-collapse-changed', {collapsed: false})}>
+
+
+ this.fire('source-collapse-changed', {collapsed: true})}>
+
+
+ this.fire('source-flip')}>
+
+
+ this.fire('source-rotate')}>
+
+
+ `;
+ }
+}
diff --git a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
index 6fef4f7..bb7034e 100644
--- a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
+++ b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
@@ -51,5 +51,122 @@ code-highlighter code {
cursor: pointer;
}
+.source-code-viewer {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ overflow: hidden;
+}
+
+.source-code-viewer-codeviewer-wrapper {
+ display: flex;
+ flex-grow: 1;
+ overflow: auto;
+}
+
+.source-code-viewer-codeviewer-wrapper > code-viewer {
+ flex-grow: 1;
+}
+
+.source-code-viewer-buttons-wrapper {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+}
+
+source-code-viewer-buttons {
+ position: absolute;
+ z-index: 1;
+ right: calc(0.25rem + var(--code-viewer-gutter, 0px));
+ top: 0.25rem;
+ display: flex;
+ gap: var(--lumo-space-xs, 0.25rem);
+ container-type: inline-size;
+ width: 100%;
+ justify-content: end;
+ pointer-events: none;
+}
+
+vaadin-button.source-code-viewer-button {
+ color: color-mix(in srgb, #f8f8f2 70%, transparent);
+ pointer-events: auto;
+ background: transparent;
+ display: none;
+ padding: 0;
+}
+
+vaadin-button.source-code-viewer-button vaadin-icon {
+ --vaadin-icon-size: 20px;
+ padding: 0.125em;
+}
+
+@container style(--lumo-size-m) {
+ vaadin-button.source-code-viewer-button vaadin-icon {
+ padding: 0.25em;
+ }
+}
+
+
+vaadin-button.source-code-viewer-show-button {
+ display: var(--source-code-viewer-show-button-display, none);
+ color: var(--lumo-body-text-color, var(--vaadin-text-color));
+ position: fixed;
+}
+
+[orientation="horizontal"] [slot="primary"] vaadin-button.source-code-viewer-show-button {
+ right: 0;
+}
+
+[orientation="horizontal"] [slot="secondary"] vaadin-button.source-code-viewer-show-button {
+ right: 0.5rem;
+}
+
+[orientation="vertical"] [slot="primary"] vaadin-button.source-code-viewer-show-button {
+ top: 0.5rem;
+}
+
+[orientation="vertical"] [slot="secondary"] vaadin-button.source-code-viewer-show-button {
+ top: 0;
+}
+
+/* Rotate the icons to match the layout disposition.*/
+[orientation="horizontal"] [slot="secondary"] vaadin-button.source-code-viewer-button{
+ transform: rotate(0deg);
+ &.source-code-viewer-rotate-button { transform: scalex(-1) rotate(90deg); }
+}
+
+[orientation="horizontal"] [slot="primary"] vaadin-button.source-code-viewer-button {
+ transform: rotate(180deg);
+ &.source-code-viewer-rotate-button { transform: rotate(0deg); }
+}
+
+[orientation="vertical"] [slot="secondary"] vaadin-button.source-code-viewer-button {
+ transform: rotate(90deg);
+ &.source-code-viewer-rotate-button { transform: rotate(0deg); }
+}
+
+[orientation="vertical"] [slot="primary"] vaadin-button.source-code-viewer-button {
+ transform: rotate(270deg);
+ &.source-code-viewer-rotate-button { transform: scalex(-1) rotate(90deg); }
+}
+
+@container (min-width: 82px) {
+ vaadin-button.source-code-viewer-flip-button {
+ display: block;
+ }
+}
+
+@container (min-width: 53px) {
+ vaadin-button.source-code-viewer-rotate-button {
+ display: block;
+ }
+}
+
+@container (min-width: 24px) {
+ vaadin-button.source-code-viewer-hide-button {
+ display: block;
+ }
+}
+
.commons-demo-split-layout { overflow: hidden }
.commons-demo-split-layout > [slot] { overflow: auto; }
\ No newline at end of file
From fee7f8c9fbe6044732f06573efa79d1e92797ddf Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 13:29:17 -0300
Subject: [PATCH 09/18] build: set version of maven-clean-plugin
---
base/pom.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/base/pom.xml b/base/pom.xml
index 372902e..d2e3426 100644
--- a/base/pom.xml
+++ b/base/pom.xml
@@ -324,6 +324,7 @@
org.apache.maven.plugins
maven-clean-plugin
+ 3.3.2
From fc6726b76d50c7464c34579c86287d747761eed8 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 14:58:02 -0300
Subject: [PATCH 10/18] refactor: remove setSplitterPosition(int) from
SplitLayoutDemo
---
.../com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java | 4 ----
.../java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
index 25aee66..b4b446f 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
@@ -93,10 +93,6 @@ public Orientation getOrientation() {
return getContent().getOrientation();
}
- public void setSplitterPosition(int pos) {
- getContent().setSplitterPosition(pos);
- }
-
public void setSizeFull() {
getContent().setSizeFull();
}
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
index 7a12934..a7c1754 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
@@ -406,7 +406,7 @@ private void setOrientation(Orientation orientation, boolean fromClient) {
splitOrientation = orientation;
if (currentLayout != null) {
currentLayout.setOrientation(orientation);
- currentLayout.setSplitterPosition(50);
+ currentLayout.showSourceCode();
}
fireOrientationChangedEvent(orientation, fromClient);
}
From 1e43fd1b28c0b1233de1c5fd71a9284738d911b9 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 15:06:23 -0300
Subject: [PATCH 11/18] refactor: remove splitOrientation variable in
TabbedDemo
---
.../vaadin/addons/demo/TabbedDemo.java | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
index a7c1754..9abf747 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
@@ -78,7 +78,6 @@ public class TabbedDemo extends VerticalLayout implements RouterLayout {
private HorizontalLayout footer;
private SplitLayoutDemo currentLayout;
private Checkbox themeCB;
- private Orientation splitOrientation;
private Button helperButton;
private DemoHelperViewer demoHelperViewer;
@@ -223,6 +222,11 @@ public void showRouterLayoutContent(HasElement content) {
createSourceCodeTab(demo.getClass(), demoSource).ifPresent(sourceTabs::add);
}
+ Orientation splitOrientation = null;
+ if (currentLayout != null) {
+ splitOrientation = currentLayout.getOrientation();
+ }
+
if (!sourceTabs.isEmpty()) {
currentLayout = new SplitLayoutDemo(demo, sourceTabs);
if (currentLayout.isEmpty()) {
@@ -376,6 +380,8 @@ private void toggleSplitterOrientation(boolean fromClient) {
if (currentLayout == null) {
return;
}
+
+ Orientation splitOrientation = getOrientation();
if (Orientation.HORIZONTAL.equals(splitOrientation)) {
splitOrientation = Orientation.VERTICAL;
} else {
@@ -403,12 +409,11 @@ public void setOrientation(Orientation orientation) {
}
private void setOrientation(Orientation orientation, boolean fromClient) {
- splitOrientation = orientation;
- if (currentLayout != null) {
- currentLayout.setOrientation(orientation);
- currentLayout.showSourceCode();
+ if (currentLayout != null && orientation != getOrientation()) {
+ currentLayout.setOrientation(orientation);
+ currentLayout.showSourceCode();
+ fireOrientationChangedEvent(orientation, fromClient);
}
- fireOrientationChangedEvent(orientation, fromClient);
}
/**
@@ -531,11 +536,10 @@ protected void onAttach(AttachEvent attachEvent) {
private void adjustSplitOrientation(boolean portraitOrientation) {
if (portraitOrientation) {
- splitOrientation = Orientation.VERTICAL;
+ setOrientation(Orientation.VERTICAL);
} else {
- splitOrientation = Orientation.HORIZONTAL;
+ setOrientation(Orientation.HORIZONTAL);
}
- setOrientation(splitOrientation);
}
/**
From 6261172152058c61f59d4651fc896863209455c1 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 15:18:04 -0300
Subject: [PATCH 12/18] refactor: unify hide/show source methods in
SplitLayoutDemo
---
.../vaadin/addons/demo/SplitLayoutDemo.java | 24 +++++++++----------
.../vaadin/addons/demo/TabbedDemo.java | 8 ++-----
2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
index b4b446f..d093d54 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java
@@ -97,18 +97,18 @@ public void setSizeFull() {
getContent().setSizeFull();
}
- public void showSourceCode() {
- getContent().setSplitterPosition(50);
- }
-
- public void hideSourceCode() {
- switch (sourcePosition) {
- case PRIMARY:
- getContent().setSplitterPosition(0);
- break;
- case SECONDARY:
- getContent().setSplitterPosition(100);
- break;
+ public void setSourceCollapsed(boolean collapsed) {
+ if (!collapsed) {
+ getContent().setSplitterPosition(50);
+ } else {
+ switch (sourcePosition) {
+ case PRIMARY:
+ getContent().setSplitterPosition(0);
+ break;
+ case SECONDARY:
+ getContent().setSplitterPosition(100);
+ break;
+ }
}
}
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
index 9abf747..267791b 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
@@ -330,11 +330,7 @@ public void removeRouterLayoutContent(HasElement oldContent) {
private void updateSplitterPosition() {
if (currentLayout != null) {
- if (sourceCollapsed) {
- currentLayout.hideSourceCode();
- } else {
- currentLayout.showSourceCode();
- }
+ currentLayout.setSourceCollapsed(sourceCollapsed);
}
}
@@ -411,7 +407,7 @@ public void setOrientation(Orientation orientation) {
private void setOrientation(Orientation orientation, boolean fromClient) {
if (currentLayout != null && orientation != getOrientation()) {
currentLayout.setOrientation(orientation);
- currentLayout.showSourceCode();
+ currentLayout.setSourceCollapsed(false);
fireOrientationChangedEvent(orientation, fromClient);
}
}
From 542ae4d631f1b340e7a21137dd8afd41b27dcc80 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:17:06 -0300
Subject: [PATCH 13/18] WIP: ....
Co-Authored-By: Claude Opus 4.8 (1M context)
---
.../resources/frontend/styles/commons-demo/shared-styles.css | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
index bb7034e..cd860cf 100644
--- a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
+++ b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
@@ -132,7 +132,7 @@ vaadin-button.source-code-viewer-show-button {
/* Rotate the icons to match the layout disposition.*/
[orientation="horizontal"] [slot="secondary"] vaadin-button.source-code-viewer-button{
transform: rotate(0deg);
- &.source-code-viewer-rotate-button { transform: scalex(-1) rotate(90deg); }
+ &.source-code-viewer-rotate-button { transform: scaleX(-1) rotate(90deg); }
}
[orientation="horizontal"] [slot="primary"] vaadin-button.source-code-viewer-button {
@@ -147,7 +147,7 @@ vaadin-button.source-code-viewer-show-button {
[orientation="vertical"] [slot="primary"] vaadin-button.source-code-viewer-button {
transform: rotate(270deg);
- &.source-code-viewer-rotate-button { transform: scalex(-1) rotate(90deg); }
+ &.source-code-viewer-rotate-button { transform: scaleX(-1) rotate(90deg); }
}
@container (min-width: 82px) {
From eb996c045fc061d1f76d68fd053c1a8e09fc10c4 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:19:52 -0300
Subject: [PATCH 14/18] WIP: comment formatting nit flagged by stylelint.
---
.../resources/frontend/styles/commons-demo/shared-styles.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
index cd860cf..be7f6fb 100644
--- a/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
+++ b/base/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.css
@@ -129,7 +129,7 @@ vaadin-button.source-code-viewer-show-button {
top: 0;
}
-/* Rotate the icons to match the layout disposition.*/
+/* Rotate the icons to match the layout disposition. */
[orientation="horizontal"] [slot="secondary"] vaadin-button.source-code-viewer-button{
transform: rotate(0deg);
&.source-code-viewer-rotate-button { transform: scaleX(-1) rotate(90deg); }
From 212e63229b3f077c3e43e600d9ba2f2bf89b18e7 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:20:12 -0300
Subject: [PATCH 15/18] WIP: use ${project.version} for commons-demo dependency
in processor
Co-Authored-By: Claude Opus 4.8 (1M context)
---
processor/pom.xml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/processor/pom.xml b/processor/pom.xml
index b775913..48f9113 100644
--- a/processor/pom.xml
+++ b/processor/pom.xml
@@ -23,7 +23,6 @@
UTF-8
17
17
- 5.3.2-SNAPSHOT
@@ -50,7 +49,7 @@
com.flowingcode.vaadin.addons.demo
commons-demo
- ${commons-demo.version}
+ ${project.version}
provided
From b789df57e0cfcac5d7a5ba41963ff2c39bf90499 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:20:38 -0300
Subject: [PATCH 16/18] WIP: ....
Co-Authored-By: Claude Opus 4.8 (1M context)
---
.../com/flowingcode/vaadin/addons/demo/SourceCodeViewer.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeViewer.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeViewer.java
index f2016d2..cd73ca9 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeViewer.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeViewer.java
@@ -94,8 +94,9 @@ public SourceCodeViewer(String url, String language, Map propert
* events that nothing consumes.
*
* The controls are rendered by the {@code source-code-viewer-buttons} client-side web component,
- * which dispatches the events directly on click, so no server roundtrip is involved. This method
- * is idempotent: the component is added only once.
+ * which dispatches the events locally on click; the enclosing layout (see {@link TabbedDemo})
+ * handles them through Vaadin server-side listeners. This method is idempotent: the component is
+ * added only once.
*/
public void withButtons() {
if (buttonsWrapper.getElement().getChildCount() == 0) {
From eb8d0290f6561ddb478c8403d14d8fa8b8f7b730 Mon Sep 17 00:00:00 2001
From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com>
Date: Wed, 1 Jul 2026 17:21:21 -0300
Subject: [PATCH 17/18] WIP: ....
Co-Authored-By: Claude Opus 4.8 (1M context)
---
.../flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java
index 478f8d7..11baff5 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java
@@ -84,7 +84,9 @@ public MultiSourceCodeViewer(List sourceCodeTabs, Map
Date: Wed, 1 Jul 2026 17:23:20 -0300
Subject: [PATCH 18/18] WIP:...
---
.../com/flowingcode/vaadin/addons/demo/CommonsDemoIcons.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/base/src/main/java/com/flowingcode/vaadin/addons/demo/CommonsDemoIcons.java b/base/src/main/java/com/flowingcode/vaadin/addons/demo/CommonsDemoIcons.java
index af68c25..49277fc 100644
--- a/base/src/main/java/com/flowingcode/vaadin/addons/demo/CommonsDemoIcons.java
+++ b/base/src/main/java/com/flowingcode/vaadin/addons/demo/CommonsDemoIcons.java
@@ -65,7 +65,7 @@ public Icon create() {
}
/**
- * Server side component for {@code Brands}
+ * Server side component for CommonsDemo icons.
*/
@JsModule("./commons-demo-iconset.ts")
@SuppressWarnings("serial")