CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-google-android-material--material

Google's official Material Design components library for Android applications with comprehensive UI components, theming, and animations.

Pending
Overview
Eval results
Files

theming-and-styling.mddocs/

Theming and Styling

Material Design theming system including colors, shapes, typography, elevation, and dynamic colors.

Core Imports

import com.google.android.material.color.MaterialColors;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.color.ColorRoles;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.CornerTreatment;
import com.google.android.material.shape.CornerSize;
import com.google.android.material.shape.AbsoluteCornerSize;
import com.google.android.material.shape.RelativeCornerSize;
import com.google.android.material.shape.RoundedCornerTreatment;
import com.google.android.material.shape.CutCornerTreatment;
import com.google.android.material.elevation.ElevationOverlayProvider;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.typography.TypographyUtils;

Material Colors

Utility class for working with Material Design colors and theme attributes.

class MaterialColors {
    // Get color from theme attributes
    static int getColor(View view, @AttrRes int colorAttributeResId);
    static int getColor(Context context, @AttrRes int colorAttributeResId, int defaultValue);
    static int getColor(View view, @AttrRes int colorAttributeResId, int defaultValue);
    
    // Get ColorStateList from theme attributes
    static ColorStateList getColorStateList(View view, @AttrRes int colorAttributeResId);
    static ColorStateList getColorStateList(Context context, @AttrRes int colorAttributeResId, ColorStateList defaultValue);
    
    // Color layering and blending
    static int layer(View view, @AttrRes int backgroundColorAttributeResId, @AttrRes int overlayColorAttributeResId);
    static int layer(View view, @AttrRes int backgroundColorAttributeResId, @AttrRes int overlayColorAttributeResId, float overlayAlpha);
    static int layer(@ColorInt int backgroundColor, @ColorInt int overlayColor, @FloatRange(from = 0.0, to = 1.0) float overlayAlpha);
    
    // Alpha composition
    static int compositeARGBWithAlpha(@ColorInt int originalColor, @IntRange(from = 0, to = 255) int alpha);
    
    // Color analysis
    static boolean isColorLight(@ColorInt int color);
}

Usage Example

// Get theme colors
int primaryColor = MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimary);
int surfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface, Color.WHITE);

// Get ColorStateList for different states
ColorStateList primaryColorStateList = MaterialColors.getColorStateList(
    view, com.google.android.material.R.attr.colorPrimary);

// Layer colors with alpha
int layeredColor = MaterialColors.layer(
    view, 
    com.google.android.material.R.attr.colorSurface,
    com.google.android.material.R.attr.colorPrimary,
    0.08f // 8% alpha overlay
);

// Apply elevation overlay
int elevatedSurfaceColor = MaterialColors.layer(surfaceColor, primaryColor, 0.05f);

// Check if color is light for contrast decisions
boolean isLight = MaterialColors.isColorLight(backgroundColor);
int textColor = isLight ? Color.BLACK : Color.WHITE;

// Composite color with alpha
int transparentColor = MaterialColors.compositeARGBWithAlpha(primaryColor, 128); // 50% alpha

Dynamic Colors

Support for Android 12+ dynamic color theming (Material You).

class DynamicColors {
    // Apply dynamic colors to activities
    static void applyToActivitiesIfAvailable(Application application);
    static void applyToActivitiesIfAvailable(Application application, DynamicColorsOptions options);
    static void applyToActivityIfAvailable(Activity activity);
    static void applyToActivityIfAvailable(Activity activity, DynamicColorsOptions options);
    
    // Check dynamic color availability
    static boolean isDynamicColorAvailable();
    
    // Context wrapping for dynamic colors
    static Context wrapContextIfAvailable(Context context);
    static Context wrapContextIfAvailable(Context context, DynamicColorsOptions options);
}

class DynamicColorsOptions {
    int getThemeOverlay();
    OnAppliedCallback getOnAppliedCallback();
    Precondition getPrecondition();
    
    interface OnAppliedCallback {
        void onApplied(DynamicColorsOptions options);
    }
    
