@teachinglab/omd 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { BoundingBox } from '../utils/boundingBox.js';
2
-
2
+ import { jsvgPath } from '@teachinglab/jsvg';
3
3
  /**
4
4
  * Represents a drawing stroke made up of connected points
5
5
  */
@@ -60,21 +60,6 @@ export class Toolbar {
60
60
 
61
61
  // Add to main SVG so it is rendered
62
62
  this.canvas.svg.appendChild(this.toolbarGroup.svgObject);
63
-
64
-
65
- // Check if the SVG is actually in the DOM
66
- setTimeout(() => {
67
-
68
-
69
- // Check the actual SVG content
70
- console.log('Toolbar SVG innerHTML:', this.toolbarGroup.svgObject.innerHTML);
71
- console.log('Background SVG object:', this.background.svgObject);
72
- console.log('Background SVG innerHTML:', this.background.svgObject.outerHTML);
73
-
74
- // Check if the background is visible
75
- console.log('Background fill color:', this.background.svgObject.getAttribute('fill'));
76
- console.log('Background width/height:', this.background.svgObject.getAttribute('width'), this.background.svgObject.getAttribute('height'));
77
- }, 100);
78
63
  }
79
64
 
80
65
  /**
@@ -34,7 +34,9 @@ export class omdEquationStack extends jsvgGroup {
34
34
 
35
35
  // The sequence is the core. If a visualizer is needed, that's our sequence.
36
36
  if (options.stepVisualizer) {
37
- this.sequence = new omdStepVisualizer(steps, this.stylingOptions || {});
37
+ // Pass through step visualizer styling options
38
+ const stepVisualizerStyling = this.stylingOptions?.stepVisualizer || {};
39
+ this.sequence = new omdStepVisualizer(steps, stepVisualizerStyling);
38
40
  } else {
39
41
  this.sequence = new omdEquationSequenceNode(steps);
40
42
  }
@@ -44,6 +46,13 @@ export class omdEquationStack extends jsvgGroup {
44
46
  this.sequence.setDefaultEquationBackground(this.stylingOptions.equationBackground);
45
47
  }
46
48
 
49
+ // Apply step visualizer background styling if provided
50
+ if (options.stepVisualizer && this.stylingOptions?.stepVisualizerBackground) {
51
+ if (typeof this.sequence.setBackgroundStyle === 'function') {
52
+ this.sequence.setBackgroundStyle(this.stylingOptions.stepVisualizerBackground);
53
+ }
54
+ }
55
+
47
56
  // If a toolbar is needed, create it.
48
57
  if (this.toolbarOptions?.enabled) {
49
58
  // Default undo: call global hook if provided
@@ -508,7 +517,7 @@ export class omdEquationStack extends jsvgGroup {
508
517
  }
509
518
  if (seq.layoutManager) {
510
519
  try {
511
- seq.layoutManager.updateVisualLayout();
520
+ seq.layoutManager.updateVisualLayout(true); // Allow repositioning for equation stack changes
512
521
  seq.layoutManager.updateVisualVisibility();
513
522
  seq.layoutManager.updateAllLinePositions();
514
523
  } catch (_) {}
@@ -20,6 +20,7 @@ export class omdDisplay {
20
20
  autoScale: true, // Automatically scale content to fit container
21
21
  maxScale: 1, // Do not upscale beyond 1 by default
22
22
  edgePadding: 16, // Horizontal padding from edges when scaling
23
+ autoCloseStepVisualizer: true, // Close active step visualizer text boxes before autoscale to avoid shrink
23
24
  ...options
24
25
  };
25
26
 
@@ -27,6 +28,13 @@ export class omdDisplay {
27
28
  this.svg = new jsvgContainer();
28
29
  this.node = null;
29
30
 
31
+ // Internal guards to prevent recursive resize induced growth
32
+ this._suppressResizeObserver = false; // When true, _handleResize is a no-op
33
+ this._lastViewbox = null; // Cache last applied viewBox string
34
+ this._lastContentExtents = null; // Cache last measured content extents to detect real growth
35
+ this._viewboxLocked = false; // When true, suppress micro growth adjustments
36
+ this._viewboxLockThreshold = 8; // Require at least 8px growth once locked
37
+
30
38
  // Set up the SVG
31
39
  this._setupSVG();
32
40
  }
@@ -64,8 +72,13 @@ export class omdDisplay {
64
72
  }
65
73
 
66
74
  _handleResize() {
75
+ if (this._suppressResizeObserver) return; // Prevent re-entrant resize loops
67
76
  const width = this.container.offsetWidth;
68
77
  const height = this.container.offsetHeight;
78
+ // Skip if size unchanged; avoids loops where internal changes trigger observer without real container delta
79
+ if (this._lastContainerWidth === width && this._lastContainerHeight === height) return;
80
+ this._lastContainerWidth = width;
81
+ this._lastContainerHeight = height;
69
82
  this.svg.setViewbox(width, height);
70
83
 
71
84
  if (this.options.centerContent && this.node) {
@@ -131,8 +144,50 @@ export class omdDisplay {
131
144
  const desiredW = Math.max(curW, desiredRight - desiredX);
132
145
  const desiredH = Math.max(curH, desiredBottom - desiredY);
133
146
 
134
- if (desiredW !== curW || desiredH !== curH) {
135
- this.svg.svgObject.setAttribute('viewBox', `${desiredX} ${desiredY} ${desiredW} ${desiredH}`);
147
+ // Guard: If the desired size change is negligible (< 0.5px), skip.
148
+ const widthDelta = Math.abs(desiredW - curW);
149
+ const heightDelta = Math.abs(desiredH - curH);
150
+
151
+ // Safety cap to avoid runaway expansion due to logic errors.
152
+ const MAX_DIM = 10000; // arbitrary large but finite limit
153
+ if (desiredW > MAX_DIM || desiredH > MAX_DIM) {
154
+ console.warn('omdDisplay: viewBox growth capped to prevent runaway expansion', desiredW, desiredH);
155
+ return;
156
+ }
157
+
158
+ if (widthDelta < 0.5 && heightDelta < 0.5) return;
159
+
160
+ // Detect repeated growth with identical content extents (suggests feedback loop)
161
+ const curExtSignature = `${minX},${minY},${maxX},${maxY}`;
162
+ if (this._lastContentExtents === curExtSignature && heightDelta > 0 && desiredH > curH) {
163
+ return; // content unchanged, skip
164
+ }
165
+
166
+ // If locked, only allow substantial growth
167
+ if (this._viewboxLocked) {
168
+ const growW = desiredW - curW;
169
+ const growH = desiredH - curH;
170
+ if (growW < this._viewboxLockThreshold && growH < this._viewboxLockThreshold) {
171
+ return; // ignore micro growth attempts
172
+ }
173
+ }
174
+
175
+ const newViewBox = `${desiredX} ${desiredY} ${desiredW} ${desiredH}`;
176
+ if (this._lastViewbox === newViewBox) return;
177
+
178
+ this._suppressResizeObserver = true;
179
+ try {
180
+ this.svg.svgObject.setAttribute('viewBox', newViewBox);
181
+ } finally {
182
+ // Allow ResizeObserver events after microtask; use timeout to defer
183
+ setTimeout(() => { this._suppressResizeObserver = false; }, 0);
184
+ }
185
+ this._lastViewbox = newViewBox;
186
+ this._lastContentExtents = curExtSignature;
187
+
188
+ // Lock if the growth applied was small; prevents future tiny increments
189
+ if (heightDelta < 2 && widthDelta < 2 && !this._viewboxLocked) {
190
+ this._viewboxLocked = true;
136
191
  }
137
192
  }
138
193
 
@@ -396,9 +451,28 @@ export class omdDisplay {
396
451
 
397
452
  centerNode() {
398
453
  if (!this.node) return;
454
+ if (!this._centerCallCount) this._centerCallCount = 0;
455
+ this._centerCallCount++;
456
+ if (this._centerCallCount > 500) {
457
+ console.warn('omdDisplay: excessive centerNode calls detected; halting further centering to prevent loop');
458
+ return;
459
+ }
399
460
  const containerWidth = this.container.offsetWidth || 0;
400
461
  const containerHeight = this.container.offsetHeight || 0;
401
462
 
463
+ // Early auto-close of step visualizer UI before measuring dimensions to avoid transient height inflation
464
+ if (this.options.autoCloseStepVisualizer && this.node) {
465
+ try {
466
+ if (typeof this.node.forceCloseAll === 'function') {
467
+ this.node.forceCloseAll();
468
+ } else if (typeof this.node.closeAllTextBoxes === 'function') {
469
+ this.node.closeAllTextBoxes();
470
+ } else if (typeof this.node.closeActiveDot === 'function') {
471
+ this.node.closeActiveDot();
472
+ }
473
+ } catch (e) { /* no-op */ }
474
+ }
475
+
402
476
  // Determine actual content size (prefer sequence/current step when available)
