@mathscan/math-exercise-engine 1.1.15 → 1.1.16

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.
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { createToken, Lexer, CstParser } from "chevrotain";
2
2
  import { z } from "zod";
3
3
  import { create, all } from "mathjs";
4
4
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
5
- import React, { useLayoutEffect, useEffect, useRef, useMemo, useCallback, useState, createContext, memo, useReducer, useContext, forwardRef, cloneElement, useImperativeHandle } from "react";
5
+ import React, { useLayoutEffect, useEffect, useRef, useMemo, useCallback, useState, createContext, memo, useReducer, useContext, forwardRef, cloneElement, useId, useImperativeHandle } from "react";
6
6
  import { unstable_batchedUpdates, createPortal } from "react-dom";
7
7
  import { createRoot } from "react-dom/client";
8
8
  const AST_TYPES = {
@@ -229,6 +229,9 @@ const SIDE_PAD = 7;
229
229
  const CSS_VAR_SIDE_PAD = "--nl-side-pad";
230
230
  const NUMBER_LINE_LABELS = ["all", "extremes", "min-only", "max-only", "none"];
231
231
  const NUMBER_LINE_HIGHLIGHT_COLORS = ["blue", "red", "green", "orange", "purple", "yellow"];
232
+ const HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
233
+ const isNumberLineHighlightColor = (value) => NUMBER_LINE_HIGHLIGHT_COLORS.includes(value) || HEX_COLOR_REGEX.test(value);
234
+ const highlightColorMessage = (block) => `${block}: color must be one of ${NUMBER_LINE_HIGHLIGHT_COLORS.join(", ")} or a hex value (e.g. "#3B82F6")`;
232
235
  const NUMBER_LINE_DRAG_MODES = ["axis", "inputs"];
233
236
  function getFractionKey(widgetId, part) {
234
237
  return `${widgetId}__${part}`;
@@ -1599,7 +1602,9 @@ const ImageInlineSchema = z.object({
1599
1602
  }),
1600
1603
  alt: z.string(),
1601
1604
  width: z.number().positive().optional(),
1602
- height: z.number().positive().optional()
1605
+ height: z.number().positive().optional(),
1606
+ /** Opt-in: show an expand control that opens the image fullscreen. */
1607
+ fullscreen: z.boolean().optional()
1603
1608
  });
