diff --git a/.github/styles/Vaadin/Abbr.yml b/.github/styles/Vaadin/Abbr.yml index 5c66375abd..cbacb54b02 100644 --- a/.github/styles/Vaadin/Abbr.yml +++ b/.github/styles/Vaadin/Abbr.yml @@ -84,7 +84,6 @@ exceptions: - RAM - RFC - SAP - - SASS - SBOM - SDK - SPA diff --git a/.github/styles/Vaadin/ReferTo.yml b/.github/styles/Vaadin/ReferTo.yml index 94506ab870..2f230a5d32 100644 --- a/.github/styles/Vaadin/ReferTo.yml +++ b/.github/styles/Vaadin/ReferTo.yml @@ -6,6 +6,6 @@ scope: raw action: name: replace swap: - 'refer to(?: the)? (?:<<|link|xref|https?)': see + 'refer to(?: the)? (?:<<#?|link|xref|https?)': see 'check(?: out)?(?: the)? (?:<<|link|xref|https?)': see 'check this (?:<<|link|xref|https?)': see diff --git a/.github/styles/config/vocabularies/Docs/accept.txt b/.github/styles/config/vocabularies/Docs/accept.txt index 217cdc2b93..702e394cdf 100644 --- a/.github/styles/config/vocabularies/Docs/accept.txt +++ b/.github/styles/config/vocabularies/Docs/accept.txt @@ -23,9 +23,7 @@ bun [bB]undlers? [cC]acheable classpath -[cC]onfig -[cC]onfigurer -configurator +[cC]onfig(|uration|urer|urator) [cC]onformant [cC]ontainer-less Coolors @@ -205,6 +203,8 @@ WebDriver webpack websockets? WebSphere +[wW]idgets? +widget's WildFly Workbox Xcode diff --git a/README.md b/README.md index 393bfa488c..5bb08c362e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Official documentation and code examples for Vaadin. -This repository does not generate the [vaadin.com/docs](https://vaadin.com/docs) or [hilla.dev/docs](https://hilla.dev/docs) websites. It only contains the content for them. The builds are done using [Vaadin Design System Publisher](https://vaadin.com/design-system-publisher). +This repository does not generate the [vaadin.com/docs](https://vaadin.com/docs) website. It only contains the content for them. The builds are done using [Vaadin Design System Publisher](https://vaadin.com/design-system-publisher). ## Contents diff --git a/articles/_commercial-banner.adoc b/articles/_commercial-banner.adoc index 4996e39e6e..a7e244f48a 100644 --- a/articles/_commercial-banner.adoc +++ b/articles/_commercial-banner.adoc @@ -65,7 +65,7 @@ ifndef::commercial-banner-content[] :commercial-banner-content: A commercial Vaadin subscription is required to use {commercial-feature} in your project. endif::[] -.Commercial feature +.Commercial Feature [.commercial.skip-search-index] [NOTE] ==== diff --git a/articles/_preview-banner.adoc b/articles/_preview-banner.adoc index a454e9c9b2..dfd397e8b2 100644 --- a/articles/_preview-banner.adoc +++ b/articles/_preview-banner.adoc @@ -78,7 +78,7 @@ endif::[] // Preview Feature behind a Feature Flag ifdef::feature-flag[] -This is a preview version of {preview-feature}. It needs to be enabled with the {feature-flag-docs-link} `{feature-flag}`. Preview versions may lack some planned features, and breaking changes may be introduced in any Vaadin version. We encourage you to try it out and {feedback-link} to help us improve it. +This is a preview version of {preview-feature}. You need to enable it with the {feature-flag-docs-link} `{feature-flag}`. Preview versions may lack some planned features, and breaking changes may be introduced in any Vaadin version. We encourage you to try it out and {feedback-link} to help us improve it. endif::[] ==== diff --git a/articles/_vaadin-version.adoc b/articles/_vaadin-version.adoc index 982f134831..d219e7abfb 100644 --- a/articles/_vaadin-version.adoc +++ b/articles/_vaadin-version.adoc @@ -1,4 +1,4 @@ -:vaadin-version: 24.5.6 -:vaadin-flow-version: 24.5.7 +:vaadin-version: 24.6.0 +:vaadin-flow-version: 24.6.0 :vaadin-seven-version: 7.7.38 :vaadin-eight-version: 8.20.0 diff --git a/articles/building-apps/presentation-layer/design/index.adoc b/articles/building-apps/presentation-layer/design/index.adoc deleted file mode 100644 index 10bcccf2be..0000000000 --- a/articles/building-apps/presentation-layer/design/index.adoc +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: UX Design -description: The basics of designing user interfaces for Vaadin applications. -order: 10 ---- - - -= Introduction to UX Design - -The primary focus when designing an application should be the user. Understanding their needs, goals, and challenges is key to creating a meaningful user experience. An application is only as good as its ability to solve problems efficiently and intuitively. - -Ideally, developers should engage directly with users to grasp fully what they're trying to accomplish. This can be done through interviews, surveys, or usability tests. These can provide valuable insights into users' motivations and pain points. However, developers don't always have direct access to users. Therefore, you'll have to imagine the user experience while using the application. - -Many common challenges can be addressed by applying established UI/UX best practices. This includes focusing on clarity, simplicity, and ease of navigation. Avoid what's often referred to as 'Developer UX'. This is a method in which the application becomes a reflection of a database or a feature dump. This approach typically leads to a cluttered, overwhelming experience -- particularly for non-technical users. It makes the application unnecessarily difficult to use. - -A user-centered design approach should involve constant reflection on what users need at each stage. By prioritizing key features, using layouts that are easy to follow, and adhering to design principles like accessibility, performance, and consistency, you can create a streamlined, practical UI. - -Ultimately, successful design balances functionality with user empathy, paying attention to visual hierarchy, responsiveness, simplicity, and user feedback—even when actual user input is limited. - - -== Key Concepts - -section_outline::[] diff --git a/articles/building-apps/presentation-layer/design/visuals/color.adoc b/articles/building-apps/presentation-layer/design/visuals/color.adoc deleted file mode 100644 index 263745679e..0000000000 --- a/articles/building-apps/presentation-layer/design/visuals/color.adoc +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Color -description: Using colors effectively in design, including tips on creating a color palette, ensuring color contrast, and maintaining accessibility. -order: 10 ---- - - -= Color - -When starting from scratch, without a brand guideline, choose a primary and an accent color that suits your design's mood or tone. Lumo defaults to blue, a common yet neutral and safe choice. If you opt for green or red, be mindful as they're often tied to success and error messages. Purple and vibrant gradients have gained popularity in AI branding and design. - -image::images/color-ui-example.png[Generate Button shows Vibrant Gradient Trend for AI] - - -== Generating a Color Palette - -Should you need help generating a color palette, there are many tools available online, such as: - -- https://coolors.co/[Coolors] -- https://color.adobe.com/[Adobe Color] -- https://colors.eva.design/[Eva Design] - -Lumo's <<{articles}/styling/lumo/lumo-style-properties/color#,color palette>> consists of grayscale shades, blue as the primary color, red for errors, green for success, yellow for warnings, and text colors. - -image::images/color-palette.png[Lumo's Color Palette] - -Follow the "less is more" approach when using color in your application. Limiting your color palette to a few strategic choices -- such as one primary color, a couple of accent shades, and neutral tones -- helps to create a clean, cohesive interface. This reduces visual clutter and ensures that important elements stand out. Keep it simple for a more intuitive and focused user experience. - - -== Color Contrast - -Ensure there is sufficient contrast between the text and its background. For legibility purposes, you should target a contrast ratio of at least 4.5:1, in accordance with https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum[WCAG 1.4.3]. Most browsers feature a built-in color contrast checker that can be accessed through their inspection tools. - -image::images/color-contrast-chrome.png[Chrome's Color Contrast Checker] - -Lumo is compliant by default. However, if you customize the text colors, be sure to check the contrast. - -image::images/color-contrast.png[Contrast Comparison: Left Insufficient (2.68:1); Right Sufficient (8.2:1)] - -Avoid relying on color alone to convey information, as outlined in https://www.w3.org/WAI/WCAG21/Understanding/use-of-color[WCAG 1.4.1]. Use text labels, patterns, or shapes in addition to colors to ensure accessibility. - -image::images/color-shapes1.png[Comparison: Left without Background; Right Highlights Selected] - -// TODO, RUSSELL: These two images should be described -- in addition to the captions. - -image::images/color-shapes2.png[Comparison: Left Uses Only Colors for Status; Right Uses Text & Color] diff --git a/articles/building-apps/presentation-layer/design/visuals/index.adoc b/articles/building-apps/presentation-layer/design/visuals/index.adoc deleted file mode 100644 index 98bead9dbd..0000000000 --- a/articles/building-apps/presentation-layer/design/visuals/index.adoc +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Customizing Visuals -description: Learn how to use color, typography, size, and other visuals to make your application look good. -order: 10 ---- - - -= Customizing Visuals - -// TODO Write an introduction here. - - -//== Topics - -section_outline::[] diff --git a/articles/building-apps/presentation-layer/design/visuals/typography.adoc b/articles/building-apps/presentation-layer/design/visuals/typography.adoc deleted file mode 100644 index 9264d0a85b..0000000000 --- a/articles/building-apps/presentation-layer/design/visuals/typography.adoc +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Typography -description: Selecting font families, font sizes, and a typographic scale to create cohesive and legible designs. -order: 20 ---- - - -= Typography - -Typography is a key element of business application design that directly affects the user experience and readability. By thoughtfully selecting the right font families and sizes, designers can create interfaces that are both visually appealing and easy to use. - -This page explores the key components of typography, offering insights on making choices that enhance the overall effectiveness of your application’s design. - - -== Font Family - -Choose a font family that suits your application and its content. Generally, serif fonts are more traditional, while sans-serif fonts are more modern. Some research suggests that the latter slightly outperforms serif fonts in legibility tests for those with poor eyesight. - -The default font family in Lumo depends on the operating system: Segoe UI on Windows; Roboto on Android and Chrome OS; San Francisco on macOS, iOS, and iPadOS; and Helvetica and Arial as the fallback fonts on other systems. All of these font families, regardless of the operating system, are sans serif fonts. - -The image below compare a serif font on the left with a sans serif on the right: - -image::images/typography-serif-sans-serif.png[Comparison: Left Form with Serif Font; Right using Sans-Serif] - -Notice in the image above the difference in styles and how it affects readability. - -Monospace fonts are excellent for displaying numeric values when comparisons are necessary. Notice how the font in this next image makes the numbers easier to read: - -image::images/typography-monospace.png[Table with Amount Right-Aligned; Monospace Font for Numbers] - -Alternatively, you can use link:https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-numeric[CSS to display numbers in a monospace style], depending on font support. - -image::images/typography-monospace-css.png[Table with Amount Right-Aligned and `font-variant-numeric: tabular-nums`] - - -== Font Size - -WCAG doesn't specify a minimum font size requirement. Still, be cautious about using less than 12 pixels. This also depends on the inherent size of the typeface: some typefaces may appear smaller or larger at the same size, which affects legibility. - -image::images/typography-font-size.png[Left Table Font is 11 pixels; Right uses 14 pixels] - -The image above shows two tables for comparison of font sizes. The one on the left uses a very small font size, and the one on the right has a larger size. This comparison highlights the difference in readability with font sizes. - - -== Type Scale - -A type scale is a system for choosing font sizes based on a base size and scaling ratio. This approach creates a clear visual hierarchy for headings and body text, improving content navigation for users. Alongside font size, variations in font weight and color also contribute to this hierarchy. - -image::images/typography-type-scale.png[Left Form has a Uniform Font Size; Right uses Varying Font Sizes] - -Looking at the image above: notice how using varying font sizes in the form on the right provides a clear visual hierarchy. It enhances readability and ease of navigation. - -You can find online several tools to help you preview and select a type scale that suits your needs, including: - -- https://baseline.is/tools/type-scale-generator/[Baseline] -- https://typescale.com/[Typescale] \ No newline at end of file diff --git a/articles/components/app-layout/index.adoc b/articles/components/app-layout/index.adoc index ed02ce46af..6981e06b59 100644 --- a/articles/components/app-layout/index.adoc +++ b/articles/components/app-layout/index.adoc @@ -12,7 +12,7 @@ page-links: = App Layout // tag::description[] -App Layout is a component for building common application layouts. +App Layout is a component for the root layout of a Vaadin application. It provides predefined areas for the navigation drawer, the header, and the view's content. // end::description[] include::{articles}/components/_shared.adoc[tag=scaled-examples] @@ -42,17 +42,132 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-basic.tsx[re endif::[] -- -The layout consists of three sections: a horizontal navigation bar (*navbar*), a collapsible navigation drawer (*drawer*) and a content area. -An application's main navigation blocks should be positioned in the navbar and/or drawer, whereas views are rendered in the content area. +The layout consists of three sections: -App Layout is responsive and adjusts automatically to fit desktop, tablet, and mobile screen sizes. +- <<#content-area,Content area>>, a view content area; +- <<#navbar,Navbar>>, a horizontal navigation bar; and +- <<#drawer,Drawer>>, a collapsible navigation drawer- -== Navbar Placement +An application's main navigation blocks should be positioned in the `navbar` or the `drawer` or both, whereas views are rendered in the content area. App Layout is responsive and adjusts automatically to fit desktop, tablet, and mobile screen sizes. -The navbar can be located on top or to the side of the drawer. -When put on top, the navbar is typically used as an application header. -Application headers contain, for example, the application's name and branding, as well as actions that apply to the entire application, such as notifications, settings, etc. +== Usage as Root Layout + +App Layout is designed to be the application's root layout, within which most or all views are rendered. It's not intended to be nested inside other elements. + + +=== Flow + +With Flow, the root layout can be defined using the <<{articles}/flow/routing/layout#automatic-layout-using-layout,`@Layout` annotation>>, [since:com.vaadin:vaadin@V24.5]#which tells the router to render all routes or views inside of it#. + +[source,java] +---- +@Layout +public class MainLayout extends AppLayout implements RouterLayout { + +} +---- + + +=== Hilla + +Files named [filename]`@layout.tsx` define the root layout for the other views defined in the same directory or its subdirectories. A [filename]`@layout.tsx` in the root of the `views` directory acts as the default root layout for all views in the application. An `` element is used to tell the router where to render the contents of routes or views. + +.@layout.tsx +[source,tsx] +---- +export default function MainLayout() { + return ( + + + + ); +} +---- + +See <<{articles}/hilla/guides/routing#adding-layout-routes,Hilla routing documentation>> for details. + + +== Content Area + +The content area is where individual views are rendered. The <<#usage-as-root-layout,route layout mechanisms in Flow and Hilla>> can automatically render the contents of routes and views there, but it can be invoked manually: + +[.example.show-code] +-- + +[source,java] +---- + +public class MainLayout extends AppLayout { + public MainLayout() { + MyView view = new MyView(); + setContent(view); + } +} +---- + +[source,tsx] +---- + + + + +---- + +[source,html] +---- + + + + +---- + +-- + + +== Navbar + +The `navbar` is a header above the content area. It can contain primary or secondary navigation elements, the application's title, or view-specific content such as the title of the current view. + +[.example.show-code] +-- + +[source,java] +---- + +@Layout +public class MainLayout extends AppLayout implements RouterLayout { + public MainLayout() { + H1 title = new H1("My App"); + addToNavbar(title); + } +} +---- + +[source,tsx] +---- + + +

