]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Tooltip specific scriptable context (#8561)
authorEvert Timberg <evert.timberg+github@gmail.com>
Thu, 4 Mar 2021 13:25:24 +0000 (08:25 -0500)
committerGitHub <noreply@github.com>
Thu, 4 Mar 2021 13:25:24 +0000 (08:25 -0500)
* Update plugin to use it's own tooltip context

* Scriptable tooltip option types

* Tests

* Update types to use UnionToIntersection

* Update TooltipItem to use UnionToIntersection

src/plugins/plugin.tooltip.js
test/specs/plugin.tooltip.tests.js
types/index.esm.d.ts
types/tests/plugins/plugin.tooltip/tooltip_scriptable_background_color.ts [new file with mode: 0644]

index 7adcd2604e514a07e3c8bc96d5f3d04332ff4030..16aef128d7e5c4e69dee319d8fef3569d9b7d758 100644 (file)
@@ -136,9 +136,9 @@ function createTooltipItem(chart, item) {
 /**
  * Get the size of the tooltip
  */
-function getTooltipSize(tooltip) {
+function getTooltipSize(tooltip, options) {
   const ctx = tooltip._chart.ctx;
-  const {body, footer, options, title} = tooltip;
+  const {body, footer, title} = tooltip;
   const {bodyFont, footerFont, titleFont, boxWidth, boxHeight} = options;
   const titleLineCount = title.length;
   const footerLineCount = footer.length;
@@ -322,8 +322,7 @@ function getBackgroundPoint(options, size, alignment, chart) {
   return {x, y};
 }
 
-function getAlignedX(tooltip, align) {
-  const options = tooltip.options;
+function getAlignedX(tooltip, align, options) {
   const padding = toPadding(options.padding);
 
   return align === 'center'
@@ -340,6 +339,14 @@ function getBeforeAfterBodyLines(callback) {
   return pushOrConcat([], splitNewlines(callback));
 }
 
+function createTooltipContext(parent, tooltip, tooltipItems) {
+  return Object.assign(Object.create(parent), {
+    tooltip,
+    tooltipItems,
+    type: 'tooltip'
+  });
+}
+
 export class Tooltip extends Element {
   constructor(config) {
     super();
@@ -350,7 +357,9 @@ export class Tooltip extends Element {
     this._eventPosition = undefined;
     this._size = undefined;
     this._cachedAnimations = undefined;
+    this._tooltipItems = [];
     this.$animations = undefined;
+    this.$context = undefined;
     this.options = config.options;
     this.dataPoints = undefined;
     this.title = undefined;
@@ -374,6 +383,7 @@ export class Tooltip extends Element {
   initialize(options) {
     this.options = options;
     this._cachedAnimations = undefined;
+    this.$context = undefined;
   }
 
   /**
@@ -388,7 +398,7 @@ export class Tooltip extends Element {
     }
 
     const chart = me._chart;
-    const options = me.options;
+    const options = me.options.setContext(me.getContext());
     const opts = options.enabled && chart.options.animation && options.animations;
     const animations = new Animations(me._chart, opts);
     if (opts._cacheable) {
@@ -398,10 +408,18 @@ export class Tooltip extends Element {
     return animations;
   }
 
-  getTitle(context) {
+  /**
+        * @protected
+        */
+  getContext() {
+    const me = this;
+    return me.$context ||
+                       (me.$context = createTooltipContext(me._chart.getContext(), me, me._tooltipItems));
+  }
+
+  getTitle(context, options) {
     const me = this;
-    const opts = me.options;
-    const callbacks = opts.callbacks;
+    const {callbacks} = options;
 
     const beforeTitle = callbacks.beforeTitle.apply(me, [context]);
     const title = callbacks.title.apply(me, [context]);
@@ -415,13 +433,13 @@ export class Tooltip extends Element {
     return lines;
   }
 
-  getBeforeBody(tooltipItems) {
-    return getBeforeAfterBodyLines(this.options.callbacks.beforeBody.apply(this, [tooltipItems]));
+  getBeforeBody(tooltipItems, options) {
+    return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems]));
   }
 
-  getBody(tooltipItems) {
+  getBody(tooltipItems, options) {
     const me = this;
-    const callbacks = me.options.callbacks;
+    const {callbacks} = options;
     const bodyItems = [];
 
     each(tooltipItems, (context) => {
@@ -440,14 +458,14 @@ export class Tooltip extends Element {
     return bodyItems;
   }
 
-  getAfterBody(tooltipItems) {
-    return getBeforeAfterBodyLines(this.options.callbacks.afterBody.apply(this, [tooltipItems]));
+  getAfterBody(tooltipItems, options) {
+    return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems]));
   }
 
   // Get the footer and beforeFooter and afterFooter lines
-  getFooter(tooltipItems) {
+  getFooter(tooltipItems, options) {
     const me = this;
-    const callbacks = me.options.callbacks;
+    const {callbacks} = options;
 
     const beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]);
     const footer = callbacks.footer.apply(me, [tooltipItems]);
@@ -464,10 +482,9 @@ export class Tooltip extends Element {
   /**
         * @private
         */
-  _createItems() {
+  _createItems(options) {
     const me = this;
     const active = me._active;
-    const options = me.options;
     const data = me._chart.data;
     const labelColors = [];
     const labelPointStyles = [];
@@ -505,9 +522,10 @@ export class Tooltip extends Element {
 
   update(changed) {
     const me = this;
-    const options = me.options;
+    const options = me.options.setContext(me.getContext());
     const active = me._active;
     let properties;
+    let tooltipItems = [];
 
     if (!active.length) {
       if (me.opacity !== 0) {
@@ -517,15 +535,15 @@ export class Tooltip extends Element {
       }
     } else {
       const position = positioners[options.position].call(me, active, me._eventPosition);
-      const tooltipItems = me._createItems();
+      tooltipItems = me._createItems(options);
 
-      me.title = me.getTitle(tooltipItems);
-      me.beforeBody = me.getBeforeBody(tooltipItems);
-      me.body = me.getBody(tooltipItems);
-      me.afterBody = me.getAfterBody(tooltipItems);
-      me.footer = me.getFooter(tooltipItems);
+      me.title = me.getTitle(tooltipItems, options);
+      me.beforeBody = me.getBeforeBody(tooltipItems, options);
+      me.body = me.getBody(tooltipItems, options);
+      me.afterBody = me.getAfterBody(tooltipItems, options);
+      me.footer = me.getFooter(tooltipItems, options);
 
-      const size = me._size = getTooltipSize(me);
+      const size = me._size = getTooltipSize(me, options);
       const positionAndSize = Object.assign({}, position, size);
       const alignment = determineAlignment(me._chart, options, positionAndSize);
       const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart);
@@ -544,6 +562,9 @@ export class Tooltip extends Element {
       };
     }
 
+    me._tooltipItems = tooltipItems;
+    me.$context = undefined;
+
     if (properties) {
       me._resolveAnimations().update(me, properties);
     }
@@ -553,16 +574,16 @@ export class Tooltip extends Element {
     }
   }
 
-  drawCaret(tooltipPoint, ctx, size) {
-    const caretPosition = this.getCaretPosition(tooltipPoint, size);
+  drawCaret(tooltipPoint, ctx, size, options) {
+    const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
 
     ctx.lineTo(caretPosition.x1, caretPosition.y1);
     ctx.lineTo(caretPosition.x2, caretPosition.y2);
     ctx.lineTo(caretPosition.x3, caretPosition.y3);
   }
 
-  getCaretPosition(tooltipPoint, size) {
-    const {xAlign, yAlign, options} = this;
+  getCaretPosition(tooltipPoint, size, options) {
+    const {xAlign, yAlign} = this;
     const {cornerRadius, caretSize} = options;
     const {x: ptX, y: ptY} = tooltipPoint;
     const {width, height} = size;
@@ -617,9 +638,8 @@ export class Tooltip extends Element {
     return {x1, x2, x3, y1, y2, y3};
   }
 
-  drawTitle(pt, ctx) {
+  drawTitle(pt, ctx, options) {
     const me = this;
-    const options = me.options;
     const title = me.title;
     const length = title.length;
     let titleFont, titleSpacing, i;
@@ -627,7 +647,7 @@ export class Tooltip extends Element {
     if (length) {
       const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
 
-      pt.x = getAlignedX(me, options.titleAlign);
+      pt.x = getAlignedX(me, options.titleAlign, options);
 
       ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
       ctx.textBaseline = 'middle';
@@ -652,13 +672,12 @@ export class Tooltip extends Element {
   /**
         * @private
         */
-  _drawColorBox(ctx, pt, i, rtlHelper) {
+  _drawColorBox(ctx, pt, i, rtlHelper, options) {
     const me = this;
-    const options = me.options;
     const labelColors = me.labelColors[i];
     const labelPointStyle = me.labelPointStyles[i];
     const {boxHeight, boxWidth, bodyFont} = options;
-    const colorX = getAlignedX(me, 'left');
+    const colorX = getAlignedX(me, 'left', options);
     const rtlColorX = rtlHelper.x(colorX);
     const yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0;
     const colorY = pt.y + yOffSet;
@@ -703,9 +722,9 @@ export class Tooltip extends Element {
     ctx.fillStyle = me.labelTextColors[i];
   }
 
-  drawBody(pt, ctx) {
+  drawBody(pt, ctx, options) {
     const me = this;
-    const {body, options} = me;
+    const {body} = me;
     const {bodyFont, bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options;
     let bodyLineHeight = bodyFont.size;
     let xLinePadding = 0;
@@ -724,7 +743,7 @@ export class Tooltip extends Element {
     ctx.textBaseline = 'middle';
     ctx.font = toFontString(bodyFont);
 
-    pt.x = getAlignedX(me, bodyAlignForCalculation);
+    pt.x = getAlignedX(me, bodyAlignForCalculation, options);
 
     // Before body lines
     ctx.fillStyle = options.bodyColor;
@@ -745,7 +764,7 @@ export class Tooltip extends Element {
       lines = bodyItem.lines;
       // Draw Legend-like boxes if needed
       if (displayColors && lines.length) {
-        me._drawColorBox(ctx, pt, i, rtlHelper);
+        me._drawColorBox(ctx, pt, i, rtlHelper, options);
         bodyLineHeight = Math.max(bodyFont.size, boxHeight);
       }
 
@@ -767,9 +786,8 @@ export class Tooltip extends Element {
     pt.y -= bodySpacing; // Remove last body spacing
   }
 
-  drawFooter(pt, ctx) {
+  drawFooter(pt, ctx, options) {
     const me = this;
-    const options = me.options;
     const footer = me.footer;
     const length = footer.length;
     let footerFont, i;
@@ -777,7 +795,7 @@ export class Tooltip extends Element {
     if (length) {
       const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
 
-      pt.x = getAlignedX(me, options.footerAlign);
+      pt.x = getAlignedX(me, options.footerAlign, options);
       pt.y += options.footerMarginTop;
 
       ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
@@ -795,8 +813,8 @@ export class Tooltip extends Element {
     }
   }
 
-  drawBackground(pt, ctx, tooltipSize) {
-    const {xAlign, yAlign, options} = this;
+  drawBackground(pt, ctx, tooltipSize, options) {
+    const {xAlign, yAlign} = this;
     const {x, y} = pt;
     const {width, height} = tooltipSize;
     const radius = options.cornerRadius;
@@ -808,22 +826,22 @@ export class Tooltip extends Element {
     ctx.beginPath();
     ctx.moveTo(x + radius, y);
     if (yAlign === 'top') {
-      this.drawCaret(pt, ctx, tooltipSize);
+      this.drawCaret(pt, ctx, tooltipSize, options);
     }
     ctx.lineTo(x + width - radius, y);
     ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
     if (yAlign === 'center' && xAlign === 'right') {
-      this.drawCaret(pt, ctx, tooltipSize);
+      this.drawCaret(pt, ctx, tooltipSize, options);
     }
     ctx.lineTo(x + width, y + height - radius);
     ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
     if (yAlign === 'bottom') {
-      this.drawCaret(pt, ctx, tooltipSize);
+      this.drawCaret(pt, ctx, tooltipSize, options);
     }
     ctx.lineTo(x + radius, y + height);
     ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
     if (yAlign === 'center' && xAlign === 'left') {
-      this.drawCaret(pt, ctx, tooltipSize);
+      this.drawCaret(pt, ctx, tooltipSize, options);
     }
     ctx.lineTo(x, y + radius);
     ctx.quadraticCurveTo(x, y, x + radius, y);
@@ -840,10 +858,9 @@ export class Tooltip extends Element {
         * Update x/y animation targets when _active elements are animating too
         * @private
         */
-  _updateAnimationTarget() {
+  _updateAnimationTarget(options) {
     const me = this;
     const chart = me._chart;
-    const options = me.options;
     const anims = me.$animations;
     const animX = anims && anims.x;
     const animY = anims && anims.y;
@@ -852,7 +869,7 @@ export class Tooltip extends Element {
       if (!position) {
         return;
       }
-      const size = me._size = getTooltipSize(me);
+      const size = me._size = getTooltipSize(me, options);
       const positionAndSize = Object.assign({}, position, me._size);
       const alignment = determineAlignment(chart, options, positionAndSize);
       const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
@@ -870,14 +887,14 @@ export class Tooltip extends Element {
 
   draw(ctx) {
     const me = this;
-    const options = me.options;
+    const options = me.options.setContext(me.getContext());
     let opacity = me.opacity;
 
     if (!opacity) {
       return;
     }
 
-    me._updateAnimationTarget();
+    me._updateAnimationTarget(options);
 
     const tooltipSize = {
       width: me.width,
@@ -901,20 +918,20 @@ export class Tooltip extends Element {
       ctx.globalAlpha = opacity;
 
       // Draw Background
-      me.drawBackground(pt, ctx, tooltipSize);
+      me.drawBackground(pt, ctx, tooltipSize, options);
 
       overrideTextDirection(ctx, options.textDirection);
 
       pt.y += padding.top;
 
       // Titles
-      me.drawTitle(pt, ctx);
+      me.drawTitle(pt, ctx, options);
 
       // Body
-      me.drawBody(pt, ctx);
+      me.drawBody(pt, ctx, options);
 
       // Footer
-      me.drawFooter(pt, ctx);
+      me.drawFooter(pt, ctx, options);
 
       restoreTextDirection(ctx, options.textDirection);
 
index 9a7291d6216f751342250d305f1a774359c550bc..836b499fa782c82106ce9ac6e536f1b71f463a36 100644 (file)
@@ -1265,7 +1265,7 @@ describe('Plugin.Tooltip', function() {
   describe('text align', function() {
     var defaults = Chart.defaults;
     var makeView = function(title, body, footer) {
-      return {
+      const model = {
         // Positioning
         x: 100,
         y: 100,
@@ -1275,6 +1275,7 @@ describe('Plugin.Tooltip', function() {
         yAlign: 'top',
 
         options: {
+          setContext: () => model.options,
           enabled: true,
 
           padding: 5,
@@ -1343,6 +1344,7 @@ describe('Plugin.Tooltip', function() {
           backgroundColor: 'rgb(0, 255, 255)'
         }]
       };
+      return model;
     };
     var drawBody = [
       {name: 'save', args: []},
@@ -1370,6 +1372,7 @@ describe('Plugin.Tooltip', function() {
     var mockContext = window.createMockContext();
     var tooltip = new Tooltip({
       _chart: {
+        getContext: () => ({}),
         options: {
           plugins: {
             tooltip: {
index 370ff84955014ffb6e98c451071efe034054be25..29f66fb1dea6d01105961532887e776b93ec8de2 100644 (file)
@@ -2315,12 +2315,19 @@ export interface ExtendedPlugin<
    */
   afterTooltipDraw?(chart: Chart, args: { tooltip: Model }, options: O): void;
 }
+
+export interface ScriptableTooltipContext<TType extends ChartType> {
+  chart: UnionToIntersection<Chart<TType>>;
+  tooltip: UnionToIntersection<TooltipModel<TType>>;
+  tooltipItems: TooltipItem<TType>[];
+}
+
 export interface TooltipOptions<TType extends ChartType> extends CoreInteractionOptions {
   /**
    * Are on-canvas tooltips enabled?
    * @default true
    */
-  enabled: boolean;
+  enabled: Scriptable<boolean, ScriptableTooltipContext<TType>>;
   /**
    *   See custom tooltip section.
    */
@@ -2328,13 +2335,13 @@ export interface TooltipOptions<TType extends ChartType> extends CoreInteraction
   /**
    * The mode for positioning the tooltip
    */
-  position: 'average' | 'nearest';
+  position: Scriptable<'average' | 'nearest', ScriptableTooltipContext<TType>>
 
   /**
    * Override the tooltip alignment calculations
    */
-  xAlign: TooltipAlignment;
-  yAlign: TooltipAlignment;
+  xAlign: Scriptable<TooltipAlignment, ScriptableTooltipContext<TType>>;
+  yAlign: Scriptable<TooltipAlignment, ScriptableTooltipContext<TType>>;
 
   /**
    * Sort tooltip items.
@@ -2347,142 +2354,142 @@ export interface TooltipOptions<TType extends ChartType> extends CoreInteraction
    * Background color of the tooltip.
    * @default 'rgba(0, 0, 0, 0.8)'
    */
-  backgroundColor: Color;
+  backgroundColor: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    * Color of title
    * @default '#fff'
    */
-  titleColor: Color;
+  titleColor: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    * See Fonts
    * @default {style: 'bold'}
    */
-  titleFont: FontSpec;
+  titleFont: Scriptable<FontSpec, ScriptableTooltipContext<TType>>;
   /**
    * Spacing to add to top and bottom of each title line.
    * @default 2
    */
-  titleSpacing: number;
+  titleSpacing: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Margin to add on bottom of title section.
    * @default 6
    */
-  titleMarginBottom: number;
+  titleMarginBottom: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Horizontal alignment of the title text lines.
    * @default 'left'
    */
-  titleAlign: TextAlign;
+  titleAlign: Scriptable<TextAlign, ScriptableTooltipContext<TType>>;
   /**
    * Spacing to add to top and bottom of each tooltip item.
    * @default 2
    */
-  bodySpacing: number;
+  bodySpacing: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Color of body
    * @default '#fff'
    */
-  bodyColor: Color;
+  bodyColor: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    *   See Fonts.
    * @default {}
    */
-  bodyFont: FontSpec;
+  bodyFont: Scriptable<FontSpec, ScriptableTooltipContext<TType>>;
   /**
    * Horizontal alignment of the body text lines.
    * @default 'left'
    */
-  bodyAlign: TextAlign;
+  bodyAlign: Scriptable<TextAlign, ScriptableTooltipContext<TType>>;
   /**
    * Spacing to add to top and bottom of each footer line.
    * @default 2
    */
-  footerSpacing: number;
+  footerSpacing: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Margin to add before drawing the footer.
    * @default 6
    */
-  footerMarginTop: number;
+  footerMarginTop: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Color of footer
    * @default '#fff'
    */
-  footerColor: Color;
+  footerColor: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    * See Fonts
    * @default {style: 'bold'}
    */
-  footerFont: FontSpec;
+  footerFont: Scriptable<FontSpec, ScriptableTooltipContext<TType>>;
   /**
    * Horizontal alignment of the footer text lines.
    * @default 'left'
    */
-  footerAlign: TextAlign;
+  footerAlign: Scriptable<TextAlign, ScriptableTooltipContext<TType>>;
   /**
    * Padding to add to the tooltip
    * @default 6
    */
-  padding: number | ChartArea;
+  padding: Scriptable<number | ChartArea, ScriptableTooltipContext<TType>>;
   /**
    *   Extra distance to move the end of the tooltip arrow away from the tooltip point.
    * @default 2
    */
-  caretPadding: number;
+  caretPadding: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Size, in px, of the tooltip arrow.
    * @default 5
    */
-  caretSize: number;
+  caretSize: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Radius of tooltip corner curves.
    * @default 6
    */
-  cornerRadius: number;
+  cornerRadius: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Color to draw behind the colored boxes when multiple items are in the tooltip.
    * @default '#fff'
    */
-  multiKeyBackground: Color;
+  multiKeyBackground: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    * If true, color boxes are shown in the tooltip.
    * @default true
    */
-  displayColors: boolean;
+  displayColors: Scriptable<boolean, ScriptableTooltipContext<TType>>;
   /**
    * Width of the color box if displayColors is true.
    * @default bodyFont.size
    */
-  boxWidth: number;
+  boxWidth: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Height of the color box if displayColors is true.
    * @default bodyFont.size
    */
-  boxHeight: number;
+  boxHeight: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * Use the corresponding point style (from dataset options) instead of color boxes, ex: star, triangle etc. (size is based on the minimum value between boxWidth and boxHeight)
    * @default false
    */
-  usePointStyle: boolean;
+  usePointStyle: Scriptable<boolean, ScriptableTooltipContext<TType>>;
   /**
    * Color of the border.
    * @default 'rgba(0, 0, 0, 0)'
    */
-  borderColor: Color;
+  borderColor: Scriptable<Color, ScriptableTooltipContext<TType>>;
   /**
    * Size of the border.
    * @default 0
    */
-  borderWidth: number;
+  borderWidth: Scriptable<number, ScriptableTooltipContext<TType>>;
   /**
    * true for rendering the legends from right to left.
    */
-  rtl: boolean;
+  rtl: Scriptable<boolean, ScriptableTooltipContext<TType>>;
 
   /**
    * This will force the text direction 'rtl' or 'ltr on the canvas for rendering the tooltips, regardless of the css specified on the canvas
    * @default canvas's default
    */
-  textDirection: string;
+  textDirection: Scriptable<string, ScriptableTooltipContext<TType>>;
 
   animation: AnimationSpec<TType>;
   animations: AnimationsSpec<TType>;
@@ -2503,7 +2510,7 @@ export interface TooltipItem<TType extends ChartType> {
   /**
    * Parsed data values for the given `dataIndex` and `datasetIndex`
    */
-  parsed: ParsedDataType<TType>;
+  parsed: UnionToIntersection<ParsedDataType<TType>>;
 
   /**
    * Raw data values for the given `dataIndex` and `datasetIndex`
diff --git a/types/tests/plugins/plugin.tooltip/tooltip_scriptable_background_color.ts b/types/tests/plugins/plugin.tooltip/tooltip_scriptable_background_color.ts
new file mode 100644 (file)
index 0000000..a55d445
--- /dev/null
@@ -0,0 +1,18 @@
+import { Chart } from '../../../index.esm';
+
+const chart = new Chart('id', {
+  type: 'bar',
+  data: {
+    labels: [],
+    datasets: [{
+      data: []
+    }]
+  },
+  options: {
+    plugins: {
+      tooltip: {
+        backgroundColor: (ctx) => 'black',
+      }
+    }
+  },
+});