    interface Precondition {
        boolean shouldApplyDynamicColors(Activity activity, int theme);
    }
}

Usage Example

// Enable dynamic colors globally in Application class
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        
        // Apply dynamic colors to all activities if available
        DynamicColors.applyToActivitiesIfAvailable(this);
        
        // Or with options
        DynamicColorsOptions options = new DynamicColorsOptions.Builder()
            .setOnAppliedCallback(appliedOptions -> {
                Log.d("DynamicColors", "Dynamic colors applied");
            })
            .build();
        DynamicColors.applyToActivitiesIfAvailable(this, options);
    }
}

// Check if dynamic colors are available
if (DynamicColors.isDynamicColorAvailable()) {
    // Use dynamic colors
    DynamicColors.applyToActivityIfAvailable(this);
} else {
    // Fallback to static colors
    setTheme(R.style.AppTheme_StaticColors);
}

// Wrap context for dynamic colors
Context dynamicContext = DynamicColors.wrapContextIfAvailable(this);
LayoutInflater.from(dynamicContext).inflate(R.layout.dynamic_layout, parent);

Color Roles

Represents semantic color roles in Material Design color system.

class ColorRoles {
    @ColorInt int getAccent();
    @ColorInt int getOnAccent();
    @ColorInt int getAccentContainer();
    @ColorInt int getOnAccentContainer();
}

Shape Appearance Model

Defines the appearance and shape characteristics of Material components.

class ShapeAppearanceModel {
    // Factory methods
    static Builder builder();
    static Builder builder(Context context, @StyleRes int styleRes, @StyleRes int defaultStyleRes);
    static Builder builder(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes);
    
    // Corner treatments
    CornerTreatment getTopLeftCorner();
    CornerTreatment getTopRightCorner();
    CornerTreatment getBottomRightCorner();
    CornerTreatment getBottomLeftCorner();
    
    // Corner sizes
    CornerSize getTopLeftCornerSize();
    CornerSize getTopRightCornerSize();
    CornerSize getBottomRightCornerSize();
    CornerSize getBottomLeftCornerSize();
    
    // Edge treatments
    EdgeTreatment getTopEdge();
    EdgeTreatment getRightEdge();
    EdgeTreatment getBottomEdge();
    EdgeTreatment getLeftEdge();
    
    // Builder for modifications
    Builder toBuilder();
    
    // Transform corner sizes
    ShapeAppearanceModel withTransformedCornerSizes(CornerSizeUnaryOperator cornerSizeUnaryOperator);
}

class ShapeAppearanceModel.Builder {
    // Set all corners
    Builder setAllCorners(CornerTreatment cornerTreatment);
    Builder setAllCornerSizes(float cornerSize);
    Builder setAllCornerSizes(CornerSize cornerSize);
    
    // Individual corners
    Builder setTopLeftCorner(CornerTreatment cornerTreatment);
    Builder setTopLeftCornerSize(float cornerSize);
    Builder setTopLeftCornerSize(CornerSize cornerSize);
    Builder setTopRightCorner(CornerTreatment cornerTreatment);
    Builder setTopRightCornerSize(float cornerSize);
    Builder setTopRightCornerSize(CornerSize cornerSize);
    Builder setBottomLeftCorner(CornerTreatment cornerTreatment);
    Builder setBottomLeftCornerSize(float cornerSize);
    Builder setBottomLeftCornerSize(CornerSize cornerSize);
    Builder setBottomRightCorner(CornerTreatment cornerTreatment);
    Builder setBottomRightCornerSize(float cornerSize);
    Builder setBottomRightCornerSize(CornerSize cornerSize);
    
    // Edge treatments
    Builder setAllEdges(EdgeTreatment edgeTreatment);
    Builder setTopEdge(EdgeTreatment topEdge);
    Builder setRightEdge(EdgeTreatment rightEdge);
    Builder setBottomEdge(EdgeTreatment bottomEdge);
    Builder setLeftEdge(EdgeTreatment leftEdge);
    
