How to print a Component in Vaadin? - vaadin

I have been struggling for sometime now, trying to find ways to print out/generate document using vaadin.
i have tried using the below code but this prints all the components. I wanted to print only a particular form or layout.
UI.getCurrent().getElement().executeJs("print();")
Can some one guide me?

You'll need some CSS (similar to the approach mentioned here) that will hide everything when printing is invoked, except for the Layout or Component that needs to be printed.
For example, assuming you have the following two DIVs in your view:
Div printable = new Div(new Span("printable"));
Div nonPrintable = new Div(new Span("nonPrintable"));
You can give one of those a classname:
printable.addClassName("printable");
Then, you would add the following CSS to the global scope:
#media print {
body, body * {
visibility: hidden;
}
.printable, .printable * {
visibility: visible;
}
.printable {
position: absolute;
left: 0;
top: 0;
}
}
Note, in a Vaadin 14 project, the previous CSS is most easily incorporated using the #CssImport annotation. For example, the following annotations can be added to one of your Java classes:
#CssImport("./shared-styles.css")
Then under the directory {projecr-root-directory}/frontend, you'd need to create shared-styles.css and place the aforementioned styling there.

Related

Web components with vaadin and rollup with svelte: Primary button ignores theme attribute

Maybe someone tried this before and is able to give me a hint.
I have used normal svelte setup (mentioned in the main page) which scaffolds the app;
npx degit sveltejs/template my-svelte-project
I wanted to use vaadin web components in Svelte. I've installed it;
npm install #vaadin/vaadin
the code of main.ts:
<script lang="ts">
import '#vaadin/button/theme/material'
</script>
<main>
<vaadin-button theme="primary">Primary</vaadin-button>
<vaadin-button theme="secondary">Sec</vaadin-button>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
#media (min-width: 640px) {
main {
max-width: none;
}
}
</style>
And the thing is that it almost works :) The buttons are styled, I can click on them but... the theme is ignored;
The primary should have a background color like stated in docs;
https://vaadin.com/docs/latest/ds/components/button/#styles
any idea???
This is happening because of how Svelte sets data on custom elements. If a property exists on the element with the same name as the attribute you set, Svelte will set the property instead of the attribute. Otherwise, it will fall back to the attribute. So, the following...
<vaadin-button theme="primary">Primary</vaadin-button>
...gets compiled to something like:
button.theme = "primary";
Normally this works great, especially when setting array and object properties. However, the vaadin-button styles expect the theme attribute to be set, not the property. Because Svelte sets the property instead, the styles don't apply.
:host([theme~="primary"]) {
background-color: var(--_lumo-button-primary-background-color, var(--lumo-primary-color));
color: var(--_lumo-button-primary-color, var(--lumo-primary-contrast-color));
font-weight: 600;
min-width: calc(var(--lumo-button-size) * 2.5);
}
I would argue that this is a Vaadin bug - if you expose an attribute and a property for the same data, it shouldn't matter which one the consumer sets. Setting the property should have the same effect as setting the attribute. A quick way to fix this would be for vaadin-button to reflect the theme property, so that setting theme also sets the attribute. Here's how to do that in Lit.
However, that change requires the component library authors to implement it. As a consumer of the library, you can also work around this in Svelte by using an action to force Svelte to set the attribute instead.
<script>
import "#vaadin/button";
function setAttributes(node, attributes) {
for (const [attr, value] of Object.entries(attributes))
node.setAttribute(attr, value);
}
</script>
<main>
<vaadin-button use:setAttributes={{ theme: "primary" }}>Primary</vaadin-button>
<vaadin-button>Normal</vaadin-button>
</main>
I wrote an article about this behavior and other workarounds at CSS-Tricks, if you want a more in-depth explanation.
You seem to be importing the Material theme version of the Button component. The "primary" theme variant is only available if you use the default Lumo theme. To import that, use import '#vaadin/button';
For the Material theme, you can use the "outlined" and "contained" theme variants instead: https://cdn.vaadin.com/vaadin-material-styles/1.3.2/demo/buttons.html

Customise ant.design components style

I read about few of the posts for custom theme and styles from less variables But can I modify at the level of say
.ant-collapse > .ant-collapse-item > .ant-collapse-header .arrow {
right: 16px; // instead of left:16px
}
What do I want? In this specific case I just want my arrow to show on right instead of left in Collapse.Panel component.
From where from I copied the styles? In the component's .css itself.
This even if possible via .less modification and compiling may not be best solution, so open to hearing the workarounds, if any?
In less file, same would translate to
right: #padding-md; // instead of original entry of left: #padding-md;
and in customization guides, I can modify only variables. Now?
Write the below code in css file
:global {
.ant-collapse-header{
//code
}
}
I'm not sure that I understand your question but what about implementing your own Collaps.panel?
import 'myPanelStyle.css'
export default class MyCollapsePanel{
render(){
return(<Collapse.panel id="my-panle" {...this.props}>{this.props.children}</Collapse.panel>)
}
}
myPanle.css:
#my-panle{
.ant-collapse > .ant-collapse-item > .ant-collapse-header .arrow {
right: 16px; // instead of left:16px
}
}
in this way, anytime you use your panel it will be as you wish and you are not corrupt any other css sheets of default Antd library.

