Feat: Add carousel view theme (#164769)

Feat: Add carousel view theme
fixes: #159679 

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
This commit is contained in:
Kishan Rathore 2025-04-17 00:40:38 +05:30 committed by GitHub
parent 909aeccfe4
commit ddc95409bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 466 additions and 9 deletions

View File

@ -47,6 +47,7 @@ export 'src/material/calendar_date_picker.dart';
export 'src/material/card.dart';
export 'src/material/card_theme.dart';
export 'src/material/carousel.dart';
export 'src/material/carousel_theme.dart';
export 'src/material/checkbox.dart';
export 'src/material/checkbox_list_tile.dart';
export 'src/material/checkbox_theme.dart';

View File

@ -12,6 +12,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'carousel_theme.dart';
import 'color_scheme.dart';
import 'colors.dart';
import 'ink_well.dart';
import 'material.dart';
@ -401,25 +403,30 @@ class _CarouselViewState extends State<CarouselView> {
}
}
Widget _buildCarouselItem(ThemeData theme, int index) {
final EdgeInsets effectivePadding = widget.padding ?? const EdgeInsets.all(4.0);
Widget _buildCarouselItem(int index) {
final CarouselViewThemeData carouselTheme = CarouselViewTheme.of(context);
final ColorScheme colorScheme = ColorScheme.of(context);
final EdgeInsets effectivePadding =
widget.padding ?? carouselTheme.padding ?? const EdgeInsets.all(4.0);
final Color effectiveBackgroundColor =
widget.backgroundColor ?? Theme.of(context).colorScheme.surface;
final double effectiveElevation = widget.elevation ?? 0.0;
widget.backgroundColor ?? carouselTheme.backgroundColor ?? colorScheme.surface;
final double effectiveElevation = widget.elevation ?? carouselTheme.elevation ?? 0.0;
final ShapeBorder effectiveShape =
widget.shape ??
carouselTheme.shape ??
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0)));
final WidgetStateProperty<Color?> effectiveOverlayColor =
widget.overlayColor ??
carouselTheme.overlayColor ??
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
if (states.contains(WidgetState.pressed)) {
return theme.colorScheme.onSurface.withOpacity(0.1);
return colorScheme.onSurface.withOpacity(0.1);
}
if (states.contains(WidgetState.hovered)) {
return theme.colorScheme.onSurface.withOpacity(0.08);
return colorScheme.onSurface.withOpacity(0.08);
}
if (states.contains(WidgetState.focused)) {
return theme.colorScheme.onSurface.withOpacity(0.1);
return colorScheme.onSurface.withOpacity(0.1);
}
return null;
});
@ -461,7 +468,7 @@ class _CarouselViewState extends State<CarouselView> {
itemExtent: _itemExtent!,
minExtent: widget.shrinkExtent,
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return _buildCarouselItem(theme, index);
return _buildCarouselItem(index);
}, childCount: widget.children.length),
);
}
@ -475,7 +482,7 @@ class _CarouselViewState extends State<CarouselView> {
shrinkExtent: widget.shrinkExtent,
weights: _flexWeights!,
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return _buildCarouselItem(theme, index);
return _buildCarouselItem(index);
}, childCount: widget.children.length),
);
}

View File

