From e972a4e0bc08f1dc72fdbf40fbec4a9302856c8e Mon Sep 17 00:00:00 2001 From: MatthewHawkins Date: Thu, 7 May 2026 13:27:13 -0400 Subject: [PATCH 1/4] refactor: overhaul of the ComponentDemo, split into multiple files, improved file passing, fixed bugs and logical errors, and updated markdown files for new props usage --- docs/blog/2024-04-08-webforj-v24.00/24.00.md | 28 +- docs/blog/2024-04-26-webforj-v24.01/24.01.md | 8 +- docs/blog/2024-06-03-webforj-v24.02/24.02.md | 14 +- docs/blog/2024-07-23-webforj-v24.10/24.10.md | 32 +- docs/blog/2025-05-19-webforj-v25.01/25.01.md | 8 +- .../2025-08-21-buildingbettercss/index.md | 11 +- docs/blog/2025-09-09-webforj-v25.03/25.03.md | 12 +- docs/blog/2026-01-27-webforj-v25.11/25.11.md | 18 +- docs/blog/2026-03-17-webforj-v25.12/25.12.md | 20 +- docs/blog/2026-04-28-webforj-v26.00/26.00.md | 4 +- docs/docs/advanced/debouncing.md | 2 +- docs/docs/advanced/view-transitions.md | 50 +- docs/docs/building-ui/composite-components.md | 16 +- docs/docs/building-ui/element-composite.md | 18 +- docs/docs/building-ui/elements.md | 40 +- docs/docs/building-ui/events.md | 6 +- docs/docs/building-ui/using-components.md | 30 +- docs/docs/components/accordion.md | 14 +- docs/docs/components/alert.md | 30 +- docs/docs/components/app-layout.md | 98 ++-- docs/docs/components/appnav.md | 11 +- docs/docs/components/avatar.md | 18 +- docs/docs/components/badge.md | 10 +- docs/docs/components/busyindicator.md | 16 +- docs/docs/components/button.md | 32 +- docs/docs/components/checkbox.md | 24 +- docs/docs/components/columns-layout.md | 40 +- docs/docs/components/dialog.md | 72 +-- docs/docs/components/drawer.md | 26 +- docs/docs/components/fields/color-field.md | 10 +- docs/docs/components/fields/date-field.md | 4 +- .../docs/components/fields/date-time-field.md | 6 +- .../components/fields/masked/datefield.md | 33 +- .../components/fields/masked/numberfield.md | 32 +- .../components/fields/masked/textfield.md | 18 +- .../components/fields/masked/timefield.md | 33 +- docs/docs/components/fields/number-field.md | 4 +- docs/docs/components/fields/password-field.md | 6 +- docs/docs/components/fields/text-field.md | 4 +- docs/docs/components/fields/time-field.md | 6 +- docs/docs/components/flex-layout.md | 80 +-- docs/docs/components/google-charts.md | 40 +- docs/docs/components/icon.md | 18 +- docs/docs/components/infinitescroll.md | 39 +- docs/docs/components/lists/choice-box.md | 16 +- docs/docs/components/lists/combo-box.md | 32 +- docs/docs/components/lists/list-box.md | 8 +- docs/docs/components/loading.md | 24 +- docs/docs/components/login.md | 44 +- docs/docs/components/markdownviewer.md | 18 +- docs/docs/components/navigator.md | 24 +- .../docs/components/option-dialogs/confirm.md | 16 +- .../components/option-dialogs/file-chooser.md | 16 +- .../components/option-dialogs/file-save.md | 16 +- .../components/option-dialogs/file-upload.md | 8 +- docs/docs/components/option-dialogs/input.md | 16 +- .../docs/components/option-dialogs/message.md | 8 +- docs/docs/components/progressbar.md | 24 +- docs/docs/components/radio-button.md | 24 +- docs/docs/components/radio-group.md | 10 +- docs/docs/components/refresher.md | 52 +- docs/docs/components/slider.md | 48 +- docs/docs/components/spinner.md | 40 +- docs/docs/components/splitter.md | 72 ++- docs/docs/components/tabbed-pane.md | 48 +- docs/docs/components/table/overview.md | 18 +- .../components/table/table_column_groups.md | 74 +-- docs/docs/components/table/table_columns.md | 48 +- .../components/table/table_dynamic_styling.md | 36 +- .../components/table/table_edit_refresh.md | 10 +- docs/docs/components/table/table_filtering.md | 10 +- .../docs/components/table/table_large_data.md | 10 +- docs/docs/components/table/table_rendering.md | 28 +- docs/docs/components/table/table_selection.md | 24 +- docs/docs/components/table/table_sorting.md | 48 +- docs/docs/components/terminal.md | 36 +- docs/docs/components/textarea.md | 44 +- docs/docs/components/toast.md | 26 +- docs/docs/components/toolbar.md | 30 +- docs/docs/components/tree.md | 24 +- docs/siteConfig.js | 3 +- .../components/DocsTools/AppLayoutViewer.js | 86 --- .../src/components/DocsTools/ComponentDemo.js | 512 ------------------ .../DocsTools/ComponentDemo/CodePanel.js | 134 +++++ .../DocsTools/ComponentDemo/DemoFrame.js | 403 ++++++++++++++ .../DocsTools/ComponentDemo/index.js | 147 +++++ docs/src/theme/MDXComponents.js | 2 - 87 files changed, 1825 insertions(+), 1533 deletions(-) delete mode 100644 docs/src/components/DocsTools/AppLayoutViewer.js delete mode 100644 docs/src/components/DocsTools/ComponentDemo.js create mode 100644 docs/src/components/DocsTools/ComponentDemo/CodePanel.js create mode 100644 docs/src/components/DocsTools/ComponentDemo/DemoFrame.js create mode 100644 docs/src/components/DocsTools/ComponentDemo/index.js diff --git a/docs/blog/2024-04-08-webforj-v24.00/24.00.md b/docs/blog/2024-04-08-webforj-v24.00/24.00.md index 0c065c824..b49106486 100644 --- a/docs/blog/2024-04-08-webforj-v24.00/24.00.md +++ b/docs/blog/2024-04-08-webforj-v24.00/24.00.md @@ -28,11 +28,13 @@ See the [GitHub release overview](https://github.com/webforj/webforj/releases/ta This release introduces a new [`Table`](/docs/components/table/overview) component, allowing developers access to a lightweight, fast and optimized way to display their data. - @@ -47,9 +49,9 @@ Using the `Table` in your app is simple, and follows a few easy steps outlined i ## Navigator component - @@ -66,10 +68,12 @@ The `Navigator` can be customized with various settings that configure the text, ## Splitter component - diff --git a/docs/blog/2024-04-26-webforj-v24.01/24.01.md b/docs/blog/2024-04-26-webforj-v24.01/24.01.md index 40904dc9b..eabdc39a9 100644 --- a/docs/blog/2024-04-26-webforj-v24.01/24.01.md +++ b/docs/blog/2024-04-26-webforj-v24.01/24.01.md @@ -42,10 +42,10 @@ Functionality such as transformation and validation further enhance the binding ## Login component - The latest `Login` component in webforJ offers an intuitive and efficient interface for user authentication, enabling users to log in using their username and password. This component is highly customizable to enhance user experiences across various devices and locales. diff --git a/docs/blog/2024-06-03-webforj-v24.02/24.02.md b/docs/blog/2024-06-03-webforj-v24.02/24.02.md index 615c7634b..d78222954 100644 --- a/docs/blog/2024-06-03-webforj-v24.02/24.02.md +++ b/docs/blog/2024-06-03-webforj-v24.02/24.02.md @@ -25,10 +25,10 @@ As always, see the [GitHub release overview](https://github.com/webforj/webforj/ ## Option dialogs - With 24.02, webforJ introduces a robust option dialog feature that allows applications to interact with users and gather input effectively. These dialogs are modal, meaning they halt app execution until the user provides input, ensuring critical messages are addressed before proceeding. These function similarly to `JOptionPane` in Swing, addressing the need for blocking dialogs in web applications. @@ -47,9 +47,9 @@ The various dialog options are provided to help clarify and specify the type of The `ProgressBar` in 24.02 has gotten a powerful, comprehensive overhaul. This component provides a visual representation of task progress, making it easy for users to monitor the completion status of ongoing tasks. The progress bar fills up as the task progresses, displaying the percentage of completion both visually and textually. - diff --git a/docs/blog/2024-07-23-webforj-v24.10/24.10.md b/docs/blog/2024-07-23-webforj-v24.10/24.10.md index adaf97a41..c931a7d04 100644 --- a/docs/blog/2024-07-23-webforj-v24.10/24.10.md +++ b/docs/blog/2024-07-23-webforj-v24.10/24.10.md @@ -57,10 +57,10 @@ The `Spinner` and `BusyIndicator` components have both been added in this releas Building on the `Spinner`, the `BusyIndicator` is an app-level loading overlay that indicates when the app is busy or processing data. It blocks user interaction until the process is complete. This component displays both a `Spinner` and a textual description while the process is occurring. - The `Loading` component uses the same client component, but allows the addition of children and can be attached to any parent component, making it scoped to its parent. @@ -77,10 +77,10 @@ The webforJ `Terminal` component represents an exciting opportunity to emulate a The `ColumnsLayout` component has come to webforJ in `24.10`, and is designed to offer a flexible and responsive layout solution in addition to the [FlexLayout](/docs/components/flex-layout) component. The `ColumnsLayout` easily facilitates two-dimensional layouts by providing columns rather than just rows. It dynamically adjusts the number of columns based on the width of the layout and utilizes breakpoints to determine how many columns should be displayed at different viewport widths to help with responsiveness. - In addition to dynamic column adjustments, `ColumnsLayout` supports customizable alignment and spacing options. The `ColumnsLayout` component is designed to be intuitive and easy to use. It includes built-in methods for setting column spans and positions, making it simple to create complex layouts with minimal effort. @@ -93,10 +93,10 @@ The `Slider` component has received on overhaul in this release. The appearance However, with this rework, a few of the methods have changed to better reflect modern standards. If you are using this component in your app, review the following methods to ensure you're using the updated API. An example of the various methods can be seen in the code demo below: - ### Toast component @@ -105,10 +105,10 @@ Another powerful component introduced in `24.10` is the `Toast` component, which Developers can set the display duration, choose from various themes, and configure the position of the toast on the screen. The component supports multiple placements, and also allows for setting custom text and HTML content, giving developers the ability to style the messages as needed. - ### Debugging tooling diff --git a/docs/blog/2025-05-19-webforj-v25.01/25.01.md b/docs/blog/2025-05-19-webforj-v25.01/25.01.md index d4cc1d767..6c47e2414 100644 --- a/docs/blog/2025-05-19-webforj-v25.01/25.01.md +++ b/docs/blog/2025-05-19-webforj-v25.01/25.01.md @@ -38,10 +38,10 @@ For more information on the `Tree` component, how to use it in an app, and the v Below is an example of a `Tree` component: - ## Introducing startforJ diff --git a/docs/blog/2025-08-21-buildingbettercss/index.md b/docs/blog/2025-08-21-buildingbettercss/index.md index 704cbc78c..f6e2d56be 100644 --- a/docs/blog/2025-08-21-buildingbettercss/index.md +++ b/docs/blog/2025-08-21-buildingbettercss/index.md @@ -165,10 +165,13 @@ The `::part()` pseudo-element is like having a key to specific rooms in an other Here's a dashboard I put together that uses most of the stuff I've mentioned - CSS Grid, DWC tokens, and component-specific styling: - This dashboard shows how all the pieces work together in practice. The responsive layout uses CSS Grid with custom media queries for mobile optimization. All the colors and spacing come from DWC tokens, so changing the primary color at the root level updates the entire interface. The combination of external CSS and inline component styles keeps everything maintainable, which is great because I definitely needed to go back and fix things multiple times. diff --git a/docs/blog/2025-09-09-webforj-v25.03/25.03.md b/docs/blog/2025-09-09-webforj-v25.03/25.03.md index ed75c6308..4954681ac 100644 --- a/docs/blog/2025-09-09-webforj-v25.03/25.03.md +++ b/docs/blog/2025-09-09-webforj-v25.03/25.03.md @@ -75,11 +75,13 @@ The new column management APIs offer both interactive and programmatic control. These features are particularly valuable in data-heavy applications like financial dashboards and reporting tools, where different users need to arrange columns to match their workflow patterns. - diff --git a/docs/blog/2026-01-27-webforj-v25.11/25.11.md b/docs/blog/2026-01-27-webforj-v25.11/25.11.md index 7de5c4d18..4b9c24308 100644 --- a/docs/blog/2026-01-27-webforj-v25.11/25.11.md +++ b/docs/blog/2026-01-27-webforj-v25.11/25.11.md @@ -24,10 +24,12 @@ Starting with one of the most exciting changes, webforJ now provides a first-cla The programmatic API handles any DOM update. All a developer needs to do is use `Page.getCurrent().startViewTransition()`, which returns a builder for configuring the transition: Elements with matching transition names animate between states, with the browser handling the animation automatically. @@ -85,9 +87,11 @@ User avatars appear everywhere—in profiles, comments, team lists, and more. Th Passing a name to the `Avatar` generates initials automatically. To use photos, simply add an image as a child element. The `Avatar` comes with seven themes, two shapes, and multiple sizes to cover common cases. diff --git a/docs/blog/2026-03-17-webforj-v25.12/25.12.md b/docs/blog/2026-03-17-webforj-v25.12/25.12.md index a28c672ce..122bd6abe 100644 --- a/docs/blog/2026-03-17-webforj-v25.12/25.12.md +++ b/docs/blog/2026-03-17-webforj-v25.12/25.12.md @@ -26,9 +26,11 @@ Tables with lots of columns can get hard to read fast. Column groups solve this @@ -57,9 +59,11 @@ No more writing custom lodash templates for common patterns. `25.12` ships a com @@ -176,7 +180,7 @@ First up, the [`Accordion`](/docs/components/accordion): a vertically stacked se @@ -215,7 +219,7 @@ Badges integrate naturally with other components. Attach one to a `Button` with diff --git a/docs/blog/2026-04-28-webforj-v26.00/26.00.md b/docs/blog/2026-04-28-webforj-v26.00/26.00.md index f83157cda..90567722f 100644 --- a/docs/blog/2026-04-28-webforj-v26.00/26.00.md +++ b/docs/blog/2026-04-28-webforj-v26.00/26.00.md @@ -60,7 +60,7 @@ By default, a `Dialog` stretches to fill the available horizontal space, perfect @@ -81,7 +81,7 @@ The `TabbedPane` picks up a new rendering mode in `26.00`. Flip `setSegment(true diff --git a/docs/docs/advanced/debouncing.md b/docs/docs/advanced/debouncing.md index cbad23bee..6c1c5b57b 100644 --- a/docs/docs/advanced/debouncing.md +++ b/docs/docs/advanced/debouncing.md @@ -11,7 +11,7 @@ Debouncing is a technique that delays executing an action until a specified time diff --git a/docs/docs/advanced/view-transitions.md b/docs/docs/advanced/view-transitions.md index 9a220d60b..96473af0a 100644 --- a/docs/docs/advanced/view-transitions.md +++ b/docs/docs/advanced/view-transitions.md @@ -13,10 +13,12 @@ title: View Transitions View transitions provide animated transitions when the [DOM](/docs/glossary#dom) changes, reducing visual jarring and maintaining spatial context during navigation or content updates. webforJ integrates with the browser's [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) to handle the complexity of coordinating animations between old and new states. @@ -97,14 +99,14 @@ When working with lists or repeated components, include a unique identifier in t ::: ### List reordering {#list-reordering} @@ -125,13 +127,13 @@ Page.getCurrent().startViewTransition() ``` ## Custom CSS animations {#custom-css-animations} @@ -185,10 +187,12 @@ Page.getCurrent().startViewTransition() ``` ## CSS customization {#css-customization} diff --git a/docs/docs/building-ui/composite-components.md b/docs/docs/building-ui/composite-components.md index 144e9c406..1e3bd6007 100644 --- a/docs/docs/building-ui/composite-components.md +++ b/docs/docs/building-ui/composite-components.md @@ -155,10 +155,12 @@ public class InteractiveMap extends Composite
{ The following example demonstrates a Todo app where each item is a `Composite` component consisting of a [`RadioButton`](../components/radiobutton) styled as a switch and a Div with text: - @@ -168,7 +170,9 @@ Sometimes you may want to use a `Composite` to group related components together diff --git a/docs/docs/building-ui/element-composite.md b/docs/docs/building-ui/element-composite.md index eab05f969..fe8c6eb08 100644 --- a/docs/docs/building-ui/element-composite.md +++ b/docs/docs/building-ui/element-composite.md @@ -17,9 +17,9 @@ it's possible to do everything with the `Element` class itself, without using `E This guide demonstrates how to implement the [Shoelace QR code web component](https://shoelace.style/components/qr-code) using the `ElementComposite` class. - @@ -60,9 +60,9 @@ String title = get(TITLE, false, String); In the demo below, properties have been added for the QR code based on the documentation for the web component. Methods have then been implemented which allow users to get and set the various properties that have been implemented. - @@ -101,9 +101,9 @@ For specialized event handling, create custom event classes with configured payl In the example below, a click event has been created and then added to the QR code component. This event, when fired, will display the "X" coordinate of the mouse at the time of clicking the component, which is provided to the Java event as data. A method is then implemented to allow the user to access this data, which is how it's displayed in the app. - diff --git a/docs/docs/building-ui/elements.md b/docs/docs/building-ui/elements.md index cf9f0636a..9758e5b05 100644 --- a/docs/docs/building-ui/elements.md +++ b/docs/docs/building-ui/elements.md @@ -12,10 +12,12 @@ webforJ developers have the option of choosing not only from the rich library of The `Element` component cannot be extended, and is not the base component for all components within webforJ. To read more about webforJ's component hierarchy, read [this article](../architecture/controls-components.md). ::: - ## Adding events {#adding-events} @@ -24,10 +26,12 @@ In order to utilize events that may come with your element, you can use the `Ele There are also additional options to further customize events by using the Event Options configurations. - @@ -47,10 +51,12 @@ The `Element` component supports the composition of child components. Developers 3. **`setText(String text)`**: This method behaves similarly to the `setHtml()` method, but injects literal text into the `Element`. - @@ -97,10 +103,12 @@ Both synchronous and asynchronous function calling will wait to call a method un In the demo below, an event is added to an HTML `Button`. This event is then fired programmatically by calling the `callJsFunctionAsync()` method. The resulting PendingResult is then used to create another message box once the asynchronous function has been completed. - diff --git a/docs/docs/building-ui/events.md b/docs/docs/building-ui/events.md index b6628c3ef..f27e884c7 100644 --- a/docs/docs/building-ui/events.md +++ b/docs/docs/building-ui/events.md @@ -96,8 +96,8 @@ This approach minimizes the need to query the component for information, as the Below is a demonstration showing the addition of a ButtonClickEvent to a [`Button`](#). This [`Button`](#) also uses information coming with the event's payload to display information on the screen. - \ No newline at end of file diff --git a/docs/docs/building-ui/using-components.md b/docs/docs/building-ui/using-components.md index 34c42c9f2..aab57492b 100644 --- a/docs/docs/building-ui/using-components.md +++ b/docs/docs/building-ui/using-components.md @@ -121,10 +121,12 @@ nameField.addValueChangeListener(e -> submitButton.setEnabled(!e.getValue().isBl The following login form demonstrates `setEnabled()` in practice. The sign-in button stays disabled until both fields have content, making it clear to the user that input is required before proceeding: - @@ -158,10 +160,12 @@ A common use of `setVisible()` in containers is revealing additional UI only whe The following settings panel demonstrates this: basic notification preferences are always visible, and a section of advanced options only appears when the user asks for it. The save button activates as soon as any setting is changed: - @@ -189,10 +193,12 @@ This is preferable to showing validation errors only after the user clicks submi In this contact form, the name field must not be empty, the email must contain an `@` symbol, and the message must be at least 10 characters long: - diff --git a/docs/docs/components/accordion.md b/docs/docs/components/accordion.md index 1cda9d663..18b2e8ad1 100644 --- a/docs/docs/components/accordion.md +++ b/docs/docs/components/accordion.md @@ -33,7 +33,7 @@ AccordionPanel panel = new AccordionPanel("Title", new Paragraph("Body content." @@ -76,7 +76,7 @@ Accordion accordion = new Accordion(panel1, panel2, panel3); @@ -102,7 +102,7 @@ accordion.closeAll(); @@ -128,7 +128,7 @@ accordion.setEnabled(false); @@ -158,7 +158,7 @@ Content added via `addToHeader()` fully replaces the default label text. `setLab @@ -178,7 +178,7 @@ panel.setIcon(null); @@ -199,7 +199,7 @@ outer.add(innerAccordion); diff --git a/docs/docs/components/alert.md b/docs/docs/components/alert.md index d1eef2aed..24143c8a2 100644 --- a/docs/docs/components/alert.md +++ b/docs/docs/components/alert.md @@ -18,10 +18,10 @@ Alerts help draw attention to key information without disrupting the user's work An `Alert` can hold rich content like text, buttons, and other components. Set a theme to visually distinguish the type of message being displayed. - ## Dismissing alerts {#dismissing-alerts} @@ -34,10 +34,10 @@ closableAlert.setClosable(true); ``` Alerts often do more than display messages—they can trigger follow-up actions when dismissed. Use the `AlertCloseEvent` to handle these cases and respond when the user dismisses the `Alert`. - :::tip Reusable Alert Component @@ -51,10 +51,10 @@ Closing the alert only hides it—it doesn’t destroy the component, so you can The `Alert` component supports multiple themes to visually distinguish different types of messages—such as success, error, warning, or info. These themes can be applied using the `setTheme()` method or directly in the constructor. - @@ -62,10 +62,10 @@ height = '650px' The expanse defines the visual size of the `Alert` component. You can set it using the `setExpanse()` method or pass it directly to the constructor. The available options come from the Expanse enum: `XSMALL`, `SMALL`, `MEDIUM`, `LARGE`, and `XLARGE`. - diff --git a/docs/docs/components/app-layout.md b/docs/docs/components/app-layout.md index 0c0116858..aeb10b07b 100644 --- a/docs/docs/components/app-layout.md +++ b/docs/docs/components/app-layout.md @@ -36,11 +36,16 @@ Each part of the layout is a `Div`, which can contain any valid webforJ control. The following code sample will result in an app with a collapsible sidebar that contains a logo and tabs for various content options and a header. The demo uses the dwc-icon-button web component to create a drawer toggle button. The button has the data-drawer-toggle attribute which instructs the DwcAppLayout to listen to click events coming from that component to toggle the drawer state. - + ## Full width navbar {#full-width-navbar} @@ -55,11 +60,16 @@ myApp.setFooterOffscreen(false); ``` - + ## Multiple toolbars {#multiple-toolbars} @@ -69,12 +79,17 @@ The navbar has no limit to the number of toolbars you can add. A `Toolbar` is a The following demo shows how to use two toolbars, The first one houses the drawer's toggle button and the app's title. The second toolbar houses a secondary navigation menu. - + ## Sticky toolbars {#sticky-toolbars} @@ -88,12 +103,17 @@ When `AppLayout.setHeaderReveal(true)` is set called, the header will be visible With the help of the CSS custom property `--dwc-app-layout-header-collapse-height` it's possible to control how much of the header navbar will be hidden. - + ## Mobile navigation layout {#mobile-navigation-layout} @@ -107,12 +127,17 @@ Same as `AppLayout.setHeaderReveal()`, `AppLayout.setFooterReveal()` is supporte By default, when the screen width is 800px or less , the drawer will be switched to popover mode. This is called the breakpoint. The popover mode means that the drawer will pop over the content area with an overlay. It's possible to configure the breakpoint by using the `setDrawerBreakpoint()` method and the breakpoint must be a valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries). - + ## Drawer utilities {#drawer-utilities} @@ -160,12 +185,17 @@ layout.addToDrawerHeaderActions( Drawer actions appear in the **right-aligned section** of the drawer’s header. - + diff --git a/docs/docs/components/appnav.md b/docs/docs/components/appnav.md index cb43845f2..9115572e4 100644 --- a/docs/docs/components/appnav.md +++ b/docs/docs/components/appnav.md @@ -37,10 +37,13 @@ If you want the group header to trigger a custom action (such as opening externa ::: - diff --git a/docs/docs/components/avatar.md b/docs/docs/components/avatar.md index 6b9bd690e..ce878ed98 100644 --- a/docs/docs/components/avatar.md +++ b/docs/docs/components/avatar.md @@ -30,11 +30,13 @@ Avatar avatar = new Avatar("John Doe", "J"); The example below showcases avatars in a team panel context. Each `Avatar` displays either a profile image or auto-generated initials based on the user's name. Clicking an `Avatar` opens a dialog with an enlarged view. - ## Displaying images {#displaying-images} @@ -98,7 +100,7 @@ Avatars can be displayed as circles or squares. The default shape is `CIRCLE`, w @@ -120,7 +122,7 @@ Each theme also has an outlined variant for a lighter visual treatment: @@ -130,7 +132,7 @@ Control the avatar size using the `setExpanse()` method. The component supports diff --git a/docs/docs/components/badge.md b/docs/docs/components/badge.md index d660a050c..a80b9e48a 100644 --- a/docs/docs/components/badge.md +++ b/docs/docs/components/badge.md @@ -56,7 +56,7 @@ Icon-only badges work especially well for compact status indicators in dense lay @@ -80,7 +80,7 @@ Attach a `Badge` to a `Button` using `setBadge()`. The badge appears at the top- @@ -92,7 +92,7 @@ Add a `Badge` as a suffix on a `Tab` using `setSuffixComponent()`. This is a nat @@ -112,7 +112,7 @@ Apply a theme using `setTheme()` or through the constructor. @@ -133,7 +133,7 @@ Use `setExpanse()` to control badge size. Nine sizes are available, ranging from diff --git a/docs/docs/components/busyindicator.md b/docs/docs/components/busyindicator.md index 427672898..154dfd5ab 100644 --- a/docs/docs/components/busyindicator.md +++ b/docs/docs/components/busyindicator.md @@ -18,10 +18,10 @@ The `BusyIndicator` in webforJ displays as a simple spinner, making it easy to u In this example, the `BusyIndicator` prevents any user actions across the entire interface until the operation completes. - ## Backdrops {#backdrops} @@ -45,10 +45,10 @@ The `BusyIndicator` component in webforJ includes a `Spinner` that visually indi Here's an example of how you can customize the spinner within a `BusyIndicator` component: - ## Use cases {#use-cases} diff --git a/docs/docs/components/button.md b/docs/docs/components/button.md index 672f4c2d8..ad2bfa9d4 100644 --- a/docs/docs/components/button.md +++ b/docs/docs/components/button.md @@ -39,9 +39,9 @@ The `Button` class is a versatile component that is commonly used in various sit The following example demonstrates buttons used for form submission and clearing input: - @@ -60,10 +60,10 @@ By default, an `Icon` inherits the button's theme and expanse. Below are examples of buttons with text to the left and right, as well as a button with only an icon: - ### Names {#names} @@ -74,9 +74,9 @@ The `Button` component utilizes naming, which is used for accessibility. When a Button components, like many others, can be disabled to convey to a user that a certain action is not yet or is no longer available. A disabled button will decrease the opacity of the button, and is available for all button themes and expanses. - Disabling a button can be done at any time in the code by using the setEnabled(boolean enabled) function. For added convenience, a button can also be disabled when clicked using the built-in setDisabledOnClick(boolean enabled) function. @@ -105,9 +105,9 @@ While there are many use cases for each of the various themes, some examples use Shown below are example buttons with each of the supported Themes applied:
- @@ -121,9 +121,9 @@ Different sizes are often appropriate for different uses: Below are the various expanses supported for the `Button` component:
- diff --git a/docs/docs/components/checkbox.md b/docs/docs/components/checkbox.md index 536a99904..1ee9dd097 100644 --- a/docs/docs/components/checkbox.md +++ b/docs/docs/components/checkbox.md @@ -37,10 +37,10 @@ Check boxes can utilize the Position enum. Show below are the two settings:
-
@@ -53,10 +53,10 @@ The `CheckBox` component supports indeterminism, which is a UI pattern commonly - **Hierarchical data**: Indeterminism can be employed in scenarios where there is a hierarchical relationship between CheckBoxes. For example, when selecting categories and subcategories, indeterminism can represent that some subcategories are selected while others are not, and the parent component is in the indeterminate state. - ## Styling {#styling} @@ -66,10 +66,10 @@ height = '150px' The following Expanses values allow for quick styling without using CSS. Expanses are supported by use of the `Expanse` enum class. Below are the expanses supported for the checkbox component:
-
diff --git a/docs/docs/components/columns-layout.md b/docs/docs/components/columns-layout.md index 48c1c67e8..cb4031ab2 100644 --- a/docs/docs/components/columns-layout.md +++ b/docs/docs/components/columns-layout.md @@ -16,10 +16,10 @@ The `ColumnsLayout` component arranges items into a responsive column-based layo By default, a `ColumnsLayout` arranges items in two columns and takes the full width of its parent. The display can be further adjusted with breakpoints and alignment settings, covered in the sections below. - :::info Horizontal Layouts @@ -71,10 +71,10 @@ layout.setBreakpoints(breakpoints); The demonstration below shows an example of setting multiple breakpoints at construction, using breakpoints to configure the [`Span`](#column-span-and-spans-per-breakpoint) of a component, and demonstrates the resizing capabilities of the `ColumnsLayout` when the app is resized: - ## Column `Span` and spans per `Breakpoint` {#column-span-and-spans-per-breakpoint} @@ -151,10 +151,10 @@ columnsLayout.setColumn(email, "medium", 2); In the following demonstration, notice that when the `"medium"` breakpoint is triggered, the `email` field spans both columns, and the `confirmPassword` field is placed into the first column, rather than its default placement in the second column: - :::tip Avoid collisions @@ -178,10 +178,10 @@ Available `Alignment` options include: - `BASELINE`: Aligns based on the text or content inside the column, aligning items to the text baseline rather than other alignment options. - `AUTO`: Auto alignment. - In the demo above, the `Submit` button has been given `ColumnsLayout.Alignment.END` to ensure that it appears at the end, or in this case to the right, of its column. @@ -212,10 +212,10 @@ You can use an integer to define the minimum width in pixels or use a `String` t Building responsive and attractive layouts is possible using both the [`FlexLayout`](./flex-layout) component and the `ColumnsLayout` component, as well as a combination of the two. Below is a sample of the [form created in the FlexLayout](./flex-layout#example-form) article, but using a `ColumnLayout` scheme instead: - ## Styling {#styling} diff --git a/docs/docs/components/dialog.md b/docs/docs/components/dialog.md index 08efc5a7d..d301f0b18 100644 --- a/docs/docs/components/dialog.md +++ b/docs/docs/components/dialog.md @@ -17,10 +17,10 @@ The `Dialog` component displays a popup window that overlays the current view, d The `Dialog` is organized into three sections: a header, a content area, and a footer. Components can be added to each section using `addToHeader()`, `addToContent()`, and `addToFooter()`. - ## Usages {#usages} @@ -44,10 +44,10 @@ height = '225px' By enabling the backdrop attribute of the webforJ `Dialog` component, a backdrop will be displayed behind the `Dialog`. Additionally, when enabled, the Dialog's blurred attribute will blur the backdrop of the `Dialog`. Modifying these settings can help users by providing depths, visual hierarchy, and context, leading to more clear guidance for a user. - ## Opening and closing the `Dialog` {#opening-and-closing-the-dialog} @@ -59,20 +59,20 @@ After creating a new `Dialog` object, use the `open()` method to display the dia Developers can choose which interactions close the `Dialog` with `setCancelOnEscKey()` and `setCancelOnOutsideClick()`. Additionally, the `setClosable()` method can prevent or allow both hitting the ESC key and clicking outside the `Dialog` to close the component. - ## Auto-focus {#auto-focus} When enabled, auto-focus will automatically give focus to the first element within the dialog that can be focused. This is useful in helping to direct the attention of users, and is customizable via the `setAutoFocus()` method. - ## Draggable {#draggable} @@ -82,30 +82,30 @@ The `Dialog` has built in functionality to be draggable, allowing the user to re ### Snap to edge {#snap-to-edge} It is also possible to calibrate this behavior to snap to the edge of the screen, meaning the `Dialog` will automatically align itself with the edge of the display when released from its drag and drop date. Snapping can be changed via the `setSnapToEdge()` method. The `setSnapThreshold()` takes a number of pixels, which will set how far the `Dialog` should be from the sides of the screen before it will automatically snap to the edges. - ## Positioning {#positioning} The dialog's position can be manipulated using the built-in `setPosx()` and `setPosy()` methods. These methods take a string argument which can represent any applicable CSS unit of length, such as pixels or view height/width. A list of these measurements [can be found at this link](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#numbers_lengths_and_percentages). - ### Vertical alignment {#vertical-alignment} In addition to manual assignment of a dialog's X and Y position, it is possible to use the dialog's built-in enum class to align the `Dialog`. There are three possible values, `TOP`, `CENTER` and `BOTTOM`, each of which can be used with the `setAlignment()` method. - ### Full screen and breakpoints {#full-screen-and-breakpoints} @@ -116,10 +116,10 @@ The `Dialog` can be set to enter full screen mode. When full screen is enabled, By default, the `Dialog` stretches to fill the available horizontal space. When auto width is enabled via `setAutoWidth(true)`, the `Dialog` sizes itself based on its content width instead. - ## Styling {#styling} @@ -138,10 +138,10 @@ While there are many use cases for each of the various themes, some examples use - **Gray**: Good for subtle actions, such as minor settings or actions that are more supplementary to a page, and not part of the main functionality. - **Info**: The Info theme is a good choice to provide clarifying, additional information to a user when pushed. - \ No newline at end of file diff --git a/docs/docs/components/drawer.md b/docs/docs/components/drawer.md index d0e7a41e1..a49fdcf65 100644 --- a/docs/docs/components/drawer.md +++ b/docs/docs/components/drawer.md @@ -18,9 +18,13 @@ Drawers stack automatically when multiple are opened, making them a flexible cho The example below shows this behavior within the [`AppLayout`](../components/app-layout) component. The navigation drawer triggered by the hamburger menu is built into [`AppLayout`](../components/app-layout), while the welcome popup at the bottom uses a standalone `Drawer` instance. Both coexist and stack independently, demonstrating how Drawers can be integrated within layout components or used as standalone elements. - ## Autofocus @@ -29,7 +33,7 @@ The `Drawer` component supports autofocus, which automatically sets focus on the @@ -99,7 +103,7 @@ Available placement options: @@ -134,8 +138,10 @@ Each contact displays an avatar, name, location, and action button for quick acc @@ -145,8 +151,10 @@ This example uses a `Drawer` as a task manager. You can add tasks, check them of diff --git a/docs/docs/components/fields/color-field.md b/docs/docs/components/fields/color-field.md index c4592bb67..9c42b5ab9 100644 --- a/docs/docs/components/fields/color-field.md +++ b/docs/docs/components/fields/color-field.md @@ -20,10 +20,12 @@ The `ColorField` component lets users select a color through the browser's nativ `ColorField` extends the shared `Field` class, which provides common features across all field components. The following example lets the user pick a color and displays its tetradic complements. - diff --git a/docs/docs/components/fields/date-field.md b/docs/docs/components/fields/date-field.md index ae815461d..f433beabe 100644 --- a/docs/docs/components/fields/date-field.md +++ b/docs/docs/components/fields/date-field.md @@ -20,9 +20,9 @@ The `DateField` component lets users input or select a date by year, month, and `DateField` extends the shared `Field` class, which provides common features across all field components. The following example creates departure and return DateFields that stay in sync, with min and max constraints to limit the selectable range. - ## Field value (`LocalDate`) {#field-value-localdate} diff --git a/docs/docs/components/fields/date-time-field.md b/docs/docs/components/fields/date-time-field.md index b8733b708..82eaa11e9 100644 --- a/docs/docs/components/fields/date-time-field.md +++ b/docs/docs/components/fields/date-time-field.md @@ -20,9 +20,9 @@ The `DateTimeField` component lets users input both a date and a time in a singl `DateTimeField` extends the shared `Field` class, which provides common features across all field components. The following example creates a labeled `DateTimeField` for selecting a departure date and time. - ## Usages {#usages} diff --git a/docs/docs/components/fields/masked/datefield.md b/docs/docs/components/fields/masked/datefield.md index cf6005c58..947c3b689 100644 --- a/docs/docs/components/fields/masked/datefield.md +++ b/docs/docs/components/fields/masked/datefield.md @@ -20,7 +20,11 @@ The `MaskedDateField` is focused solely on **date** values. If you need a simila The `MaskedDateField` can be instantiated with or without parameters. You can define an initial value, a label, a placeholder, and an event listener for value changes. - + ## Mask rules {#mask-rules} @@ -187,10 +191,11 @@ dateField.restoreValue(); You can set the value to restore with `setRestoreValue()`, passing a [`LocalDate`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/LocalDate.html) instance. - + ## Validation patterns {#validation-patterns} @@ -215,10 +220,11 @@ You should always validate the input value in your app logic, even if a regular The `MaskedDateField` includes a built-in calendar picker that lets users select a date visually, rather than typing it. This enhances usability for less technical users or when precise input is required. - + ### Accessing the picker {#accessing-the-picker} @@ -281,10 +287,11 @@ picker.setShowWeeks(true); The `MaskedDateFieldSpinner` extends [`MaskedDateField`](#basics) by adding spinner controls that let users increment or decrement the date using arrow keys or UI buttons. It provides a more guided interaction style, especially useful in desktop-style applications. - + ### Key features {#key-features} diff --git a/docs/docs/components/fields/masked/numberfield.md b/docs/docs/components/fields/masked/numberfield.md index 01967ea07..ce587b092 100644 --- a/docs/docs/components/fields/masked/numberfield.md +++ b/docs/docs/components/fields/masked/numberfield.md @@ -20,10 +20,10 @@ The `MaskedNumberField` can be instantiated with or without parameters. It suppo This demo showcases a **Tip Calculator** that uses `MaskedNumberField` for intuitive numeric input. One field is configured to accept a formatted bill amount, while the other captures a whole-number tip percentage. Both fields apply numeric masks to ensure consistent and predictable formatting. - ## Mask rules {#mask-rules} @@ -95,10 +95,10 @@ field.setNegateable(false); When `negatable` is set to `false`, the field blocks any attempts to enter a minus sign or otherwise input negative values. - ## Min and max values {#min-and-max-values} @@ -144,10 +144,10 @@ numberField.restoreValue(); The restore value must be explicitly set. If not defined, the feature will not revert the field. - ## `MaskedNumberFieldSpinner` {#maskednumberfieldspinner} @@ -155,10 +155,10 @@ height = '150px' The `MaskedNumberFieldSpinner` extends [`MaskedNumberField`](#basics) by adding spinner controls that let users increase or decrease the value using step buttons or arrow keys. This is ideal for inputs like quantities, pricing adjustments, rating controls, or any scenario where users make incremental changes. - ### Key features {#key-features} diff --git a/docs/docs/components/fields/masked/textfield.md b/docs/docs/components/fields/masked/textfield.md index 3ba37dac9..fc5d18aa2 100644 --- a/docs/docs/components/fields/masked/textfield.md +++ b/docs/docs/components/fields/masked/textfield.md @@ -62,9 +62,9 @@ If the mask only contains `X`, the field behaves like a standard [`TextField`](. This is useful when you want to reserve the ability to format without applying strict character rules. ::: - @@ -106,9 +106,9 @@ field.restoreValue(); You can set the value to restore with `setRestoreValue()`. If no restore value is set, the field will revert to the initial value at the time it was rendered. - @@ -117,9 +117,9 @@ height='200px' The `MaskedTextFieldSpinner` extends [`MaskedTextField`](#basics) by adding spinner controls that let users cycle through a list of predefined values. This improves the user experience in situations where the input should be constrained to a fixed set of valid options. - diff --git a/docs/docs/components/fields/masked/timefield.md b/docs/docs/components/fields/masked/timefield.md index e5f111285..adf8bf9da 100644 --- a/docs/docs/components/fields/masked/timefield.md +++ b/docs/docs/components/fields/masked/timefield.md @@ -20,7 +20,11 @@ The `MaskedTimeField` is built for **time-only** input. If you’re looking for The `MaskedTimeField` can be instantiated with or without parameters. You can define an initial value, a label, a placeholder, and an event listener for value changes. - + ## Mask rules {#mask-rules} @@ -103,10 +107,11 @@ field.restoreValue(); - **Programmatically**, by calling `restoreValue()` - **Via keyboard**, by pressing ESC (this is the default restore key unless overridden by an event listener) - + ## Validation patterns {#validation-patterns} @@ -131,10 +136,11 @@ You should always validate the input value in your app logic, even if a regular The `MaskedTimeField` includes a built-in time picker that lets users select a time visually, rather than typing it. This enhances usability for less technical users or when precise input is required. - + ### Accessing the picker {#accessing-the-picker} @@ -203,10 +209,11 @@ This ensures the dropdown list contains predictable, evenly spaced values like ` The `MaskedTimeFieldSpinner` extends [`MaskedTimeField`](#basics) by adding spinner controls that let users increment or decrement the time using arrow keys or UI buttons. It provides a more guided interaction style, especially useful in desktop-style applications. - + ### Key features {#key-features} diff --git a/docs/docs/components/fields/number-field.md b/docs/docs/components/fields/number-field.md index 9a0f44bdc..ffdef76c3 100644 --- a/docs/docs/components/fields/number-field.md +++ b/docs/docs/components/fields/number-field.md @@ -20,9 +20,9 @@ The `NumberField` component accepts numeric input and rejects invalid values aut `NumberField` extends the shared `Field` class, which provides common features across all field components. The following example creates a `NumberField` with a label and placeholder text. - ## Field value {#field-value} diff --git a/docs/docs/components/fields/password-field.md b/docs/docs/components/fields/password-field.md index b0b608e7d..01ff912e2 100644 --- a/docs/docs/components/fields/password-field.md +++ b/docs/docs/components/fields/password-field.md @@ -20,9 +20,9 @@ The `PasswordField` component allows users to input a password securely. It's di `PasswordField` extends the shared `Field` class, which provides common features across all field components. The following example creates a `PasswordField` with a label and placeholder text. - ## Field value {#field-value} diff --git a/docs/docs/components/fields/text-field.md b/docs/docs/components/fields/text-field.md index c3558aecd..c79a15eef 100644 --- a/docs/docs/components/fields/text-field.md +++ b/docs/docs/components/fields/text-field.md @@ -44,9 +44,9 @@ You can specify the type of the TextField using the `setType()` method. Similarl - `Type.SEARCH`: A single-line text field for entering search strings. Line-breaks are automatically removed from the input value. - diff --git a/docs/docs/components/fields/time-field.md b/docs/docs/components/fields/time-field.md index f62ae7114..214e36d4b 100644 --- a/docs/docs/components/fields/time-field.md +++ b/docs/docs/components/fields/time-field.md @@ -20,9 +20,9 @@ description: A component that provides a default browser-based time picker for s `TimeField` extends the shared `Field` class, which provides common features across all field components. The following example creates a reminder `TimeField` initialized to the current time. - ## Usages {#usages} diff --git a/docs/docs/components/flex-layout.md b/docs/docs/components/flex-layout.md index fd536dc98..8da8fff9b 100644 --- a/docs/docs/components/flex-layout.md +++ b/docs/docs/components/flex-layout.md @@ -28,11 +28,13 @@ The `FlexLayout` adds components next to one another according to its direction, To set the direction on an existing `FlexLayout` object, use the `setDirection()` method. The horizontal options are `FlexDirection.ROW` (left to right) or `FlexDirection.ROW_REVERSE` (right to left), and the vertical options are `FlexDirection.COLUMN` (top to bottom) or `FlexDirection.COLUMN_REVERSE` (bottom to top). - ### Positioning {#positioning} @@ -47,11 +49,13 @@ The `setAlignment()` method controls how items will display along the cross axis The `setAlignContent()` method controls the space around the cross axis, and will take effect only when a layout has multiple lines. ::: - ### Wrapping {#wrapping} @@ -78,11 +82,13 @@ use the `.vertical().wrap()` combination. The following demo allows you to build a container with the desired flex properties selected from the various menus. This tool can be used not only to create a visual example of the various methods, but also to create your own layouts with your desired properties. To use a layout you customize, simply copy the output code and add your desired elements for use in your program. - @@ -101,11 +107,13 @@ This property accepts a unitless integer value that specifies the relative order It's important to note that the order property only affects the visual order of the items within the container, not their actual position in the DOM. This means that screen readers and other assistive technologies will still read the items in the order they appear in the source code, not in the visual order. ::: - ### Self alignment {#self-alignment} @@ -120,11 +128,13 @@ Self alignment uses the same values as content alignment. This property is especially useful when you need to align a specific item differently from the other items in the container. See the sample below for an example of aligning a single item: - ### Flex basis {#flex-basis} @@ -139,10 +149,10 @@ By default, the `Item Basis` property is set to `auto`, which means that the siz The following demo allows you to select one or more boxes and change the `Item Basis` for the selected items. - ### Flex grow and shrink {#flex-grow--shrink} @@ -164,9 +174,11 @@ The form below demonstrates how `FlexLayout` organizes input fields into a struc If you prefer a column-based structure, look at the `ColumnsLayout` version of this form in the [`ColumnsLayout`](../components/columns-layout) article to see how it compares. ::: - \ No newline at end of file diff --git a/docs/docs/components/google-charts.md b/docs/docs/components/google-charts.md index 6d9f43ceb..469b09979 100644 --- a/docs/docs/components/google-charts.md +++ b/docs/docs/components/google-charts.md @@ -30,10 +30,12 @@ To create a chart, specify a chart type, configure its visual options, and provi This example creates a geo chart that maps revenue data across different countries, with custom colors, legend positioning, and chart area sizing: - @@ -41,10 +43,12 @@ height='300px' The `GoogleChart` addon offers a comprehensive array of chart types to suit various data visualization requirements. Selecting the appropriate chart type is essential for effectively communicating the data's story. See the gallery below for examples of common charts that can be used in a webforJ app. - @@ -108,14 +112,12 @@ chart.setData(data); Once the data is prepared, it can be applied to the GoogleChart using the setData method. - - - ### Loading data and options from JSON {#loading-data-and-options-from-json} You can also load data and options from JSON files using Gson for easier management. This approach helps keep your data and options organized and easy to update. @@ -147,15 +149,15 @@ Invoke `redraw()` in scenarios such as: - **Upon Changing Options**: Applies new styling or configuration changes to the chart. - **For Responsive Adjustments**: Adjusts the chart's layout or size when the container's dimensions change, ensuring optimal display across devices. - - - ## Exporting charts as images {#exporting-charts-as-images} The `getImageUri()` method provides a way to export your Google Charts as base64-encoded PNG images. This method is particularly useful for sharing charts outside the web environment, embedding them into emails or documents, or simply for archival purposes. diff --git a/docs/docs/components/icon.md b/docs/docs/components/icon.md index 0f7444a5a..f2d08fd11 100644 --- a/docs/docs/components/icon.md +++ b/docs/docs/components/icon.md @@ -20,9 +20,9 @@ Additionally, `Icon` components are loaded on demand from a content delivery net When creating an `Icon`, you'll need to identify a specific pool and the name of the icon itself. Some icons also offer the choice between an outlined or a filled version via [variations](#variations). - @@ -87,9 +87,9 @@ Icon music = FontAwesomeIcon.create("user", FontAwesomeIcon.Variate.SOLID); The following demo illustrates how to use icons from different pools, apply variations, and seamlessly integrate them into components. - @@ -112,9 +112,9 @@ Icons after a component's text is ideal for components that either offer supplem Ultimately, consistency is key. Once you choose a style, maintain it across your site for a cohesive and user-friendly design. -️ diff --git a/docs/docs/components/infinitescroll.md b/docs/docs/components/infinitescroll.md index 96cc873bf..ccb5ab9ba 100644 --- a/docs/docs/components/infinitescroll.md +++ b/docs/docs/components/infinitescroll.md @@ -18,12 +18,13 @@ When users reach the bottom of scrollable content, `InfiniteScroll` triggers an The `InfiniteScroll` component emits events and maintains internal state to help manage how and when content is loaded. - To fetch more data when the user scrolls, use the `onScroll()` or `addScrollListener()` method to register a listener. Inside the listener, you typically load additional content and call `update()` to refresh the `InfiniteScroll` state. @@ -59,12 +60,13 @@ infiniteScroll.setText("Loading more items..."); Similarly, you can customize the [`Icon`](../components/icon) displayed during loading by using `setIcon()`. - ### Full customization {#full-customization} @@ -74,12 +76,13 @@ you can add content directly into the special content slot using `addToContent() When you populate the content slot, it replaces the default loading layout entirely. - ## Styling {#styling} diff --git a/docs/docs/components/lists/choice-box.md b/docs/docs/components/lists/choice-box.md index 5f97be273..823be53a5 100644 --- a/docs/docs/components/lists/choice-box.md +++ b/docs/docs/components/lists/choice-box.md @@ -45,10 +45,12 @@ dropdown using CSS or shadow part selectors from the parent component becomes ch In the demo below, the Dropdown type is set and used in the CSS file to select the dropdown and change the background color. - @@ -60,9 +62,9 @@ By default, the number of rows displayed in the dropdown of a `ChoiceBox` will b Using a number that is less than or equal to 0 will result in unsetting this property. ::: - diff --git a/docs/docs/components/lists/combo-box.md b/docs/docs/components/lists/combo-box.md index 2f0479bf3..4f0518011 100644 --- a/docs/docs/components/lists/combo-box.md +++ b/docs/docs/components/lists/combo-box.md @@ -36,20 +36,20 @@ The ComboBox component is a versatile input element that combines the features o Changing the custom value property allows control over whether or not a user is able to change the value in the `ComboBox` component's input field. If `true`, which is the default, then a user can change the value. If set to `false`, the user won't be able to change the value. This can be set using the setAllowCustomValue() method. - ## Placeholder {#placeholder} A placeholder can be set for a `ComboBox` which will display in the text field of the component when it is empty to prompt users for the desired entry in the field. This can be done using the setPlaceholder() method. - ## Dropdown type {#dropdown-type} @@ -61,10 +61,12 @@ dropdown using CSS or shadow part selectors from the parent component becomes ch In the demo below, the Dropdown type is set and used in the CSS file to select the dropdown and change the background color. - @@ -76,9 +78,9 @@ By default, the number of rows displayed in the dropdown of a `ComboBox` will be Using a number that is less than or equal to 0 will result in unsetting this property. ::: - diff --git a/docs/docs/components/lists/list-box.md b/docs/docs/components/lists/list-box.md index 32e1b9662..c21b166d1 100644 --- a/docs/docs/components/lists/list-box.md +++ b/docs/docs/components/lists/list-box.md @@ -42,10 +42,10 @@ On touch devices, when multiple selection is enabled, users can select multiple Additionally, the arrow keys can be used to navigate the `ListBox`, and typing a letter key while the `ListBox` has focus will select the option that begins with that letter, or cycle through the options beginning with that letter should multiple options exist. - ## Styling {#styling} diff --git a/docs/docs/components/loading.md b/docs/docs/components/loading.md index bc5731894..4aba227b7 100644 --- a/docs/docs/components/loading.md +++ b/docs/docs/components/loading.md @@ -18,11 +18,13 @@ The simplest way to create a `Loading` component is by initializing it without a Here's an example of creating a `Loading` component with a message: - ## Scoping {#scoping} @@ -60,11 +62,13 @@ The `Loading` component in webforJ includes a `Spinner` that visually indicates Here's an example of how you can customize the spinner within a `Loading` component: - ## Use cases {#use-cases} diff --git a/docs/docs/components/login.md b/docs/docs/components/login.md index bdfc7ca84..537c9ff37 100644 --- a/docs/docs/components/login.md +++ b/docs/docs/components/login.md @@ -16,10 +16,10 @@ The `Login` component simplifies user authentication by providing a ready-to-use Create a `Login` dialog by instantiating the component and calling `open()` to display it. The dialog includes username and password fields, input validation, and a sign-in button by default. - ## Login submission {#login-submission} @@ -28,10 +28,10 @@ When users enter their username and password, the `Login` component validates th The following illustrates a basic `Login` component. If the username and password are both set to `"admin"` respectively, the login dialog closes, and a [Logout] button appears. If the credentials don't match, the default error message is displayed. - :::info Disabling the [Sign in] Button @@ -61,10 +61,10 @@ If no action URL is set, form submission is handled through the `LoginSubmitEven The titles, descriptions, labels, and messages within the `Login` component are fully customizable using the `LoginI18n` class. This flexibility allows you to tailor the login interface to meet specific localization requirements or personalization preferences. - ## Custom fields {#custom-fields} @@ -73,11 +73,13 @@ The `Login` component includes several slots that allow you to add extra fields The following login has a custom field added for a customer ID. This can help you manage companies or departments with shared content across multiple users. - :::info Name Required @@ -90,10 +92,10 @@ Custom fields must have a name set using `setName()` to be included in the form To make the cancel button visible, provide a label for it. You can also listen to cancel events to handle the cancellation appropriately. - :::tip Hiding Elements diff --git a/docs/docs/components/markdownviewer.md b/docs/docs/components/markdownviewer.md index a9adc754e..58ae85138 100644 --- a/docs/docs/components/markdownviewer.md +++ b/docs/docs/components/markdownviewer.md @@ -31,9 +31,9 @@ String content = viewer.getContent(); :::tip The component implements `HasText`, so `setText()` and `getText()` work as aliases for the content methods. ::: - @@ -67,9 +67,9 @@ viewer.setProgressiveRender(true); When enabled, content added via `setContent()` or `append()` goes into a buffer and displays incrementally. When disabled, content appears immediately. - @@ -139,9 +139,9 @@ When using progressive rendering, don't re-enable input fields based solely on w The following demo simulates an AI chat interface using `append()` with progressive rendering enabled: - diff --git a/docs/docs/components/navigator.md b/docs/docs/components/navigator.md index 2cf8842c2..c8dc03021 100644 --- a/docs/docs/components/navigator.md +++ b/docs/docs/components/navigator.md @@ -18,9 +18,9 @@ Often, a `Navigator` component displays information found in a bound `Repository To do this, simply pass the desired `Repository` object to an applicable `Navigator` object's constructor: - @@ -54,9 +54,9 @@ The `setMax()` method allows you to define the maximum number of page links to d navigator.getPaginator().setMax(maxPages); ``` - @@ -76,9 +76,9 @@ The `Navigator` component provides extensive customization options for buttons, In the following example, the `setText()` method displays a numeric value to the user. Clicking the buttons fires the `onChange` method of the `Navigator`, which comes with a `Direction` value the clicked button. - @@ -124,9 +124,9 @@ navigator.setTooltipText("Go to the last page", Navigator.Part.LAST_BUTTON); Various layout options exist for the `Navigator` component to provide flexibility in displaying pagination controls. To access these layouts, use the `Navigator.Layout` enum's values. The options are as follows: - diff --git a/docs/docs/components/option-dialogs/confirm.md b/docs/docs/components/option-dialogs/confirm.md index 49f319249..508c4c1a0 100644 --- a/docs/docs/components/option-dialogs/confirm.md +++ b/docs/docs/components/option-dialogs/confirm.md @@ -15,10 +15,10 @@ A `ConfirmDialog` is a modal dialog designed to allow the user to choose one of The `ConfirmDialog` provides a way to ask users for confirmation or to choose between multiple options, such as `Yes/No` or `OK/Cancel`, ensuring that they acknowledge and confirm their actions. - ## Types {#types} @@ -47,10 +47,10 @@ The `ConfirmDialog` supports the following message types. When you configures a In the following sample, the code configures a confirm dialog of type `CUSTOM` with a custom title and message. - ## Result {#result} diff --git a/docs/docs/components/option-dialogs/file-chooser.md b/docs/docs/components/option-dialogs/file-chooser.md index bcaaa8dcf..830788c20 100644 --- a/docs/docs/components/option-dialogs/file-chooser.md +++ b/docs/docs/components/option-dialogs/file-chooser.md @@ -15,10 +15,10 @@ sidebar_position: 10 The `FileChooserDialog` provides a way to select files or directories from the file system, enabling users to choose directories for saving data, or perform file operations. - ## Result {#result} @@ -71,10 +71,10 @@ dialog.show(); When the seletion mode is `FILES`, The `FileChooserDialog` allows you to set filters to limit the types of files that listed. You can configure filters using the `setFilters(List filters)` method. - ### Custom filters {#custom-filters} diff --git a/docs/docs/components/option-dialogs/file-save.md b/docs/docs/components/option-dialogs/file-save.md index 63d75fdab..032b2feda 100644 --- a/docs/docs/components/option-dialogs/file-save.md +++ b/docs/docs/components/option-dialogs/file-save.md @@ -15,10 +15,10 @@ sidebar_position: 15 The `FileSaveDialog` provides a streamlined method for saving files to the file system, offering user-configurable options for file naming and handling existing files. - ## Result {#result} @@ -115,10 +115,10 @@ dialog.setI18n(i18n); The `FileSaveDialog` allows you to set filters to limit the types of files that can be saved using the `setFilters(List filters)` method. - ### Custom filters {#custom-filters} diff --git a/docs/docs/components/option-dialogs/file-upload.md b/docs/docs/components/option-dialogs/file-upload.md index 7ec5d410b..bff1d94ec 100644 --- a/docs/docs/components/option-dialogs/file-upload.md +++ b/docs/docs/components/option-dialogs/file-upload.md @@ -27,10 +27,10 @@ The `FileUploadDialog` returns an `UploadedFile` object that contains informatio The resulting string will be returned from the `show()` method, or the equivalent `OptionDialog` method as shown below. ::: - ### Moving uploaded files {#moving-uploaded-files} diff --git a/docs/docs/components/option-dialogs/input.md b/docs/docs/components/option-dialogs/input.md index 65b15f595..235dba621 100644 --- a/docs/docs/components/option-dialogs/input.md +++ b/docs/docs/components/option-dialogs/input.md @@ -15,10 +15,10 @@ An `InputDialog` is a modal dialog designed to prompt the user for input. The di The `InputDialog` prompts users for input, such as text, numbers, or other data. Because the dialog is modal, the app waits for the user to respond before continuing: - ## Types {#types} @@ -51,10 +51,10 @@ The `InputDialog` supports the following message types. When you configures a ty In the following sample, The user is prompted to enter its password to access the app. If login fails, the user will prompted again. - ## Result {#result} diff --git a/docs/docs/components/option-dialogs/message.md b/docs/docs/components/option-dialogs/message.md index 1f6723b82..170b0143e 100644 --- a/docs/docs/components/option-dialogs/message.md +++ b/docs/docs/components/option-dialogs/message.md @@ -41,10 +41,10 @@ The `MessageDialog` supports the following message types. When you configures a In the following sample, The code configures a message dialog of type `WARNING`. with a custom title and message. - :::tip Dialog & Button Theme diff --git a/docs/docs/components/progressbar.md b/docs/docs/components/progressbar.md index 1e4cc670a..94d440514 100644 --- a/docs/docs/components/progressbar.md +++ b/docs/docs/components/progressbar.md @@ -22,9 +22,9 @@ The `ProgressBar` component is useful for visualizing the completion status of t The following example shows a striped, animated progress bar with start, pause, and reset controls: - @@ -43,9 +43,9 @@ bar.setValue(50); The `ProgressBar` can be oriented horizontally or vertically. - @@ -53,9 +53,9 @@ height='175px' The `ProgressBar` supports an indeterminate state for tasks with unknown completion time. - @@ -75,9 +75,9 @@ ProgressBar bar = new ProgressBar(15, "Downloading: {{x}}%"); The `ProgressBar` component comes with themes built in for quick styling without the use of CSS. These themes are pre-defined styles that can be applied to buttons to change their appearance and visual presentation. They offer a quick and consistent way to customize the look of ProgressBars throughout an app. - diff --git a/docs/docs/components/radio-button.md b/docs/docs/components/radio-button.md index 59977f777..904cc0e4f 100644 --- a/docs/docs/components/radio-button.md +++ b/docs/docs/components/radio-button.md @@ -32,10 +32,10 @@ Use a [`RadioButtonGroup`](/docs/components/radiobuttongroup) to manage a set of Radio buttons can utilize the ```setText(String text)``` method, which will be positioned near the radio button according to the built-in `Position`. Radio buttons have built-in functionality to set text to be displayed either to the right or left of the component. By default, the text will be displayed to the right of the component. Positioning of the horizontal text is supported by use of the `HorizontalAlignment` enum class. Show below are the two settings:
- @@ -43,10 +43,10 @@ height="120px" Radio buttons can be controlled using two types of activation: manual activation and auto activation. These dictate when a `RadioButton` will change its state. - ### Manual activation {#manual-activation} @@ -72,10 +72,10 @@ The default activation value is **`MANUAL`** activation. A `RadioButton` can also be set to display as a switch provides which provides alternative visual representation for selecting options. Normally, radio buttons are circular or rounded in shape and indicate a single choice from a group of options. - A `RadioButton` can be transformed into a switch that resembles a toggle switch or slider using one of two methods: diff --git a/docs/docs/components/radio-group.md b/docs/docs/components/radio-group.md index 70cc340a6..f1c02d528 100644 --- a/docs/docs/components/radio-group.md +++ b/docs/docs/components/radio-group.md @@ -19,10 +19,10 @@ The `RadioButtonGroup` component doesn't render an HTML element. It only provide Create individual `RadioButton` components and pass them to the `RadioButtonGroup` constructor. Only one button in the group can be selected at a time. - @@ -73,7 +73,7 @@ The following sample from [Drawer Placement](/docs/components/drawer#placement) diff --git a/docs/docs/components/refresher.md b/docs/docs/components/refresher.md index 6382ecc40..008578318 100644 --- a/docs/docs/components/refresher.md +++ b/docs/docs/components/refresher.md @@ -20,12 +20,13 @@ Add a `Refresher` by instantiating it and registering a refresh listener. When r To activate the `Refresher`, **click and drag downward** from the top of the scrollable area. While this gesture is familiar on mobile, it's less common on desktop—make sure to hold and pull with your mouse. ::: - This approach is commonly used to refresh paginated lists or restart infinite scroll loading. @@ -40,24 +41,26 @@ Each state label can also be localized using the `RefresherI18n` object. The thr This allows multilingual support and branding adjustments as needed. - ## Icon customization {#icon-customization} You can change the [`Icons`](../components/icon) used for the `pull`/`release` and `refreshing` stages using either a predefined [`Icon`](../components/icon) or an [Icon URL](../managing-resources/assets-protocols). These are useful when you want to apply branding or a custom animation. - ## Pull behavior configuration {#pull-behavior-configuration} @@ -109,12 +112,13 @@ The `Refresher` component supports multiple themes to visually distinguish diffe The following sample cycles through all available themes each time you pull to refresh, giving you a live preview of how the `Refresher` looks across different themes: - \ No newline at end of file diff --git a/docs/docs/components/slider.md b/docs/docs/components/slider.md index f9a0f7fd6..a173e9ab9 100644 --- a/docs/docs/components/slider.md +++ b/docs/docs/components/slider.md @@ -18,10 +18,10 @@ The `Slider` is designed to work right out of the box, requiring no additional s Here’s an example of a `Slider` that allows users to adjust volume levels within a predefined range: - ## `Slider` value {#slider-value} @@ -56,10 +56,10 @@ These intervals are evenly distributed along the slider track, with their spacin Below is an example of creating a `Slider` with a custom range: - ## Tick configuration {#tick-configuration} @@ -98,10 +98,10 @@ slider.setSnapToTicks(true); // Enable snapping Here’s an example of a fully configured `Slider` showing major and minor tick settings along with the snapping capability for precise adjustments: - ## Orientation and inversion {#orientation-and-inversion} @@ -115,10 +115,10 @@ In addition to orientation, the `Slider` can also be inverted. By default: When inverted, this direction is reversed. Use the `setInverted(true)` method to enable inversion. - ## Labels {#labels} @@ -154,10 +154,10 @@ slider.setLabelsVisible(true); Whether you're using default or custom labels, you can control their visibility with `setLabelsVisible(true)` or hide them with `setLabelsVisible(false)`. - ## Tooltips {#tooltips} @@ -202,10 +202,10 @@ slider.setTooltipText("x + ' units'"); The `Slider` comes with 6 themes built in for quick styling without the use of CSS. Theming is supported by use of a built-in enum class. Shown below are sliders with each of the supported Themes applied: - \ No newline at end of file diff --git a/docs/docs/components/spinner.md b/docs/docs/components/spinner.md index 677c9060b..baaf68d44 100644 --- a/docs/docs/components/spinner.md +++ b/docs/docs/components/spinner.md @@ -16,10 +16,10 @@ The `Spinner` component provides a visual indicator that indicates ongoing proce To create a `Spinner`, you can specify the theme and expanse. The basic syntax involves creating a `Spinner` instance and defining its appearance and behavior through methods such as `setTheme()` and `setExpanse()`. - ## Managing speed and pausing {#managing-speed-and-pausing} @@ -53,10 +53,10 @@ spinner.setPaused(false); // Resume the spinner This example shows how to go about setting the speed and how to pause/resume the `Spinner`: - ## Spin direction {#spin-direction} @@ -70,10 +70,10 @@ spinner.setClockwise(true); // Rotates clockwise This option visually indicates a special state or serves as a unique design choice. Changing the spin direction can help differentiate between types of processes, such as progress vs. reversal, or provide a distinct visual cue in specific contexts. - ## Styling {#styling} @@ -100,20 +100,20 @@ You can apply these themes programmatically to the spinner, providing visual cue You can specify this behavior using the `setTheme()` method. - ### Expanses {#expanses} You can adjust the size of the spinner, known as **expanse**, to fit the visual space you need. The spinner supports various sizes including `Expanse.SMALL`, `Expanse.MEDIUM`, and `Expanse.LARGE`. - diff --git a/docs/docs/components/splitter.md b/docs/docs/components/splitter.md index f1847fcef..49803976e 100644 --- a/docs/docs/components/splitter.md +++ b/docs/docs/components/splitter.md @@ -16,11 +16,13 @@ The `Splitter` component, designed to divide and resize content within your app, Create a `Splitter` by passing two components to its constructor. The first becomes the master panel and the second becomes the detail panel. - @@ -34,11 +36,13 @@ The `setMasterMinSize(String masterMinSize)` method specifies the minimum size f You can specify sizes using any valid CSS units, as shown below: - @@ -48,11 +52,13 @@ You can configure orientation in the `Splitter` component, allowing you to creat To configure the orientation, use the supported orientations Enum to specify whether the `Splitter` should render horizontally or vertically: - @@ -60,11 +66,13 @@ height='300px' To set the initial position of the divider bar in the `Splitter` component, use `setPositionRelative`. This method takes a numeric value from `0` to `100` representing the percentage of the given space in the `Splitter`, and displays the divider at the given percentage of total width: - @@ -74,11 +82,13 @@ Splitter nesting allows you to create complex layouts with levels of resizable p To nest Splitter components, instantiate new `Splitter` instances and add them as children to existing `Splitter` components. This hierarchical structure allows for the creation of multi-level layouts with flexible resizing capabilities. The program below demonstrates this: - @@ -92,11 +102,13 @@ When you set the auto-save configuration, the `Splitter` component automatically To programmatically revert the `Splitter` back to default settings and dimensions, call the `cleanState()` method to remove any saved state data related to the `Splitter` component from the local storage of the web browser. - diff --git a/docs/docs/components/tabbed-pane.md b/docs/docs/components/tabbed-pane.md index 6d9425c69..3837d57cf 100644 --- a/docs/docs/components/tabbed-pane.md +++ b/docs/docs/components/tabbed-pane.md @@ -126,10 +126,10 @@ The `TabbedPane` supports navigating through the various tabs via swiping. This The `Tabs` within a `TabbedPane` can be placed in various positions within the component based on the application developers preference. Provided options are set using the provided enum, which has the values of `TOP`, `BOTTOM`, `LEFT`, `RIGHT`, or `HIDDEN`. The default setting is `TOP`. - ### Alignment {#alignment} @@ -138,10 +138,10 @@ In addition to changing the placement of the `Tab` elements within the `TabbedPa The other options are `START`, `END`, `CENTER`, and `STRETCH`. The first three describe the position relative to the component, with `STRETCH` making the tabs fill the available space. - ### Border and activity indicator {#border-and-activity-indicator} @@ -158,10 +158,10 @@ This border doesn't apply to the entirety of the `TabbedPane` component, and mer To set the visibility of the active indicator, the `setHideActiveIndicator(boolean)` method can be used. Passing `true` to this method will hide the active indicator beneath an active `Tab`, whereas `false`, the default, keeps the indicator displayed. - ### Activation modes {#activation-modes} @@ -172,10 +172,10 @@ For more fine-grained control over how the `TabbedPane` behaves when being navig - **`Manual`**: When set to manual, the tab will receive focus but will not show until the user presses space or enter. - ### Removal options {#removal-options} @@ -190,10 +190,10 @@ Individual `Tab` elements can be set to be closable. Closable tabs will have a c The `TabbedPane` can be rendered as a segment control by enabling the `segment` property with `setSegment(true)`. In this mode, tabs are displayed with a sliding pill indicator that highlights the active selection, providing a compact alternative to the standard tabbed interface. - ## Styling {#styling} @@ -202,10 +202,10 @@ height="250px" The `TabbedPane` comes with built-in `Expanse` and `Theme` options similar to other webforJ components. These can be used to quickly add styling that conveys various meaning to the end user without needing to style the component with CSS. - diff --git a/docs/docs/components/table/overview.md b/docs/docs/components/table/overview.md index c0f185155..06ec4e77f 100644 --- a/docs/docs/components/table/overview.md +++ b/docs/docs/components/table/overview.md @@ -16,9 +16,9 @@ The `Table` class is a versatile component designed for presenting tabular infor ## Creating a `Table` {#creating-a-table} - @@ -83,11 +83,13 @@ Alternatively, the `setItems()` method can be passed any valid Java collection, Below is an example of the above steps implemented to create a basic `Table` component: - diff --git a/docs/docs/components/table/table_column_groups.md b/docs/docs/components/table/table_column_groups.md index 8da66e334..f796be830 100644 --- a/docs/docs/components/table/table_column_groups.md +++ b/docs/docs/components/table/table_column_groups.md @@ -11,11 +11,13 @@ Column groups let you organize related columns under shared, multi-row headers. Create a group with the `ColumnGroup.of()` factory method, then chain `add()` calls to populate it with column references, other groups, or a mix of both. Apply the groups to a `Table` with `setColumnGroups()`. - @@ -23,11 +25,13 @@ height='600px' When groups are set, the `Table` renders a multi-row header where each group label spans across its child columns. The nesting depth determines how many header rows appear. A flat group adds one extra row, while a two-level nesting adds two, and so on. - @@ -64,11 +68,13 @@ Visual order: Number, Title, Artist, Genre, Label, Cost The following demo illustrates this behavior. `Number` and `Label` aren't referenced in any group, but they retain their natural positions based on the order they were added to the `Table`. - @@ -111,11 +117,13 @@ ColumnGroup idInfo = ColumnGroup.of("id-info", "ID Info") Ungrouped columns retain their own pin direction from their column definition. - @@ -144,12 +152,14 @@ Group headers and columns expose CSS parts for styling via `::part()`. The follo | `cell-label-group-{ID}` | Label within a group header | - @@ -197,11 +207,13 @@ dwc-table::part(cell-group-depth-1) { Hidden columns are excluded from the visual order and the header layout. If a group contains a mix of visible and hidden columns, only the visible ones appear and the group `colspan` adjusts accordingly. If every column in a group is hidden, the group header isn't rendered at all. - \ No newline at end of file diff --git a/docs/docs/components/table/table_columns.md b/docs/docs/components/table/table_columns.md index cfd2144a5..ff50cc89c 100644 --- a/docs/docs/components/table/table_columns.md +++ b/docs/docs/components/table/table_columns.md @@ -73,11 +73,13 @@ After establishing a column’s identity, the next step is to control how its co Setting a column’s alignment lets you create organized tables, which can help users identify the different sections in the `Table`. - @@ -95,11 +97,13 @@ In the preceding example, the final column for `Cost` has been right-aligned to Column pinning is a feature that allows users to affix or "pin" a column to a specific side of the `Table`. This is useful when certain columns, such as identifiers or essential information, need to remain visible while scrolling horizontally through a table. - @@ -190,11 +194,13 @@ Key flex behaviors: - **Respects constraints**: Works with minimum width/maximum width constraints. Without minimum width, flex columns can shrink to 0. - @@ -237,11 +243,13 @@ Auto-sizing methods return `PendingResult` because they require client-sid ::: - diff --git a/docs/docs/components/table/table_dynamic_styling.md b/docs/docs/components/table/table_dynamic_styling.md index cf8c443ae..0d90ddf6a 100644 --- a/docs/docs/components/table/table_dynamic_styling.md +++ b/docs/docs/components/table/table_dynamic_styling.md @@ -22,10 +22,12 @@ For more on how shadow parts work and how to define and target them, see the [St ::: - @@ -35,10 +37,12 @@ The `setCellPartProvider()` method styles individual cells based on both the dat Like row parts, cell parts are defined by a name and targeted using the `::part()` selector. - @@ -48,10 +52,12 @@ If your app modifies data programmatically, such as updating a user's age, the t In this demo, cells in the Age column are styled based on a threshold: ages over 30 appear green, while ages 30 and under appear red. Clicking the button toggles Alice's age between 28 and 31, triggering the `setCellPartProvider` to reapply the appropriate style when the data is committed. - @@ -78,9 +84,9 @@ table.setBordersVisible(EnumSet.noneOf(Table.Border.class)); The demo below showcases a simple way to align your `Table's` visual appearance with the rest of your app using `setStriped()` and `setBordersVisible()`. - diff --git a/docs/docs/components/table/table_edit_refresh.md b/docs/docs/components/table/table_edit_refresh.md index fb936fc76..77c9782b4 100644 --- a/docs/docs/components/table/table_edit_refresh.md +++ b/docs/docs/components/table/table_edit_refresh.md @@ -6,10 +6,12 @@ slug: refreshing Editing data within the `Table` works via interaction with the `Repository` containing the data for the `Table`. The `Repository` serves as a bridge between the `Table` and the underlying dataset, offering methods for data retrieval, modification, and refreshing. Below is an example which implements behavior to edit the "Title" of a desired row based. - diff --git a/docs/docs/components/table/table_filtering.md b/docs/docs/components/table/table_filtering.md index b865ec1cf..7f6d3e954 100644 --- a/docs/docs/components/table/table_filtering.md +++ b/docs/docs/components/table/table_filtering.md @@ -10,10 +10,12 @@ The following example uses a user-defined criteria from the search field and the diff --git a/docs/docs/components/table/table_large_data.md b/docs/docs/components/table/table_large_data.md index 5601f661c..c5e6839a1 100644 --- a/docs/docs/components/table/table_large_data.md +++ b/docs/docs/components/table/table_large_data.md @@ -25,10 +25,12 @@ The main advantage of virtual scrolling is improved performance, especially when The below `Table` shows all olympic winners - a large dataset that benefits greatly from the table's virtual scrolling functionality: diff --git a/docs/docs/components/table/table_rendering.md b/docs/docs/components/table/table_rendering.md index e26659f1f..749de0528 100644 --- a/docs/docs/components/table/table_rendering.md +++ b/docs/docs/components/table/table_rendering.md @@ -97,9 +97,11 @@ The following example shows conditional rendering applied to an invoice status c @@ -109,9 +111,11 @@ It also works well for numeric thresholds. This server dashboard uses `Condition @@ -161,7 +165,7 @@ The employee directory below uses a `CompositeRenderer` on the *Employee* column @@ -269,7 +273,7 @@ When `setLazyRender(true)` is set on a column, cells display a lightweight anima @@ -287,9 +291,11 @@ webforJ ships with a comprehensive set of renderers for the most common use case diff --git a/docs/docs/components/table/table_selection.md b/docs/docs/components/table/table_selection.md index 7f7772432..7b74cf87c 100644 --- a/docs/docs/components/table/table_selection.md +++ b/docs/docs/components/table/table_selection.md @@ -38,11 +38,13 @@ The `TableItemSelectEvent` and `TableItemDeselectEvent` are not triggered when m In the example below, a `TableItemSelectEvent` event will be fired whenever a user selects a row. The event can be handled by adding a listener to the table using the `onItemSelect()` method. - @@ -52,11 +54,13 @@ Checkbox selection is enabled when the selection mode is `MULTI`, and allows use By using the `setCheckboxSelection(boolean checkboxSelection)` method, checkboxes can be configured to be displayed next to each row, allowing users to select items. The program below shows multiple selection and checkbox selection enabled: - diff --git a/docs/docs/components/table/table_sorting.md b/docs/docs/components/table/table_sorting.md index e053cdc15..48f6e0ad8 100644 --- a/docs/docs/components/table/table_sorting.md +++ b/docs/docs/components/table/table_sorting.md @@ -10,11 +10,13 @@ Sorting lets users arrange data in columns by order, making information easier t For information on how to use the `Repository` pattern to manage and query collections, see the [Repository articles](/docs/advanced/repository/overview). ::: - @@ -38,11 +40,13 @@ table.setMultiSorting(true); With multi-sorting enabled, clicking multiple column headers will sort them sequentially. The sorting priority is visually indicated in the table UI. - @@ -58,11 +62,13 @@ ageColumn.setSortOrder(2); Unless `setSortOrder()` is used, the table defaults to sorting by the order in which columns are declared. ::: - @@ -142,11 +148,13 @@ The `Column` component allows developers to use Java `Comparators` for dynamic a To leverage `Comparator` sorting in a `Column`, you can use the `setComparator()` method. This method allows you to define a custom `Comparator` function that dictates the sorting logic. - diff --git a/docs/docs/components/terminal.md b/docs/docs/components/terminal.md index e04e078b5..a5d791c6c 100644 --- a/docs/docs/components/terminal.md +++ b/docs/docs/components/terminal.md @@ -27,19 +27,19 @@ To use the `Terminal` component in your app, ensure that you include the followi The following example builds an interactive command shell with typed commands, history navigation, and custom output. - @@ -155,9 +155,9 @@ pty.onData(chunk -> { }); ``` - @@ -199,9 +199,9 @@ theme.setBackground("#1e1e1e"); theme.setForeground("#cccccc"); terminal.setTheme(theme); ``` - diff --git a/docs/docs/components/textarea.md b/docs/docs/components/textarea.md index 53e43ddd2..ea53fe85f 100644 --- a/docs/docs/components/textarea.md +++ b/docs/docs/components/textarea.md @@ -16,10 +16,10 @@ The `TextArea` component provides a multi-line text input field where users can Create a `TextArea` by passing a label to its constructor. Properties like placeholder text, character limits, and wrapping behavior can be configured through setter methods. - ## Managing paragraphs {#managing-paragraphs} @@ -64,10 +64,10 @@ The `TextArea` component supports two complementary types of validation: structu The following demo allows users to adjust validation limits—such as maximum character count, paragraph length, and line count—in real time and see how the `TextArea` responds. - ## Word wrap and Line wrapping {#word-wrap-and-line-wrapping} @@ -80,10 +80,10 @@ To further refine how wrapping behaves, `setWrapStyle()` lets you choose between These wrapping options work hand-in-hand with structural constraints like line count and paragraph length limits. While wrapping determines *how* text flows within the available space, the structural limits define *how much* space text is allowed to occupy. Together, they help maintain both visual structure and user input boundaries. - ## Predicted text {#predicted-text} @@ -94,11 +94,13 @@ Predictions can be accepted by pressing the `Tab` or `ArrowRight` key, inserting This predictive behavior enhances both speed and accuracy, especially in repetitive input scenarios or applications where consistency of phrasing is important. - :::info @@ -115,10 +117,10 @@ A **disabled** text area, on the other hand, blocks all interaction—including Use read-only mode when the content is relevant but immutable, and disabled mode when the input isn't currently applicable or should be temporarily inactive. - ## Styling {#styling} diff --git a/docs/docs/components/toast.md b/docs/docs/components/toast.md index 7c1ce9dda..258de6fab 100644 --- a/docs/docs/components/toast.md +++ b/docs/docs/components/toast.md @@ -28,10 +28,12 @@ Toast toast = new Toast("Operation completed successfully!", 3000, Theme.SUCCESS toast.open(); ``` - @@ -93,9 +95,9 @@ toast.setPlacement(Toast.Placement.TOP_LEFT); toast.open(); ``` - @@ -109,9 +111,9 @@ The `Toast` component can display multiple notifications simultaneously, stackin Although `Toast` notifications don't require user interaction by default, webforJ allows you to add buttons or other interactive elements to make them more useful than simple notifications. - @@ -140,10 +142,12 @@ To add a custom theme to a `Toast`, you can define custom CSS variables, which m Since the `Toast` isn't located in a specific position in the DOM, you can target it using CSS variables. These variables make it easy to apply consistent custom styles across all Toast notifications. ::: - diff --git a/docs/docs/components/toolbar.md b/docs/docs/components/toolbar.md index cbfaf075a..6832c3148 100644 --- a/docs/docs/components/toolbar.md +++ b/docs/docs/components/toolbar.md @@ -26,11 +26,13 @@ Each slot has a method for adding components: `addToStart()`, `addToTitle()`, `a The following demo shows how to add a `Toolbar` to an [AppLayout](./app-layout) and utilize all supported slots effectively. To read more about implementing toolbars within an `AppLayout`, see [Sticky toolbars](./app-layout#sticky-toolbars) and [Mobile navigation layout](./app-layout#mobile-navigation-layout). - ## Compact mode {#compact-mode} @@ -42,8 +44,10 @@ Toolbar toolbar = new Toolbar(); toolbar.setCompact(true); ``` - ## `ProgressBar` in toolbars {#progressbar-in-toolbars} @@ -52,8 +56,10 @@ A `ProgressBar` serves as a visual indicator for ongoing processes, such as load You can combine it with other components in the toolbar like buttons or labels without disrupting the layout. - ## Styling {#styling} @@ -62,10 +68,10 @@ javaE='https://raw.githubusercontent.com/webforj/webforj-documentation/refs/head `Toolbar` components include seven built-in themes for quick visual customization: - diff --git a/docs/docs/components/tree.md b/docs/docs/components/tree.md index 820b0c7b3..157e3f5a4 100644 --- a/docs/docs/components/tree.md +++ b/docs/docs/components/tree.md @@ -39,9 +39,9 @@ tree.add(parent); Attempting to assign the same node to more than one parent will result in an exception being thrown. This safeguard ensures the tree maintains a proper hierarchy by preventing nodes from having multiple parents, which would break the integrity of the structure and cause unexpected behavior. ::: - @@ -59,10 +59,12 @@ Each node supports storing additional information on the server side using `setU In the demo, double-click a node to open an editor for its text. Enter the new text and save it to update the node’s label in the tree. ::: - @@ -109,9 +111,9 @@ tree.setGroupIconsVisible(false); tree.setLeafIconsVisible(false); ``` - @@ -146,9 +148,9 @@ The tree supports lazy loading of node children by reacting to expand events. Wh Use the `onExpand` event to detect when a node is expanded. Inside the handler, check if the node’s children are placeholders (for example, a spinner or empty node) and replace them with actual data once loaded. - @@ -207,9 +209,9 @@ Object selectedKey = tree.getSelectedKey(); List selectedKeys = tree.getSelectedKeys(); ``` - diff --git a/docs/siteConfig.js b/docs/siteConfig.js index 8bc1df7b4..655146d3c 100644 --- a/docs/siteConfig.js +++ b/docs/siteConfig.js @@ -1,6 +1,7 @@ const GLOBALS = { IFRAME_SRC_LIVE: "", - IFRAME_SRC_DEV: "http://localhost:8080" + IFRAME_SRC_DEV: "http://localhost:8080", + RAW_CONTENT_BASE: "https://raw.githubusercontent.com/webforj/webforj-documentation/main/", }; export default GLOBALS; diff --git a/docs/src/components/DocsTools/AppLayoutViewer.js b/docs/src/components/DocsTools/AppLayoutViewer.js deleted file mode 100644 index dead57b35..000000000 --- a/docs/src/components/DocsTools/AppLayoutViewer.js +++ /dev/null @@ -1,86 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import { React, useState, useEffect, useRef } from 'react' -import { jsx, css } from '@emotion/react'; -import { useColorMode } from '@docusaurus/theme-common'; -import ComponentDemo, {OpenNewWindowButton, isLocalhost} from './ComponentDemo'; -import GLOBALS from "../../../siteConfig"; - -export default function AppLayoutViewer({path, mobile, javaE, cssURL, urls}) { - - const [buttonVisible, setButtonVisible] = useState(false); - const iframeRef = useRef(null); - const { colorMode } = useColorMode() - - - useEffect(() => { - if (!iframeRef.current) return; - - const applyThemeToIframe = () => { - try { - const iframeDoc = iframeRef.current.contentDocument || iframeRef.current.contentWindow.document; - if (iframeDoc) { - iframeDoc.documentElement.setAttribute("data-app-theme", colorMode); - } - } catch (error) { - console.error("Failed to apply theme to iframe:", error); - } - }; - - applyThemeToIframe(); - iframeRef.current.onload = applyThemeToIframe; - - }, [colorMode]); - - const demoStyles = css` - display: flex; - flex-direction: column; - align-items: center; - margin: 4rem 0; - /* width: 110%; */ - /* margin-left: -5%; */ - ` - - const demoPreview = css` - position: relative; - width : 100%; - max-width: ${mobile == 'true' ? '375px' : '100%'}; - height: ${mobile == 'true' ? '700px' : '600px'}; - border-radius: 32px; - overflow: hidden; - box-shadow: 0 0 0 10px black, 0 3px 22px black; - outline: thin solid black; - ` - - const demoContent = css` - width: 100%; - height: 100%; - background: var(--dwc-surface-3); - ` - const fadeInButton = css` - display: flex; - justify-content: flex-end; - opacity: 0; - transition: opacity 0.3s ease-in-out; - ${buttonVisible && "opacity: 1;"}; - margin: 10px 0 0 0; - position: absolute; - top: 10px; - right: 5px; - ` - - return ( -
-
setButtonVisible(true)} - onMouseLeave={() => setButtonVisible(false)}> -
- {OpenNewWindowButton({ url: (isLocalhost ? GLOBALS.IFRAME_SRC_DEV : GLOBALS.IFRAME_SRC_LIVE) + path })} -
- -
- -
- ); -} \ No newline at end of file diff --git a/docs/src/components/DocsTools/ComponentDemo.js b/docs/src/components/DocsTools/ComponentDemo.js deleted file mode 100644 index e64f0a104..000000000 --- a/docs/src/components/DocsTools/ComponentDemo.js +++ /dev/null @@ -1,512 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import { React, useState, useEffect, useRef } from "react"; -import { jsx, css } from "@emotion/react"; -import PropTypes from "prop-types"; -import { translate } from '@docusaurus/Translate'; - -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import CodeBlock from "@theme/CodeBlock"; -import test3 from "../../../static/img/window-maximize.png"; -import { useColorMode } from "@docusaurus/theme-common"; -import GLOBALS from "../../../siteConfig"; - -import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; - - -export function OpenNewWindowButton({ url }) { - const { colorMode } = useColorMode() - const buttonStyles = css` - position: relative; - cursor: pointer; - z-index: 10; - height: 35px; - width: 35px; - border: none; - justify-self: flex-end; - margin-top: -5px; - margin-bottom: -20px; - background-color: transparent; - margin-right: 12px; - `; - - const iconStyles = css` - filter: ${colorMode === "dark" ? "invert(1)" : "none"}; - background-color: #ffffff80; - border-radius: var(--dwc-border-radius-s); - `; - - const openNewWindow = () => { - window.open(url, "_blank"); // '_blank' will open the URL in a new tab - }; - - return ( - - ); -} - -export const isLocalhost = typeof window !== "undefined" && -window.location.hostname === "localhost" && -window.location.port === "3000"; - -export default function ComponentDemo({ - path, - javaE, - urls, - cssURL, - javaHighlight, - height, - frame, - tabs, -}) { - ComponentDemo.propTypes = { - path: PropTypes.string.isRequired, - javaE: PropTypes.string, - urls: PropTypes.arrayOf(PropTypes.string), - cssURL: PropTypes.string, - javaHighlight: PropTypes.string, - height: PropTypes.string, - frame: PropTypes.string, - tabs: PropTypes.arrayOf(PropTypes.string), - }; - - const [javaExpand, setJavaExpand] = useState(""); - const [additionalFiles, setAdditionalFiles] = useState({}); - const [cssCode, setCssCode] = useState(""); - const [buttonVisible, setButtonVisible] = useState(false); - const [fileNames, setFileNames] = useState({}); - - const [isResizing, setIsResizing] = useState(false); - const [initialMouseX, setInitialMouseX] = useState(0); - const [initialWidth, setInitialWidth] = useState(0); - - const [initialRight, setInitialRight] = useState(25); - const [newRight, setNewRight] = useState(25); - const [originalWidth, setOriginalWidth] = useState(0); - - const [showCode, setShowCode] = useState(false); - - const iframeRef = useRef(null); - const codeButtonRef = useRef(null); - const { colorMode } = useColorMode() - - useEffect(() => { - if (javaE) { - fetch(javaE) - .then((response) => response.text()) - .then((textString) => { - setJavaExpand(textString); - const parsedUrl = new URL(javaE); - const pathname = parsedUrl.pathname; - const parts = pathname.split("/"); - const fileName = parts[parts.length - 1]; - setFileNames((prevFileNames) => ({ - ...prevFileNames, - javaFile: fileName, - })); - }); - } - if (cssURL) { - const rootPath = 'https://raw.githubusercontent.com/webforj/webforj-documentation/main/src/main/resources/static' - fetch(rootPath + cssURL) - .then((response) => response.text()) - .then((textString) => { - setCssCode(textString); - const parsedUrl = new URL(rootPath + cssURL); - const pathname = parsedUrl.pathname; - const parts = pathname.split("/"); - const fileName = parts[parts.length - 1]; - setFileNames((prevFileNames) => ({ - ...prevFileNames, - cssFile: fileName, - })); - }); - } - if (urls) { - urls.forEach(fetchAndProcessURL); - } - - function fetchAndProcessURL(url) { - const parsedUrl = new URL(url); - const pathname = parsedUrl.pathname; - const parts = pathname.split("/"); - const fileName = parts[parts.length - 1]; - - fetch(url) - .then((response) => response.text()) - .then((textString) => { - setAdditionalFile(fileName, textString); - }); - } - - function setAdditionalFile(fileName, textString) { - setAdditionalFiles((prevAdditionalFiles) => ({ - ...prevAdditionalFiles, - [fileName]: { - fileName: fileName, - code: textString, - }, - })); - } - setOriginalWidth(iframeRef.current ? iframeRef.current.offsetWidth : 0); - }, []); - - // Apply theme to iframe whenever colorMode changes, and catch any - // iframes that loaded before React hydration attached the onLoad handler. - useEffect(() => { - if (!iframeRef.current) return; - try { - const iframeDoc = iframeRef.current.contentDocument || iframeRef.current.contentWindow.document; - if (iframeDoc) { - iframeDoc.documentElement.setAttribute("data-app-theme", colorMode); - } - } catch (error) { - console.error("Failed to apply theme to iframe:", error); - } - - // If the iframe already loaded before React hydrated and attached the - // onLoad handler, apply patches now as a fallback. - try { - const iframeDoc = iframeRef.current.contentDocument; - if (iframeDoc && iframeDoc.readyState === 'complete') { - handleIframeLoad(); - } - } catch (e) { - // Silently ignore cross-origin errors - } - }, [colorMode]); - - // Called via the onLoad prop on the iframe element. React attaches - // onLoad during the commit phase (before paint), so this is guaranteed - // to fire even for fast-loading same-origin iframes — unlike useEffect - // which runs after paint and can miss early load events. - const handleIframeLoad = () => { - if (!iframeRef.current) return; - - // Apply theme - try { - const iframeDoc = iframeRef.current.contentDocument || iframeRef.current.contentWindow.document; - if (iframeDoc) { - iframeDoc.documentElement.setAttribute("data-app-theme", colorMode); - } - } catch (error) { - console.error("Failed to apply theme to iframe:", error); - } - - // Patch scroll-related methods inside the iframe to prevent DWC - // components from scrolling the parent documentation page. - // The confirmed culprit is scrollIntoViewIfNeeded on DWC-TREE-NODE - // elements, but we also patch scrollIntoView and focus defensively. - // - // Known limitation: these patches apply on iframe load, so a demo - // component that calls focus() during initialization (before load - // fires) can still cause a one-time scroll jump. Avoid calling - // focus() in demo view constructors to prevent this. - try { - const iframeWindow = iframeRef.current.contentWindow; - - if (iframeWindow && iframeWindow.Element) { - const originalScrollIntoView = iframeWindow.Element.prototype.scrollIntoView; - iframeWindow.Element.prototype.scrollIntoView = function (...args) { - const parentScrollX = window.scrollX; - const parentScrollY = window.scrollY; - originalScrollIntoView.apply(this, args); - window.scrollTo(parentScrollX, parentScrollY); - }; - - if (iframeWindow.Element.prototype.scrollIntoViewIfNeeded) { - const originalScrollIntoViewIfNeeded = iframeWindow.Element.prototype.scrollIntoViewIfNeeded; - iframeWindow.Element.prototype.scrollIntoViewIfNeeded = function (...args) { - const parentScrollX = window.scrollX; - const parentScrollY = window.scrollY; - originalScrollIntoViewIfNeeded.apply(this, args); - window.scrollTo(parentScrollX, parentScrollY); - }; - } - - const originalFocus = iframeWindow.HTMLElement.prototype.focus; - iframeWindow.HTMLElement.prototype.focus = function (options) { - originalFocus.call(this, { ...options, preventScroll: true }); - }; - } - } catch (error) { - // Silently ignore cross-origin errors - } - }; - - - function renderCodeBlocks(files, codeBlockStyles, javaHighlight) { - return( - - {files.code} - - ); - } - - const startResizing = (e) => { - e.preventDefault(); - setIsResizing(true); - setInitialMouseX(e.clientX); - setInitialWidth(iframeRef.current ? iframeRef.current.offsetWidth : 0); - setInitialRight(newRight); - }; - - const stopResizing = () => { - setIsResizing(false); - }; - - const resize = (e) => { - if (isResizing) { - const dx = e.clientX - initialMouseX; - if (initialWidth + dx > originalWidth / 3) { - iframeRef.current.style.width = `${initialWidth + dx}px`; - codeButtonRef.current.style.right = `${ - initialRight - dx < 25 ? 25 : initialRight - dx - }px`; - setNewRight(initialRight - dx < 25 ? 25 : initialRight - dx); - } - } - }; - - const mainStyles = css` - display: flex; - flex-direction: column; - width: 100%; - margin-bottom: 16px; - @media screen and (max-width: 768px) { - width: 100vw; - margin-left: -1em; - } - `; - - const demoFrameStyles = css` - width: 100%; - border: 1px solid var(--ifm-toc-border-color); - border-right: none; - background-color: transparent; - display: flex; - position: relative; - `; - - const iframeStyles = css` - min-height: 100px; - height: 100%; - width: 100%; - height: ${height || "100%"}; - pointer-events: ${isResizing ? "none" : "auto"}; - `; - - const fadeInButton = css` - display: flex; - justify-content: flex-end; - opacity: 0; - transition: opacity 0.3s ease-in-out; - ${buttonVisible && "opacity: 1;"}; - margin: 10px 0 0 0; - position: absolute; - right: 25px; - `; - - const resizeBarStyles = css` - display: flex; - align-items: center; - cursor: ew-resize; - border-left: 1px solid var(--ifm-toc-border-color); - border-right: 1px solid var(--ifm-toc-border-color); - background-color: var(--dwc-surface-3); - - @media screen and (max-width: 768px) { - display: none; - } - `; - - const detailsStyles = css` - overflow: hidden; - background-color: var(--dwc-surface-3); - border: 1px solid var(--ifm-toc-border-color); - ${frame !== "hidden" && "border-top: none;"} - margin: ${frame == "hidden" - ? "40px 0px 0px 0px" - : "0px"}; - padding: 0px; - position: relative; - - div { - border-color: var(--ifm-toc-border-color); - padding: 2px 0px 0px 0px; - margin: 0px; - } - - summary { - cursor: pointer; - border-bottom: ${showCode ? "1px solid var(--ifm-toc-border-color)" : "none"}; - display: flex; - justify-content: center; - padding: 10px 0; - font-weight: bold; - } - - &::details-content { - block-size: auto; - block-size: ${showCode ? "calc-size(auto, size)" : "0"}; - transition: - block-size var(--dwc-transition-slow), - content-visibility var(--dwc-transition-slow); - transition-behavior: allow-discrete; - } - - .margin-top--md { - margin-top: 0px !important; - } - ul { - margin: -4px 0px !important; - } - `; - - const showCodeIconStyles = css` - transition: transform var(--dwc-transition-medium); - transform: rotate(${showCode ? "90": "0)"}deg); - margin-top: 2px; - `; - - const tabStyles = css` - li[aria-selected="true"] { - border-color: var(--ifm-color-primary); - } - - .tabs__item { - padding: 5px 20px -2px 20px; - border-radius: 0px; - } - `; - - const codeBlockStyles = css` - border-radius: 0px; - box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px 0px inset; - `; - - return ( -
- {frame != "hidden" ? ( -
{ - setButtonVisible(true); - }} - onMouseLeave={() => setButtonVisible(false)} - css={demoFrameStyles} - > - -
- -
-
- -
-
- ) : null} - -
- setShowCode(!showCode)}> - {showCode - ? translate({ - id: 'componentDemo.hideCode', - message: 'Hide Code', - description: 'Button text to hide the code section' - }) - : translate({ - id: 'componentDemo.showCode', - message: 'Show Code', - description: 'Button text to show the code section' - }) - } - - - {cssURL ? ( - - - - {javaExpand} - - - {Object.keys(additionalFiles).map((fileName, index) => ( - - {renderCodeBlocks(additionalFiles[fileName], codeBlockStyles, javaHighlight)} - - ))} - - - {cssCode} - - - - ) : ( - - - - {javaExpand} - - - {Object.keys(additionalFiles).map((fileName, index) => ( - - {renderCodeBlocks(additionalFiles[fileName], codeBlockStyles, javaHighlight)} - - ))} - - )} -
- -
- ); -} diff --git a/docs/src/components/DocsTools/ComponentDemo/CodePanel.js b/docs/src/components/DocsTools/ComponentDemo/CodePanel.js new file mode 100644 index 000000000..a0ec0c23f --- /dev/null +++ b/docs/src/components/DocsTools/ComponentDemo/CodePanel.js @@ -0,0 +1,134 @@ +/** @jsxImportSource @emotion/react */ + +import { useState } from "react"; +import { css } from "@emotion/react"; +import { translate } from '@docusaurus/Translate'; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import CodeBlock from "@theme/CodeBlock"; + +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; + +const tabStyles = css` + li[aria-selected="true"] { + border-color: var(--ifm-color-primary); + } + + .tabs__item { + padding: 5px 20px -2px 20px; + border-radius: 0px; + } +`; + +const codeBlockStyles = css` + border-radius: 0px; + box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px 0px inset; +`; + +/** + * Collapsible code panel that renders a tab per file, with each tab body + * showing the fetched source. Owns the open/closed state via the native + * `
` element's `onToggle` event so keyboard activation stays in sync. + * + * @param {object} props + * @param {Array} props.files Normalized file records from the parent + * (`{ url, label, language, highlight }`). + * @param {object} props.loadedFiles Map of resolved url → fetched code string. + * Pre-seeded with empty strings so tabs + * render in input order before fetches resolve. + * @param {boolean} [props.detached] If true, the panel renders standalone + * (top border + 40px top margin). If false + * (default), it sits visually attached + * beneath a frame above (no top border). + */ +export default function CodePanel({ files, loadedFiles, detached = false }) { + const [showCode, setShowCode] = useState(false); + + const detailsStyles = css` + overflow: hidden; + background-color: var(--dwc-surface-3); + border: 1px solid var(--ifm-toc-border-color); + ${detached ? "" : "border-top: none;"} + margin: ${detached ? "40px 0px 0px 0px" : "0px"}; + padding: 0px; + position: relative; + + div { + border-color: var(--ifm-toc-border-color); + padding: 2px 0px 0px 0px; + margin: 0px; + } + + summary { + cursor: pointer; + border-bottom: ${showCode ? "1px solid var(--ifm-toc-border-color)" : "none"}; + display: flex; + justify-content: center; + padding: 10px 0; + font-weight: bold; + } + + &::details-content { + block-size: auto; + block-size: ${showCode ? "calc-size(auto, size)" : "0"}; + transition: + block-size var(--dwc-transition-slow), + content-visibility var(--dwc-transition-slow); + transition-behavior: allow-discrete; + } + + .margin-top--md { + margin-top: 0px !important; + } + ul { + margin: -4px 0px !important; + } + `; + + const showCodeIconStyles = css` + transition: transform var(--dwc-transition-medium); + transform: rotate(${showCode ? "90" : "0"}deg); + margin-top: 2px; + `; + + return ( +
setShowCode(e.currentTarget.open)}> + + {showCode + ? translate({ + id: 'componentDemo.hideCode', + message: 'Hide Code', + description: 'Button text to hide the code section', + }) + : translate({ + id: 'componentDemo.showCode', + message: 'Show Code', + description: 'Button text to show the code section', + }) + } + + + + {files.map((f, index) => ( + + + {loadedFiles[f.url] ?? ''} + + + ))} + +
+ ); +} diff --git a/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js b/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js new file mode 100644 index 000000000..50abcb3f1 --- /dev/null +++ b/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js @@ -0,0 +1,403 @@ +/** @jsxImportSource @emotion/react */ + +import { useState, useEffect, useRef, useCallback } from "react"; +import { css } from "@emotion/react"; +import { translate } from '@docusaurus/Translate'; +import { useColorMode } from "@docusaurus/theme-common"; + +import openInNewIcon from "../../../../static/img/window-maximize.png"; +import GLOBALS from "../../../../siteConfig"; + +import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; + +// True when the docs site is being served by `docusaurus start` on the local +// machine. Drives which iframe base URL we point at (Maven/Jetty in dev, +// production demo host otherwise). +const isLocalhost = typeof window !== "undefined" && + window.location.hostname === "localhost" && + window.location.port === "3000"; + +// Writes the current Docusaurus theme onto the iframe's root element so the +// embedded demo follows light/dark mode toggles. Wrapped in try/catch because +// cross-origin iframes throw on contentDocument access. +function applyTheme(iframe, colorMode) { + try { + const doc = iframe?.contentDocument || iframe?.contentWindow?.document; + doc?.documentElement.setAttribute("data-app-theme", colorMode); + } catch (error) { + console.error("Failed to apply theme to iframe:", error); + } +} + +// Patches scroll-related methods inside the iframe to prevent DWC components +// from scrolling the parent documentation page. Confirmed culprit is +// scrollIntoViewIfNeeded on DWC-TREE-NODE elements; scrollIntoView and focus +// are patched defensively. +// +// Idempotent — sets a marker on the iframe's window so re-running on iframe +// reload (HMR, internal navigation) doesn't wrap already-wrapped functions +// and stack call layers. +// +// Known limitation: patches apply on iframe load, so a demo that calls focus() +// during initialization (before load fires) can still cause a one-time scroll +// jump. This is also blocked silently when the iframe is cross-origin (e.g. +// `npm start` mode where docs serve on :3000 and demos on :8080). +function applyScrollPatches(iframe) { + try { + const win = iframe?.contentWindow; + if (!win || !win.Element || win.__demoScrollPatched) return; + win.__demoScrollPatched = true; + + const preserveParentScroll = (originalFn) => function (...args) { + const x = window.scrollX; + const y = window.scrollY; + originalFn.apply(this, args); + window.scrollTo(x, y); + }; + + win.Element.prototype.scrollIntoView = + preserveParentScroll(win.Element.prototype.scrollIntoView); + + if (win.Element.prototype.scrollIntoViewIfNeeded) { + win.Element.prototype.scrollIntoViewIfNeeded = + preserveParentScroll(win.Element.prototype.scrollIntoViewIfNeeded); + } + + const originalFocus = win.HTMLElement.prototype.focus; + win.HTMLElement.prototype.focus = function (options) { + originalFocus.call(this, { ...options, preventScroll: true }); + }; + } catch (error) { + // Silently ignore cross-origin errors + } +} + +// Theme-application + scroll-patches lifecycle for an iframe. Re-applies the +// theme when colorMode changes. Returns an `onLoad` callback to attach to the +// iframe element so patches apply as soon as content is available. +function useIframeBehavior(iframeRef) { + const { colorMode } = useColorMode(); + + useEffect(() => { + const iframe = iframeRef.current; + if (!iframe) return; + applyTheme(iframe, colorMode); + try { + if (iframe.contentDocument?.readyState === 'complete') { + applyScrollPatches(iframe); + } + } catch (e) { + // Silently ignore cross-origin errors + } + }, [colorMode]); + + return useCallback(() => { + const iframe = iframeRef.current; + if (!iframe) return; + applyTheme(iframe, colorMode); + applyScrollPatches(iframe); + }, [colorMode]); +} + +/** + * Drag-to-resize hook for the resizable frame variant. + * + * Drag bookkeeping (mouse origin, starting width, etc.) lives in refs so + * 60fps mousemoves don't trigger React renders; only `isResizing` is state + * because the iframe needs `pointer-events: none` during the drag and the + * listener-attaching effect needs to react to it. + * + * Container width is tracked via ResizeObserver so the min/max clamps stay + * correct after viewport changes. + */ +function useResizable({ minWidthFactor = 1 / 3, minRight = 25 } = {}) { + const containerRef = useRef(null); + const elementRef = useRef(null); + const buttonRef = useRef(null); + const containerWidthRef = useRef(0); + const dragRef = useRef({ startX: 0, startWidth: 0, startRight: minRight, currentRight: minRight }); + const [isResizing, setIsResizing] = useState(false); + + useEffect(() => { + if (!containerRef.current) return; + const observer = new ResizeObserver((entries) => { + containerWidthRef.current = entries[0].contentRect.width; + }); + observer.observe(containerRef.current); + return () => observer.disconnect(); + }, []); + + const startResizing = (e) => { + e.preventDefault(); + dragRef.current = { + startX: e.clientX, + startWidth: elementRef.current?.offsetWidth ?? 0, + startRight: dragRef.current.currentRight, + currentRight: dragRef.current.currentRight, + }; + setIsResizing(true); + }; + + useEffect(() => { + if (!isResizing) return; + + const onMove = (e) => { + const drag = dragRef.current; + const containerWidth = containerWidthRef.current; + if (!containerWidth) return; + const dx = e.clientX - drag.startX; + + const minWidth = containerWidth * minWidthFactor; + const proposed = drag.startWidth + dx; + const nextWidth = Math.max(minWidth, Math.min(containerWidth, proposed)); + + if (elementRef.current) { + elementRef.current.style.width = `${nextWidth}px`; + } + if (buttonRef.current) { + const nextRight = Math.max(minRight, drag.startRight - dx); + buttonRef.current.style.right = `${nextRight}px`; + drag.currentRight = nextRight; + } + }; + const onUp = () => setIsResizing(false); + + window.addEventListener('mousemove', onMove); + window.addEventListener('mouseup', onUp); + return () => { + window.removeEventListener('mousemove', onMove); + window.removeEventListener('mouseup', onUp); + }; + }, [isResizing, minWidthFactor, minRight]); + + return { containerRef, elementRef, buttonRef, isResizing, startResizing }; +} + +// Small button that opens the demo URL in a new browser tab. Decorative icon +// (alt=""); the button itself carries the accessible label. +function OpenNewWindowButton({ url }) { + const { colorMode } = useColorMode(); + + const buttonStyles = css` + position: relative; + cursor: pointer; + z-index: 10; + height: 35px; + width: 35px; + border: none; + justify-self: flex-end; + margin-top: -5px; + margin-bottom: -20px; + background-color: transparent; + margin-right: 12px; + `; + + const iconStyles = css` + filter: ${colorMode === "dark" ? "invert(1)" : "none"}; + background-color: #ffffff80; + border-radius: var(--dwc-border-radius-s); + `; + + const openNewWindow = () => { + window.open(url, "_blank", "noopener,noreferrer"); + }; + + const openInNewWindowLabel = translate({ + id: 'componentDemo.openInNewWindow', + message: 'Open demo in new window', + description: 'Accessible label for the button that opens the demo iframe URL in a new browser tab', + }); + + return ( + + ); +} + +// ============================================================ +// Styles +// ============================================================ + +const resizableFrameStyles = css` + width: 100%; + border: 1px solid var(--ifm-toc-border-color); + border-right: none; + background-color: transparent; + display: flex; + position: relative; + + &:hover .open-window-button-wrapper { + opacity: 1; + } +`; + +const fadeInButton = css` + display: flex; + justify-content: flex-end; + opacity: 0; + transition: opacity 0.3s ease-in-out; + margin: 10px 0 0 0; + position: absolute; + right: 25px; +`; + +const resizeBarStyles = css` + display: flex; + align-items: center; + cursor: ew-resize; + border-left: 1px solid var(--ifm-toc-border-color); + border-right: 1px solid var(--ifm-toc-border-color); + background-color: var(--dwc-surface-3); + + @media screen and (max-width: 768px) { + display: none; + } +`; + +const phoneOuterStyles = css` + display: flex; + flex-direction: column; + align-items: center; + /* Top spacing only — the gap below the phone preview is owned by CodePanel's + detached top margin so the phone + code panel act as one visual unit. */ + margin-top: 4rem; +`; + +const phoneInnerStyles = css` + position: relative; + width: 100%; + border-radius: 32px; + overflow: hidden; + box-shadow: 0 0 0 10px black, 0 3px 22px black; + outline: thin solid black; + + &:hover .open-window-button-wrapper { + opacity: 1; + } +`; + +const phoneMobileSize = css` + max-width: 375px; + height: 700px; +`; + +const phoneDesktopSize = css` + max-width: 100%; + height: 600px; +`; + +const phoneIframeStyles = css` + width: 100%; + height: 100%; + background: var(--dwc-surface-3); +`; + +const phoneFadeInButton = css` + display: flex; + justify-content: flex-end; + opacity: 0; + transition: opacity 0.3s ease-in-out; + position: absolute; + top: 10px; + right: 5px; + z-index: 10; +`; + +const iframeTitle = () => translate({ + id: 'componentDemo.iframeTitle', + message: 'Component demo', + description: 'Accessible title for the demo iframe', +}); + +// ============================================================ +// Variant components +// ============================================================ + +function ResizableFrame({ path, height }) { + const { + containerRef, + elementRef: iframeRef, + buttonRef: codeButtonRef, + isResizing, + startResizing, + } = useResizable(); + const handleIframeLoad = useIframeBehavior(iframeRef); + + const iframeSrc = (isLocalhost ? GLOBALS.IFRAME_SRC_DEV : GLOBALS.IFRAME_SRC_LIVE) + path; + + const iframeStyles = css` + min-height: 100px; + width: 100%; + height: ${height || "100%"}; + pointer-events: ${isResizing ? "none" : "auto"}; + `; + + return ( +
+ +
+ +
+
+ +
+
+ ); +} + +function PhoneFrame({ path, variant }) { + const iframeRef = useRef(null); + const handleIframeLoad = useIframeBehavior(iframeRef); + + const iframeSrc = (isLocalhost ? GLOBALS.IFRAME_SRC_DEV : GLOBALS.IFRAME_SRC_LIVE) + path; + const sizeStyles = variant === 'mobile' ? phoneMobileSize : phoneDesktopSize; + + return ( +
+
+
+ +
+ +
+
+ ); +} + +/** + * Renders the iframe pane for a webforJ demo. Three variants: + * + * - `'resizable'` (default): standard rectangle with a drag handle on the right. + * Honors the `height` prop. + * - `'mobile'`: phone-shaped 375x700 preview, centered with a margin. + * - `'desktop'`: phone-shaped 100%x600 preview, centered with a margin. + * + * Phone variants ignore `height` (their dimensions are fixed) and have no + * drag-resize. + * + * @param {object} props + * @param {string} props.path Path appended to the iframe base URL. + * @param {string} [props.height] CSS height (resizable variant only). + * @param {'resizable'|'mobile'|'desktop'} [props.variant='resizable'] + */ +export default function DemoFrame({ path, height, variant = 'resizable' }) { + if (variant === 'mobile' || variant === 'desktop') { + return ; + } + return ; +} diff --git a/docs/src/components/DocsTools/ComponentDemo/index.js b/docs/src/components/DocsTools/ComponentDemo/index.js new file mode 100644 index 000000000..8f72a4d3f --- /dev/null +++ b/docs/src/components/DocsTools/ComponentDemo/index.js @@ -0,0 +1,147 @@ +/** @jsxImportSource @emotion/react */ + +import { useState, useEffect } from "react"; +import { css } from "@emotion/react"; + +import GLOBALS from "../../../../siteConfig"; +import DemoFrame from "./DemoFrame"; +import CodePanel from "./CodePanel"; + +// File extension → Prism language identifier. Keeps syntax highlighting honest +// when callers mix Java with CSS, Kotlin, JSON, etc. +const EXT_TO_LANG = { + java: 'java', kt: 'kotlin', kts: 'kotlin', + css: 'css', scss: 'scss', + js: 'javascript', mjs: 'javascript', cjs: 'javascript', + jsx: 'jsx', ts: 'typescript', tsx: 'tsx', + json: 'json', xml: 'xml', html: 'html', htm: 'html', + yml: 'yaml', yaml: 'yaml', md: 'markdown', + py: 'python', rb: 'ruby', sh: 'bash', +}; + +function inferLanguage(url) { + const ext = url.split('?')[0].split('#')[0].split('.').pop().toLowerCase(); + return EXT_TO_LANG[ext] ?? 'text'; +} + +function basename(url) { + return new URL(url).pathname.split('/').pop(); +} + +// Repo-relative paths get the GitHub raw-content base prepended; absolute +// http(s) URLs are an escape hatch and are used as-is. +function resolveUrl(url) { + if (/^https?:\/\//.test(url)) return url; + return GLOBALS.RAW_CONTENT_BASE + url.replace(/^\//, ''); +} + +// Accepts the `files` prop (array of strings or objects) and returns a +// uniform list of { url, label, language, highlight } records, in input order. +function normalizeFiles(files) { + if (!files) return []; + return files.map((entry) => { + const raw = typeof entry === 'string' ? { url: entry } : entry; + const url = resolveUrl(raw.url); + return { + url, + label: raw.label ?? basename(url), + language: raw.language ?? inferLanguage(url), + highlight: raw.highlight, + }; + }); +} + +/** + * Fetches every file in `normalized` and exposes a {url: code} map. + * Pre-seeds entries so the consumer can render the tab list in input order + * before any fetch resolves. Aborts in-flight requests on unmount or when + * the input set changes. + */ +function useRemoteFiles(filesKey, normalized) { + const [loadedFiles, setLoadedFiles] = useState({}); + + useEffect(() => { + const controller = new AbortController(); + + async function loadInto(url) { + try { + const response = await fetch(url, { signal: controller.signal }); + if (!response.ok) throw new Error(`${response.status} ${response.statusText}`); + const text = await response.text(); + setLoadedFiles((prev) => ({ ...prev, [url]: text })); + } catch (err) { + if (err.name === 'AbortError') return; + console.error(`ComponentDemo: failed to load ${url}`, err); + setLoadedFiles((prev) => ({ + ...prev, + [url]: `// Failed to load ${url}\n// ${err.message}`, + })); + } + } + + setLoadedFiles((prev) => { + const seeded = { ...prev }; + normalized.forEach((f) => { + if (!(f.url in seeded)) seeded[f.url] = ''; + }); + return seeded; + }); + + normalized.forEach((f) => loadInto(f.url)); + + return () => controller.abort(); + }, [filesKey]); + + return loadedFiles; +} + +const mainStyles = css` + display: flex; + flex-direction: column; + width: 100%; + margin-bottom: 16px; + @media screen and (max-width: 768px) { + width: 100vw; + margin-left: -1em; + } +`; + +/** + * Renders an embedded webforJ demo iframe alongside a collapsible code panel + * showing the source for one or more files (Java, CSS, Kotlin, etc.). + * + * @param {object} props + * @param {string} props.path Required. Path appended to the + * iframe base URL (e.g. "/webforj/qrdemo?"). + * @param {Array} [props.files] Source files shown in the code panel, + * in array order. Each entry is either: + * - a string: a repo-relative path (e.g. "src/main/java/.../View.java") or a full URL. + * - an object: `{ url, label?, language?, highlight? }`. `label` defaults to the + * file's basename, `language` is inferred from the file extension, `highlight` + * is a Docusaurus metastring (e.g. "{3-7}") for line highlighting. + * @param {string} [props.height] CSS height for the iframe in + * `'resizable'` mode (e.g. "175px"). + * Ignored for phone variants. + * @param {'resizable'|'mobile'|'desktop'} [props.frame='resizable'] + * Iframe pane variant. `'resizable'` is the standard rectangle with drag-to-resize. + * `'mobile'` renders a phone-shaped 375x700 preview, useful for app-layout demos. + * `'desktop'` renders a 100%x600 phone-shaped preview for desktop app layouts. + */ +export default function ComponentDemo({ path, files, height, frame = 'resizable' }) { + const normalized = normalizeFiles(files); + const filesKey = normalized.map((f) => f.url).join('|'); + const loadedFiles = useRemoteFiles(filesKey, normalized); + + return ( +
+ + {normalized.length > 0 && ( + + )} +
+ ); +} diff --git a/docs/src/theme/MDXComponents.js b/docs/src/theme/MDXComponents.js index 47b32115a..604b09bfc 100644 --- a/docs/src/theme/MDXComponents.js +++ b/docs/src/theme/MDXComponents.js @@ -2,7 +2,6 @@ import React from 'react'; // Import Components here and add to the export list to include in global scope import MDXComponents from '@theme-original/MDXComponents'; -import AppLayoutViewer from '@site/src/components/DocsTools/AppLayoutViewer'; import ComponentDemo from '@site/src/components/DocsTools/ComponentDemo'; import DocChip from '@site/src/components/DocsTools/DocChip'; import JavadocLink from '@site/src/components/DocsTools/JavadocLink'; @@ -31,7 +30,6 @@ import AISkillTip from '@site/src/components/DocsTools/AISkillTip'; export default { ...MDXComponents, - AppLayoutViewer, ComponentDemo, DocCardList, DocChip, From b715763ca0eeafcd901b8d2337731a84fdacabbb Mon Sep 17 00:00:00 2001 From: Ben Brennan Date: Fri, 8 May 2026 15:18:21 -0600 Subject: [PATCH 2/4] chore: added extra languages for Prism styling --- docs/docusaurus.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 389fe176d..18df18185 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -344,7 +344,7 @@ module.exports = async function createConfig() { prism: { theme: codeTheme, darkTheme: codeTheme, - additionalLanguages: ['java', 'Ini', 'bash', 'powershell', 'groovy'] + additionalLanguages: ['java', 'Ini', 'bash', 'powershell', 'groovy', 'scss', 'javascript', 'ruby'] }, } }; From 570b05d97e73824dc52db87ab7202e2b7bc019b2 Mon Sep 17 00:00:00 2001 From: MatthewHawkins Date: Tue, 12 May 2026 14:04:45 -0400 Subject: [PATCH 3/4] chore: removing question marks as query param starters in demo URL paths --- docs/blog/2024-04-08-webforj-v24.00/24.00.md | 6 +++--- docs/blog/2024-04-26-webforj-v24.01/24.01.md | 2 +- docs/blog/2024-06-03-webforj-v24.02/24.02.md | 4 ++-- docs/blog/2024-07-23-webforj-v24.10/24.10.md | 8 ++++---- docs/blog/2025-05-19-webforj-v25.01/25.01.md | 2 +- .../blog/2025-08-21-buildingbettercss/index.md | 2 +- docs/blog/2025-09-09-webforj-v25.03/25.03.md | 2 +- docs/blog/2026-01-27-webforj-v25.11/25.11.md | 4 ++-- docs/blog/2026-03-17-webforj-v25.12/25.12.md | 6 +++--- docs/blog/2026-04-28-webforj-v26.00/26.00.md | 4 ++-- docs/docs/advanced/debouncing.md | 2 +- docs/docs/advanced/view-transitions.md | 8 ++++---- docs/docs/architecture/controls-components.md | 10 +++++----- docs/docs/building-ui/composite-components.md | 4 ++-- docs/docs/building-ui/element-composite.md | 6 +++--- docs/docs/building-ui/elements.md | 8 ++++---- docs/docs/building-ui/events.md | 2 +- docs/docs/building-ui/using-components.md | 6 +++--- docs/docs/components/alert.md | 8 ++++---- docs/docs/components/app-layout.md | 12 ++++++------ docs/docs/components/appnav.md | 2 +- docs/docs/components/avatar.md | 8 ++++---- docs/docs/components/badge.md | 10 +++++----- docs/docs/components/busyindicator.md | 4 ++-- docs/docs/components/button.md | 10 +++++----- docs/docs/components/checkbox.md | 6 +++--- docs/docs/components/columns-layout.md | 10 +++++----- docs/docs/components/dialog.md | 18 +++++++++--------- docs/docs/components/drawer.md | 10 +++++----- docs/docs/components/fields/color-field.md | 2 +- docs/docs/components/fields/date-field.md | 2 +- docs/docs/components/fields/date-time-field.md | 2 +- .../docs/components/fields/masked/datefield.md | 8 ++++---- .../components/fields/masked/numberfield.md | 8 ++++---- .../docs/components/fields/masked/textfield.md | 6 +++--- .../docs/components/fields/masked/timefield.md | 8 ++++---- docs/docs/components/fields/number-field.md | 2 +- docs/docs/components/fields/password-field.md | 2 +- docs/docs/components/fields/text-field.md | 2 +- docs/docs/components/fields/time-field.md | 2 +- docs/docs/components/flex-layout.md | 14 +++++++------- docs/docs/components/google-charts.md | 8 ++++---- docs/docs/components/icon.md | 6 +++--- docs/docs/components/infinitescroll.md | 6 +++--- docs/docs/components/lists/choice-box.md | 4 ++-- docs/docs/components/lists/combo-box.md | 8 ++++---- docs/docs/components/lists/list-box.md | 2 +- docs/docs/components/loading.md | 4 ++-- docs/docs/components/login.md | 10 +++++----- docs/docs/components/markdownviewer.md | 6 +++--- docs/docs/components/navigator.md | 8 ++++---- docs/docs/components/option-dialogs/confirm.md | 4 ++-- .../components/option-dialogs/file-chooser.md | 4 ++-- .../components/option-dialogs/file-save.md | 4 ++-- .../components/option-dialogs/file-upload.md | 2 +- docs/docs/components/option-dialogs/input.md | 4 ++-- docs/docs/components/option-dialogs/message.md | 2 +- docs/docs/components/progressbar.md | 8 ++++---- docs/docs/components/radio-button.md | 6 +++--- docs/docs/components/radio-group.md | 4 ++-- docs/docs/components/refresher.md | 8 ++++---- docs/docs/components/slider.md | 12 ++++++------ docs/docs/components/spinner.md | 10 +++++----- docs/docs/components/splitter.md | 12 ++++++------ docs/docs/components/tabbed-pane.md | 12 ++++++------ docs/docs/components/table/overview.md | 4 ++-- .../components/table/table_column_groups.md | 12 ++++++------ docs/docs/components/table/table_columns.md | 8 ++++---- .../components/table/table_dynamic_styling.md | 8 ++++---- .../components/table/table_edit_refresh.md | 2 +- docs/docs/components/table/table_filtering.md | 2 +- docs/docs/components/table/table_large_data.md | 2 +- docs/docs/components/table/table_rendering.md | 8 ++++---- docs/docs/components/table/table_selection.md | 4 ++-- docs/docs/components/table/table_sorting.md | 8 ++++---- docs/docs/components/terminal.md | 6 +++--- docs/docs/components/textarea.md | 10 +++++----- docs/docs/components/toast.md | 8 ++++---- docs/docs/components/toolbar.md | 8 ++++---- docs/docs/components/tree.md | 10 +++++----- 80 files changed, 248 insertions(+), 248 deletions(-) diff --git a/docs/blog/2024-04-08-webforj-v24.00/24.00.md b/docs/blog/2024-04-08-webforj-v24.00/24.00.md index b49106486..eae5a92d4 100644 --- a/docs/blog/2024-04-08-webforj-v24.00/24.00.md +++ b/docs/blog/2024-04-08-webforj-v24.00/24.00.md @@ -29,7 +29,7 @@ See the [GitHub release overview](https://github.com/webforj/webforj/releases/ta This release introduces a new [`Table`](/docs/components/table/overview) component, allowing developers access to a lightweight, fast and optimized way to display their data. @@ -69,7 +69,7 @@ The `Navigator` can be customized with various settings that configure the text, ## Splitter component diff --git a/docs/blog/2024-06-03-webforj-v24.02/24.02.md b/docs/blog/2024-06-03-webforj-v24.02/24.02.md index d78222954..2621691b7 100644 --- a/docs/blog/2024-06-03-webforj-v24.02/24.02.md +++ b/docs/blog/2024-06-03-webforj-v24.02/24.02.md @@ -26,7 +26,7 @@ As always, see the [GitHub release overview](https://github.com/webforj/webforj/ ## Option dialogs @@ -48,7 +48,7 @@ The various dialog options are provided to help clarify and specify the type of The `ProgressBar` in 24.02 has gotten a powerful, comprehensive overhaul. This component provides a visual representation of task progress, making it easy for users to monitor the completion status of ongoing tasks. The progress bar fills up as the task progresses, displaying the percentage of completion both visually and textually. diff --git a/docs/blog/2024-07-23-webforj-v24.10/24.10.md b/docs/blog/2024-07-23-webforj-v24.10/24.10.md index c931a7d04..d92d31ab6 100644 --- a/docs/blog/2024-07-23-webforj-v24.10/24.10.md +++ b/docs/blog/2024-07-23-webforj-v24.10/24.10.md @@ -58,7 +58,7 @@ The `Spinner` and `BusyIndicator` components have both been added in this releas Building on the `Spinner`, the `BusyIndicator` is an app-level loading overlay that indicates when the app is busy or processing data. It blocks user interaction until the process is complete. This component displays both a `Spinner` and a textual description while the process is occurring. @@ -78,7 +78,7 @@ The webforJ `Terminal` component represents an exciting opportunity to emulate a The `ColumnsLayout` component has come to webforJ in `24.10`, and is designed to offer a flexible and responsive layout solution in addition to the [FlexLayout](/docs/components/flex-layout) component. The `ColumnsLayout` easily facilitates two-dimensional layouts by providing columns rather than just rows. It dynamically adjusts the number of columns based on the width of the layout and utilizes breakpoints to determine how many columns should be displayed at different viewport widths to help with responsiveness. @@ -94,7 +94,7 @@ The `Slider` component has received on overhaul in this release. The appearance However, with this rework, a few of the methods have changed to better reflect modern standards. If you are using this component in your app, review the following methods to ensure you're using the updated API. An example of the various methods can be seen in the code demo below: @@ -106,7 +106,7 @@ Another powerful component introduced in `24.10` is the `Toast` component, which Developers can set the display duration, choose from various themes, and configure the position of the toast on the screen. The component supports multiple placements, and also allows for setting custom text and HTML content, giving developers the ability to style the messages as needed. diff --git a/docs/blog/2025-05-19-webforj-v25.01/25.01.md b/docs/blog/2025-05-19-webforj-v25.01/25.01.md index 6c47e2414..e38021312 100644 --- a/docs/blog/2025-05-19-webforj-v25.01/25.01.md +++ b/docs/blog/2025-05-19-webforj-v25.01/25.01.md @@ -39,7 +39,7 @@ For more information on the `Tree` component, how to use it in an app, and the v Below is an example of a `Tree` component: diff --git a/docs/blog/2025-08-21-buildingbettercss/index.md b/docs/blog/2025-08-21-buildingbettercss/index.md index f6e2d56be..b26af639e 100644 --- a/docs/blog/2025-08-21-buildingbettercss/index.md +++ b/docs/blog/2025-08-21-buildingbettercss/index.md @@ -166,7 +166,7 @@ The `::part()` pseudo-element is like having a key to specific rooms in an other Here's a dashboard I put together that uses most of the stuff I've mentioned - CSS Grid, DWC tokens, and component-specific styling: diff --git a/docs/blog/2026-04-28-webforj-v26.00/26.00.md b/docs/blog/2026-04-28-webforj-v26.00/26.00.md index 90567722f..7404b21ab 100644 --- a/docs/blog/2026-04-28-webforj-v26.00/26.00.md +++ b/docs/blog/2026-04-28-webforj-v26.00/26.00.md @@ -59,7 +59,7 @@ See the [webforJ AI plugin](/docs/integrations/ai-tooling) documentation for per By default, a `Dialog` stretches to fill the available horizontal space, perfect for larger forms, overkill for a compact "Are you sure?" prompt. The new `setAutoWidth(true)` method flips that behavior, sizing the dialog to its content so small prompts stay small. @@ -80,7 +80,7 @@ See the [Dialog auto width](/docs/components/dialog#auto-width) documentation fo The `TabbedPane` picks up a new rendering mode in `26.00`. Flip `setSegment(true)` and the tabs snap into a compact segment control with a sliding pill indicator, a natural fit for toggling between a few related views or filter options. diff --git a/docs/docs/advanced/debouncing.md b/docs/docs/advanced/debouncing.md index 6c1c5b57b..7c858fd16 100644 --- a/docs/docs/advanced/debouncing.md +++ b/docs/docs/advanced/debouncing.md @@ -10,7 +10,7 @@ slug: debouncing Debouncing is a technique that delays executing an action until a specified time has elapsed since the last call. Each new call resets the timer. This is useful for scenarios like search-as-you-type, where you want to wait until the user stops typing before executing a search query. diff --git a/docs/docs/advanced/view-transitions.md b/docs/docs/advanced/view-transitions.md index 96473af0a..dfff76185 100644 --- a/docs/docs/advanced/view-transitions.md +++ b/docs/docs/advanced/view-transitions.md @@ -13,7 +13,7 @@ title: View Transitions View transitions provide animated transitions when the [DOM](/docs/glossary#dom) changes, reducing visual jarring and maintaining spatial context during navigation or content updates. webforJ integrates with the browser's [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) to handle the complexity of coordinating animations between old and new states. -## Composite components: extending through composition {#composite-components-extending-through-composition} +## Composite components: extending through composition {#composite-components-extending-through-composition} In webforJ framework, the concept of composite components plays a pivotal role in extending component functionality. Composite components are Java classes that are not restricted by the final keyword, allowing developers to create new components that extends the behavior of a single component, or combines multiple components into one, by composing existing components. Classes which facilitate this behavior have been created for developer use. See the `Composite` and `ElementComposite` sections to see how to properly create composite components. This approach encourages a more modular and flexible development style, enabling developers to build tailored components that meet specific requirements. \ No newline at end of file diff --git a/docs/docs/building-ui/composite-components.md b/docs/docs/building-ui/composite-components.md index 1e3bd6007..6f08ac499 100644 --- a/docs/docs/building-ui/composite-components.md +++ b/docs/docs/building-ui/composite-components.md @@ -156,7 +156,7 @@ public class InteractiveMap extends Composite
{ The following example demonstrates a Todo app where each item is a `Composite` component consisting of a [`RadioButton`](../components/radiobutton) styled as a switch and a Div with text: @@ -61,7 +61,7 @@ String title = get(TITLE, false, String); In the demo below, properties have been added for the QR code based on the documentation for the web component. Methods have then been implemented which allow users to get and set the various properties that have been implemented. @@ -102,7 +102,7 @@ For specialized event handling, create custom event classes with configured payl In the example below, a click event has been created and then added to the QR code component. This event, when fired, will display the "X" coordinate of the mouse at the time of clicking the component, which is provided to the Java event as data. A method is then implemented to allow the user to access this data, which is how it's displayed in the app. diff --git a/docs/docs/building-ui/elements.md b/docs/docs/building-ui/elements.md index 76d110968..0e1032e37 100644 --- a/docs/docs/building-ui/elements.md +++ b/docs/docs/building-ui/elements.md @@ -13,7 +13,7 @@ The `Element` component cannot be extended, and is not the base component for al ::: PendingResult is then used to create another message box once the asynchronous function has been completed. ButtonClickEvent to a [`Button`](#). This [`Button`](#) also uses information coming with the event's payload to display information on the screen. \ No newline at end of file diff --git a/docs/docs/building-ui/using-components.md b/docs/docs/building-ui/using-components.md index aab57492b..d71878ee2 100644 --- a/docs/docs/building-ui/using-components.md +++ b/docs/docs/building-ui/using-components.md @@ -122,7 +122,7 @@ nameField.addValueChangeListener(e -> submitButton.setEnabled(!e.getValue().isBl The following login form demonstrates `setEnabled()` in practice. The sign-in button stays disabled until both fields have content, making it clear to the user that input is required before proceeding: @@ -35,7 +35,7 @@ closableAlert.setClosable(true); Alerts often do more than display messages—they can trigger follow-up actions when dismissed. Use the `AlertCloseEvent` to handle these cases and respond when the user dismisses the `Alert`. @@ -52,7 +52,7 @@ Closing the alert only hides it—it doesn’t destroy the component, so you can The `Alert` component supports multiple themes to visually distinguish different types of messages—such as success, error, warning, or info. These themes can be applied using the `setTheme()` method or directly in the constructor. @@ -63,7 +63,7 @@ height='650px' The expanse defines the visual size of the `Alert` component. You can set it using the `setExpanse()` method or pass it directly to the constructor. The available options come from the Expanse enum: `XSMALL`, `SMALL`, `MEDIUM`, `LARGE`, and `XLARGE`. diff --git a/docs/docs/components/app-layout.md b/docs/docs/components/app-layout.md index aeb10b07b..256101d4b 100644 --- a/docs/docs/components/app-layout.md +++ b/docs/docs/components/app-layout.md @@ -37,7 +37,7 @@ The following code sample will result in an app with a collapsible sidebar that { Avatars can be displayed as circles or squares. The default shape is `CIRCLE`, which is standard for user avatars. Use `SQUARE` for entities like teams, companies, or applications. @@ -121,7 +121,7 @@ The following themes are available: Each theme also has an outlined variant for a lighter visual treatment: @@ -131,7 +131,7 @@ height='120px' Control the avatar size using the `setExpanse()` method. The component supports nine size options ranging from `XXXSMALL` to `XXXLARGE`. diff --git a/docs/docs/components/badge.md b/docs/docs/components/badge.md index a80b9e48a..e164cf88a 100644 --- a/docs/docs/components/badge.md +++ b/docs/docs/components/badge.md @@ -55,7 +55,7 @@ Icon-only badges work especially well for compact status indicators in dense lay @@ -79,7 +79,7 @@ Attach a `Badge` to a `Button` using `setBadge()`. The badge appears at the top- @@ -91,7 +91,7 @@ Add a `Badge` as a suffix on a `Tab` using `setSuffixComponent()`. This is a nat @@ -111,7 +111,7 @@ Apply a theme using `setTheme()` or through the constructor. @@ -132,7 +132,7 @@ Use `setExpanse()` to control badge size. Nine sizes are available, ranging from diff --git a/docs/docs/components/busyindicator.md b/docs/docs/components/busyindicator.md index 154dfd5ab..8a25d43db 100644 --- a/docs/docs/components/busyindicator.md +++ b/docs/docs/components/busyindicator.md @@ -19,7 +19,7 @@ The `BusyIndicator` in webforJ displays as a simple spinner, making it easy to u In this example, the `BusyIndicator` prevents any user actions across the entire interface until the operation completes. @@ -46,7 +46,7 @@ The `BusyIndicator` component in webforJ includes a `Spinner` that visually indi Here's an example of how you can customize the spinner within a `BusyIndicator` component: diff --git a/docs/docs/components/button.md b/docs/docs/components/button.md index ad2bfa9d4..84e68bebd 100644 --- a/docs/docs/components/button.md +++ b/docs/docs/components/button.md @@ -40,7 +40,7 @@ The `Button` class is a versatile component that is commonly used in various sit The following example demonstrates buttons used for form submission and clearing input: @@ -61,7 +61,7 @@ By default, an `Icon` inherits the button's theme and expanse. Below are examples of buttons with text to the left and right, as well as a button with only an icon: @@ -75,7 +75,7 @@ The `Button` component utilizes naming, which is used for accessibility. When a Button components, like many others, can be disabled to convey to a user that a certain action is not yet or is no longer available. A disabled button will decrease the opacity of the button, and is available for all button themes and expanses. @@ -106,7 +106,7 @@ While there are many use cases for each of the various themes, some examples use Shown below are example buttons with each of the supported Themes applied:
@@ -122,7 +122,7 @@ Different sizes are often appropriate for different uses: Below are the various expanses supported for the `Button` component:
diff --git a/docs/docs/components/checkbox.md b/docs/docs/components/checkbox.md index 1ee9dd097..3d1e70b7a 100644 --- a/docs/docs/components/checkbox.md +++ b/docs/docs/components/checkbox.md @@ -38,7 +38,7 @@ Check boxes can utilize the Position enum. Show below are the two settings:
@@ -54,7 +54,7 @@ The `CheckBox` component supports indeterminism, which is a UI pattern commonly - **Hierarchical data**: Indeterminism can be employed in scenarios where there is a hierarchical relationship between CheckBoxes. For example, when selecting categories and subcategories, indeterminism can represent that some subcategories are selected while others are not, and the parent component is in the indeterminate state. @@ -67,7 +67,7 @@ The following @@ -179,7 +179,7 @@ Available `Alignment` options include: - `AUTO`: Auto alignment. @@ -213,7 +213,7 @@ You can use an integer to define the minimum width in pixels or use a `String` t Building responsive and attractive layouts is possible using both the [`FlexLayout`](./flex-layout) component and the `ColumnsLayout` component, as well as a combination of the two. Below is a sample of the [form created in the FlexLayout](./flex-layout#example-form) article, but using a `ColumnLayout` scheme instead: diff --git a/docs/docs/components/dialog.md b/docs/docs/components/dialog.md index d301f0b18..986fe948a 100644 --- a/docs/docs/components/dialog.md +++ b/docs/docs/components/dialog.md @@ -18,7 +18,7 @@ The `Dialog` component displays a popup window that overlays the current view, d The `Dialog` is organized into three sections: a header, a content area, and a footer. Components can be added to each section using `addToHeader()`, `addToContent()`, and `addToFooter()`. @@ -45,7 +45,7 @@ height='225px' By enabling the backdrop attribute of the webforJ `Dialog` component, a backdrop will be displayed behind the `Dialog`. Additionally, when enabled, the Dialog's blurred attribute will blur the backdrop of the `Dialog`. Modifying these settings can help users by providing depths, visual hierarchy, and context, leading to more clear guidance for a user. @@ -60,7 +60,7 @@ After creating a new `Dialog` object, use the `open()` method to display the dia Developers can choose which interactions close the `Dialog` with `setCancelOnEscKey()` and `setCancelOnOutsideClick()`. Additionally, the `setClosable()` method can prevent or allow both hitting the ESC key and clicking outside the `Dialog` to close the component. @@ -70,7 +70,7 @@ height='350px' When enabled, auto-focus will automatically give focus to the first element within the dialog that can be focused. This is useful in helping to direct the attention of users, and is customizable via the `setAutoFocus()` method. @@ -83,7 +83,7 @@ The `Dialog` has built in functionality to be draggable, allowing the user to re It is also possible to calibrate this behavior to snap to the edge of the screen, meaning the `Dialog` will automatically align itself with the edge of the display when released from its drag and drop date. Snapping can be changed via the `setSnapToEdge()` method. The `setSnapThreshold()` takes a number of pixels, which will set how far the `Dialog` should be from the sides of the screen before it will automatically snap to the edges. @@ -93,7 +93,7 @@ height='350px' The dialog's position can be manipulated using the built-in `setPosx()` and `setPosy()` methods. These methods take a string argument which can represent any applicable CSS unit of length, such as pixels or view height/width. A list of these measurements [can be found at this link](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#numbers_lengths_and_percentages). @@ -103,7 +103,7 @@ height='350px' In addition to manual assignment of a dialog's X and Y position, it is possible to use the dialog's built-in enum class to align the `Dialog`. There are three possible values, `TOP`, `CENTER` and `BOTTOM`, each of which can be used with the `setAlignment()` method. @@ -117,7 +117,7 @@ The `Dialog` can be set to enter full screen mode. When full screen is enabled, By default, the `Dialog` stretches to fill the available horizontal space. When auto width is enabled via `setAutoWidth(true)`, the `Dialog` sizes itself based on its content width instead. @@ -139,7 +139,7 @@ While there are many use cases for each of the various themes, some examples use - **Info**: The Info theme is a good choice to provide clarifying, additional information to a user when pushed. diff --git a/docs/docs/components/drawer.md b/docs/docs/components/drawer.md index a49fdcf65..fff2f0c02 100644 --- a/docs/docs/components/drawer.md +++ b/docs/docs/components/drawer.md @@ -19,7 +19,7 @@ Drawers stack automatically when multiple are opened, making them a flexible cho The example below shows this behavior within the [`AppLayout`](../components/app-layout) component. The navigation drawer triggered by the hamburger menu is built into [`AppLayout`](../components/app-layout), while the welcome popup at the bottom uses a standalone `Drawer` instance. Both coexist and stack independently, demonstrating how Drawers can be integrated within layout components or used as standalone elements. @@ -102,7 +102,7 @@ Available placement options: @@ -137,7 +137,7 @@ The `Drawer` component exposes additional content without disrupting the current Each contact displays an avatar, name, location, and action button for quick access to details or communication. This approach works well for building compact tools like contact pickers, settings panels, or notifications. diff --git a/docs/docs/components/fields/date-time-field.md b/docs/docs/components/fields/date-time-field.md index 82eaa11e9..56808535f 100644 --- a/docs/docs/components/fields/date-time-field.md +++ b/docs/docs/components/fields/date-time-field.md @@ -21,7 +21,7 @@ The `DateTimeField` component lets users input both a date and a time in a singl `DateTimeField` extends the shared `Field` class, which provides common features across all field components. The following example creates a labeled `DateTimeField` for selecting a departure date and time. diff --git a/docs/docs/components/fields/masked/datefield.md b/docs/docs/components/fields/masked/datefield.md index 947c3b689..bb7fe7243 100644 --- a/docs/docs/components/fields/masked/datefield.md +++ b/docs/docs/components/fields/masked/datefield.md @@ -21,7 +21,7 @@ The `MaskedDateField` is focused solely on **date** values. If you need a simila The `MaskedDateField` can be instantiated with or without parameters. You can define an initial value, a label, a placeholder, and an event listener for value changes. @@ -192,7 +192,7 @@ dateField.restoreValue(); You can set the value to restore with `setRestoreValue()`, passing a [`LocalDate`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/LocalDate.html) instance. @@ -221,7 +221,7 @@ You should always validate the input value in your app logic, even if a regular The `MaskedDateField` includes a built-in calendar picker that lets users select a date visually, rather than typing it. This enhances usability for less technical users or when precise input is required. @@ -288,7 +288,7 @@ picker.setShowWeeks(true); The `MaskedDateFieldSpinner` extends [`MaskedDateField`](#basics) by adding spinner controls that let users increment or decrement the date using arrow keys or UI buttons. It provides a more guided interaction style, especially useful in desktop-style applications. diff --git a/docs/docs/components/fields/masked/numberfield.md b/docs/docs/components/fields/masked/numberfield.md index ce587b092..f934fb56b 100644 --- a/docs/docs/components/fields/masked/numberfield.md +++ b/docs/docs/components/fields/masked/numberfield.md @@ -21,7 +21,7 @@ The `MaskedNumberField` can be instantiated with or without parameters. It suppo This demo showcases a **Tip Calculator** that uses `MaskedNumberField` for intuitive numeric input. One field is configured to accept a formatted bill amount, while the other captures a whole-number tip percentage. Both fields apply numeric masks to ensure consistent and predictable formatting. @@ -96,7 +96,7 @@ field.setNegateable(false); When `negatable` is set to `false`, the field blocks any attempts to enter a minus sign or otherwise input negative values. @@ -145,7 +145,7 @@ numberField.restoreValue(); The restore value must be explicitly set. If not defined, the feature will not revert the field. @@ -156,7 +156,7 @@ The `MaskedNumberFieldSpinner` extends [`MaskedNumberField`](#basics) by adding This is ideal for inputs like quantities, pricing adjustments, rating controls, or any scenario where users make incremental changes. diff --git a/docs/docs/components/fields/masked/textfield.md b/docs/docs/components/fields/masked/textfield.md index fc5d18aa2..e9e871e38 100644 --- a/docs/docs/components/fields/masked/textfield.md +++ b/docs/docs/components/fields/masked/textfield.md @@ -63,7 +63,7 @@ This is useful when you want to reserve the ability to format without applying s ::: @@ -107,7 +107,7 @@ field.restoreValue(); You can set the value to restore with `setRestoreValue()`. If no restore value is set, the field will revert to the initial value at the time it was rendered. @@ -118,7 +118,7 @@ The `MaskedTextFieldSpinner` extends [`MaskedTextField`](#basics) by adding spin This improves the user experience in situations where the input should be constrained to a fixed set of valid options. diff --git a/docs/docs/components/fields/masked/timefield.md b/docs/docs/components/fields/masked/timefield.md index adf8bf9da..2739ed6c8 100644 --- a/docs/docs/components/fields/masked/timefield.md +++ b/docs/docs/components/fields/masked/timefield.md @@ -21,7 +21,7 @@ The `MaskedTimeField` is built for **time-only** input. If you’re looking for The `MaskedTimeField` can be instantiated with or without parameters. You can define an initial value, a label, a placeholder, and an event listener for value changes. @@ -108,7 +108,7 @@ field.restoreValue(); - **Via keyboard**, by pressing ESC (this is the default restore key unless overridden by an event listener) @@ -137,7 +137,7 @@ You should always validate the input value in your app logic, even if a regular The `MaskedTimeField` includes a built-in time picker that lets users select a time visually, rather than typing it. This enhances usability for less technical users or when precise input is required. @@ -210,7 +210,7 @@ This ensures the dropdown list contains predictable, evenly spaced values like ` The `MaskedTimeFieldSpinner` extends [`MaskedTimeField`](#basics) by adding spinner controls that let users increment or decrement the time using arrow keys or UI buttons. It provides a more guided interaction style, especially useful in desktop-style applications. diff --git a/docs/docs/components/fields/number-field.md b/docs/docs/components/fields/number-field.md index ffdef76c3..c1ac9e37e 100644 --- a/docs/docs/components/fields/number-field.md +++ b/docs/docs/components/fields/number-field.md @@ -21,7 +21,7 @@ The `NumberField` component accepts numeric input and rejects invalid values aut `NumberField` extends the shared `Field` class, which provides common features across all field components. The following example creates a `NumberField` with a label and placeholder text. diff --git a/docs/docs/components/fields/password-field.md b/docs/docs/components/fields/password-field.md index 01ff912e2..d1a6c917c 100644 --- a/docs/docs/components/fields/password-field.md +++ b/docs/docs/components/fields/password-field.md @@ -21,7 +21,7 @@ The `PasswordField` component allows users to input a password securely. It's di `PasswordField` extends the shared `Field` class, which provides common features across all field components. The following example creates a `PasswordField` with a label and placeholder text. diff --git a/docs/docs/components/fields/text-field.md b/docs/docs/components/fields/text-field.md index c79a15eef..987a32cde 100644 --- a/docs/docs/components/fields/text-field.md +++ b/docs/docs/components/fields/text-field.md @@ -45,7 +45,7 @@ You can specify the type of the TextField using the `setType()` method. Similarl - `Type.SEARCH`: A single-line text field for entering search strings. Line-breaks are automatically removed from the input value. diff --git a/docs/docs/components/fields/time-field.md b/docs/docs/components/fields/time-field.md index 214e36d4b..b15af956d 100644 --- a/docs/docs/components/fields/time-field.md +++ b/docs/docs/components/fields/time-field.md @@ -21,7 +21,7 @@ description: A component that provides a default browser-based time picker for s `TimeField` extends the shared `Field` class, which provides common features across all field components. The following example creates a reminder `TimeField` initialized to the current time. diff --git a/docs/docs/components/flex-layout.md b/docs/docs/components/flex-layout.md index 8da8fff9b..de4dd24f0 100644 --- a/docs/docs/components/flex-layout.md +++ b/docs/docs/components/flex-layout.md @@ -29,7 +29,7 @@ The `FlexLayout` adds components next to one another according to its direction, To set the direction on an existing `FlexLayout` object, use the `setDirection()` method. The horizontal options are `FlexDirection.ROW` (left to right) or `FlexDirection.ROW_REVERSE` (right to left), and the vertical options are `FlexDirection.COLUMN` (top to bottom) or `FlexDirection.COLUMN_REVERSE` (bottom to top). @@ -175,7 +175,7 @@ If you prefer a column-based structure, look at the `ColumnsLayout` version of t ::: @@ -150,7 +150,7 @@ Invoke `redraw()` in scenarios such as: - **For Responsive Adjustments**: Adjusts the chart's layout or size when the container's dimensions change, ensuring optimal display across devices. @@ -88,7 +88,7 @@ Icon music = FontAwesomeIcon.create("user", FontAwesomeIcon.Variate.SOLID); The following demo illustrates how to use icons from different pools, apply variations, and seamlessly integrate them into components. @@ -113,7 +113,7 @@ Icons after a component's text is ideal for components that either offer supplem Ultimately, consistency is key. Once you choose a style, maintain it across your site for a cohesive and user-friendly design. ️ diff --git a/docs/docs/components/infinitescroll.md b/docs/docs/components/infinitescroll.md index ccb5ab9ba..baf0264a3 100644 --- a/docs/docs/components/infinitescroll.md +++ b/docs/docs/components/infinitescroll.md @@ -19,7 +19,7 @@ When users reach the bottom of scrollable content, `InfiniteScroll` triggers an The `InfiniteScroll` component emits events and maintains internal state to help manage how and when content is loaded. diff --git a/docs/docs/components/lists/combo-box.md b/docs/docs/components/lists/combo-box.md index 4f0518011..c437da8eb 100644 --- a/docs/docs/components/lists/combo-box.md +++ b/docs/docs/components/lists/combo-box.md @@ -37,7 +37,7 @@ The ComboBox component is a versatile input element that combines the features o Changing the custom value property allows control over whether or not a user is able to change the value in the `ComboBox` component's input field. If `true`, which is the default, then a user can change the value. If set to `false`, the user won't be able to change the value. This can be set using the setAllowCustomValue() method. @@ -47,7 +47,7 @@ height='200px' A placeholder can be set for a `ComboBox` which will display in the text field of the component when it is empty to prompt users for the desired entry in the field. This can be done using the setPlaceholder() method. @@ -62,7 +62,7 @@ dropdown using CSS or shadow part selectors from the parent component becomes ch In the demo below, the Dropdown type is set and used in the CSS file to select the dropdown and change the background color. diff --git a/docs/docs/components/lists/list-box.md b/docs/docs/components/lists/list-box.md index c21b166d1..944c6fe3b 100644 --- a/docs/docs/components/lists/list-box.md +++ b/docs/docs/components/lists/list-box.md @@ -43,7 +43,7 @@ On touch devices, when multiple selection is enabled, users can select multiple Additionally, the arrow keys can be used to navigate the `ListBox`, and typing a letter key while the `ListBox` has focus will select the option that begins with that letter, or cycle through the options beginning with that letter should multiple options exist. diff --git a/docs/docs/components/loading.md b/docs/docs/components/loading.md index 4aba227b7..a29283234 100644 --- a/docs/docs/components/loading.md +++ b/docs/docs/components/loading.md @@ -19,7 +19,7 @@ The simplest way to create a `Loading` component is by initializing it without a Here's an example of creating a `Loading` component with a message: @@ -29,7 +29,7 @@ When users enter their username and password, the `Login` component validates th The following illustrates a basic `Login` component. If the username and password are both set to `"admin"` respectively, the login dialog closes, and a [Logout] button appears. If the credentials don't match, the default error message is displayed. @@ -62,7 +62,7 @@ If no action URL is set, form submission is handled through the `LoginSubmitEven The titles, descriptions, labels, and messages within the `Login` component are fully customizable using the `LoginI18n` class. This flexibility allows you to tailor the login interface to meet specific localization requirements or personalization preferences. @@ -74,7 +74,7 @@ The `Login` component includes several slots that allow you to add extra fields The following login has a custom field added for a customer ID. This can help you manage companies or departments with shared content across multiple users. diff --git a/docs/docs/components/markdownviewer.md b/docs/docs/components/markdownviewer.md index 58ae85138..da6d499cb 100644 --- a/docs/docs/components/markdownviewer.md +++ b/docs/docs/components/markdownviewer.md @@ -32,7 +32,7 @@ String content = viewer.getContent(); The component implements `HasText`, so `setText()` and `getText()` work as aliases for the content methods. ::: @@ -68,7 +68,7 @@ viewer.setProgressiveRender(true); When enabled, content added via `setContent()` or `append()` goes into a buffer and displays incrementally. When disabled, content appears immediately. @@ -140,7 +140,7 @@ When using progressive rendering, don't re-enable input fields based solely on w The following demo simulates an AI chat interface using `append()` with progressive rendering enabled: diff --git a/docs/docs/components/navigator.md b/docs/docs/components/navigator.md index c8dc03021..7d6066550 100644 --- a/docs/docs/components/navigator.md +++ b/docs/docs/components/navigator.md @@ -19,7 +19,7 @@ Often, a `Navigator` component displays information found in a bound `Repository To do this, simply pass the desired `Repository` object to an applicable `Navigator` object's constructor: @@ -55,7 +55,7 @@ navigator.getPaginator().setMax(maxPages); ``` @@ -77,7 +77,7 @@ The `Navigator` component provides extensive customization options for buttons, In the following example, the `setText()` method displays a numeric value to the user. Clicking the buttons fires the `onChange` method of the `Navigator`, which comes with a `Direction` value the clicked button. @@ -125,7 +125,7 @@ navigator.setTooltipText("Go to the last page", Navigator.Part.LAST_BUTTON); Various layout options exist for the `Navigator` component to provide flexibility in displaying pagination controls. To access these layouts, use the `Navigator.Layout` enum's values. The options are as follows: diff --git a/docs/docs/components/option-dialogs/confirm.md b/docs/docs/components/option-dialogs/confirm.md index 508c4c1a0..c4bd78955 100644 --- a/docs/docs/components/option-dialogs/confirm.md +++ b/docs/docs/components/option-dialogs/confirm.md @@ -16,7 +16,7 @@ A `ConfirmDialog` is a modal dialog designed to allow the user to choose one of The `ConfirmDialog` provides a way to ask users for confirmation or to choose between multiple options, such as `Yes/No` or `OK/Cancel`, ensuring that they acknowledge and confirm their actions. @@ -48,7 +48,7 @@ The `ConfirmDialog` supports the following message types. When you configures a In the following sample, the code configures a confirm dialog of type `CUSTOM` with a custom title and message. diff --git a/docs/docs/components/option-dialogs/file-chooser.md b/docs/docs/components/option-dialogs/file-chooser.md index 830788c20..8b7aed9c5 100644 --- a/docs/docs/components/option-dialogs/file-chooser.md +++ b/docs/docs/components/option-dialogs/file-chooser.md @@ -16,7 +16,7 @@ sidebar_position: 10 The `FileChooserDialog` provides a way to select files or directories from the file system, enabling users to choose directories for saving data, or perform file operations. @@ -72,7 +72,7 @@ dialog.show(); When the seletion mode is `FILES`, The `FileChooserDialog` allows you to set filters to limit the types of files that listed. You can configure filters using the `setFilters(List filters)` method. diff --git a/docs/docs/components/option-dialogs/file-save.md b/docs/docs/components/option-dialogs/file-save.md index 032b2feda..ddbae4816 100644 --- a/docs/docs/components/option-dialogs/file-save.md +++ b/docs/docs/components/option-dialogs/file-save.md @@ -16,7 +16,7 @@ sidebar_position: 15 The `FileSaveDialog` provides a streamlined method for saving files to the file system, offering user-configurable options for file naming and handling existing files. @@ -116,7 +116,7 @@ dialog.setI18n(i18n); The `FileSaveDialog` allows you to set filters to limit the types of files that can be saved using the `setFilters(List filters)` method. diff --git a/docs/docs/components/option-dialogs/file-upload.md b/docs/docs/components/option-dialogs/file-upload.md index bff1d94ec..8994ac4df 100644 --- a/docs/docs/components/option-dialogs/file-upload.md +++ b/docs/docs/components/option-dialogs/file-upload.md @@ -28,7 +28,7 @@ The resulting string will be returned from the `show()` method, or the equivalen ::: diff --git a/docs/docs/components/option-dialogs/input.md b/docs/docs/components/option-dialogs/input.md index 235dba621..daaa5ced6 100644 --- a/docs/docs/components/option-dialogs/input.md +++ b/docs/docs/components/option-dialogs/input.md @@ -16,7 +16,7 @@ An `InputDialog` is a modal dialog designed to prompt the user for input. The di The `InputDialog` prompts users for input, such as text, numbers, or other data. Because the dialog is modal, the app waits for the user to respond before continuing: @@ -52,7 +52,7 @@ In the following sample, The user is prompted to enter its password to access th again. diff --git a/docs/docs/components/option-dialogs/message.md b/docs/docs/components/option-dialogs/message.md index 170b0143e..d6cdd8f89 100644 --- a/docs/docs/components/option-dialogs/message.md +++ b/docs/docs/components/option-dialogs/message.md @@ -42,7 +42,7 @@ The `MessageDialog` supports the following message types. When you configures a In the following sample, The code configures a message dialog of type `WARNING`. with a custom title and message. diff --git a/docs/docs/components/progressbar.md b/docs/docs/components/progressbar.md index 94d440514..6356bb385 100644 --- a/docs/docs/components/progressbar.md +++ b/docs/docs/components/progressbar.md @@ -23,7 +23,7 @@ The `ProgressBar` component is useful for visualizing the completion status of t The following example shows a striped, animated progress bar with start, pause, and reset controls: @@ -44,7 +44,7 @@ bar.setValue(50); The `ProgressBar` can be oriented horizontally or vertically. @@ -54,7 +54,7 @@ height='175px' The `ProgressBar` supports an indeterminate state for tasks with unknown completion time. @@ -76,7 +76,7 @@ The `ProgressBar` component comes with ` because they require client-sid diff --git a/docs/docs/components/table/table_edit_refresh.md b/docs/docs/components/table/table_edit_refresh.md index 77c9782b4..a2df0aefb 100644 --- a/docs/docs/components/table/table_edit_refresh.md +++ b/docs/docs/components/table/table_edit_refresh.md @@ -7,7 +7,7 @@ slug: refreshing Editing data within the `Table` works via interaction with the `Repository` containing the data for the `Table`. The `Repository` serves as a bridge between the `Table` and the underlying dataset, offering methods for data retrieval, modification, and refreshing. Below is an example which implements behavior to edit the "Title" of a desired row based. @@ -272,7 +272,7 @@ When `setLazyRender(true)` is set on a column, cells display a lightweight anima @@ -290,7 +290,7 @@ webforJ ships with a comprehensive set of renderers for the most common use case { ``` @@ -200,7 +200,7 @@ theme.setForeground("#cccccc"); terminal.setTheme(theme); ``` diff --git a/docs/docs/components/textarea.md b/docs/docs/components/textarea.md index ea53fe85f..e5f5971d3 100644 --- a/docs/docs/components/textarea.md +++ b/docs/docs/components/textarea.md @@ -17,7 +17,7 @@ The `TextArea` component provides a multi-line text input field where users can Create a `TextArea` by passing a label to its constructor. Properties like placeholder text, character limits, and wrapping behavior can be configured through setter methods. @@ -65,7 +65,7 @@ The `TextArea` component supports two complementary types of validation: structu The following demo allows users to adjust validation limits—such as maximum character count, paragraph length, and line count—in real time and see how the `TextArea` responds. @@ -81,7 +81,7 @@ To further refine how wrapping behaves, `setWrapStyle()` lets you choose between These wrapping options work hand-in-hand with structural constraints like line count and paragraph length limits. While wrapping determines *how* text flows within the available space, the structural limits define *how much* space text is allowed to occupy. Together, they help maintain both visual structure and user input boundaries. @@ -95,7 +95,7 @@ Predictions can be accepted by pressing the `Tab` or `ArrowRight` key, inserting This predictive behavior enhances both speed and accuracy, especially in repetitive input scenarios or applications where consistency of phrasing is important. diff --git a/docs/docs/components/toast.md b/docs/docs/components/toast.md index 258de6fab..d0ac13472 100644 --- a/docs/docs/components/toast.md +++ b/docs/docs/components/toast.md @@ -29,7 +29,7 @@ toast.open(); ``` @@ -112,7 +112,7 @@ The `Toast` component can display multiple notifications simultaneously, stackin Although `Toast` notifications don't require user interaction by default, webforJ allows you to add buttons or other interactive elements to make them more useful than simple notifications. @@ -143,7 +143,7 @@ Since the `Toast` isn't located in a specific position in the DOM, you can targe ::: @@ -57,7 +57,7 @@ A `ProgressBar` serves as a visual indicator for ongoing processes, such as load You can combine it with other components in the toolbar like buttons or labels without disrupting the layout. @@ -69,7 +69,7 @@ files={['src/main/java/com/webforj/samples/views/toolbar/ToolbarProgressbarView. `Toolbar` components include seven built-in themes for quick visual customization: diff --git a/docs/docs/components/tree.md b/docs/docs/components/tree.md index 157e3f5a4..fea952409 100644 --- a/docs/docs/components/tree.md +++ b/docs/docs/components/tree.md @@ -40,7 +40,7 @@ Attempting to assign the same node to more than one parent will result in an exc ::: @@ -60,7 +60,7 @@ In the demo, double-click a node to open an editor for its text. Enter the new t ::: @@ -149,7 +149,7 @@ The tree supports lazy loading of node children by reacting to expand events. Wh Use the `onExpand` event to detect when a node is expanded. Inside the handler, check if the node’s children are placeholders (for example, a spinner or empty node) and replace them with actual data once loaded. @@ -210,7 +210,7 @@ List selectedKeys = tree.getSelectedKeys(); ``` From 6f81a95206be22b69b31a6cfa44e8a1252ffd841 Mon Sep 17 00:00:00 2001 From: MatthewHawkins Date: Tue, 12 May 2026 22:30:43 -0400 Subject: [PATCH 4/4] feat: refactor iframe source handling and remove deprecated siteConfig --- docs/docusaurus.config.js | 7 +++++++ docs/siteConfig.js | 7 ------- .../DocsTools/ComponentDemo/DemoFrame.js | 16 +++++++++++++--- .../components/DocsTools/ComponentDemo/index.js | 13 +++++++------ docs/src/theme/MDXComponents.js | 1 - 5 files changed, 27 insertions(+), 17 deletions(-) delete mode 100644 docs/siteConfig.js diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 18df18185..c16567faa 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -23,6 +23,10 @@ async function resolveWebforjVersion() { /** @returns {Promise} */ module.exports = async function createConfig() { const webforjVersion = await resolveWebforjVersion(); + // Demo iframes load from the Maven/Jetty server on this port in local dev. + // Mirrors the `-Dport=...` Maven flag from PR #754. Production builds use an + // empty base so the iframe `src` becomes a relative path on the docs domain. + const webforjPort = process.env.WEBFORJ_PORT || '8080'; return { title: 'webforJ Documentation', @@ -36,6 +40,9 @@ module.exports = async function createConfig() { trailingSlash: false, customFields: { webforjVersion: `${webforjVersion}`, + iframeSrcDev: `http://localhost:${webforjPort}`, + iframeSrcLive: '', + rawContentBase: 'https://raw.githubusercontent.com/webforj/webforj-documentation/main/', }, i18n: { defaultLocale: 'en', diff --git a/docs/siteConfig.js b/docs/siteConfig.js deleted file mode 100644 index 655146d3c..000000000 --- a/docs/siteConfig.js +++ /dev/null @@ -1,7 +0,0 @@ -const GLOBALS = { - IFRAME_SRC_LIVE: "", - IFRAME_SRC_DEV: "http://localhost:8080", - RAW_CONTENT_BASE: "https://raw.githubusercontent.com/webforj/webforj-documentation/main/", -}; - -export default GLOBALS; diff --git a/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js b/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js index 50abcb3f1..4c128a329 100644 --- a/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js +++ b/docs/src/components/DocsTools/ComponentDemo/DemoFrame.js @@ -4,9 +4,9 @@ import { useState, useEffect, useRef, useCallback } from "react"; import { css } from "@emotion/react"; import { translate } from '@docusaurus/Translate'; import { useColorMode } from "@docusaurus/theme-common"; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import openInNewIcon from "../../../../static/img/window-maximize.png"; -import GLOBALS from "../../../../siteConfig"; import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; @@ -72,6 +72,16 @@ function applyScrollPatches(iframe) { } } +// Resolves the iframe `src` URL for the current environment. In local dev, +// uses `iframeSrcDev` from customFields (which honors the WEBFORJ_PORT env +// var, default 8080). In production, uses `iframeSrcLive` (empty string, so +// the iframe src becomes a relative path on the docs domain). +function useIframeSrc(path) { + const { siteConfig } = useDocusaurusContext(); + const { iframeSrcDev, iframeSrcLive } = siteConfig.customFields; + return (isLocalhost ? iframeSrcDev : iframeSrcLive) + path; +} + // Theme-application + scroll-patches lifecycle for an iframe. Re-applies the // theme when colorMode changes. Returns an `onLoad` callback to attach to the // iframe element so patches apply as soon as content is available. @@ -324,7 +334,7 @@ function ResizableFrame({ path, height }) { } = useResizable(); const handleIframeLoad = useIframeBehavior(iframeRef); - const iframeSrc = (isLocalhost ? GLOBALS.IFRAME_SRC_DEV : GLOBALS.IFRAME_SRC_LIVE) + path; + const iframeSrc = useIframeSrc(path); const iframeStyles = css` min-height: 100px; @@ -357,7 +367,7 @@ function PhoneFrame({ path, variant }) { const iframeRef = useRef(null); const handleIframeLoad = useIframeBehavior(iframeRef); - const iframeSrc = (isLocalhost ? GLOBALS.IFRAME_SRC_DEV : GLOBALS.IFRAME_SRC_LIVE) + path; + const iframeSrc = useIframeSrc(path); const sizeStyles = variant === 'mobile' ? phoneMobileSize : phoneDesktopSize; return ( diff --git a/docs/src/components/DocsTools/ComponentDemo/index.js b/docs/src/components/DocsTools/ComponentDemo/index.js index 8f72a4d3f..9c37f6695 100644 --- a/docs/src/components/DocsTools/ComponentDemo/index.js +++ b/docs/src/components/DocsTools/ComponentDemo/index.js @@ -2,8 +2,8 @@ import { useState, useEffect } from "react"; import { css } from "@emotion/react"; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import GLOBALS from "../../../../siteConfig"; import DemoFrame from "./DemoFrame"; import CodePanel from "./CodePanel"; @@ -30,18 +30,18 @@ function basename(url) { // Repo-relative paths get the GitHub raw-content base prepended; absolute // http(s) URLs are an escape hatch and are used as-is. -function resolveUrl(url) { +function resolveUrl(url, rawContentBase) { if (/^https?:\/\//.test(url)) return url; - return GLOBALS.RAW_CONTENT_BASE + url.replace(/^\//, ''); + return rawContentBase + url.replace(/^\//, ''); } // Accepts the `files` prop (array of strings or objects) and returns a // uniform list of { url, label, language, highlight } records, in input order. -function normalizeFiles(files) { +function normalizeFiles(files, rawContentBase) { if (!files) return []; return files.map((entry) => { const raw = typeof entry === 'string' ? { url: entry } : entry; - const url = resolveUrl(raw.url); + const url = resolveUrl(raw.url, rawContentBase); return { url, label: raw.label ?? basename(url), @@ -128,7 +128,8 @@ const mainStyles = css` * `'desktop'` renders a 100%x600 phone-shaped preview for desktop app layouts. */ export default function ComponentDemo({ path, files, height, frame = 'resizable' }) { - const normalized = normalizeFiles(files); + const { siteConfig } = useDocusaurusContext(); + const normalized = normalizeFiles(files, siteConfig.customFields.rawContentBase); const filesKey = normalized.map((f) => f.url).join('|'); const loadedFiles = useRemoteFiles(filesKey, normalized); diff --git a/docs/src/theme/MDXComponents.js b/docs/src/theme/MDXComponents.js index 604b09bfc..7322e2ece 100644 --- a/docs/src/theme/MDXComponents.js +++ b/docs/src/theme/MDXComponents.js @@ -20,7 +20,6 @@ import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import GLOBALS from '../../siteConfig'; import GalleryCard from '@site/src/components/GalleryCard/GalleryCard'; import GalleryGrid from '@site/src/components/GalleryGrid/GalleryGrid'; import ExperimentalWarning from '@site/src/components/DocsTools/ExperimentalWarning';