    // Build
    ShapeAppearanceModel build();
}

interface ShapeAppearanceModel.CornerSizeUnaryOperator {
    CornerSize apply(CornerSize cornerSize);
}

Usage Example

// Create basic rounded shape
ShapeAppearanceModel roundedShape = ShapeAppearanceModel.builder()
    .setAllCorners(CornerFamily.ROUNDED, 16f)
    .build();

// Create cut corner shape
ShapeAppearanceModel cutShape = ShapeAppearanceModel.builder()
    .setAllCorners(CornerFamily.CUT, 8f)
    .build();

// Mixed corner styles
ShapeAppearanceModel mixedShape = ShapeAppearanceModel.builder()
    .setTopLeftCorner(CornerFamily.ROUNDED, 16f)
    .setTopRightCorner(CornerFamily.ROUNDED, 16f)
    .setBottomLeftCorner(CornerFamily.CUT, 8f)
    .setBottomRightCorner(CornerFamily.CUT, 8f)
    .build();

// Pill shape (fully rounded)
ShapeAppearanceModel pillShape = ShapeAppearanceModel.builder()
    .setAllCorners(CornerFamily.ROUNDED, 50f) // 50% of height
    .build();

// Apply to MaterialCardView
MaterialCardView cardView = findViewById(R.id.card_view);
cardView.setShapeAppearanceModel(roundedShape);

// Apply to MaterialButton
MaterialButton button = findViewById(R.id.button);
button.setShapeAppearanceModel(pillShape);

// Transform existing shape (add 8dp to all corners)
ShapeAppearanceModel transformedShape = existingShape.withTransformedCornerSizes(
    cornerSize -> new AbsoluteCornerSize(cornerSize.getCornerSize(bounds) + 8f)
);

Material Shape Drawable

Drawable that renders Material Design shapes with fill, stroke, and elevation.

class MaterialShapeDrawable extends Drawable {
    // Constructors
    MaterialShapeDrawable();
    MaterialShapeDrawable(ShapeAppearanceModel shapeAppearanceModel);
    MaterialShapeDrawable(MaterialShapeDrawableState drawableState);
    
    // Factory methods with elevation overlay
    static MaterialShapeDrawable createWithElevationOverlay(Context context);
    static MaterialShapeDrawable createWithElevationOverlay(Context context, float elevation);
    
    // Shape appearance
    void setShapeAppearanceModel(ShapeAppearanceModel shapeAppearanceModel);
    ShapeAppearanceModel getShapeAppearanceModel();
    
    // Fill color
    void setFillColor(ColorStateList fillColor);
    ColorStateList getFillColor();
    
    // Stroke
    void setStroke(float strokeWidth, @ColorInt int strokeColor);
    void setStroke(float strokeWidth, ColorStateList strokeColor);
    float getStrokeWidth();
    ColorStateList getStrokeColor();
    
    // Elevation and shadow
    void setElevation(float elevation);
    float getElevation();
    void setShadowColor(@ColorInt int shadowColor);
    int getShadowColor();
    void setUseTintColorForShadow(boolean useTintColorForShadow);
    boolean isUseTintColorForShadow();
    void setShadowCompatibilityMode(int mode);
    int getShadowCompatibilityMode();
    
    // Paint style
    void setPaintStyle(Paint.Style style);
    Paint.Style getPaintStyle();
    
    // Interpolation for animations
    void setInterpolation(float interpolation);
    float getInterpolation();
    
    // Parent elevation for relative shadows
    void setParentAbsoluteElevation(float parentAbsoluteElevation);
    float getParentAbsoluteElevation();
}

Shadow Compatibility Mode Constants

public static final int SHADOW_COMPAT_MODE_DEFAULT = 0;
public static final int SHADOW_COMPAT_MODE_ALWAYS = 1;
public static final int SHADOW_COMPAT_MODE_NEVER = 2;

Usage Example

// Create shape drawable with elevation
MaterialShapeDrawable shapeDrawable = MaterialShapeDrawable.createWithElevationOverlay(this, 8f);

