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