403
477
  let contentWidth = this.node.width || 0;
404
478
  let contentHeight = this.node.height || 0;
@@ -406,14 +480,18 @@ export class omdDisplay {
406
480
  const seq = this.node.getSequence();
407
481
  if (seq) {
408
482
  if (seq.width && seq.height) {
409
- contentWidth = seq.width;
410
- contentHeight = seq.height;
483
+ // For step visualizers, use sequenceWidth/Height instead of total dimensions to exclude visualizer elements from autoscale
484
+ contentWidth = seq.sequenceWidth || seq.width;
485
+ contentHeight = seq.sequenceHeight || seq.height;
411
486
  }
412
487
  if (seq.getCurrentStep) {
413
488
  const step = seq.getCurrentStep();
414
489
  if (step && step.width && step.height) {
415
- contentWidth = Math.max(contentWidth, step.width);
416
- contentHeight = Math.max(contentHeight, step.height);
490
+ // For step visualizers, prioritize sequenceWidth/Height for dimension calculations
491
+ const stepWidth = seq.sequenceWidth || step.width;
492
+ const stepHeight = seq.sequenceHeight || step.height;
493
+ contentWidth = Math.max(contentWidth, stepWidth);
494
+ contentHeight = Math.max(contentHeight, stepHeight);
417
495
  }
418
496
  }
419
497
  }
@@ -422,22 +500,45 @@ export class omdDisplay {
422
500
  // Compute scale to keep within bounds
423
501
  let scale = 1;
424
502
  if (this.options.autoScale && contentWidth > 0 && contentHeight > 0) {
425
- const hPad = this.options.edgePadding || 0;
426
- const vPadTop = this.options.topMargin || 0;
427
- const vPadBottom = this.options.bottomMargin || 0;
428
- // Reserve extra space for overlay toolbar if needed
429
- let reserveBottom = vPadBottom;
430
- if (this.node && typeof this.node.isToolbarOverlay === 'function' && this.node.isToolbarOverlay()) {
431
- const tH = (typeof this.node.getToolbarVisualHeight === 'function') ? this.node.getToolbarVisualHeight() : 0;
432
- reserveBottom += (tH + (this.node.getOverlayPadding ? this.node.getOverlayPadding() : 16));
503
+ // Optionally close any open step visualizer textbox to prevent transient height expansion
504
+ if (this.options.autoCloseStepVisualizer && this.node) {
505
+ try {
506
+ if (typeof this.node.closeActiveDot === 'function') {
507
+ this.node.closeActiveDot();
508
+ } else if (typeof this.node.closeAllTextBoxes === 'function') {
509
+ this.node.closeAllTextBoxes();
510
+ }
511
+ } catch (e) { /* no-op */ }
512
+ }
513
+ // Detect step visualizer directly on node (getSequence returns underlying sequence only)
514
+ let hasStepVisualizer = false;
515
+ if (this.node) {
516
+ const ctorName = this.node.constructor?.name;
517
+ hasStepVisualizer = (ctorName === 'omdStepVisualizer') || this.node.type === 'omdStepVisualizer' || (typeof omdStepVisualizer !== 'undefined' && this.node instanceof omdStepVisualizer);
518
+ }
519
+
520
+ if (hasStepVisualizer) {
521
+ // Preserve existing scale if already set on node; otherwise lock to 1.
522
+ const existingScale = (this.node && typeof this.node.scale === 'number') ? this.node.scale : undefined;
523
+ scale = (existingScale && existingScale > 0) ? existingScale : 1;
524
+ } else {
525
+ const hPad = this.options.edgePadding || 0;
526
+ const vPadTop = this.options.topMargin || 0;
527
+ const vPadBottom = this.options.bottomMargin || 0;
528
+ // Reserve extra space for overlay toolbar if needed
529
+ let reserveBottom = vPadBottom;
530
+ if (this.node && typeof this.node.isToolbarOverlay === 'function' && this.node.isToolbarOverlay()) {
531
+ const tH = (typeof this.node.getToolbarVisualHeight === 'function') ? this.node.getToolbarVisualHeight() : 0;
532
+ reserveBottom += (tH + (this.node.getOverlayPadding ? this.node.getOverlayPadding() : 16));
533
+ }
534
+ const availW = Math.max(0, containerWidth - hPad * 2);
535
+ const availH = Math.max(0, containerHeight - (vPadTop + reserveBottom));
536
+ const sx = availW > 0 ? (availW / contentWidth) : 1;
537
+ const sy = availH > 0 ? (availH / contentHeight) : 1;
538
+ const maxScale = (typeof this.options.maxScale === 'number') ? this.options.maxScale : 1;
539
+ scale = Math.min(sx, sy, maxScale);
540
+ if (!isFinite(scale) || scale <= 0) scale = 1;
433
541
  }
434
- const availW = Math.max(0, containerWidth - hPad * 2);
435
- const availH = Math.max(0, containerHeight - (vPadTop + reserveBottom));
436
- const sx = availW > 0 ? (availW / contentWidth) : 1;
437
- const sy = availH > 0 ? (availH / contentHeight) : 1;
438
- const maxScale = (typeof this.options.maxScale === 'number') ? this.options.maxScale : 1;
439
- scale = Math.min(sx, sy, maxScale);
440
- if (!isFinite(scale) || scale <= 0) scale = 1;
441
542
  }
442
543
 
443
544
  // Apply scale
@@ -451,19 +552,27 @@ export class omdDisplay {
451
552
  const screenCenterX = containerWidth / 2;
452
553
  x = screenCenterX - (this.node.alignPointX * scale);
453
554
  } else {
454
- const scaledWidth = (this.node.width || contentWidth) * scale;
555
+ const scaledWidth = contentWidth * scale;
455
556
  x = (containerWidth - scaledWidth) / 2;
456
557
  }
457
558
 
458
559
  // Decide whether positioning would move content outside container. If so,
459
560
  // prefer expanding the SVG viewBox instead of moving nodes.
460
- const scaledWidthFinal = (this.node.width || contentWidth) * scale;
461
- const scaledHeightFinal = (this.node.height || contentHeight) * scale;
561
+ const scaledWidthFinal = contentWidth * scale;
562
+ const scaledHeightFinal = contentHeight * scale;
462
563
  const totalNeededH = scaledHeightFinal + (this.options.topMargin || 0) + (this.options.bottomMargin || 0);
463
564
 
464
565
  const willOverflowHoriz = scaledWidthFinal > containerWidth;
465
566
  const willOverflowVert = totalNeededH > containerHeight;
466
567
 
568
+ // Avoid looping if content dimension signature hasn't changed
569
+ const contentSig = `${contentWidth}x${contentHeight}x${scale}`;
570
+ if (this._lastCenterSignature === contentSig && !willOverflowHoriz && !willOverflowVert) {
571
+ // Only update position; skip expensive ensureViewboxFits
572
+ if (this.node.setPosition) this.node.setPosition(x, this.options.topMargin);
573
+ return;
574
+ }
575
+
467
576
  if (willOverflowHoriz || willOverflowVert) {
468
577
  // Set scale but do NOT reposition node (preserve its absolute positions).
469
578
  if (this.node.setScale) this.node.setScale(scale);
@@ -499,6 +608,8 @@ export class omdDisplay {
499
608
  }
500
609
  if (this.options.debugExtents) this._drawDebugOverlays();
501
610
  }
611
+
612
+ this._lastCenterSignature = contentSig;
502
613
  }
503
614
 
504
615
  fitToContent() {
@@ -517,15 +628,17 @@ export class omdDisplay {
517
628
  if (this.node.getSequence) {
518
629
  const sequence = this.node.getSequence();
519
630
  if (sequence && sequence.width && sequence.height) {
520
- sequenceWidth = sequence.width;
521
- sequenceHeight = sequence.height;
631
+ // For step visualizers, use sequenceWidth/Height instead of total dimensions to exclude visualizer elements from autoscale
632
+ sequenceWidth = sequence.sequenceWidth || sequence.width;
633
+ sequenceHeight = sequence.sequenceHeight || sequence.height;
522
634
 
523
635
  // Check current step dimensions too
524
636
  if (sequence.getCurrentStep) {
525
637
  const currentStep = sequence.getCurrentStep();
526
638
  if (currentStep && currentStep.width && currentStep.height) {
527
- stepWidth = currentStep.width;
528
- stepHeight = currentStep.height;
639
+ // For step visualizers, prioritize sequenceWidth/Height for dimension calculations
640
+ stepWidth = sequence.sequenceWidth || currentStep.width;
641
+ stepHeight = sequence.sequenceHeight || currentStep.height;
529
642
  }
530
643
  }
531
644
 
@@ -624,10 +737,7 @@ export class omdDisplay {
624
737
 
625
738
  // Apply any stored font settings
626
739
  if (this.options.fontFamily) {
627
- // Small delay to ensure SVG elements are fully rendered
628
- setTimeout(() => {
629
740
  this.setFont(this.options.fontFamily, this.options.fontWeight || '400');
630
- }, 10);
631
741
  }
632
742
 
633
743
  // Only use fitToContent for tight sizing when explicitly requested
@@ -834,4 +944,12 @@ export class omdDisplay {
834
944
  node.positionToolbarOverlay(containerWidth, containerHeight, padding);
835
945
  }
836
946
  }
947
+
948
+ /**
949
+ * Public API: returns the currently rendered root node (could be a step visualizer, sequence, or plain node)
950
+ * @returns {object|null}
951
+ */
952
+ getCurrentNode() {
953
+ return this.node;
954
+ }
837
955
  }
@@ -1005,7 +1005,7 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1005
1005
  case 'table':
1006
1006
  return this._renderToTable(mergedOptions);
1007
1007
  case 'hanger':
1008
- return this._renderToHanger();
1008
+ return this._renderToHanger(mergedOptions);
1009
1009
  case 'tileequation': {
1010
1010
  const leftExpr = this.getLeft().toString();
1011
1011
  const rightExpr = this.getRight().toString();
@@ -1089,6 +1089,11 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1089
1089
  tickInterval: (options.tickInterval !== undefined) ? options.tickInterval : 1,
1090
1090
  forceAllTickLabels: (options.forceAllTickLabels !== undefined) ? options.forceAllTickLabels : true,
1091
1091
  showTickLabels: (options.showTickLabels !== undefined) ? options.showTickLabels : true,
1092
+ // Background customization options
1093
+ backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
1094
+ backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
1095
+ backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
1096
+ showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
1092
1097
  graphEquations,
1093
1098
  lineSegments: [],
1094
1099
  dotValues: [],
@@ -1113,7 +1118,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1113
1118
  equation: `y = ${expr}`,
1114
1119
  xMin: options.xMin,
1115
1120
  xMax: options.xMax,
1116
- stepSize: options.stepSize
1121
+ stepSize: options.stepSize,
1122
+ // Background customization options
1123
+ backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
1124
+ backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
1125
+ backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
1126
+ showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
1127
+ // Alternating row color options
1128
+ alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
1129
+ evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
1130
+ oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
1131
+ alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
1117
1132
  };
1118
1133
  } else if (options.side === 'right') {
1119
1134
  const expr = this._normalizeExpressionString(this.getRight().toString());
@@ -1124,7 +1139,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1124
1139
  equation: `y = ${expr}`,
1125
1140
  xMin: options.xMin,
1126
1141
  xMax: options.xMax,
1127
- stepSize: options.stepSize
1142
+ stepSize: options.stepSize,
1143
+ // Background customization options
1144
+ backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
1145
+ backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
1146
+ backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
1147
+ showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
1148
+ // Alternating row color options
1149
+ alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
1150
+ evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
1151
+ oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
1152
+ alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
1128
1153
  };
1129
1154
  }
1130
1155
 
@@ -1155,7 +1180,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1155
1180
  omdType: "table",
1156
1181
  title: `Equation Table: ${this.toString()}`,
1157
1182
  headers,
1158
- data
1183
+ data,
1184
+ // Background customization options
1185
+ backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
1186
+ backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
1187
+ backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
1188
+ showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
1189
+ // Alternating row color options
1190
+ alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
1191
+ evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
1192
+ oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
1193
+ alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
1159
1194
  };
1160
1195
  }
1161
1196
 
@@ -1184,7 +1219,7 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1184
1219
  * @returns {Object} JSON configuration for omdBalanceHanger
1185
1220
  * @private
1186
1221
  */
1187
- _renderToHanger() {
1222
+ _renderToHanger(options = {}) {
1188
1223
  // Convert equation sides to hanger representation
1189
1224
  const leftValues = this._convertToHangerValues(this.getLeft());
1190
1225
  const rightValues = this._convertToHangerValues(this.getRight());
@@ -1193,7 +1228,12 @@ _propagateBackgroundStyle(style, visited = new Set()) {
1193
1228
  omdType: "balanceHanger",
1194
1229
  leftValues: leftValues,
1195
1230
  rightValues: rightValues,
1196
- tilt: "none" // Equations should be balanced by definition
1231
+ tilt: "none", // Equations should be balanced by definition
1232
+ // Background customization options
1233
+ backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
1234
+ backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
1235
+ backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
1236
+ showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined
1197
1237
  };
1198
1238
  }
1199
1239