styled components styled overriden by thrid party (antd) style

I've got a simple styled-components that is being applied to an antd component:
import { Card } from 'antd';
export const UsageCard = styled(Card)`
box-shadow: 1px 1px;
padding: 2px;
`
This creates a div with a class attribute that looks like : "ant-card edit-style__UsageCard-jsklqS hBLsXc ant-card-bordered"
Where .hBLsXc is my styled-component. Unfortunately the padding which is 2px in my styled-componentn gets overriden by the ant-card (0px).
Any idea why this is happening? The styled-components is supposed to come first since it's implemented over the thrid-party component. Is this a problem with the forwarding of className from third-party component I've read on multiple occasion? In any case, I don't really gets how this is supposed to work.
Thanks for your help!
The className has to be put in the Card Component, otherwise this will not work. You should check with antd to see if they did so. It has to look something like this:
const Card = ({ className }) => (
<div className={className}>
...
</div>
)
Here is the documentation for it:
https://www.styled-components.com/docs/basics#styling-any-components
edit:
I checked with antd and it looks like you can pass the className to it. There is a section in https://github.com/ant-design/ant-design/blob/master/components/card/index.tsx:
const classString = classNames(prefixCls, className, {
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-bordered`]: bordered,
[`${prefixCls}-hoverable`]: this.getCompatibleHoverable(),
[`${prefixCls}-wider-padding`]: this.state.widerPadding,
[`${prefixCls}-padding-transition`]: this.updateWiderPaddingCalled,
[`${prefixCls}-contain-grid`]: this.isContainGrid(),
[`${prefixCls}-contain-tabs`]: tabList && tabList.length,
[`${prefixCls}-type-${type}`]: !!type,
});
You can pass the className via props. So this should actually work, but the passed className goes first, so I guess the antd styles will always override the styled-components ones, if they are the same. Maybe a fork might help?

Is there a template creation Event in Darts Web_ui?

Is there anything like a notification mechanism for the instantiation of a template?
Assume the following simple template:
<template iterate="name in names">
<div>{{name}}</div>
</template>
When a name is very long, it might be possible that the container of the name div is overflown. So what I would like to do is to get an event when the name div is added to the DOM so that I can take a look at the resulting width. I would then shorten the name until it fits nicely.
Note: I assume you can't achieve what you want with CSS. So here's a code solution.
I am not aware of any event or a way to hook into the creation process.
However, I have done something like this with success:
import 'dart:async';
inserted() {
Timer.run(() {
// Do your calculations here...
});
}
If you set your name variable later, then you could alternatively make it observable and set the timer after the value changes:
observe(() => name), (_) {
Timer.run(() {
// Recalculate...
});
});
And remember to mark it #observable and set the listener in created().
You should really handle something like this in CSS:
.name {
width: 50px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
And give your div a class of name.
This will automatically shrink the text down to the container width and add an ellipsis to indicate that the text has been truncated.

jQuery iframeFix on a Sortable

On my CMS I have a list of thumbnails (Sortable). The thumbnails work great and now I'm writing a plug-in to drag-them to a tinyMCE window.
As the tinyMCE window has an iFrame it doesn't work that well.
jQuery has an option for Draggables called iframeFix that works exactly as I need. However that list must be a Sortables. I've looked quite extensively on Google and found no-one with my requirements. Has anyone here on StackOverflow done it?
Apply the iframeFix to a Sortables?
If not... I'm on my way to a jQuery plug-in.
Thank you in advance!
I've done it.
You need to have a DIV on top of the iFrame to let the Draggable/Sortable flow without problems. So I used jQuery to create a DIV right on top of the iframe. Then it show's it when you grab the element and destroys it when you drop it. Works like a charm. If anyone is in need of something like that let me know.
update (by popular request):
On my specific scenario I use the following DIV:
<div id="iframeDivFixer" class="ui-draggable-iframeFix" style="background-color: rgb(255, 255, 255); display: none; width: 665px; height: 665px; position: absolute; opacity: 0.001; z-index: 1000; left: 362px; top: 290px; background-position: initial initial; background-repeat: initial initial;"></div>
And, as soon as I grab the thumbnail javascript is used to set the display property to block. The process is reversed when you release the dragabble.
A seriously old question here, but there's another way to do it using css - pointer-events:none; which is supported on all the currently supported browsers (IE11 and above - caniuse.com)
$("#sortable").sortable({
start: function() {
$("iframe").css("pointer-events", "none");
},
stop: function() {
$("iframe").css("pointer-events", "");
},
});

Resources