@ -0,0 +1,183 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'carousel.dart';
import 'material.dart';
import 'theme.dart';
/// Defines default property values for descendant [CarouselView] widgets.
///
/// Descendant widgets obtain the current [CarouselViewThemeData] object using
/// `CarouselViewTheme.of(context)`. Instances of [CarouselViewThemeData] can be
/// customized with [CarouselViewThemeData.copyWith].
///
/// Typically a [CarouselViewThemeData] is specified as part of the overall [Theme]
/// with [ThemeData.carouselViewTheme].
///
/// All [CarouselViewThemeData] properties are `null` by default. When null, the [CarouselView]
/// will provide its own defaults.
///
/// See also:
///
/// * [CarouselViewTheme], an [InheritedWidget] that propagates the theme to its descendants.
/// * [ThemeData], which describes the overall theme information for the application.
@immutable
class CarouselViewThemeData with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.carouselViewTheme].
const CarouselViewThemeData({
this.elevation,
this.backgroundColor,
this.overlayColor,
this.shape,
this.padding,
});
/// The amount of space to surround each carousel item with.
///
/// Overrides the default value for [CarouselView.padding].
final EdgeInsets? padding;
/// The background color for each carousel item.
///
/// Overrides the default value for [CarouselView.backgroundColor].
final Color? backgroundColor;
/// The z-coordinate of each carousel item.
///
/// This controls the size of the shadow below the carousel.
///
/// Overrides the default value for [CarouselView.elevation].
final double? elevation;
/// The shape of the carousel item's [Material].
///
/// Overrides the default value for [CarouselView.shape].
final OutlinedBorder? shape;
/// The highlight color to indicate the carousel items are in pressed, hovered
/// or focused states.
///
/// Overrides the default value for [CarouselView.overlayColor].
final WidgetStateProperty<Color?>? overlayColor;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
CarouselViewThemeData copyWith({
Color? backgroundColor,
double? elevation,
OutlinedBorder? shape,
WidgetStateProperty<Color?>? overlayColor,
EdgeInsets? padding,
}) {
return CarouselViewThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
elevation: elevation ?? this.elevation,
shape: shape ?? this.shape,
overlayColor: overlayColor ?? this.overlayColor,
padding: padding ?? this.padding,
);
}
/// Linearly interpolate between two carousel themes.
///
/// {@macro dart.ui.shadow.lerp}
static CarouselViewThemeData lerp(CarouselViewThemeData? a, CarouselViewThemeData? b, double t) {
if (identical(a, b) && a != null) {
return a;
}
return CarouselViewThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t) as OutlinedBorder?,
overlayColor: WidgetStateProperty.lerp<Color?>(
a?.overlayColor,
b?.overlayColor,
t,
Color.lerp,
),
padding: EdgeInsets.lerp(a?.padding, b?.padding, t),
);
}
@override
int get hashCode => Object.hash(backgroundColor, elevation, shape, overlayColor, padding);
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is CarouselViewThemeData &&
other.backgroundColor == backgroundColor &&
other.elevation == elevation &&
other.shape == shape &&
other.overlayColor == overlayColor &&
other.padding == padding;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
properties.add(DiagnosticsProperty<OutlinedBorder>('shape', shape, defaultValue: null));
properties.add(
DiagnosticsProperty<WidgetStateProperty<Color?>>(
'overlayColor',
overlayColor,
defaultValue: null,
),
);
properties.add(DiagnosticsProperty<EdgeInsets>('padding', padding, defaultValue: null));
}
}
/// Applies a carousel theme to descendant [CarouselView] widgets.
///
/// Descendant widgets obtain the current theme's [CarouselViewThemeData] using
/// [CarouselViewTheme.of]. When a widget uses [CarouselViewTheme.of], it is automatically
/// rebuilt if the theme later changes.
///
/// A carousel theme can be specified as part of the overall Material theme using
/// [ThemeData.carouselViewTheme].
///
/// See also:
///
/// * [CarouselViewThemeData], which describes the actual configuration of a carousel
/// theme.
/// * [Theme], which controls the overall theme inheritance.
class CarouselViewTheme extends InheritedTheme {
/// Creates a carousel theme that configures all descendant [CarouselView] widgets.
const CarouselViewTheme({super.key, required this.data, required super.child});
/// The properties for descendant carousel widgets.
final CarouselViewThemeData data;
/// Returns the configuration [data] from the closest [CarouselViewTheme] ancestor.
///
/// If there is no ancestor, it returns [ThemeData.carouselViewTheme].
static CarouselViewThemeData of(BuildContext context) {
final CarouselViewTheme? inheritedTheme =
context.dependOnInheritedWidgetOfExactType<CarouselViewTheme>();
return inheritedTheme?.data ?? Theme.of(context).carouselViewTheme;
}
/// Wraps the given [child] with a [CarouselViewTheme] containing the [data].
@override
Widget wrap(BuildContext context, Widget child) {
return CarouselViewTheme(data: data, child: child);
}
/// Returns true if the [data] fields of the two themes are different.
@override
bool updateShouldNotify(CarouselViewTheme oldWidget) => data != oldWidget.data;
}

View File

