@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.d.ts +344 -54
- package/dist/index.js +268 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +269 -35
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +183 -11
- package/package.json +1 -1
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.
|
|
1908
|
-
|
|
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(
|
|
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
|
|
1952
|
-
message: "ARROW: from must be
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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
|
|
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,
|
|
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(
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
18481
|
+
ImageItem,
|
|
18247
18482
|
{
|
|
18248
|
-
className: "image-item text-item",
|
|
18249
18483
|
src: item.src,
|
|
18250
18484
|
alt: item.alt,
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18485
|
+
width: item.width,
|
|
18486
|
+
height: item.height,
|
|
18487
|
+
fullscreen: item.fullscreen
|
|
18254
18488
|
}
|
|
18255
18489
|
);
|
|
18256
18490
|
case JSON_TYPES.WIDGET_REF: {
|