Closed mshabarov closed 9 months ago
A clean sample for adding the flow component could be:
import {VerticalLayout} from "@vaadin/react-components/VerticalLayout.js";
import React, {useEffect} from "react";
const LOGIN_COMPONENT = "my-flow-component";
function MyLoginView() {
loadComponentScript(LOGIN_COMPONENT);
return React.createElement(LOGIN_COMPONENT);
}
const loadComponentScript = (name: String) => {
useEffect(() => {
const script = document.createElement('script');
script.src = `/web-component/${name}.js`;
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
}
}, []);
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyLoginView/>
</VerticalLayout>
</>
);
}
from where loadComponentScript
could be moved to Flow.tsx for instance making the sample:
import {VerticalLayout} from "@vaadin/react-components/VerticalLayout.js";
import React, {useEffect} from "react";
import { loadComponentScript } from "Frontend/generated/flow/Flow";
function MyLoginView() {
const LOGIN_COMPONENT = "my-flow-component";
loadComponentScript(LOGIN_COMPONENT);
return React.createElement(LOGIN_COMPONENT);
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyLoginView/>
</VerticalLayout>
</>
);
}
Documentation start:
---
title: Flow components in Hilla view
order: 10
---
= Use Custom Flow Components In Hilla
Custom Flow components can be embedded into Hilla views by implementing a [classname]`WebComponentExporter` and using it in the view.
A [classname]`WebComponentExporter` can target any Flow Component, for instance the following component:
[source,java]
----
public class CustomComponent extends Div {
public CustomComponent(@Autowired GreetService service) {
Button button = new Button("Say hello", e -> {
Notification.show("Hello!");
});
add(button);
}
}
----
would be made into a [classname]`WebComponent` like:
[source,java]
----
public class MyFlowComponentExporter
extends WebComponentExporter<CustomComponent> {
public static final String TAG = "my-flow-component";
public MyFlowComponentExporter() {
super(TAG);
}
@Override
protected void configureInstance(WebComponent<CustomComponent> webComponent,
CustomComponent component) {
}
}
----
For more information see <<{articles}/flow/integrations/embedding/exporter,Creating an Embedded Vaadin Application>>
To add the exported [classname]`WebComponent` to a hilla view import `createWebComponent` from Flow and create a React.DOMElement for the [classname]`WebComponent` `TAG` and then use the element inside the view layout.
[source,typescriptjsx]
----
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { createWebComponent } from "Frontend/generated/flow/Flow";
function MyLoginView() {
return createWebComponent("my-flow-component");
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyLoginView/>
</VerticalLayout>
</>
);
}
----
If the component needs attributes or other custom parts in `React.createElement` then instead of importing `createWebComponent` import `loadComponentScript` and create the element in the function.
[source,typescriptjsx]
----
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { loadComponentScript } from "Frontend/generated/flow/Flow";
import React from "react";
function MyLoginView() {
loadComponentScript("my-flow-component");
// Use the wanted createElement here!
return React.createElement("my-flow-component");
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyLoginView/>
</VerticalLayout>
</>
);
}
----
[discussion-id]`920dc03d-5eb4-4826-8934-4416b58a9a3e`
++++
<style>
[class^=PageHeader-module--descriptionContainer] {display: none;}
</style>
++++
The documentation part is not merged yet, but I propose to handle it separately via normal review.
Describe your motivation
Hilla framework gives you an opportunity to develop UI using Lit or React libraries using corresponding Vaadin components: React or Lit-based.
For unification reasons, Vaadin should also allow to use custom Flow components on the Hilla views, like follows (example for Lit):
Where the
login-form
is a Flow server-side component:Describe the solution you'd like
The Flow component can be exported using
WebComponentExporter
API:and adding the web-component's script into
index.ts
:However, this doesn't work out-of-the-box with both Lit and React, the following errors are shown up in the browser console preventing Hilla to render the component:
Apparently, the Flow client part isn't completely initialised and web-component cannot be initialised in turn. This should be properly handled by
WebComponentBootstrapHandler
/WebComponentProvider
/WebComponentExporter
implementation.However, if I open the Flow view and navigate back to the Hilla view with my component, it's rendered fine, which proves my assumption of incomplete Flow initialisation.
This error can be reproduced with Hilla-React or Hilla-Lit examples:
http://localhost:8080/hilla
in the browserYou can also check that
window.Vaadin.Flow.registerWidgetset
is defined when component is rendered, and undefined when not.Describe alternatives you've considered
Apart from the essential problem described above, the example projects show the following inconveniences:
for the React example, I need to add my web-component programmatically (not into markup):
Perhaps I'm lacking a React expertise to properly do this, but anyway, this would be better to have included into Flow somehow so that I only need to add an import and tag to my Hilla view.
I have to use
document.head.appendChild(script);
in index.ts to load the JS module, because if I place it intoindex.html
as a<script>
tag, I get the url with/VAADIN/
segment auto-added by Vaadin, which isn't then handled byWebComponentBootstrapHandler
, but by Vite dev server.Additional context
When I navigate to the Flow view and do a refresh in step 4 (see above), I got the following error on server that prevents the page to render:
Not sure if this is a part of the same issue or a separate one. A new ticket can be created for it later, if it has a different root cause.