Skip to content

Commit

Permalink
feat: Embedded component appTheme support
Browse files Browse the repository at this point in the history
Add support for application theme with
embedded components.

Fixes #8564
  • Loading branch information
caalador committed Dec 7, 2020
1 parent c60b51b commit 89cd62f
Show file tree
Hide file tree
Showing 27 changed files with 544 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.LoggerFactory;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.DomEvent;
Expand All @@ -42,8 +44,8 @@
import com.vaadin.flow.theme.AbstractTheme;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.ThemeDefinition;

import elemental.json.JsonObject;
import org.slf4j.LoggerFactory;

/**
* Custom UI for use with WebComponents served from the server.
Expand Down Expand Up @@ -286,7 +288,8 @@ private void assignThemeVariant() {
WebComponentConfigurationRegistry registry = getConfigurationRegistry();
Optional<Theme> theme = registry
.getEmbeddedApplicationAnnotation(Theme.class);
if (!theme.isPresent()) {
if (!theme.isPresent() || theme.get().themeClass()
.equals(AbstractTheme.class)) {
return;
}
AbstractTheme themeInstance = Instantiator.get(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.vaadin.flow.component.WebComponentExporterFactory;
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
import com.vaadin.flow.server.webcomponent.WebComponentModulesWriter;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.ThemeDefinition;

/**
* Generates embeddable web component files in npm mode, hiding the complexity
Expand Down Expand Up @@ -67,12 +69,16 @@ public FrontendWebComponentGenerator(ClassFinder finder) {
* outputDirectory}.
*
* @param outputDirectory
* target directory for the web component module files
* target directory for the web component module files
* @param theme
* the theme defined using {@link Theme} or {@code null} if not
* defined
* @return generated files
* @throws java.lang.IllegalStateException
* if {@code finder} cannot locate required classes
*/
public Set<File> generateWebComponents(File outputDirectory) {
public Set<File> generateWebComponents(File outputDirectory,
ThemeDefinition theme) {
try {
final Class<?> writerClass = finder
.loadClass(WebComponentModulesWriter.class.getName());
Expand All @@ -83,7 +89,8 @@ public Set<File> generateWebComponents(File outputDirectory) {
.forEach(exporterRelatedClasses::add);
return WebComponentModulesWriter.DirectoryWriter
.generateWebComponentsToDirectory(writerClass,
exporterRelatedClasses, outputDirectory, false);
exporterRelatedClasses, outputDirectory, false,
theme.getName());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(
"Unable to locate a required class using custom class "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ private NodeTasks(Builder builder) {
if (builder.generateEmbeddableWebComponents) {
FrontendWebComponentGenerator generator = new FrontendWebComponentGenerator(
classFinder);
generator.generateWebComponents(builder.generatedFolder);
generator.generateWebComponents(builder.generatedFolder, frontendDependencies.getThemeDefinition());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.slf4j.LoggerFactory;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.WebComponentExporter;
import com.vaadin.flow.component.WebComponentExporterFactory;
import com.vaadin.flow.component.webcomponent.WebComponentConfiguration;
import com.vaadin.flow.shared.util.SharedUtil;
import com.vaadin.flow.theme.Theme;

import elemental.json.JsonArray;
import elemental.json.JsonValue;
Expand Down Expand Up @@ -90,18 +92,20 @@ private static String getTemplate(boolean compatibilityMode) {
* @param compatibilityMode
* {@code true} to generate Polymer2 template, {@code false} to
* generate Polymer3 template
* @param themeName
* the theme defined using {@link Theme} or {@code null} if not defined
* @return generated web component html/JS to be served to the client
*/
public static String generateModule(
WebComponentExporterFactory<? extends Component> factory,
String frontendURI, boolean compatibilityMode) {
String frontendURI, boolean compatibilityMode, String themeName) {
Objects.requireNonNull(factory);
Objects.requireNonNull(frontendURI);

WebComponentConfiguration<? extends Component> config = new WebComponentExporter.WebComponentConfigurationFactory()
.create(factory.create());

return generateModule(config, frontendURI, false, compatibilityMode);
return generateModule(config, frontendURI, false, compatibilityMode, themeName);
}

/**
Expand All @@ -114,22 +118,24 @@ public static String generateModule(
* @param compatibilityMode
* {@code true} to generate Polymer2 template, {@code false} to
* generate Polymer3 template
* @param themeName
* the theme defined using {@link Theme} or {@code null} if not defined
* @return generated web component html/JS to be served to the client
*/
public static String generateModule(
WebComponentConfiguration<? extends Component> webComponentConfiguration,
String frontendURI, boolean compatibilityMode) {
String frontendURI, boolean compatibilityMode, String themeName) {
Objects.requireNonNull(webComponentConfiguration);
Objects.requireNonNull(frontendURI);

return generateModule(webComponentConfiguration, frontendURI, true,
compatibilityMode);
compatibilityMode, themeName);
}

private static String generateModule(
WebComponentConfiguration<? extends Component> webComponentConfiguration,
String frontendURI, boolean generateUiImport,
boolean compatibilityMode) {
boolean compatibilityMode, String themeName) {
Objects.requireNonNull(webComponentConfiguration);
Objects.requireNonNull(frontendURI);

Expand All @@ -138,7 +144,7 @@ private static String generateModule(

Map<String, String> replacements = getReplacementsMap(
webComponentConfiguration.getTag(), propertyDataSet,
frontendURI, generateUiImport);
frontendURI, generateUiImport, themeName);

String template = getTemplate(compatibilityMode);
for (Map.Entry<String, String> replacement : replacements.entrySet()) {
Expand All @@ -150,9 +156,17 @@ private static String generateModule(

static Map<String, String> getReplacementsMap(String tag,
Set<PropertyData<? extends Serializable>> propertyDataSet,
String frontendURI, boolean generateUiImport) {
String frontendURI, boolean generateUiImport, String themeName) {
Map<String, String> replacements = new HashMap<>();

if (themeName != null && !themeName.isEmpty()) {
replacements.put("ThemeImport",
"import {applyTheme} from 'theme/theme-generated.js';\n\n");
replacements.put("ApplyTheme", "applyTheme(shadow);\n");
} else {
replacements.put("ThemeImport", "");
replacements.put("ApplyTheme", "");
}
replacements.put("TagDash", tag);
replacements.put("TagCamel", SharedUtil
.capitalize(SharedUtil.dashSeparatedToCamelCase(tag)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.vaadin.flow.component.WebComponentExporter;
import com.vaadin.flow.component.WebComponentExporterFactory;
import com.vaadin.flow.internal.ReflectTools;
import com.vaadin.flow.theme.Theme;

/**
* Writes web components generated from
Expand Down Expand Up @@ -66,6 +67,8 @@ private WebComponentModulesWriter() {
* @param compatibilityMode
* {@code true} to generated html modules, {@code false} to
* generate JavaScript modules
* @param themeName
* the theme defined using {@link Theme} or {@code null} if not defined
* @return generated files
* @throws java.lang.NullPointerException
* if {@code exportedClasses} or {@code outputDirectory} is null
Expand All @@ -74,7 +77,7 @@ private WebComponentModulesWriter() {
*/
private static Set<File> writeWebComponentsToDirectory( // NOSONAR
Set<Class<?>> exporterClasses, File outputDirectory,
boolean compatibilityMode) {
boolean compatibilityMode, String themeName) {
// this method is used via reflection by DirectoryWriter
Objects.requireNonNull(exporterClasses,
"Parameter 'exporterClasses' must not be null");
Expand All @@ -89,7 +92,7 @@ private static Set<File> writeWebComponentsToDirectory( // NOSONAR

return WebComponentExporterUtils.getFactories(exporterClasses).stream()
.map(factory -> writeWebComponentToDirectory(factory,
outputDirectory, compatibilityMode))
outputDirectory, compatibilityMode, themeName))
.collect(Collectors.toSet());
}

Expand All @@ -101,11 +104,13 @@ private static Set<File> writeWebComponentsToDirectory( // NOSONAR
* web component exporter factory
* @param outputDirectory
* folder into which the generate file is written
* @param themeName
* the theme defined using {@link Theme} or {@code null} if not defined
* @return the generated module content
*/
private static File writeWebComponentToDirectory(
WebComponentExporterFactory<?> factory, File outputDirectory,
boolean compatibilityMode) {
boolean compatibilityMode, String themeName) {
String tag = getTag(factory);

String fileName = compatibilityMode ? tag + ".html" : tag + ".js";
Expand All @@ -114,7 +119,7 @@ private static File writeWebComponentToDirectory(
FileUtils.forceMkdir(generatedFile.getParent().toFile());
Files.write(generatedFile,
Collections.singletonList(
generateModule(factory, compatibilityMode)),
generateModule(factory, compatibilityMode, themeName)),
StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(String.format(
Expand All @@ -126,9 +131,9 @@ private static File writeWebComponentToDirectory(

private static String generateModule(
WebComponentExporterFactory<? extends Component> factory,
boolean compatibilityMode) {
boolean compatibilityMode, String themeName) {
return WebComponentGenerator.generateModule(factory, "../",
compatibilityMode);
compatibilityMode, themeName);
}

private static String getTag(
Expand All @@ -149,7 +154,7 @@ public static final class DirectoryWriter implements Serializable {

/**
* Calls
* {@link #writeWebComponentsToDirectory(java.util.Set, java.io.File, boolean)}
* {@link #writeWebComponentsToDirectory(java.util.Set, java.io.File, boolean, java.lang.String)}
* via reflection on the supplied {@code writer}. The {@code writer} and
* {@code exporterClasses} must be loaded with the same class loader.
*
Expand All @@ -166,6 +171,8 @@ public static final class DirectoryWriter implements Serializable {
* @param compatibilityMode
* {@code true} to generated html modules, {@code false} to *
* generate JavaScript modules
* @param themeName
* the theme defined using {@link Theme} or {@code null} if not defined
* @return generated files
* @throws java.lang.NullPointerException
* if {@code writerClassSupplier},
Expand All @@ -179,16 +186,16 @@ public static final class DirectoryWriter implements Serializable {
* share a class loader
* @throws java.lang.IllegalStateException
* if the received {@code writer} does not have method
* {@link #writeWebComponentsToDirectory(java.util.Set, java.io.File, boolean)}
* {@link #writeWebComponentsToDirectory(java.util.Set, java.io.File, boolean, java.lang.String)}
* @throws java.lang.RuntimeException
* if reflective method invocation fails
* @see #writeWebComponentsToDirectory(java.util.Set, java.io.File,
* boolean)
* boolean, java.lang.String)
*/
@SuppressWarnings("unchecked")
public static Set<File> generateWebComponentsToDirectory(
Class<?> writerClass, Set<Class<?>> exporterClasses,
File outputDirectory, boolean compatibilityMode) {
File outputDirectory, boolean compatibilityMode, String themeName) {
Objects.requireNonNull(writerClass,
"Parameter 'writerClassSupplier' must not null");
Objects.requireNonNull(exporterClasses,
Expand Down Expand Up @@ -235,7 +242,7 @@ public static Set<File> generateWebComponentsToDirectory(
final boolean accessible = writeMethod.isAccessible();
writeMethod.setAccessible(true);
Set<File> files = ((Set<File>) writeMethod.invoke(null,
exporterClasses, outputDirectory, compatibilityMode));
exporterClasses, outputDirectory, compatibilityMode, themeName));
writeMethod.setAccessible(accessible);
return files;
} catch (IllegalAccessException | InvocationTargetException
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class _TagCamel_ extends HTMLElement {
_ThemeImport_class _TagCamel_ extends HTMLElement {
constructor() {
super();
this._propertyUpdatedFromServer = {};
Expand All @@ -12,7 +12,7 @@ class _TagCamel_ extends HTMLElement {
display: inline-block;
}
`;
shadow.appendChild(style);
_ApplyTheme_shadow.appendChild(style);
shadow.appendChild(document.createElement("slot"));

var self = this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
],
"repository": "vaadin/flow",
"name": "@vaadin/application-theme-plugin",
"version": "0.2.0",
"version": "0.2.1",
"main": "application-theme-plugin.js",
"author": "Vaadin Ltd",
"license": "Apache-2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ function generateThemeFile(themeFolder, themeName) {
const variable = camelCase(filename);
imports.push(`import ${variable} from './${filename}';\n`);
if (filename == themeFileAlwaysAddToDocument) {
globalCssCode.push(`injectGlobalCss(${variable}.toString(), document);\n`);
globalCssCode.push(`injectGlobalCss(${variable}.toString(), document);\n `);
} else {
globalCssCode.push(`injectGlobalCss(${variable}.toString(), target);\n `);
}
globalCssCode.push(`injectGlobalCss(${variable}.toString(), target);\n`);
});

componentsFiles.forEach((componentCss) => {
Expand All @@ -92,7 +93,7 @@ function generateThemeFile(themeFolder, themeName) {
\${unsafeCSS(${variable}.toString())}
\`
);
`;
`;
componentCssCode.push(componentString);
});

Expand Down
Loading

0 comments on commit 89cd62f

Please sign in to comment.