@ -21,6 +21,7 @@ import 'bottom_sheet_theme.dart';
import 'button_bar_theme.dart';
import 'button_theme.dart';
import 'card_theme.dart';
import 'carousel_theme.dart';
import 'checkbox_theme.dart';
import 'chip_theme.dart';
import 'color_scheme.dart';
@ -324,6 +325,7 @@ class ThemeData with Diagnosticable {
BottomSheetThemeData? bottomSheetTheme,
ButtonThemeData? buttonTheme,
CardThemeData? cardTheme,
CarouselViewThemeData? carouselViewTheme,
CheckboxThemeData? checkboxTheme,
ChipThemeData? chipTheme,
DataTableThemeData? dataTableTheme,
@ -528,6 +530,7 @@ class ThemeData with Diagnosticable {
bottomNavigationBarTheme ??= const BottomNavigationBarThemeData();
bottomSheetTheme ??= const BottomSheetThemeData();
cardTheme ??= const CardThemeData();
carouselViewTheme ??= const CarouselViewThemeData();
checkboxTheme ??= const CheckboxThemeData();
chipTheme ??= const ChipThemeData();
dataTableTheme ??= const DataTableThemeData();
@ -622,6 +625,7 @@ class ThemeData with Diagnosticable {
bottomSheetTheme: bottomSheetTheme,
buttonTheme: buttonTheme,
cardTheme: cardTheme,
carouselViewTheme: carouselViewTheme,
checkboxTheme: checkboxTheme,
chipTheme: chipTheme,
dataTableTheme: dataTableTheme,
@ -733,6 +737,7 @@ class ThemeData with Diagnosticable {
required this.bottomSheetTheme,
required this.buttonTheme,
required this.cardTheme,
required this.carouselViewTheme,
required this.checkboxTheme,
required this.chipTheme,
required this.dataTableTheme,
@ -1305,6 +1310,9 @@ class ThemeData with Diagnosticable {
/// This is the value returned from [CardTheme.of].
final CardThemeData cardTheme;
/// A theme for customizing the appearance and layout of [CarouselView] widgets.
final CarouselViewThemeData carouselViewTheme;
/// A theme for customizing the appearance and layout of [Checkbox] widgets.
final CheckboxThemeData checkboxTheme;
@ -1516,6 +1524,7 @@ class ThemeData with Diagnosticable {
BottomSheetThemeData? bottomSheetTheme,
ButtonThemeData? buttonTheme,
CardThemeData? cardTheme,
CarouselViewThemeData? carouselViewTheme,
CheckboxThemeData? checkboxTheme,
ChipThemeData? chipTheme,
DataTableThemeData? dataTableTheme,
@ -1634,6 +1643,7 @@ class ThemeData with Diagnosticable {
bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme,
buttonTheme: buttonTheme ?? this.buttonTheme,
cardTheme: cardTheme ?? this.cardTheme,
carouselViewTheme: carouselViewTheme ?? this.carouselViewTheme,
checkboxTheme: checkboxTheme ?? this.checkboxTheme,
chipTheme: chipTheme ?? this.chipTheme,
dataTableTheme: dataTableTheme ?? this.dataTableTheme,
@ -1954,6 +1964,7 @@ class ThemeData with Diagnosticable {
bottomSheetTheme: BottomSheetThemeData.lerp(a.bottomSheetTheme, b.bottomSheetTheme, t)!,
buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme,
cardTheme: CardThemeData.lerp(a.cardTheme, b.cardTheme, t),
carouselViewTheme: CarouselViewThemeData.lerp(a.carouselViewTheme, b.carouselViewTheme, t),
checkboxTheme: CheckboxThemeData.lerp(a.checkboxTheme, b.checkboxTheme, t),
chipTheme: ChipThemeData.lerp(a.chipTheme, b.chipTheme, t)!,
dataTableTheme: DataTableThemeData.lerp(a.dataTableTheme, b.dataTableTheme, t),
@ -2072,6 +2083,7 @@ class ThemeData with Diagnosticable {
other.bottomSheetTheme == bottomSheetTheme &&
other.buttonTheme == buttonTheme &&
other.cardTheme == cardTheme &&
other.carouselViewTheme == carouselViewTheme &&
other.checkboxTheme == checkboxTheme &&
other.chipTheme == chipTheme &&
other.dataTableTheme == dataTableTheme &&
@ -2171,6 +2183,7 @@ class ThemeData with Diagnosticable {
bottomSheetTheme,
buttonTheme,
cardTheme,
carouselViewTheme,
checkboxTheme,
chipTheme,
dataTableTheme,
@ -2549,6 +2562,14 @@ class ThemeData with Diagnosticable {
properties.add(
DiagnosticsProperty<CardThemeData>('cardTheme', cardTheme, level: DiagnosticLevel.debug),
);
properties.add(
DiagnosticsProperty<CarouselViewThemeData>(
'carouselViewTheme',
carouselViewTheme,
defaultValue: defaultData.carouselViewTheme,
level: DiagnosticLevel.debug,
),
);
properties.add(
DiagnosticsProperty<CheckboxThemeData>(
'checkboxTheme',

View File

@ -0,0 +1,242 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('CarouselViewThemeData copyWith, ==, hashCode basics', () {
expect(const CarouselViewThemeData(), const CarouselViewThemeData().copyWith());
expect(
const CarouselViewThemeData().hashCode,
const CarouselViewThemeData().copyWith().hashCode,
);
});
test('CarouselViewThemeData null fields by default', () {
const CarouselViewThemeData carouselViewTheme = CarouselViewThemeData();
expect(carouselViewTheme.backgroundColor, null);
expect(carouselViewTheme.elevation, null);
expect(carouselViewTheme.overlayColor, null);
expect(carouselViewTheme.padding, null);
expect(carouselViewTheme.shape, null);
});
testWidgets('Default CarouselViewThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const CarouselViewThemeData().debugFillProperties(builder);
final List<String> description =
builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('CarouselViewThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const CarouselViewThemeData(
backgroundColor: Color(0xFFFFFFFF),
elevation: 5.0,
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(),
overlayColor: MaterialStatePropertyAll<Color>(Colors.red),
).debugFillProperties(builder);
final List<String> description =
builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'backgroundColor: ${const Color(0xffffffff)}',
'elevation: 5.0',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
'overlayColor: WidgetStatePropertyAll(${Colors.red})',
'padding: EdgeInsets.zero',
]);
});
testWidgets('Uses value from CarouselViewThemeData', (WidgetTester tester) async {
final CarouselViewThemeData carouselViewTheme = _carouselViewThemeData();
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(carouselViewTheme: carouselViewTheme),
home: const Scaffold(
body: Center(
child: CarouselView(
itemExtent: 100,
children: <Widget>[SizedBox(width: 100, height: 100)],
),
),
),
),
);
expect(find.byType(CarouselView), findsOneWidget);
final Finder padding = find.descendant(
of: find.byType(CarouselView),
matching: find.byWidgetPredicate(
(Widget widget) => widget is Padding && widget.child is Material,
),
);
expect(padding, findsOneWidget);
final Padding paddingWidget = tester.widget<Padding>(padding);
final Material material = paddingWidget.child! as Material;
final InkWell inkWell = tester.widget<InkWell>(
find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
);
expect(paddingWidget.padding, carouselViewTheme.padding);
expect(material.color, carouselViewTheme.backgroundColor);
expect(material.elevation, carouselViewTheme.elevation);
expect(material.shape, carouselViewTheme.shape);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.antiAlias);
expect(inkWell.overlayColor, carouselViewTheme.overlayColor);
});
testWidgets('Widgets properties override theme', (WidgetTester tester) async {
final CarouselViewThemeData carouselViewTheme = _carouselViewThemeData();
const Color backgroundColor = Color(0xFFFF0000);
const double elevation = 10.0;
const EdgeInsets padding = EdgeInsets.all(15.0);
const OutlinedBorder shape = RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
);
const WidgetStateProperty<Color?> overlayColor = MaterialStatePropertyAll<Color>(Colors.green);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(carouselViewTheme: carouselViewTheme),
home: const Scaffold(
body: Center(
child: CarouselView(
backgroundColor: backgroundColor,
elevation: elevation,
padding: padding,
shape: shape,
overlayColor: overlayColor,
itemExtent: 100,
children: <Widget>[SizedBox(width: 100, height: 100)],
),
),
),
),
);
expect(find.byType(CarouselView), findsOneWidget);
final Finder paddingFinder = find.descendant(
of: find.byType(CarouselView),
matching: find.byWidgetPredicate(
(Widget widget) => widget is Padding && widget.child is Material,
),
);
expect(paddingFinder, findsOneWidget);
final Padding paddingWidget = tester.widget<Padding>(paddingFinder);
final Material material = paddingWidget.child! as Material;
final InkWell inkWell = tester.widget<InkWell>(
find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
);
expect(paddingWidget.padding, padding);
expect(material.color, backgroundColor);
expect(material.elevation, elevation);
expect(material.shape, shape);
expect(inkWell.overlayColor, overlayColor);
});
testWidgets('CarouselViewTheme can override Theme.carouselViewTheme', (
WidgetTester tester,
) async {
const Color globalBackgroundColor = Color(0xfffffff1);
const Color globalOverlayColor = Color(0xff000000);
const double globalElevation = 5.0;
const EdgeInsets globalPadding = EdgeInsets.all(10.0);
const OutlinedBorder globalShape = RoundedRectangleBorder();
const Color localBackgroundColor = Color(0xffff0000);
const Color localOverlayColor = Color(0xffffffff);
const double localElevation = 10.0;
const EdgeInsets localPadding = EdgeInsets.all(15.0);
const OutlinedBorder localShape = RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
carouselViewTheme: const CarouselViewThemeData(
backgroundColor: globalBackgroundColor,
overlayColor: MaterialStatePropertyAll<Color>(globalOverlayColor),
elevation: globalElevation,
padding: globalPadding,
shape: globalShape,
),
),
home: const Scaffold(
body: Center(
child: CarouselViewTheme(
data: CarouselViewThemeData(
backgroundColor: localBackgroundColor,
overlayColor: MaterialStatePropertyAll<Color>(localOverlayColor),
elevation: localElevation,
padding: localPadding,
shape: localShape,
),
child: CarouselView(
itemExtent: 100,
children: <Widget>[SizedBox(width: 100, height: 100)],
),
),
),
),
),
);
final Finder padding = find.descendant(
of: find.byType(CarouselView),
matching: find.byWidgetPredicate(
(Widget widget) => widget is Padding && widget.child is Material,
),
);
expect(padding, findsOneWidget);
final Padding paddingWidget = tester.widget<Padding>(padding);
final Material material = paddingWidget.child! as Material;
final InkWell inkWell = tester.widget<InkWell>(
find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
);
expect(paddingWidget.padding, localPadding);
expect(material.color, localBackgroundColor);
expect(material.elevation, localElevation);
expect(material.shape, localShape);
expect(inkWell.overlayColor?.resolve(<MaterialState>{}), localOverlayColor);
});
}
CarouselViewThemeData _carouselViewThemeData() {
const Color backgroundColor = Color(0xFF0000FF);
const double elevation = 5.0;
const EdgeInsets padding = EdgeInsets.all(10.0);
const OutlinedBorder shape = RoundedRectangleBorder();
const WidgetStateProperty<Color?> overlayColor = MaterialStatePropertyAll<Color>(Colors.red);
return const CarouselViewThemeData(
backgroundColor: backgroundColor,
elevation: elevation,
padding: padding,
shape: shape,
overlayColor: overlayColor,
);
}

View File

@ -1339,6 +1339,7 @@ void main() {
bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.black),
buttonTheme: const ButtonThemeData(colorScheme: ColorScheme.dark()),
cardTheme: const CardThemeData(color: Colors.black),
carouselViewTheme: const CarouselViewThemeData(),
checkboxTheme: const CheckboxThemeData(),
chipTheme: chipTheme,
dataTableTheme: const DataTableThemeData(),
@ -1467,6 +1468,7 @@ void main() {
bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.white),
buttonTheme: const ButtonThemeData(colorScheme: ColorScheme.light()),
cardTheme: const CardThemeData(color: Colors.white),
carouselViewTheme: const CarouselViewThemeData(),
checkboxTheme: const CheckboxThemeData(),
chipTheme: otherChipTheme,
dataTableTheme: const DataTableThemeData(),
@ -1807,6 +1809,7 @@ void main() {
'bottomSheetTheme',
'buttonTheme',
'cardTheme',
'carouselViewTheme',
'checkboxTheme',
'chipTheme',
'dataTableTheme',