// Configure shape
ShapeAppearanceModel shape = ShapeAppearanceModel.builder()
    .setAllCorners(CornerFamily.ROUNDED, 12f)
    .build();
shapeDrawable.setShapeAppearanceModel(shape);

// Configure colors
shapeDrawable.setFillColor(ColorStateList.valueOf(
    MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface)));
shapeDrawable.setStroke(2f, MaterialColors.getColor(this, 
    com.google.android.material.R.attr.colorOutline));

// Apply to view background
View customView = findViewById(R.id.custom_view);
customView.setBackground(shapeDrawable);

// Animate shape changes
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.addUpdateListener(animation -> {
    float progress = (float) animation.getAnimatedValue();
    shapeDrawable.setInterpolation(progress);
});
animator.start();

// Custom shape for specific use case
MaterialShapeDrawable buttonBackground = new MaterialShapeDrawable();
buttonBackground.setShapeAppearanceModel(ShapeAppearanceModel.builder()
    .setAllCorners(CornerFamily.ROUNDED, 20f)
    .build());
buttonBackground.setFillColor(ColorStateList.valueOf(primaryColor));
buttonBackground.setElevation(4f);

MaterialButton customButton = findViewById(R.id.custom_button);
customButton.setBackground(buttonBackground);

Corner Treatments and Sizes

Different corner styles and sizing approaches.

Corner Treatments

class RoundedCornerTreatment extends CornerTreatment {
    RoundedCornerTreatment();
    RoundedCornerTreatment(float radius);
}

class CutCornerTreatment extends CornerTreatment {
    CutCornerTreatment();
    CutCornerTreatment(float size);
}

Corner Sizes

interface CornerSize {
    float getCornerSize(RectF bounds);
}

class AbsoluteCornerSize implements CornerSize {
    AbsoluteCornerSize(float size);
    float getCornerSize(RectF bounds);
}

class RelativeCornerSize implements CornerSize {
    RelativeCornerSize(@FloatRange(from = 0.0f, to = 1.0f) float percent);
    float getCornerSize(RectF bounds);
}

Usage Example

// Absolute corner size (fixed pixels/dp)
CornerSize absoluteCorner = new AbsoluteCornerSize(16f); // 16dp corners

// Relative corner size (percentage of view size)  
CornerSize relativeCorner = new RelativeCornerSize(0.5f); // 50% = circular

// Custom corner treatments
CornerTreatment roundedCorner = new RoundedCornerTreatment(12f);
CornerTreatment cutCorner = new CutCornerTreatment(8f);

// Apply to shape
ShapeAppearanceModel customShape = ShapeAppearanceModel.builder()
    .setTopLeftCorner(roundedCorner)
    .setTopLeftCornerSize(absoluteCorner)
    .setBottomRightCorner(cutCorner)
    .setBottomRightCornerSize(relativeCorner)
    .build();

Elevation Overlay Provider

Provides elevation overlay colors for dark themes.

class ElevationOverlayProvider {
    ElevationOverlayProvider(Context context);
    
    // Overlay composition
    @ColorInt int compositeOverlayWithThemeSurfaceColorIfNeeded(float elevation);
    @ColorInt int compositeOverlayIfNeeded(@ColorInt int backgroundColor, float elevation);
    @ColorInt int compositeOverlay(@ColorInt int backgroundColor, float elevation);
    
    // Overlay alpha calculation
    int calculateOverlayAlpha(float elevation);
    
    // Theme colors
    @ColorInt int getThemeSurfaceColor();
    @ColorInt int getThemeElevationOverlayColor();
    boolean isThemeElevationOverlayEnabled();
}

Usage Example

ElevationOverlayProvider elevationProvider = new ElevationOverlayProvider(this);

// Get surface color with elevation overlay
int surfaceColor = elevationProvider.getThemeSurfaceColor();
int elevatedSurfaceColor = elevationProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(8f);