+ My App +

+
+---- + +[source,html] +---- + + +

My App

+
+---- + +-- + + +=== Navbar Placement + +The `navbar` can be located on top, or to the side of the `drawer`. When put it on top, the `navbar` is typically used as an application header. Application headers contain, for example, the application's name and branding, as well as actions that apply to the entire application (e.g., notifications, settings, etc.). [.example.desktop] -- @@ -78,7 +193,7 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-navbar-place endif::[] -- -When placed to the side, the navbar is often seen as a view header, housing the view's title, and actions and secondary navigation that relate only to the current view. +When placed to the side, the `navbar` is often seen as a view header, containing the view's title, as well as actions and secondary navigation that relate only to the current view. [.example.desktop] -- @@ -104,18 +219,62 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-navbar-place endif::[] -- -== Drawer Toggle -Show and hide the drawer using a Drawer Toggle (or a Button). -The Drawer Toggle (☰) should always be accessible (unless the drawer is empty) and is most often situated in the navbar. +== Drawer + +The `drawer` can switch between a fixed area next to the view's content and an expandable panel, toggled via the <<#drawer-toggle,drawer toggle>>. It typically contains the application's primary navigation, such as a <<../side-nav#,Side Navigation>> component. + +[.example.show-code] +-- + +[source,java] +---- + +@Layout +public class MainLayout extends AppLayout implements RouterLayout { + public MainLayout() { + SideNav nav = new SideNav(); + addToDrawer(nav); + } +} +---- + +[source,tsx] +---- + + + + ... + + +---- + +[source,html] +---- + + + + ... + + +---- + +-- + + +=== Drawer Toggle + +Show and hide the `drawer` using a Drawer Toggle or a Button. The Drawer Toggle, which is represented by the hamburger icon (i.e., ☰), should always be accessible -- unless the `drawer` is empty. It's usually situated in the `navbar`. + == Scrolling Behavior Depending on whether App Layout has a defined height, the way the content inside the layout scrolls can differ. + === Auto Height -When the App Layout has an undefined/auto height, which is the default behavior, the `` element is the scrolling container for the content inside the layout. +When the App Layout has an undefined or auto height set, which is the default, the `` element is the scrolling container for the content inside the layout. [.example] -- @@ -141,21 +300,17 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-height-auto. endif::[] -- -The vertical scrollbar crosses the App Layout navbar and the content flows under it, allowing for translucent visual styles. -Mobile browsers collapse and expand their toolbars when the user scrolls down and up, respectively. -On iOS, you can tap the status bar (signal strength, battery, clock, etc.) to scroll back to the top of the page/view. +The vertical scrollbar crosses the App Layout `navbar` and the content flows under it, allowing for translucent visual styles. Mobile browsers collapse and expand their toolbars when the user scrolls down and up, respectively. On iOS, you can tap the status bar (i.e., where signal strength, battery, and clock are indicated) to scroll back to the top of the page or view. + +This behavior isn't compatible with vertically scrollable Grids, or other scrolling containers within the content area that's height is 100%. To support those, define 100% height for the App Layout. -This behavior isn't compatible with vertically scrollable Grids, or other scrolling containers within the content area whose height is 100%. -To support those, define 100% height for the App Layout. === Full Height (100%) -To allow a nested component to take all the available vertical space inside the App Layout, you need to set an explicit height for the layout, commonly 100%. -A common use case is to let a data grid fill the entire content area. +To allow a nested component to take all of the available vertical space inside the App Layout, you need to set an explicit height for the layout, typically 100%. A common use case is to let a data grid fill the entire content area. -.Make sure all parent components/elements have 100% height [NOTE] -The full hierarchy of components from the App Layout to the `` element need to have 100% height. +Make sure all parent components and elements have 100% height. The full hierarchy of components from the App Layout to the `` element need to have 100% height. [.example] -- @@ -184,10 +339,9 @@ endif::[] The vertical scrollbar stays within the layout content area, and mobile browsers don't collapse their toolbars when the content area is scrolled down. - == Bottom Navbar on Small Touchscreens -When the navbar is used for navigation, the *touch-optimized navbar* slot can be used to provide a separate version of the navigation at the bottom of the UI, optimized for mobile phones. +When the `navbar` is used for navigation, the _touch-optimized_ `navbar` slot can be used to provide a separate version of the navigation at the bottom of the UI, optimized for mobile phones. [.example.mobile] -- @@ -213,13 +367,12 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-bottom-navba endif::[] -- + == Best Practices === Navbar vs Drawer -Make the choice between navbar and drawer based primarily on the number of items placed in it. - -The navbar is a good choice for a small number of items (3–5), as these can fit into the viewport without scrolling. +Choose between `navbar` and `drawer` based primarily on the number of items placed in it. The `navbar` is a good choice for a small number of items (i.e., three to five), as they can fit into the viewport without scrolling. [.example] -- @@ -245,8 +398,7 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-navbar.tsx[r endif::[] -- -When more items need to be displayed, or if small-screen support is a priority, the drawer is a better choice, as it can accommodate a longer list of links without scrolling, and collapses into a hamburger menu on small screens. -Furthermore, a vertical list of items is easier for the user to scan. +When more items need to be displayed, or if small-screen support is a priority, the `drawer` is a better choice. It can accommodate a longer list of links without scrolling, and collapses into a hamburger menu on small screens. Furthermore, a vertical list of items is easier for the user to scan. [.example] -- @@ -272,8 +424,7 @@ include::{root}/frontend/demo/component/app-layout/react/app-layout-drawer.tsx[r endif::[] -- -For applications that require multilevel or hierarchical navigation, use the drawer to (at least) house the first level. -The secondary (and tertiary) navigation items can be placed in either the drawer or the navbar. +For applications that require multilevel or hierarchical navigation, use the `drawer` to contain at least the first level. The secondary and tertiary navigation items can be placed in either the `drawer` or the `navbar`. [.example] -- diff --git a/articles/components/context-menu/index.adoc b/articles/components/context-menu/index.adoc index b482fc95a2..35b7789c1b 100644 --- a/articles/components/context-menu/index.adoc +++ b/articles/components/context-menu/index.adoc @@ -263,6 +263,23 @@ include::{root}/frontend/demo/component/contextmenu/react/context-menu-disabled. endif::[] -- +[role="since:com.vaadin:vaadin@V24.6"] +=== Disable on Click (Flow) + +To prevent duplicate clicks while the server is processing a request, call the `setDisableOnClick(true)` method on a menu item instance to immediately disable that menu item on the client-side when its clicked. + +[.example] +-- + +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/contextmenu/ContextMenuDisableOnClick.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +-- + == Left-Click You can use left-click to open Context Menu in situations where left-click doesn't have any other function, for example a Grid without selection support. diff --git a/articles/components/dashboard/dashboard.png b/articles/components/dashboard/dashboard.png new file mode 100644 index 0000000000..7537c53c2b Binary files /dev/null and b/articles/components/dashboard/dashboard.png differ diff --git a/articles/components/dashboard/index.adoc b/articles/components/dashboard/index.adoc new file mode 100644 index 0000000000..80876810ce --- /dev/null +++ b/articles/components/dashboard/index.adoc @@ -0,0 +1,591 @@ +--- +tab-title: Usage +layout: tabbed-page +title: Dashboard +description: A component for building static dashboard layouts and dynamic, user-configurable dashboards. +page-links: + - 'API: https://cdn.vaadin.com/vaadin-web-components/{moduleNpmVersion:@vaadin/dashboard}/#/elements/vaadin-dashboard[TypeScript] / https://vaadin.com/api/platform/{moduleMavenVersion:com.vaadin:vaadin}/com/vaadin/flow/component/dashboard/Dashboard.html[Java]' + - 'Source: https://github.com/vaadin/web-components/tree/v{moduleNpmVersion:@vaadin/dashboard}/packages/dashboard[TypeScript] / https://github.com/vaadin/flow-components/tree/{moduleMavenVersion:com.vaadin:vaadin}/vaadin-dashboard-flow-parent[Java]' +section-nav: commercial badge-preview +version: since:com.vaadin:vaadin@V24.6 +--- + + += Dashboard +:toclevels: 2 + +// tag::description[] +A component for building static dashboard layouts and dynamic, user-configurable dashboards. +// end::description[] + +:commercial-feature: Dashboard +include::{articles}/_commercial-banner.adoc[opts=optional] + +:preview-feature: Dashboard +:feature-flag: com.vaadin.experimental.dashboardComponent +:feedback-url: https://vaadin.com/forum/t/new-dashboard-component-feedback-welcome/167980 +include::{articles}/_preview-banner.adoc[opts=optional] + +[.example.tall] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardBasic.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-basic.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-basic.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + +== Key Features + +[.term-width-auto] +*Static & Dynamic Dashboards*:: ++ +*<<#static-dashboards,Static>>*: +You define a dashboard and its widgets declaratively or imperatively. The React and Web Components for this are `` & `` and `` & `` respectively. ++ +*<<#dynamic-dashboards,Dynamic>>*: +You define the data and Dashboard generates widgets using a renderer. Dynamic dashboards support edit mode that allows the end user to move, resize, and remove widgets. The React and Web Components for this are `` and ``, respectively. ++ +In Flow, the `Dashboard` and `DashboardWidget` classes are used for both approaches. + +*Widgets, Columns & Rows*:: +Widgets are placed in columns and rows automatically, in the order supplied, based on the dashboard's width and the <>. As the dashboard's width changes, the number of columns is automatically adjusted based on their configured minimum and maximum width, and the widget positions are adjusted so. ++ +You can't place a widget in a specific column or row. + +*Scrolling*:: +Dashboard scrolls vertically if the contents overflow its defined height. Individual widgets don't scroll (see <>). + + +== Configuration + +The following configuration options are available for the Dashboard component. + +[[columns-and-rows]] +=== Columns & Rows + +Column width can vary between a minimum and maximum size. The default maximum width is `1fr`, which allows the columns to expand to fill any available space. If a fixed length value is provided, empty space is reserved at the end of rows once the columns reach their maximum width. + +By default there is no limit on the number of columns, but one can be provided if needed. + +The height of each dashboard row is determined by the tallest widget in that row, whose height in turn is determined by its contents. A minimum row height determines the height of empty rows, such as when a widget's row span is stretched into an unoccupied row. The minimum height can be configured. + +[.example] +-- +ifdef::flow[] +[source,java] +---- + +dashboard.setMinimumColumnWidth("150px"); +dashboard.setMaximumColumnWidth("300px"); +dashboard.setMaximumColumnCount(4); +dashboard.setMinimumRowHeight("100px"); +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- + + +... + +---- +endif::[] + +ifdef::lit[] +[source,html] +---- + + +... + +---- +endif::[] +-- + +=== Whitespace + +The horizontal and vertical spacing between widgets, and the padding along the dashboard's edges, can be configured. + +[.example] +-- +ifdef::flow[] +[source,java] +---- + +dashboard.setGap("10px"); +dashboard.setPadding("20px"); +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- + + +... + +---- +endif::[] + +ifdef::lit[] +[source,html] +---- + + +... + +---- +endif::[] +-- + +=== Dense Layout +This mode uses the dense packing algorithm in the CSS grid layout model. It attempts to fill in empty slots in the layout by placing smaller widgets in them. This can affect the order of the widgets. It should be used with caution in user-configurable dashboards, as the automatic reordering of widgets may be confusing during editing. + +[.example] +-- +ifdef::flow[] +[source,java] +---- + +dashboard.setDenseLayout(true); +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- + + +... + +---- +endif::[] + +ifdef::lit[] +[source,html] +---- + + +... + +---- +endif::[] +-- + +[.example.render-only] +-- +[source,typescript] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-dense-layout.ts[render,indent=0] +---- +-- + +== Widgets + +Widgets consist of a content area and a header containing the widget's title and a slot for more elements. + +[.example.short] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardWidgetContents.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-widget-contents.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-widget-contents.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + +You can set the column span and row span to make a widget take up more than one column or row in the dashboard's layout. The actual number of columns a widget spans is limited by the current number of columns in the dashboard, however. + + +=== Widget Content Sizing + +The height of a widget's contents define its default height. The height can grow because of row span or other taller widgets on the same dashboard row. If the height of the widget is constrained (e.g., by an explicitly set height), the contents of the card can overflow. You may need to incorporate a scrollable area (e.g., with <<../scroller#,Scroller>>) to accommodate a height smaller than the contents you place in a widget. + +The width of a widget is determined by the current column width and the widget's column span. + +Contents that should cover the entire widget area should therefore be configured with 100% width and height, as well as a minimum height corresponding to its desired default height. + + +[#static-dashboards] +== Static Dashboards + +Static dashboards are populated declaratively (in React and Lit) / imperatively (in Flow), like normal layouts. They are a good choice for hard-coded dashboards. + +[.small] +[cols="1s,2m",frame=none,grid=rows] +|=== + +|Flow +|Dashboard + +|React +| + +|Lit Web Component +| + +|=== + +[.example.tall] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardBasic.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-basic.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-basic.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + + +[#dynamic-dashboards] +== Dynamic, Editable Dashboards + +Dynamic dashboards offer end users the possibility to edit the layout. Dynamic dashboards are populated through a data-binding API coupled with a widget renderer function. This makes the layout configuration easy to persist and load from storage, such as a database. + +[.small] +[cols="1s,2m",frame=none,grid=rows] +|=== + +|Flow +|Dashboard + +|React +| + +|Lit Web Component +| + +|=== + +[.example.tall] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardEditable.java[render,tags=snippet,indent=0,group=Flow] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=Flow] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardStorage.java[tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-editable.tsx[render,tags=snippet,indent=0,group=React] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=React] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardService.java[tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,typescript] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-editable.ts[render,tags=snippet,indent=0,group=Lit] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=Lit] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardService.java[tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + + +=== Editing + +You can make dynamic dashboards editable by turning on editing mode, as seen in the sample above. + +.Editing mode should be temporary. +[NOTE] +The end user turns on editing mode when they want to edit the dashboard's contents and turns it off when they finish editing. When turned off, you typically want to persist the dashboard configuration to a storage. + +The following operations are available in editing mode. + +==== Widget Selection by Keyboard + +In editing mode, widgets can be selected by keyboard by moving focus to the desired widget using the kbd:[Tab] key and pressing kbd:[Space] or kbd:[Enter]. Once selected, arrow keys can be used to move and resize widgets, and to engage the accessible move and resize modes. + +Widget selection is not required for editing by pointer device. + +==== Moving Widgets + +In editing mode, widgets can be moved around by: + +* drag & drop; +* arrow keys, once the widget has been selected; +* an accessible move-mode engaged by clicking the drag-handle in the widget's top left corner. Move-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc]. + +Widgets can only be moved backwards and forwards. Moving a widget past the start or end of a row moves it to the preceding or following row. + +==== Resizing Widgets + +In editing mode, widgets can be resized by increasing and decreasing their column span and row span by: + +* dragging from the drag-handle in the widget's bottom right corner; +* kbd:[Shift] + arrow keys, once the widget has been selected; +* an accessible resize-mode engaged by clicking the resize-handle. Resize-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc]. + +==== Removing Widgets + +In editing mode, widgets can be removed by clicking the [guilabel]*Remove* button in the widget's top right corner. + +==== Adding Widgets + +Dashboard has no built-in mechanism for adding new widgets. You can implement this using an external widget selector, such as a <<../select#,Select>> drop-down, that adds the corresponding item to the dashboard. + +==== Screen Reader Announcements + +Although widget selection is announced via a widget's title, and the various buttons all have accessible names, the component doesn't announce changes to a widget's position and size out of the box. These can be provided by listening to related events emitted by the component and updating custom live regions with appropriate announcements. + +[.example.tall] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardAnnouncements.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-announcements.tsx[render,tags=snippet,indent=0,group=React] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,typescript] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-announcements.ts[render,tags=snippet,indent=0,group=Lit] +---- +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/WidgetConfig.java[tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + + +=== Persisting and Loading Widgets + +Dynamic dashboards, with their user-editable capabilities, often require the ability to persist and load customized widget configurations to and from storage, such as a database. + +The most straightforward way to persist widget configurations is by defining a custom widget/item type. This type can include custom metadata relevant to the widget content, in addition to the built-in widget/item properties. + +Once you've defined your custom type, you can establish a mapping between your data model and the widget configuration. This involves: + +- Loading: When loading the persisted configuration, map the data from your storage to individual widget/item instances of your custom type. Each record corresponds to a single widget on the dashboard. +- Saving: When saving the user's customized dashboard layout, map the current configuration (e.g., column span, row span, type, custom metadata) of your dashboard's widgets back to your data model format. + +This approach allows for flexible persistence of dashboard configurations, enabling users to save and load their customized layouts across sessions. + +For a simple example of how to implement this persistence approach, see the <<#dynamic-dashboards>> section above. While the example doesn't explicitly show how to persist the data, it illustrates the concept of defining a custom type for the dashboard widgets. The specific implementation details depend on your chosen storage mechanism and data model. + + +== Dashboard Sections + +Complex dashboards can benefit from being divided into titled sections. Dashboard sections always span the full width of the dashboard, and follow the same column and row configuration as the dashboard itself. They support the same moving and removal operations in editing mode as widgets. + +[.example.tall] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardSections.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-sections.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-sections.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + +== Internationalization + +The following texts in the dashboard can be localized through the internationalization object: + + +[cols="1m,2"] +|=== +| Property | Description + +|selectWidget +|Widget selection trigger. + +|deselectWidget +|Widget deselection trigger. + +|selectSection +|Section selection trigger. + +|deselectSection +|Section deselection trigger. + +|move +|Button that engages move-mode. + +|moveForward +|Move forward button in move-mode. + +|moveBackward +|Move backward button in move-mode. + +|moveApply +|Button that disengages move-mode. + +|resize +|Button that engages resize-mode. + +|resizeGrowWidth +|Grow width button in resize-mode. + +|resizeShrinkWidth +|Shrink width button in resize-mode. + +|resizeGrowHeight +|Grow height button in resize-mode. + +|resizeShrinkHeight +|Shrink height button in resize-mode. + +|resizeApply +|Button that disengages resize-mode. + +|remove +|Remove button. + +|=== + + +[.example] +-- +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/dashboard/DashboardInternationalisation.java[tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/dashboard/react/dashboard-internationalisation.tsx[tags=snippet,indent=0,group=React] +---- +endif::[] + +ifdef::lit[] +[source,typescript] +---- +include::{root}/frontend/demo/component/dashboard/dashboard-internationalisation.ts[tags=snippet,indent=0,group=Lit] +---- +endif::[] +-- + +//// +UNCOMMENT ONCE CARD PAGE EXISTS + +== Related Components + +|=== +|Component | Usage Recommendations +|<<../card#, Card>> +|Generic card component that can be used in any layout +|=== +//// + +[discussion-id]`d59db2ee-c3dd-446d-bd0d-40224b1f141e` + +++++ + +++++ diff --git a/articles/components/dashboard/styling.adoc b/articles/components/dashboard/styling.adoc new file mode 100644 index 0000000000..9141899950 --- /dev/null +++ b/articles/components/dashboard/styling.adoc @@ -0,0 +1,136 @@ +--- +title: Styling +description: Styling API reference for the Dashboard component. +order: 50 +--- += Styling + + +include::../_styling-section-theming-props.adoc[tag=style-properties] + +[cols="1,2,1"] +|=== +| Feature | Property | Default Value + +|Minimum column width +|`--vaadin-dashboard-col-min-width` +|`25rem` + +|Maximum column width +|`--vaadin-dashboard-col-min-width` +|`1fr` + +|Maximum column count +|`--vaadin-dashboard-col-max-count` +| + +|Minimum row height +|`--vaadin-dashboard-row-min-height` +|`12rem` + +|Dashboard padding (around contents) +|`--vaadin-dashboard-padding` +|`--lumo-space-m` + +|Widget gap +|`--vaadin-dashboard-gap` +|`--lumo-space-m` + +|Widget background +|`--vaadin-dashboard-widget-background` +|`--lumo-base-color` + +|Widget corner radius +|`--vaadin-dashboard-widget-border-radius` +|`--lumo-border-radius-l` + +|Widget border width +|`--vaadin-dashboard-widget-border-width` +|`--1px` + +|Widget border color +|`--vaadin-dashboard-widget-border-color` +|`--lumo-contrast-20pct` + +|Widget shadow (non-editable) +|`--vaadin-dashboard-widget-shadow` +|`0 0 0 0 transparent` + +|Editable widget shadow +|`--vaadin-dashboard-widget-editable-shadow` +|`--lumo-box-shadow-s` + +|Selected widget shadow +|`--vaadin-dashboard-widget-selected-shadow` +|`0 2px 4px -1px var(--lumo-primary-color-10pct), 0 3px 12px -1px var(--lumo-primary-color-50pct);` + +|Drop target / resize box background color +|`--vaadin-dashboard-drop-target-background-color` +|`--lumo-primary-color-10pct` + +|Drop target / resize box border +|`--vaadin-dashboard-drop-target-border` +|`--1px dashed var(--lumo-primary-color-50pct)` + +|=== + + + +include::../_styling-section-intros.adoc[tag=selectors] + +Dashboard root element:: `vaadin-dashboard` +Static Dashboard Layout (React & Lit):: `vaadin-dashboard-layout` + + +=== Widgets + +Root element:: `vaadin-dashboard-widget` + +==== Widget States +Editable:: `vaadin-dashboard-widget++++++**[editable]**` +Focused:: `vaadin-dashboard-widget++++++**[focused]**` +Selected:: `vaadin-dashboard-widget++++++**[selected]**` +Being dragged:: `vaadin-dashboard-widget++++++**[dragging]**` +Being resized:: `vaadin-dashboard-widget++++++**[resizing]**` +Accessible move mode:: `vaadin-dashboard-widget++++++**[move-mode]**` +Accessible resize mode:: `vaadin-dashboard-widget++++++**[resize-mode]**` + +==== Widget Parts +Header:: `vaadin-dashboard-widget++++++**::part(header)**` +Title:: `vaadin-dashboard-widget++++++**::part(title)**` +Content area:: `vaadin-dashboard-widget++++++**::part(content)**` +Drag handle / Move button:: `vaadin-dashboard-widget++++++**::part(move-button)**` +Remove button:: `vaadin-dashboard-widget++++++**::part(remove-button)**` +Resize handle / button:: `vaadin-dashboard-widget++++++**::part(resize-button)**` + + +=== Sections + +Root element:: `vaadin-dashboard-section` + +==== Section States +Editable:: `vaadin-dashboard-section++++++**[editable]**` +Focused:: `vaadin-dashboard-section++++++**[focused]**` +Selected:: `vaadin-dashboard-section++++++**[selected]**` +Being dragged:: `vaadin-dashboard-section++++++**[dragging]**` +Accessible move mode:: `vaadin-dashboard-section++++++**[move-mode]**` + +==== Section Parts +Header:: `vaadin-dashboard-section++++++**::part(header)**` +Title:: `vaadin-dashboard-section++++++**::part(title)**` +Drag handle / Move button:: `vaadin-dashboard-section++++++**::part(move-button)**` +Remove button:: `vaadin-dashboard-section++++++**::part(remove-button)**` + + +=== Accessible Move & Resize Modes + +To target move-mode buttons on Sections, replace `vaadin-dashboard-widget` with `vaadin-dashboard-section` in the selectors below. + +Move backward button:: `vaadin-dashboard-widget++++++**::part(move-backward-button)**` +Move forward button:: `vaadin-dashboard-widget++++++**::part(move-forward-button)**` +Move apply button:: `vaadin-dashboard-widget++++++**::part(move-apply-button)**` +Shrink width button:: `vaadin-dashboard-widget++++++**::part(resize-shrink-width-button)**` +Grow width button:: `vaadin-dashboard-widget++++++**::part(resize-grow-width-button)**` +Shrink height button:: `vaadin-dashboard-widget++++++**::part(resize-shrink-width-button)**` +Grow height button:: `vaadin-dashboard-widget++++++**::part(resize-grow-width-button)**` +Resize apply button:: `vaadin-dashboard-widget++++++**::part(resize-apply-button)**` diff --git a/articles/components/horizontal-layout/index.adoc b/articles/components/horizontal-layout/index.adoc index 75082e2dc8..59fba1c531 100644 --- a/articles/components/horizontal-layout/index.adoc +++ b/articles/components/horizontal-layout/index.adoc @@ -179,7 +179,7 @@ Spacing is used to create space among components in the same layout. Spacing can -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-spacing.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -202,29 +202,14 @@ endif::[] Five different spacing theme variants are available: -[.example] +[.example.render-only] -- -ifdef::lit[] -[source,typescript] +[source,typescript,role=render-only] ---- -include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-spacing-variants.ts[render,tags=snippet,indent=0,group=Lit] +include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-spacing-variants.ts[render,tags=snippet,indent=0] ---- -endif::[] - -ifdef::flow[] -[source,java] ----- -include::{root}/src/main/java/com/vaadin/demo/component/basiclayouts/BasicLayoutsHorizontalLayoutSpacingVariants.java[render,tags=snippet,indent=0,group=Flow] ----- -endif::[] -ifdef::react[] -[source,tsx] ----- -include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-horizontal-layout-spacing-variants.tsx[render,tags=snippet,indent=0,group=React] ----- -endif::[] -- |=== @@ -249,8 +234,9 @@ endif::[] [.example] -- ifdef::lit[] -[source,typescript] +[source,html] ---- + @@ -260,6 +246,7 @@ endif::[] ifdef::flow[] [source,java] ---- + HorizontalLayout layout = new HorizontalLayout(); layout.setSpacing(false); layout.getThemeList().add("spacing-xs"); @@ -269,6 +256,7 @@ endif::[] ifdef::react[] [source,tsx] ---- + @@ -286,7 +274,7 @@ Padding is the space between the outer border and the content in a layout. Paddi -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-padding.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -316,7 +304,7 @@ Use margin to create space around a layout. -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-margin.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -337,6 +325,36 @@ include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-horizon endif::[] -- +[role="since:com.vaadin:vaadin@V24.6"] +== Wrapping + +By default, components in a layout either shrink or overflow when there isn't enough horizontal space. Enable wrapping to allow components to flow onto a new line when space runs out, preventing overflow. + +[.example] +-- + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/basiclayouts/basic-layouts-horizontal-layout-wrapping.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] + +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/basiclayouts/BasicLayoutsHorizontalLayoutWrapping.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-horizontal-layout-wrapping.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] +-- + == Expanding Items @@ -346,7 +364,7 @@ Components can be made to expand and take up any excess space a layout may have. -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-expanding-items.ts[render,tags=snippet,indent=0,group=Lit] ---- diff --git a/articles/components/index.adoc b/articles/components/index.adoc index a25a868e0c..f23b14d1f2 100644 --- a/articles/components/index.adoc +++ b/articles/components/index.adoc @@ -505,6 +505,17 @@ include::notification/index.adoc[tag=description] <<{components-path-prefix}notification#,See Notification>> +[.component-card] +=== Popover + +image::{components-path-prefix}popover/popover.png["", opts=inline, role="banner"] + +include::popover/index.adoc[tag=description] + +[.sr-only] +<<{components-path-prefix}popover#,See Popover>> + + [.component-card] === Progress Bar @@ -622,6 +633,17 @@ include::board/index.adoc[tag=description] <<{components-path-prefix}board#,See Board>> +[.component-card.commercial] +=== Dashboard + +image::{components-path-prefix}dashboard/dashboard.png["", opts=inline, role="banner"] + +include::dashboard/index.adoc[tag=description] + +[.sr-only] +<<{components-path-prefix}dashboard#,See Dashboard>> + + [.component-card] === Form Layout diff --git a/articles/components/popover/index.adoc b/articles/components/popover/index.adoc index 72a41eb311..efbdbc93b7 100644 --- a/articles/components/popover/index.adoc +++ b/articles/components/popover/index.adoc @@ -3,14 +3,17 @@ tab-title: Usage layout: tabbed-page title: Popover description: Popover is a generic overlay whose position is anchored to an element in the UI. +version: since:com.vaadin:vaadin@V24.5 page-links: - 'API: https://cdn.vaadin.com/vaadin-web-components/{moduleNpmVersion:@vaadin/popover}/#/elements/vaadin-popover[TypeScript] / https://vaadin.com/api/platform/{moduleMavenVersion:com.vaadin:vaadin}/com/vaadin/flow/component/popover/Popover.html[Java]' - 'Source: https://github.com/vaadin/web-components/tree/v{moduleNpmVersion:@vaadin/popover}/packages/popover[TypeScript] / https://github.com/vaadin/flow-components/tree/{moduleMavenVersion:com.vaadin:vaadin}/vaadin-popover-flow-parent[Java]' --- -= [since:com.vaadin:vaadin@V24.5]#Popover# += Popover -[since:com.vaadin:vaadin@V24.5]#A generic overlay whose position is anchored to an element in the UI#. +// tag::description[] +A generic overlay whose position is anchored to an element in the UI. +// end::description[] [.example] -- diff --git a/articles/components/popover/popover.png b/articles/components/popover/popover.png new file mode 100644 index 0000000000..75d8ebd385 Binary files /dev/null and b/articles/components/popover/popover.png differ diff --git a/articles/components/upload/index.adoc b/articles/components/upload/index.adoc index 868c8faa4f..cf3ed3844d 100644 --- a/articles/components/upload/index.adoc +++ b/articles/components/upload/index.adoc @@ -69,6 +69,9 @@ include::{root}/frontend/demo/component/upload/react/upload-drag-and-drop.tsx[re endif::[] -- +Upload supports uploading folders via drag & drop. This uploads all files from the folder and its sub-folders recursively. The folder structure is flattened and the names of the uploaded files don't indicate in which folder they were in. Uploading folders is currently not supported through the native file picker. + +[.example] == Auto-Upload diff --git a/articles/components/vertical-layout/index.adoc b/articles/components/vertical-layout/index.adoc index 39984f15cf..4988df36b2 100644 --- a/articles/components/vertical-layout/index.adoc +++ b/articles/components/vertical-layout/index.adoc @@ -183,7 +183,7 @@ Spacing is used to create space between components in the same layout. Spacing c -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-spacing.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -206,29 +206,14 @@ endif::[] Five different spacing theme variants are available: -[.example] +[.example.render-only] -- -ifdef::lit[] -[source,typescript] +[source,typescript,role=render-only] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-spacing-variants.ts[render,tags=snippet,indent=0,group=Lit] ---- -endif::[] - -ifdef::flow[] -[source,java] ----- -include::{root}/src/main/java/com/vaadin/demo/component/basiclayouts/BasicLayoutsSpacingVariants.java[render,tags=snippet,indent=0,group=Flow] ----- -endif::[] -ifdef::react[] -[source,tsx] ----- -include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-spacing-variants.tsx[render,tags=snippet,indent=0,group=React] ----- -endif::[] -- |=== @@ -255,8 +240,9 @@ endif::[] -- ifdef::lit[] -[source,typescript] +[source,html] ---- + @@ -266,6 +252,7 @@ endif::[] ifdef::flow[] [source,java] ---- + VerticalLayout layout = new VerticalLayout(); layout.setSpacing(false); layout.getThemeList().add("spacing-xs"); @@ -275,6 +262,7 @@ endif::[] ifdef::react[] [source,tsx] ---- + ---- @@ -293,7 +281,7 @@ Padding can help distinguish the content in a layout from its surrounding. Paddi -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-padding.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -323,7 +311,7 @@ Margin is the space around a layout. This is different from Padding, which is ex -- ifdef::lit[] -[source,typescript] +[source,html] ---- include::{root}/frontend/demo/component/basiclayouts/basic-layouts-margin.ts[render,tags=snippet,indent=0,group=Lit] ---- @@ -344,5 +332,37 @@ include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-margin. endif::[] -- +[role="since:com.vaadin:vaadin@V24.6"] +== Wrapping + +By default, components in a layout either shrink or overflow when there isn't enough vertical space. Enable wrapping to allow components to flow onto a new column when space runs out, preventing overflow. + +[.example] +-- + +ifdef::lit[] +[source,html] +---- +include::{root}/frontend/demo/component/basiclayouts/basic-layouts-vertical-layout-wrapping.ts[render,tags=snippet,indent=0,group=Lit] +---- +endif::[] + +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/basiclayouts/BasicLayoutsVerticalLayoutWrapping.java[render,tags=snippet,indent=0,group=Flow] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/basiclayouts/react/basic-layouts-vertical-layout-wrapping.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] +-- + + + [discussion-id]`73cc0e40-d39a-11ed-afa1-0242ac120002` diff --git a/articles/control-center/getting-started/1.1.0-pre-release.adoc b/articles/control-center/getting-started/1.1.0-pre-release.adoc new file mode 100644 index 0000000000..f378b2f48c --- /dev/null +++ b/articles/control-center/getting-started/1.1.0-pre-release.adoc @@ -0,0 +1,115 @@ +--- +title: Getting Started with Control Center 1.1 +description: Learn how to get started with Control Center 1.1 +order: 100 +--- + + += [since:com.vaadin:vaadin@V24.6]#Getting Started with Control Center 1.1# + +[NOTE] +This is for the 1.1 pre-release version of Control Center. To view the latest stable version, see the <> documentation. + +[NOTE] +Control Center is designed to run in a production environment. For local development, see the <> guide. + + +== Prerequisites + +Before you begin, make sure you have a Kubernetes cluster running and available. It can be a service like https://cloud.google.com/kubernetes-engine[Google Kubernetes Engine (GKE)], https://aws.amazon.com/eks[Amazon EKS], or https://azure.microsoft.com/en-us/products/kubernetes-service[Azure AKS]. + + +== Configure Hostnames + +You'll need to configure the hostnames for Control Center and for Keycloak (Control Center's authentication provider). They need hostnames that are accessible from a web browser running outside the cluster. + +Via your cloud provider's dashboard, create two DNS records. Point them to your cluster's public IP address provided by your cloud provider. If your domain is `mydomain.com`, create `control.mydomain.com` and `auth.mydomain.com`, both pointing to the cluster's external IP. + +You should find the external IP address in your cloud provider's dashboard. Make sure that your network security settings allow traffic to this IP on the necessary ports. + + +== Deploying Control Center + +To deploy Control Center, use the following command: + +.Terminal +[source,bash] +---- +helm install control-center oci://docker.io/vaadin/control-center \ + -n control-center --create-namespace \ + --version 1.1.0-beta2 \ + --set domain=mydomain.com \ + --set user.email=example@mydomain.com \ + -f values-ingress.yaml \ + --wait +---- + +Replace `mydomain.com` with your domain and replace email address value with your own. The email is used to create the initial user account in Control Center. + +This is an example of a custom ingress configuration: + +[.example] +-- +.values-ingress.yaml +[source,yaml,subs="+quotes,verbatim"] +---- +ingress: + enabled: true + className: "nginx" + hosts: + - host: "control.mydomain.com" + paths: + - path: "/" + pathType: Prefix + - host: "auth.mydomain.com" + paths: + - path: "/" + pathType: Prefix + tls: + - hosts: + - "control.mydomain.com" + - "auth.mydomain.com" + secretName: "control-center-tls" +---- +-- + +.Terminal +[source,bash] +---- +mkcert control.mydomain.com auth.mydomain.com +---- + +This creates the [filename]`cert.pem` and [filename]`key.pem` files. + + +== Accessing Control Center + +Once deployed, copy the temporary password for the initial user. Run the following command to retrieve it: + +.Terminal +[source,bash] +---- +kubectl -n control-center get secret control-center-user -o go-template="{{ .data.password | base64decode | println }}" +---- + +You can access Control Center through the web browser at `\http://control.mydomain.com` (replace "mydomain.com" with your domain). + + +=== Logging In + +When you first access Control Center, you'll be prompted to log in. Use the email you provided during deployment and the temporary password you retrieved earlier. + +[.device] +image::images/login-view.png[Login to Control Center] + +You'll then be prompted to change your password and then to provide a first and last name. + + +=== Accessing the Dashboard + +Upon successful authentication, you'll be taken to the Control Center dashboard, as shown in the screenshot here. + +[.device] +image::images/dashboard-view.png[Control Center Dashboard] +At this point, the dashboard should notify you that no applications are available. This is because none are deployed yet. +To start deploying your Vaadin applications and take full advantage of Control Center's features, proceed to the <<../application-deployment#,Application Deployment>> documentation page. diff --git a/articles/control-center/getting-started/index.adoc b/articles/control-center/getting-started/index.adoc index 2ca4ebac21..ecc4c44089 100644 --- a/articles/control-center/getting-started/index.adoc +++ b/articles/control-center/getting-started/index.adoc @@ -12,6 +12,9 @@ Control Center simplifies the management of Vaadin applications on Kubernetes cl [NOTE] Control Center is designed to run in a production environment. For local development, see the <> guide. +[NOTE] +If you want to try the 1.1 pre-release version of Control Center, see the <<1.1.0-pre-release#,Control Center 1.1.0>> documentation. + == Prerequisites diff --git a/articles/control-center/getting-started/local-environment.adoc b/articles/control-center/getting-started/local-environment.adoc index a972655cef..5cb9af86ec 100644 --- a/articles/control-center/getting-started/local-environment.adoc +++ b/articles/control-center/getting-started/local-environment.adoc @@ -22,7 +22,7 @@ You'll also need to install https://helm.sh/[Helm]. It's a Kubernetes package ma == Configure Hosts File -To access Control Center from your local machine, you'll need to add a couple of entries to your [filename]`hosts` file. Where you'll find this file will depend on the operating system you're using. +To access Control Center from your local machine, you'll need to add a couple of entries to your [filename]`hosts` file. Where you'll find this file will depend on the operating system you're using. === Linux & macOS diff --git a/articles/designing-apps/color.adoc b/articles/designing-apps/color.adoc new file mode 100644 index 0000000000..b4dd0bc451 --- /dev/null +++ b/articles/designing-apps/color.adoc @@ -0,0 +1,59 @@ +--- +title: Color +description: Explains how to use colors effectively in design, including tips on creating a color palette, ensuring color contrast, and maintaining accessibility. +order: 10 +--- + + += Color + +When starting from scratch, without a brand guideline, choose a primary and an accent color that suits your design's mood or tone. Lumo defaults to blue, a common yet neutral and safe choice. If you opt for green or red, be mindful as they're often tied to success and error messages. Purple and vibrant gradients have gained popularity in AI branding and design. + +In the following screenshot, you can see a gradient on the [guilabel]*Generate* button, indicating it is an AI feature: + +.Vibrant gradient colors are often used to indicate AI-driven features. +[.device] +image::images/color-ui-example.png[A screenshot of an application, with a button labelled "Generate" with a vibrant gradient background.] + + +== Generating a Color Palette + +Should you need help generating a color palette, there are many tools available online, such as: + +- https://coolors.co/[Coolors] +- https://color.adobe.com/[Adobe Color] +- https://colors.eva.design/[Eva Design] + +Lumo's <> consists of grayscale shades, blue as the primary color, red for errors, green for success, yellow for warnings, and text colors: + +.Lumo's Color Palette +image::images/color-palette.png[A grid of colors, with a color scale for grayscale, blue, red, greend, and yellow.] + +Follow the “less is more” approach when using color in your application. Limiting your color palette to a few strategic choices -- such as one primary color, a couple of accent shades, and neutral tones -- helps to create a clean, cohesive interface. This reduces visual clutter and ensures that important elements stand out. Keep it simple for a more intuitive and focused user experience. + + +== Color Contrast + +Ensure there is sufficient contrast between the text and its background. For legibility purposes, you should target a contrast ratio of at least 4.5:1, in accordance with https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum[WCAG 1.4.3]. Most browsers feature a built-in color contrast checker that can be accessed through their inspection tools. + +.Chrome's Color Contrast Checker +[.fill.white] +image::images/color-contrast-chrome.png[A screenshot of Chrome's web inspector overlay panel, focused on a text span element, indicating sufficient contrast between the background and text colors.] + +Lumo is compliant by default. However, if you customize the text colors, be sure to check the contrast. + +The following image demonstrates the difference between insufficient and sufficient contrast ratios. On the left, the contrast ratio is 2.68:1, which is less than the recommended ratio. On the right, the contrast is 8.2:1, which is greater than the recommended ratio: + +image::images/color-contrast.png[Contrast comparison of two text elements: left, insufficient (2.68:1 contrast); right, sufficient (8.2:1 contrast)] + +== Conveying Information with Color + +Avoid relying on color alone to convey information, as outlined in https://www.w3.org/WAI/WCAG21/Understanding/use-of-color[WCAG 1.4.1]. Use text labels, patterns, or shapes in addition to colors to ensure accessibility. + +In the following example, the selected mailbox folder is indicated by a blue text color only on the left. This can be difficult for some users to see. On the right, the selected folder is also indicated by a colored background, which makes it easier to notice: + +image::images/color-shapes1.png[Comparison: Left without Background; Right Highlights Selected] + +In the following example, the left version only uses colors to show whether a contact is active (green) or inactive (red). This is problematic, as it may be impossible for color blind users to distinguish between the two colors. The right version still uses colors, but also adds the labels "Active" and "Inactive". This makes the user interface accessible to color blind users as well: + +image::images/color-shapes2.png[Comparison: Left Uses Only Colors for Status; Right Uses Text & Color] diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-contrast-chrome.png b/articles/designing-apps/images/color-contrast-chrome.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-contrast-chrome.png rename to articles/designing-apps/images/color-contrast-chrome.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-contrast.png b/articles/designing-apps/images/color-contrast.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-contrast.png rename to articles/designing-apps/images/color-contrast.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-palette.png b/articles/designing-apps/images/color-palette.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-palette.png rename to articles/designing-apps/images/color-palette.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-shapes1.png b/articles/designing-apps/images/color-shapes1.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-shapes1.png rename to articles/designing-apps/images/color-shapes1.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-shapes2.png b/articles/designing-apps/images/color-shapes2.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-shapes2.png rename to articles/designing-apps/images/color-shapes2.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/color-ui-example.png b/articles/designing-apps/images/color-ui-example.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/color-ui-example.png rename to articles/designing-apps/images/color-ui-example.png diff --git a/articles/designing-apps/images/hero.svg b/articles/designing-apps/images/hero.svg new file mode 100644 index 0000000000..ac414190ef --- /dev/null +++ b/articles/designing-apps/images/hero.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/articles/designing-apps/images/responsiveness-browser-size.png b/articles/designing-apps/images/responsiveness-browser-size.png new file mode 100644 index 0000000000..63292044d3 Binary files /dev/null and b/articles/designing-apps/images/responsiveness-browser-size.png differ diff --git a/articles/designing-apps/images/responsiveness-date-picker.png b/articles/designing-apps/images/responsiveness-date-picker.png new file mode 100644 index 0000000000..c882f64645 Binary files /dev/null and b/articles/designing-apps/images/responsiveness-date-picker.png differ diff --git a/articles/designing-apps/images/responsiveness-native-inputs.png b/articles/designing-apps/images/responsiveness-native-inputs.png new file mode 100644 index 0000000000..09c4e221b8 Binary files /dev/null and b/articles/designing-apps/images/responsiveness-native-inputs.png differ diff --git a/articles/designing-apps/images/responsiveness1.png b/articles/designing-apps/images/responsiveness1.png new file mode 100644 index 0000000000..4af396c6dd Binary files /dev/null and b/articles/designing-apps/images/responsiveness1.png differ diff --git a/articles/designing-apps/images/responsiveness2.png b/articles/designing-apps/images/responsiveness2.png new file mode 100644 index 0000000000..1ad5aaf052 Binary files /dev/null and b/articles/designing-apps/images/responsiveness2.png differ diff --git a/articles/designing-apps/images/responsiveness3.png b/articles/designing-apps/images/responsiveness3.png new file mode 100644 index 0000000000..7f9c12be55 Binary files /dev/null and b/articles/designing-apps/images/responsiveness3.png differ diff --git a/articles/designing-apps/images/responsiveness4.png b/articles/designing-apps/images/responsiveness4.png new file mode 100644 index 0000000000..e4649c8b36 Binary files /dev/null and b/articles/designing-apps/images/responsiveness4.png differ diff --git a/articles/building-apps/presentation-layer/design/visuals/images/sizing.png b/articles/designing-apps/images/sizing.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/sizing.png rename to articles/designing-apps/images/sizing.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/spacing.png b/articles/designing-apps/images/spacing.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/spacing.png rename to articles/designing-apps/images/spacing.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/typography-font-size.png b/articles/designing-apps/images/typography-font-size.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/typography-font-size.png rename to articles/designing-apps/images/typography-font-size.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/typography-monospace-css.png b/articles/designing-apps/images/typography-monospace-css.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/typography-monospace-css.png rename to articles/designing-apps/images/typography-monospace-css.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/typography-monospace.png b/articles/designing-apps/images/typography-monospace.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/typography-monospace.png rename to articles/designing-apps/images/typography-monospace.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/typography-serif-sans-serif.png b/articles/designing-apps/images/typography-serif-sans-serif.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/typography-serif-sans-serif.png rename to articles/designing-apps/images/typography-serif-sans-serif.png diff --git a/articles/building-apps/presentation-layer/design/visuals/images/typography-type-scale.png b/articles/designing-apps/images/typography-type-scale.png similarity index 100% rename from articles/building-apps/presentation-layer/design/visuals/images/typography-type-scale.png rename to articles/designing-apps/images/typography-type-scale.png diff --git a/articles/designing-apps/index.adoc b/articles/designing-apps/index.adoc new file mode 100644 index 0000000000..7c5e4d5d6e --- /dev/null +++ b/articles/designing-apps/index.adoc @@ -0,0 +1,57 @@ +--- +title: Designing Apps +description: The basics of designing user interfaces for Vaadin applications. +order: 790 +section-nav: flat expanded +--- + + += Designing Applications the Vaadin Way + +[.hero] +image::images/hero.svg[opts=inline] + +[.large] +*The primary focus when designing an application should be the user*. Understanding their needs, goals, and challenges is key to creating a meaningful user experience. An application is only as good as its ability to solve problems efficiently and intuitively. + +[.large] +*Successful application design balances functionality with user empathy*, paying attention to visual hierarchy, responsiveness, simplicity, and user feedback — even when actual user input is limited. + +== Avoid ‘Developer UX’ + +Avoid what's often referred to as ‘Developer UX’. This is a method in which the application becomes a reflection of a database or a feature dump. This approach typically leads to a cluttered, overwhelming experience -- particularly for non-technical users. It makes the application unnecessarily difficult to use. + +Many common challenges can be addressed by applying established UI/UX best practices. This includes focusing on clarity, simplicity, and ease of navigation. + +== User-Centered Design + +Ideally, you should engage directly with users to grasp fully what they're trying to accomplish. You can do this through interviews, surveys, or usability tests. These offer valuable insights into users' motivations and pain points. However, you don't always have direct access to users. Therefore, you need to imagine the user experience while using the application. + +A user-centered design approach should involve constant reflection on what users need at each stage. By prioritizing key features, using layouts that are easy to follow, and adhering to design principles like accessibility, performance, and consistency, you can create a streamlined, practical UI. + + +== Topics + +.This part of the documentation is still being written. +[.small] +[NOTE] +Its content is useful, but several parts haven't yet been added. + +section_outline::[] + +++++ + + +