Skip to content

Commit

Permalink
feat: Embedded component appTheme support (#9588)
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 authored and taefi committed Mar 3, 2021
1 parent 9cc9b46 commit 313cd24
Show file tree
Hide file tree
Showing 30 changed files with 548 additions and 71 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ flow-tests/**/types.d.ts
flow-tests/test-themes/frontend/theme/app-theme/app-theme.js
package.json
package-lock.json
flow-tests/test-embedding/test-embedding-application-theme/frontend/theme/embedded-theme/embedded-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Set<File> generateWebComponentModules(File outputDirectory) {

return WebComponentModulesWriter.DirectoryWriter
.generateWebComponentsToDirectory(getWriterClass(),
exporterRelatedClasses, outputDirectory, true);
exporterRelatedClasses, outputDirectory, true, null);
}

private Class<?> getWriterClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ private void assignTheme() {
WebComponentConfigurationRegistry registry = getConfigurationRegistry();
Optional<Theme> theme = registry
.getEmbeddedApplicationAnnotation(Theme.class);
if (theme.isPresent()) {
if (theme.isPresent() && !theme.get().value().equals(AbstractTheme.class)) {
getInternals().setTheme(theme.get().value());
assignVariant(registry, theme.get());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private String generateBowerResponse(
} else {
response.setContentType(CONTENT_TYPE_TEXT_HTML_UTF_8);
return WebComponentGenerator.generateModule(configuration,
getFrontendPath(request), true);
getFrontendPath(request), true, null);
}
}

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 @@ -81,9 +87,10 @@ public Set<File> generateWebComponents(File outputDirectory) {
.forEach(exporterRelatedClasses::add);
finder.getSubTypesOf(WebComponentExporterFactory.class.getName())
.forEach(exporterRelatedClasses::add);
final String themeName = theme == null ? "" : theme.getName();
return WebComponentModulesWriter.DirectoryWriter
.generateWebComponentsToDirectory(writerClass,
exporterRelatedClasses, outputDirectory, false);
.generateWebComponentsToDirectory(writerClass,
exporterRelatedClasses, outputDirectory, false, themeName);
} 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 @@ -434,16 +434,16 @@ private NodeTasks(Builder builder) {
classFinder = new ClassFinder.CachedClassFinder(
builder.classFinder);

if (builder.generateEmbeddableWebComponents) {
FrontendWebComponentGenerator generator = new FrontendWebComponentGenerator(
classFinder);
generator.generateWebComponents(builder.generatedFolder);
}

frontendDependencies = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
.createScanner(!builder.useByteCodeScanner, classFinder,
builder.generateEmbeddableWebComponents);

if (builder.generateEmbeddableWebComponents) {
FrontendWebComponentGenerator generator = new FrontendWebComponentGenerator(
classFinder);
generator.generateWebComponents(builder.generatedFolder, frontendDependencies.getThemeDefinition());
}

commands.add(new TaskGenerateTsFiles(builder.npmFolder, frontendDependencies.getModules()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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 +91,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 +117,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 +143,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 +155,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

0 comments on commit 313cd24

Please sign in to comment.