// Apply to custom view background
View elevatedView = findViewById(R.id.elevated_view);
elevatedView.setBackgroundColor(elevatedSurfaceColor);

// Custom elevation overlay
int customColor = Color.parseColor("#121212"); // Dark surface
int overlayColor = elevationProvider.compositeOverlay(customColor, 16f);

Material Resources

Utility methods for accessing Material Design resources and attributes.

class MaterialResources {
    // ColorStateList from attributes
    static ColorStateList getColorStateList(Context context, TypedArray attributes, @StyleableRes int index);
    static ColorStateList getColorStateList(Context context, @ColorRes int colorRes);
    
    // Drawable from attributes
    static Drawable getDrawable(Context context, TypedArray attributes, @StyleableRes int index);
    
    // Text appearance from attributes
    static TextAppearance getTextAppearance(Context context, TypedArray attributes, @StyleableRes int index);
    
    // Dimension from attributes
    static int getDimensionPixelSize(Context context, TypedArray attributes, @StyleableRes int index, int defaultValue);
    
    // Boolean and integer resources
    static boolean getBoolean(Context context, @BoolRes int boolRes, boolean defaultValue);
    static int getInteger(Context context, @IntegerRes int integerRes, int defaultValue);
}

Typography Utils

Utilities for applying Material Design typography.

class TypographyUtils {
    // Apply text appearance to TextView
    static void applyTypography(TextView textView, TextAppearance textAppearance);
    
    // Resolve text appearance from style resource
    static TextAppearance resolveTextAppearance(Context context, @StyleRes int textAppearanceStyleRes);
}

Complete Theming Example

Example showing comprehensive Material theming implementation:

public class ThemingExampleActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Apply dynamic colors if available
        if (DynamicColors.isDynamicColorAvailable()) {
            DynamicColors.applyToActivityIfAvailable(this);
        }
        
        setContentView(R.layout.activity_theming_example);
        
        setupCustomTheming();
        setupShapeTheming();
        setupElevationTheming();
    }
    
    private void setupCustomTheming() {
        // Get theme colors
        int primaryColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimary);
        int surfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface);
        int onSurfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface);
        
        // Apply colors to custom views
        View headerView = findViewById(R.id.header_view);
        headerView.setBackgroundColor(primaryColor);
        
        TextView titleText = findViewById(R.id.title_text);
        titleText.setTextColor(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnPrimary));
        
        // Create layered color for subtle accent
        int accentColor = MaterialColors.layer(surfaceColor, primaryColor, 0.12f);
        View accentView = findViewById(R.id.accent_view);
        accentView.setBackgroundColor(accentColor);
        
        // Dynamic text color based on background
        boolean isLightBackground = MaterialColors.isColorLight(surfaceColor);
        int adaptiveTextColor = isLightBackground ? 
            MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface) :
            MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface);
        
        TextView bodyText = findViewById(R.id.body_text);
        bodyText.setTextColor(adaptiveTextColor);
    }
    
    private void setupShapeTheming() {
        // Card with custom shape
        MaterialCardView cardView = findViewById(R.id.themed_card);
        ShapeAppearanceModel cardShape = ShapeAppearanceModel.builder()
            .setTopLeftCorner(CornerFamily.ROUNDED, 16f)
            .setTopRightCorner(CornerFamily.ROUNDED, 16f)
            .setBottomLeftCorner(CornerFamily.CUT, 8f)
            .setBottomRightCorner(CornerFamily.CUT, 8f)
            .build();
        cardView.setShapeAppearanceModel(cardShape);
        
        // Button with pill shape
        MaterialButton pillButton = findViewById(R.id.pill_button);
        ShapeAppearanceModel pillShape = ShapeAppearanceModel.builder()
            .setAllCorners(CornerFamily.ROUNDED, 50f)
            .build();
        pillButton.setShapeAppearanceModel(pillShape);
        
        // Image with custom shape
        ShapeableImageView imageView = findViewById(R.id.shaped_image);
        ShapeAppearanceModel imageShape = ShapeAppearanceModel.builder()
            .setAllCorners(CornerFamily.ROUNDED, 12f)
            .build();
        imageView.setShapeAppearanceModel(imageShape);
        imageView.setStrokeWidth(2f);
        imageView.setStrokeColor(ColorStateList.valueOf(
            MaterialColors.getColor(this, com.google.android.material.R.attr.colorOutline)));
        
        // Custom drawable with shape
        MaterialShapeDrawable customDrawable = new MaterialShapeDrawable();
        customDrawable.setShapeAppearanceModel(ShapeAppearanceModel.builder()
            .setAllCorners(CornerFamily.ROUNDED, 8f)
            .build());
        customDrawable.setFillColor(ColorStateList.valueOf(
            MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceVariant)));
        customDrawable.setStroke(1f, MaterialColors.getColor(this, 
            com.google.android.material.R.attr.colorOutline));
        
        View customView = findViewById(R.id.custom_shaped_view);
        customView.setBackground(customDrawable);
    }
    
    private void setupElevationTheming() {
        ElevationOverlayProvider elevationProvider = new ElevationOverlayProvider(this);
        
        // Apply elevation overlays to views
        View[] elevatedViews = {
            findViewById(R.id.elevation_2dp),
            findViewById(R.id.elevation_4dp),
            findViewById(R.id.elevation_8dp),
            findViewById(R.id.elevation_16dp)
        };
        
        float[] elevations = {2f, 4f, 8f, 16f};
        
        for (int i = 0; i < elevatedViews.length; i++) {
            View view = elevatedViews[i];
            float elevation = elevations[i];
            
            // Create elevated background
            MaterialShapeDrawable background = MaterialShapeDrawable.createWithElevationOverlay(this, elevation);
            background.setShapeAppearanceModel(ShapeAppearanceModel.builder()
                .setAllCorners(CornerFamily.ROUNDED, 8f)
                .build());
            
            view.setBackground(background);
            view.setElevation(elevation);
            
            // Add elevation text
            TextView elevationText = view.findViewById(R.id.elevation_text);
            if (elevationText != null) {
                elevationText.setText(String.format("%.0fdp", elevation));
            }
        }
        
        // Animated elevation change
        MaterialButton elevationButton = findViewById(R.id.elevation_button);
        elevationButton.setOnClickListener(v -> animateElevation(v));
    }
    
    private void animateElevation(View view) {
        float startElevation = view.getElevation();
        float endElevation = startElevation == 2f ? 16f : 2f;
        
        ValueAnimator elevationAnimator = ValueAnimator.ofFloat(startElevation, endElevation);
        elevationAnimator.setDuration(300);
        elevationAnimator.addUpdateListener(animation -> {
            float elevation = (float) animation.getAnimatedValue();
            view.setElevation(elevation);
            
            // Update background overlay
            ElevationOverlayProvider provider = new ElevationOverlayProvider(this);
            int overlayColor = provider.compositeOverlayWithThemeSurfaceColorIfNeeded(elevation);
            view.setBackgroundColor(overlayColor);
        });
        elevationAnimator.start();
    }
    
    // Theme switching example
    private void switchToCustomTheme() {
        // Save current theme preference
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        prefs.edit().putString("theme", "custom").apply();
        
        // Recreate activity to apply new theme
        recreate();
    }
}

// Application class for global theming setup
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        
        // Enable dynamic colors globally
        DynamicColors.applyToActivitiesIfAvailable(this, new DynamicColorsOptions.Builder()
            .setOnAppliedCallback(options -> {
                Log.d("DynamicColors", "Dynamic colors applied successfully");
            })
            .setPrecondition((activity, theme) -> {
                // Only apply to certain activities or themes
                return !activity.getClass().getSimpleName().equals("SplashActivity");
            })
            .build());
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-google-android-material--material

docs

buttons-and-selection.md

feedback-and-communication.md

index.md

input-and-forms.md

layout-and-containers.md

navigation-components.md

pickers-and-selection.md

theming-and-styling.md

tile.json