1604
1609
  const VisualFractionInlineSchema = z.object({
1605
1610
  type: z.literal(AST_TYPES.VISUAL_FRACTION),
@@ -1904,10 +1909,8 @@ const NumberLineHighlightSchema = z.object({
1904
1909
  type: z.literal(AST_TYPES.NUMBER_LINE_HIGHLIGHT),
1905
1910
  from: z.number().finite({ message: "HIGHLIGHT: from must be a finite number" }),
1906
1911
  to: z.number().finite({ message: "HIGHLIGHT: to must be a finite number" }),
1907
- color: z.enum(NUMBER_LINE_HIGHLIGHT_COLORS, {
1908
- errorMap: () => ({
1909
- message: `HIGHLIGHT: color must be one of ${NUMBER_LINE_HIGHLIGHT_COLORS.join(", ")}`
1910
- })
1912
+ color: z.string().refine(isNumberLineHighlightColor, {
1913
+ message: highlightColorMessage("HIGHLIGHT")
1911
1914
  }).optional(),
1912
1915
  label: z.string().optional()
1913
1916
  }).refine((d) => d.from < d.to, {
@@ -1926,7 +1929,7 @@ const NumberLineCursorSchema = z.object({
1926
1929
  type: z.literal(AST_TYPES.NUMBER_LINE_CURSOR),
1927
1930
  value: z.number().finite({ message: "CURSOR: value must be a finite number" }).default(0),
1928
1931
  answer: z.number({ required_error: "CURSOR: answer is required" }).finite({ message: "CURSOR: answer must be a finite number" }),
1929
- color: z.string().regex(/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, {
1932
+ color: z.string().regex(HEX_COLOR_REGEX, {
1930
1933
  message: 'CURSOR: color must be a hex value (e.g. "#3B82F6" or "#F00")'
1931
1934
  }).optional(),
1932
1935
  fillRange: z.boolean().default(false),
@@ -1948,8 +1951,8 @@ const NumberLineArrowSchema = z.object({
1948
1951
  to: z.number().finite({ message: "ARROW: to must be a finite number" }),
1949
1952
  color: z.string().optional(),
1950
1953
  inlines: z.array(InlineNodeSchema)
1951
- }).refine((d) => d.from < d.to, {
1952
- message: "ARROW: from must be less than to"
1954
+ }).refine((d) => d.from !== d.to, {
1955
+ message: "ARROW: from and to must be different"
1953
1956
  });
1954
1957
  function createNumberLineArrow(from, to, inlines, color) {
1955
1958
  return NumberLineArrowSchema.parse({
@@ -2014,7 +2017,9 @@ const NumberLineBlockSchema = z.object({
2014
2017
  }
2015
2018
  }
2016
2019
  for (const arrow of data.arrows ?? []) {
2017
- if (arrow.from < data.min || arrow.to > data.max) {
2020
+ const lo = Math.min(arrow.from, arrow.to);
2021
+ const hi = Math.max(arrow.from, arrow.to);
2022
+ if (lo < data.min || hi > data.max) {
2018
2023
  ctx.addIssue({
2019
2024
  code: z.ZodIssueCode.custom,
2020
2025
  message: `NUMBER_LINE: ARROW range [${arrow.from}, ${arrow.to}] must be within [${data.min}, ${data.max}]`
@@ -3106,7 +3111,8 @@ class NaturalDSLVisitor extends BaseCstVisitor {
3106
3111
  const alt = params.alt;
3107
3112
  const width = params.width;
3108
3113
  const height = params.height;
3109
- return createImage(name, src, alt, { width, height });
3114
+ const fullscreen = params.fullscreen !== void 0 ? params.fullscreen === true || params.fullscreen === "true" : void 0;
3115
+ return createImage(name, src, alt, { width, height, fullscreen });
3110
3116
  }
3111
3117
  visualFraction(ctx) {
3112
3118
  const params = this.visit(ctx.parameterList);
@@ -3328,7 +3334,9 @@ const ImageItemSchema = z.object({
3328
3334
  }),
3329
3335
  alt: z.string(),
3330
3336
  width: z.number().positive().optional(),
3331
- height: z.number().positive().optional()
3337
+ height: z.number().positive().optional(),
3338
+ /** Opt-in: show an expand control that opens the image fullscreen. */
3339
+ fullscreen: z.boolean().optional()
3332
3340
  });
3333
3341
  const SpaceItemSchema = z.object({
3334
3342
  id: z.string(),
@@ -3433,7 +3441,9 @@ const NumberLineHighlightItemSchema = z.object({
3433
3441
  type: z.literal(JSON_TYPES.NUMBER_LINE_HIGHLIGHT),
3434
3442
  from: z.number().finite(),
3435
3443
  to: z.number().finite(),
3436
- color: z.enum(NUMBER_LINE_HIGHLIGHT_COLORS).optional(),
3444
+ color: z.string().refine(isNumberLineHighlightColor, {
3445
+ message: highlightColorMessage("HIGHLIGHT")
3446
+ }).optional(),
3437
3447
  label: z.string().optional()
3438
3448
  });
3439
3449
  const NumberLineCursorItemSchema = z.object({
@@ -3441,7 +3451,7 @@ const NumberLineCursorItemSchema = z.object({
3441
3451
  type: z.literal(JSON_TYPES.NUMBER_LINE_CURSOR),
3442
3452
  value: z.number().finite(),
3443
3453
  answer: z.number().finite(),
3444
- color: z.string().regex(/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/).optional(),
3454
+ color: z.string().regex(HEX_COLOR_REGEX).optional(),
3445
3455
  fillRange: z.boolean(),
3446
3456
  label: z.string().optional()
3447
3457
  });
@@ -9787,7 +9797,8 @@ function transformInline(inline, idGenerator, inlineDragIds) {
9787
9797
  src: inline.src,
9788
9798
  alt: inline.alt,
9789
9799
  ...inline.width !== void 0 && { width: inline.width },
9790
- ...inline.height !== void 0 && { height: inline.height }
9800
+ ...inline.height !== void 0 && { height: inline.height },
9801
+ ...inline.fullscreen !== void 0 && { fullscreen: inline.fullscreen }
9791
9802
  };
9792
9803
  case AST_TYPES.VISUAL_FRACTION:
9793
9804
  return {
@@ -16657,6 +16668,226 @@ const WidgetRenderer = ({
16657
16668
  }
16658
16669
  return null;
16659
16670
  };
16671
+ const ExpandDiamondIcon = () => {
16672
+ const gradientId = useId();
16673
+ return /* @__PURE__ */ jsxs(
16674
+ "svg",
16675
+ {
16676
+ className: "image-zoom-icon",
16677
+ viewBox: "0 0 60 60",
16678
+ fill: "none",
16679
+ xmlns: "http://www.w3.org/2000/svg",
16680
+ "aria-hidden": "true",
16681
+ focusable: "false",
16682
+ children: [
16683
+ /* @__PURE__ */ jsx(
16684
+ "rect",
16685
+ {
16686
+ y: "-1.41531",
16687
+ width: "31.6754",
16688
+ height: "31.6754",
16689
+ rx: "7",
16690
+ transform: "matrix(0.706556 0.707657 -0.706556 0.707657 29.4526 10.0862)",
16691
+ fill: "white"
16692
+ }
16693
+ ),
16694
+ /* @__PURE__ */ jsx(
16695
+ "rect",
16696
+ {
16697
+ y: "-1.41531",
16698
+ width: "31.6754",
16699
+ height: "31.6754",
16700
+ rx: "7",
16701
+ transform: "matrix(0.706556 0.707657 -0.706556 0.707657 29.4526 10.0862)",
16702
+ stroke: "#BDAFFE",
16703
+ strokeWidth: "2"
16704
+ }
16705
+ ),
16706
+ /* @__PURE__ */ jsx(
16707
+ "rect",
16708
+ {
16709
+ y: "-1.41531",
16710
+ width: "31.6754",
16711
+ height: "31.6754",
16712
+ rx: "7",
16713
+ transform: "matrix(0.706556 0.707657 -0.706556 0.707657 29.4526 10.0862)",
16714
+ stroke: `url(#${gradientId})`,
16715
+ strokeOpacity: "0.3",
16716
+ strokeWidth: "2"
16717
+ }
16718
+ ),
16719
+ /* @__PURE__ */ jsxs(
16720
+ "g",
16721
+ {
16722
+ stroke: "currentColor",
16723
+ strokeWidth: "2.5",
16724
+ strokeLinecap: "round",
16725
+ strokeLinejoin: "round",
16726
+ children: [
16727
+ /* @__PURE__ */ jsx("path", { d: "M22.45 27 L22.45 23.5 L25.95 23.5" }),
16728
+ /* @__PURE__ */ jsx("path", { d: "M34.95 23.5 L38.45 23.5 L38.45 27" }),
16729
+ /* @__PURE__ */ jsx("path", { d: "M38.45 36 L38.45 39.5 L34.95 39.5" }),
16730
+ /* @__PURE__ */ jsx("path", { d: "M25.95 39.5 L22.45 39.5 L22.45 36" })
16731
+ ]
16732
+ }
16733
+ ),
16734
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
16735
+ "linearGradient",
16736
+ {
16737
+ id: gradientId,
16738
+ x1: "3.84406",
16739
+ y1: "3.97407",
16740
+ x2: "24.7079",
16741
+ y2: "24.8379",
16742
+ gradientUnits: "userSpaceOnUse",
16743
+ children: [
16744
+ /* @__PURE__ */ jsx("stop", { stopColor: "#FAFAFA" }),
16745
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#8A4899" })
16746
+ ]
16747
+ }
16748
+ ) })
16749
+ ]
16750
+ }
16751
+ );
16752
+ };
16753
+ const CloseIcon = () => /* @__PURE__ */ jsxs(
16754
+ "svg",
16755
+ {
16756
+ className: "image-lightbox-close-icon",
16757
+ viewBox: "0 0 24 24",
16758
+ fill: "none",
16759
+ xmlns: "http://www.w3.org/2000/svg",
16760
+ "aria-hidden": "true",
16761
+ focusable: "false",
16762
+ children: [
16763
+ /* @__PURE__ */ jsx(
16764
+ "path",
16765
+ {
16766
+ d: "M18 6L6 18",
16767
+ stroke: "currentColor",
16768
+ strokeWidth: "2",
16769
+ strokeLinecap: "round",
16770
+ strokeLinejoin: "round"
16771
+ }
16772
+ ),
16773
+ /* @__PURE__ */ jsx(
16774
+ "path",
16775
+ {
16776
+ d: "M6 6L18 18",
16777
+ stroke: "currentColor",
16778
+ strokeWidth: "2",
16779
+ strokeLinecap: "round",
16780
+ strokeLinejoin: "round"
16781
+ }
16782
+ )
16783
+ ]
16784
+ }
16785
+ );
16786
+ const ImageItem = ({
16787
+ src,
16788
+ alt,
16789
+ width,
16790
+ height,
16791
+ fullscreen = false
16792
+ }) => {
16793
+ const [isOpen, setIsOpen] = useState(false);
16794
+ const triggerRef = useRef(null);
16795
+ const closeRef = useRef(null);
16796
+ const open = useCallback(() => setIsOpen(true), []);
16797
+ const close = useCallback(() => setIsOpen(false), []);
16798
+ const isLightboxOpen = isOpen && fullscreen;
16799
+ useEffect(() => {
16800
+ if (!isLightboxOpen) return;
16801
+ const onKeyDown = (e) => {
16802
+ if (e.key === "Escape") {
16803
+ e.stopPropagation();
16804
+ close();
16805
+ }
16806
+ };
16807
+ document.addEventListener("keydown", onKeyDown);
16808
+ return () => document.removeEventListener("keydown", onKeyDown);
16809
+ }, [isLightboxOpen, close]);
16810
+ useEffect(() => {
16811
+ if (!isLightboxOpen) return;
16812
+ const previous = document.body.style.overflow;
16813
+ document.body.style.overflow = "hidden";
16814
+ return () => {
16815
+ document.body.style.overflow = previous;
16816
+ };
16817
+ }, [isLightboxOpen]);
16818
+ const wasOpen = useRef(false);
16819
+ useEffect(() => {
16820
+ if (isLightboxOpen) {
16821
+ closeRef.current?.focus();
16822
+ } else if (wasOpen.current) {
16823
+ triggerRef.current?.focus({ preventScroll: true });
16824
+ }
16825
+ wasOpen.current = isLightboxOpen;
16826
+ }, [isLightboxOpen]);
16827
+ const overlay = isLightboxOpen && typeof document !== "undefined" ? createPortal(
16828
+ /* @__PURE__ */ jsxs(
16829
+ "div",
16830
+ {
16831
+ className: "image-lightbox",
16832
+ role: "dialog",
16833
+ "aria-modal": "true",
16834
+ "aria-label": alt || "Image",
16835
+ onClick: close,
16836
+ children: [
16837
+ /* @__PURE__ */ jsx(
16838
+ "button",
16839
+ {
16840
+ ref: closeRef,
16841
+ type: "button",
16842
+ className: "image-lightbox-close",
16843
+ "aria-label": "Close fullscreen image",
16844
+ onClick: close,
16845
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
16846
+ }
16847
+ ),
16848
+ /* @__PURE__ */ jsx(
16849
+ "img",
16850
+ {
16851
+ className: "image-lightbox-img",
16852
+ src,
16853
+ alt,
16854
+ onClick: (e) => e.stopPropagation()
16855
+ }
16856
+ )
16857
+ ]
16858
+ }
16859
+ ),
16860
+ document.body
16861
+ ) : null;
16862
+ const img = /* @__PURE__ */ jsx(
16863
+ "img",
16864
+ {
16865
+ className: `image-item text-item ${fullscreen ? "image-item-zoomable" : ""}`,
16866
+ src,
16867
+ alt,
16868
+ ...width !== void 0 && { width },
16869
+ ...height !== void 0 && { height },
16870
+ loading: "lazy",
16871
+ ...fullscreen && { onClick: open }
16872
+ }
16873
+ );
16874
+ if (!fullscreen) return img;
16875
+ return /* @__PURE__ */ jsxs("span", { className: "image-item-wrapper", children: [
16876
+ img,
16877
+ /* @__PURE__ */ jsx(
16878
+ "button",
16879
+ {
16880
+ ref: triggerRef,
16881
+ type: "button",
16882
+ className: "image-zoom-btn",
16883
+ "aria-label": alt ? `View "${alt}" fullscreen` : "View image fullscreen",
16884
+ onClick: open,
16885
+ children: /* @__PURE__ */ jsx(ExpandDiamondIcon, {})
16886
+ }
16887
+ ),
16888
+ overlay
16889
+ ] });
16890
+ };
16660
16891
  const EPSILON = 10 ** -INTERNAL_PRECISION;
16661
16892
  const cleanFloat = (n) => parseFloat(n.toFixed(INTERNAL_PRECISION));
16662
16893
  const roundTick = (n) => parseFloat(n.toFixed(DISPLAY_PRECISION));
@@ -16710,7 +16941,7 @@ const getPositionWidgetId = (content) => {
16710
16941
  }
16711
16942
  return null;
16712
16943
  };
16713
- const toHighlightColor = (color) => `var(--nl-highlight-${color})`;
16944
+ const toHighlightColor = (color) => color.startsWith("#") ? color : `var(--nl-highlight-${color})`;
16714
16945
  const getBandGeometry = (h, min, max) => {
16715
16946
  const leftPct = toPercent(Math.min(h.from, h.to), min, max);
16716
16947
  const rightPct = toPercent(Math.max(h.from, h.to), min, max);
@@ -17407,24 +17638,27 @@ function getArrowArcLabelTop(widthPct) {
17407
17638
  const arcTop = svgTop + ARROW_ARC_BASE_Y - getArrowArcLift(widthPct);
17408
17639
  return Math.max(0, arcTop - ARROW_ARC_LABEL_OFFSET);
17409
17640
  }
17410
- function getArrowArcPaths(widthPct, svgWidthPx = ARROW_ARC_VIEWBOX_WIDTH) {
17411
- const endX = getArrowArcSvgWidth(svgWidthPx);
17641
+ function getArrowArcPaths(widthPct, svgWidthPx = ARROW_ARC_VIEWBOX_WIDTH, reversed = false) {
17642
+ const width = getArrowArcSvgWidth(svgWidthPx);
17643
+ const startX = reversed ? width : 0;
17644
+ const tipX = reversed ? 0 : width;
17645
+ const sign = reversed ? -1 : 1;
17412
17646
  const controlInset = Math.min(svgWidthPx * 0.18, 48);
17413
17647
  const lift = getArrowArcLift(widthPct);
17414
17648
  const controlY = fmt(ARROW_ARC_BASE_Y - lift);
17415
- const tangentAngle = Math.atan2(ARROW_ARC_BASE_Y - controlY, endX - (endX - controlInset));
17416
- const tx = Math.cos(tangentAngle);
17649
+ const tangentAngle = Math.atan2(ARROW_ARC_BASE_Y - controlY, controlInset);
17650
+ const tx = Math.cos(tangentAngle) * sign;
17417
17651
  const ty = Math.sin(tangentAngle);
17418
- const shaftEndX = fmt(endX - tx * ARROW_ARC_HEAD_LENGTH);
17652
+ const shaftEndX = fmt(tipX - tx * ARROW_ARC_HEAD_LENGTH);
17419
17653
  const shaftEndY = fmt(ARROW_ARC_BASE_Y - ty * ARROW_ARC_HEAD_LENGTH);
17420
17654
  const endControlX = fmt(shaftEndX - tx * controlInset);
17421
17655
  const endControlY = fmt(shaftEndY - ty * controlInset);
17422
- const arcPath = `M 0 ${ARROW_ARC_BASE_Y} C ${fmt(controlInset)} ${controlY} ${endControlX} ${endControlY} ${shaftEndX} ${shaftEndY}`;
17656
+ const arcPath = `M ${fmt(startX)} ${ARROW_ARC_BASE_Y} C ${fmt(startX + sign * controlInset)} ${controlY} ${endControlX} ${endControlY} ${shaftEndX} ${shaftEndY}`;
17423
17657
  const nx = -ty;
17424
17658
  const ny = tx;
17425
- const baseX = endX - tx * ARROW_ARC_HEAD_LENGTH;
17659
+ const baseX = tipX - tx * ARROW_ARC_HEAD_LENGTH;
17426
17660
  const baseY = ARROW_ARC_BASE_Y - ty * ARROW_ARC_HEAD_LENGTH;
17427
- const headPath = `M ${fmt(endX)} ${ARROW_ARC_BASE_Y} L ${fmt(baseX + nx * ARROW_ARC_HEAD_HALF_WIDTH)} ${fmt(baseY + ny * ARROW_ARC_HEAD_HALF_WIDTH)} L ${fmt(baseX - nx * ARROW_ARC_HEAD_HALF_WIDTH)} ${fmt(baseY - ny * ARROW_ARC_HEAD_HALF_WIDTH)} Z`;
17661
+ const headPath = `M ${fmt(tipX)} ${ARROW_ARC_BASE_Y} L ${fmt(baseX + nx * ARROW_ARC_HEAD_HALF_WIDTH)} ${fmt(baseY + ny * ARROW_ARC_HEAD_HALF_WIDTH)} L ${fmt(baseX - nx * ARROW_ARC_HEAD_HALF_WIDTH)} ${fmt(baseY - ny * ARROW_ARC_HEAD_HALF_WIDTH)} Z`;
17428
17662
  return { arcPath, headPath };
17429
17663
  }
17430
17664
  function getArrowArcLayouts(arrows, min, max) {
@@ -17435,9 +17669,10 @@ function getArrowArcLayouts(arrows, min, max) {
17435
17669
  return {
17436
17670
  arrow,
17437
17671
  index,
17438
- leftPct: fromPct,
17439
- rightPct: toPct,
17440
- widthPct: toPct - fromPct,
17672
+ leftPct: Math.min(fromPct, toPct),
17673
+ rightPct: Math.max(fromPct, toPct),
17674
+ widthPct: Math.abs(toPct - fromPct),
17675
+ reversed: toPct < fromPct,
17441
17676
  level: 0
17442
17677
  };
17443
17678
  }).filter((layout) => layout.widthPct > 0).sort((a, b) => a.leftPct - b.leftPct || a.rightPct - b.rightPct || a.index - b.index);
@@ -17474,7 +17709,7 @@ function useElementWidth() {
17474
17709
  return [ref, width];
17475
17710
  }
17476
17711
  const ArrowArc = ({
17477
- layout: { arrow, leftPct, widthPct, level },
17712
+ layout: { arrow, leftPct, widthPct, reversed, level },
17478
17713
  widgets,
17479
17714
  values,
17480
17715
  droppedInputs,
@@ -17486,8 +17721,8 @@ const ArrowArc = ({
17486
17721
  const hasLabel = arrow.content.length > 0;
17487
17722
  const svgWidthPx = getArrowArcSvgWidth(renderedWidthPx);
17488
17723
  const { arcPath, headPath } = useMemo(
17489
- () => getArrowArcPaths(widthPct, svgWidthPx),
17490
- [widthPct, svgWidthPx]
17724
+ () => getArrowArcPaths(widthPct, svgWidthPx, reversed),
17725
+ [widthPct, svgWidthPx, reversed]
17491
17726
  );
17492
17727
  return /* @__PURE__ */ jsxs(
17493
17728
  "div",
@@ -18243,14 +18478,13 @@ const LayoutRenderer = ({
18243
18478
  }
18244
18479
  case JSON_TYPES.IMAGE:
18245
18480
  return /* @__PURE__ */ jsx(
18246
- "img",
18481
+ ImageItem,
18247
18482
  {
18248
- className: "image-item text-item",
18249
18483
  src: item.src,
18250
18484
  alt: item.alt,
18251
- ...item.width !== void 0 && { width: item.width },
18252
- ...item.height !== void 0 && { height: item.height },
18253
- loading: "lazy"
18485
+ width: item.width,
18486
+ height: item.height,
18487
+ fullscreen: item.fullscreen
18254
18488
  }
18255
18489
  );
18256
18490
  case JSON_TYPES.WIDGET_REF: {