@mathscan/math-exercise-engine 1.1.8 → 1.1.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.
- package/dist/index.d.ts +8069 -3402
- package/dist/index.js +700 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +700 -43
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +220 -44
- package/package.json +1 -1
package/dist/style.css
CHANGED
|
@@ -1206,6 +1206,8 @@ th.exercise-table-cell {
|
|
|
1206
1206
|
--nl-visual-fraction-size: clamp(5.5rem, 18vw, 8rem);
|
|
1207
1207
|
/* Visual gap between end ticks and arrowheads — pure CSS, no effect on calculations */
|
|
1208
1208
|
--nl-arrow-gap: 8px;
|
|
1209
|
+
--nl-arrow-arc-color: var(--exercise-danger, #D6234D);
|
|
1210
|
+
--nl-arrow-arc-stroke-width: 1.75;
|
|
1209
1211
|
}
|
|
1210
1212
|
|
|
1211
1213
|
/* ========================================
|
|
@@ -1255,7 +1257,64 @@ th.exercise-table-cell {
|
|
|
1255
1257
|
}
|
|
1256
1258
|
|
|
1257
1259
|
/* ========================================
|
|
1258
|
-
ROW 2 —
|
|
1260
|
+
ROW 2 — ARROW ANNOTATION ARCS
|
|
1261
|
+
======================================== */
|
|
1262
|
+
|
|
1263
|
+
.number-line-arrow-arcs-row {
|
|
1264
|
+
position: relative;
|
|
1265
|
+
width: 100%;
|
|
1266
|
+
margin-top: 0.1rem;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.number-line-arrow-arc {
|
|
1270
|
+
position: absolute;
|
|
1271
|
+
height: 80px;
|
|
1272
|
+
pointer-events: none;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
.number-line-arrow-arc-svg {
|
|
1276
|
+
position: absolute;
|
|
1277
|
+
left: 0;
|
|
1278
|
+
right: 0;
|
|
1279
|
+
bottom: 0;
|
|
1280
|
+
width: 100%;
|
|
1281
|
+
height: 64px;
|
|
1282
|
+
overflow: visible;
|
|
1283
|
+
pointer-events: none;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.number-line-arrow-arc-path {
|
|
1287
|
+
fill: none;
|
|
1288
|
+
stroke: var(--nl-arrow-arc-color);
|
|
1289
|
+
stroke-width: var(--nl-arrow-arc-stroke-width);
|
|
1290
|
+
stroke-linecap: round;
|
|
1291
|
+
stroke-linejoin: round;
|
|
1292
|
+
vector-effect: non-scaling-stroke;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
.number-line-arrow-arc-head {
|
|
1296
|
+
fill: var(--nl-arrow-arc-color);
|
|
1297
|
+
stroke: none;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
.number-line-arrow-arc-label {
|
|
1301
|
+
position: absolute;
|
|
1302
|
+
/* top is always set via inline style from getArrowArcLabelTop() */
|
|
1303
|
+
left: 50%;
|
|
1304
|
+
transform: translateX(-50%);
|
|
1305
|
+
color: var(--nl-arrow-arc-color);
|
|
1306
|
+
font-size: calc(var(--exercise-font-size) * 0.8);
|
|
1307
|
+
font-weight: var(--exercise-font-weight-bold, 600);
|
|
1308
|
+
line-height: 1.1;
|
|
1309
|
+
pointer-events: auto;
|
|
1310
|
+
/* Centre content horizontally; allow LayoutRenderer to size naturally */
|
|
1311
|
+
display: flex;
|
|
1312
|
+
align-items: center;
|
|
1313
|
+
justify-content: center;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/* ========================================
|
|
1317
|
+
ROW 3 — AXIS (track + ticks + arrows + dots)
|
|
1259
1318
|
======================================== */
|
|
1260
1319
|
|
|
1261
1320
|
.number-line-axis-row {
|
|
@@ -1264,6 +1323,10 @@ th.exercise-table-cell {
|
|
|
1264
1323
|
height: 2rem;
|
|
1265
1324
|
}
|
|
1266
1325
|
|
|
1326
|
+
.number-line-axis-row:has(.number-line-cursor-label) {
|
|
1327
|
+
height: 3rem;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1267
1330
|
/* In drag mode, chip zone is handled by .number-line--drag-mode padding-top on root */
|
|
1268
1331
|
|
|
1269
1332
|
/* Horizontal track line — spans [--nl-side-pad, 100% - --nl-side-pad] by default */
|
|
@@ -1543,7 +1606,7 @@ th.exercise-table-cell {
|
|
|
1543
1606
|
/* Axis glow on drag-over intentionally disabled — axis stays neutral */
|
|
1544
1607
|
|
|
1545
1608
|
/* ========================================
|
|
1546
|
-
ROW
|
|
1609
|
+
ROW 4 — NUMERIC TICK LABELS
|
|
1547
1610
|
======================================== */
|
|
1548
1611
|
|
|
1549
1612
|
.number-line-labels-row {
|
|
@@ -1563,7 +1626,7 @@ th.exercise-table-cell {
|
|
|
1563
1626
|
}
|
|
1564
1627
|
|
|
1565
1628
|
/* ========================================
|
|
1566
|
-
HIGHLIGHT BANDS
|
|
1629
|
+
ROW 5 — HIGHLIGHT BANDS / LABELS
|
|
1567
1630
|
======================================== */
|
|
1568
1631
|
|
|
1569
1632
|
/* A coloured band spanning [from%, to%] on the axis row */
|
|
@@ -1598,84 +1661,197 @@ th.exercise-table-cell {
|
|
|
1598
1661
|
pointer-events: none;
|
|
1599
1662
|
}
|
|
1600
1663
|
|
|
1664
|
+
/* ========================================
|
|
1665
|
+
CURSOR BALL
|
|
1666
|
+
======================================== */
|
|
1667
|
+
|
|
1668
|
+
/* Filled range between the cursor's initial value and its current position */
|
|
1669
|
+
|
|
1670
|
+
.number-line-cursor-fill {
|
|
1671
|
+
position: absolute;
|
|
1672
|
+
top: 50%;
|
|
1673
|
+
transform: translateY(-50%);
|
|
1674
|
+
height: 6px;
|
|
1675
|
+
background-color: var(--nl-cursor-color, var(--exercise-accent, #705DC0));
|
|
1676
|
+
opacity: 0.28;
|
|
1677
|
+
border-radius: 999px;
|
|
1678
|
+
pointer-events: none;
|
|
1679
|
+
z-index: 2;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/* The ball rendered at the cursor's current value */
|
|
1683
|
+
|
|
1684
|
+
.number-line-cursor-ball {
|
|
1685
|
+
position: absolute;
|
|
1686
|
+
top: 50%;
|
|
1687
|
+
transform: translate(-50%, -50%);
|
|
1688
|
+
width: 16px;
|
|
1689
|
+
height: 16px;
|
|
1690
|
+
border-radius: 50%;
|
|
1691
|
+
background-color: #fff;
|
|
1692
|
+
border: 2.5px solid var(--nl-cursor-color, var(--exercise-accent, #705DC0));
|
|
1693
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
|
|
1694
|
+
pointer-events: auto;
|
|
1695
|
+
cursor: grab;
|
|
1696
|
+
z-index: 4;
|
|
1697
|
+
touch-action: none; /* required for pointer capture on mobile */
|
|
1698
|
+
transition: box-shadow 0.12s ease, transform 0.12s ease;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
.number-line-cursor-ball:hover {
|
|
1702
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
|
1703
|
+
transform: translate(-50%, -50%) scale(1.15);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
.number-line-cursor-ball--dragging {
|
|
1707
|
+
cursor: grabbing;
|
|
1708
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.32);
|
|
1709
|
+
transform: translate(-50%, -50%) scale(1.25);
|
|
1710
|
+
transition: none;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
@keyframes number-line-cursor-jiggle {
|
|
1714
|
+
0%, 100% { transform: translate(-50%, -50%) translateX(0) rotate(0deg); }
|
|
1715
|
+
20% { transform: translate(-50%, -50%) translateX(-5px) rotate(-2deg); }
|
|
1716
|
+
40% { transform: translate(-50%, -50%) translateX(5px) rotate(2deg); }
|
|
1717
|
+
60% { transform: translate(-50%, -50%) translateX(-3px) rotate(-1deg); }
|
|
1718
|
+
80% { transform: translate(-50%, -50%) translateX(3px) rotate(1deg); }
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
.number-line-cursor-ball--jiggle {
|
|
1722
|
+
animation: number-line-cursor-jiggle 0.55s ease-in-out 0.4s 2 both;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
.number-line-cursor-label {
|
|
1726
|
+
position: absolute;
|
|
1727
|
+
top: calc(50% - 0.6rem);
|
|
1728
|
+
display: block;
|
|
1729
|
+
max-width: min(8rem, 26vw);
|
|
1730
|
+
transform: translate(-50%, -100%);
|
|
1731
|
+
overflow: hidden;
|
|
1732
|
+
color: var(--nl-cursor-color, var(--exercise-text-light, #555));
|
|
1733
|
+
font-size: calc(var(--exercise-font-size) * 0.75);
|
|
1734
|
+
font-weight: var(--exercise-font-weight-bold, 600);
|
|
1735
|
+
line-height: 1.1;
|
|
1736
|
+
pointer-events: none;
|
|
1737
|
+
text-align: center;
|
|
1738
|
+
text-overflow: ellipsis;
|
|
1739
|
+
white-space: nowrap;
|
|
1740
|
+
z-index: 5;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/* Validation feedback — mirrors the correct/incorrect axis colors */
|
|
1744
|
+
|
|
1745
|
+
.number-line-cursor-ball--correct,
|
|
1746
|
+
.number-line-cursor-fill--correct,
|
|
1747
|
+
.number-line-cursor-label--correct {
|
|
1748
|
+
--nl-cursor-color: #43B925;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
.number-line-cursor-ball--incorrect,
|
|
1752
|
+
.number-line-cursor-fill--incorrect,
|
|
1753
|
+
.number-line-cursor-label--incorrect {
|
|
1754
|
+
--nl-cursor-color: #D6234D;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
.number-line-cursor-ball:focus-visible {
|
|
1758
|
+
outline: 2px solid var(--nl-cursor-color, var(--exercise-accent, #705DC0));
|
|
1759
|
+
outline-offset: 3px;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1601
1762
|
/* ========================================
|
|
1602
1763
|
COUNTER UI
|
|
1764
|
+
ROW 6 — COUNTER UI
|
|
1603
1765
|
======================================== */
|
|
1604
1766
|
|
|
1605
1767
|
.number-line-counter {
|
|
1768
|
+
/* ── Color tokens (override to restyle) ── */
|
|
1769
|
+
--nl-counter-bg: #FFFFFF;
|
|
1770
|
+
--nl-counter-border-color: #FFCA76;
|
|
1771
|
+
--nl-counter-value-color: #705DC0;
|
|
1772
|
+
--nl-counter-btn-bg: #E7E2FF;
|
|
1773
|
+
--nl-counter-btn-color: #705DC0;
|
|
1774
|
+
|
|
1775
|
+
/* ── Layout ── */
|
|
1606
1776
|
display: flex;
|
|
1607
1777
|
flex-direction: column;
|
|
1608
1778
|
align-items: center;
|
|
1609
1779
|
gap: 0.25rem;
|
|
1610
|
-
margin
|
|
1780
|
+
margin: 0.5rem auto 0;
|
|
1611
1781
|
padding: 0.4rem 0.75rem;
|
|
1612
1782
|
width: fit-content;
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
border:
|
|
1617
|
-
border-radius: 8px;
|
|
1783
|
+
box-sizing: border-box;
|
|
1784
|
+
background: var(--nl-counter-bg);
|
|
1785
|
+
border: 1px solid var(--nl-counter-border-color);
|
|
1786
|
+
border-radius: 9px;
|
|
1618
1787
|
}
|
|
1619
1788
|
|
|
1620
|
-
|
|
1789
|
+
.number-line-counter-label {
|
|
1790
|
+
font-size: calc(var(--exercise-font-size) * 0.85);
|
|
1791
|
+
color: var(--exercise-text-light, #555);
|
|
1792
|
+
text-align: center;
|
|
1793
|
+
}
|
|
1621
1794
|
|
|
1622
1795
|
.number-line-counter-controls {
|
|
1623
1796
|
display: flex;
|
|
1624
1797
|
align-items: center;
|
|
1625
1798
|
justify-content: center;
|
|
1626
|
-
gap: 0.
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
.number-line-counter-label {
|
|
1630
|
-
font-size: calc(var(--exercise-font-size) * 0.85);
|
|
1631
|
-
color: var(--exercise-text-light, #555);
|
|
1632
|
-
text-align: center;
|
|
1799
|
+
gap: 0.75rem;
|
|
1633
1800
|
}
|
|
1634
1801
|
|
|
1635
1802
|
.number-line-counter-value {
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
color: var(--exercise-text, #333);
|
|
1803
|
+
display: flex;
|
|
1804
|
+
align-items: center;
|
|
1805
|
+
justify-content: center;
|
|
1640
1806
|
min-width: 2ch;
|
|
1641
|
-
|
|
1807
|
+
font-size: calc(var(--exercise-font-size) * 2);
|
|
1808
|
+
font-weight: 700;
|
|
1809
|
+
font-variant-numeric: tabular-nums;
|
|
1642
1810
|
line-height: 1;
|
|
1811
|
+
text-align: center;
|
|
1812
|
+
color: var(--nl-counter-value-color);
|
|
1643
1813
|
}
|
|
1644
1814
|
|
|
1645
1815
|
.number-line-counter-btn {
|
|
1816
|
+
position: relative;
|
|
1646
1817
|
display: inline-flex;
|
|
1647
1818
|
align-items: center;
|
|
1648
1819
|
justify-content: center;
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
color: var(--exercise-accent, #705DC0);
|
|
1657
|
-
font-size: 1.1rem;
|
|
1658
|
-
font-weight: 500;
|
|
1659
|
-
line-height: 1;
|
|
1820
|
+
width: 48px;
|
|
1821
|
+
height: 48px;
|
|
1822
|
+
border: none;
|
|
1823
|
+
border-radius: 9px;
|
|
1824
|
+
background: var(--nl-counter-btn-bg);
|
|
1825
|
+
color: var(--nl-counter-btn-color);
|
|
1826
|
+
font-size: 0;
|
|
1660
1827
|
cursor: pointer;
|
|
1661
|
-
transition:
|
|
1828
|
+
transition: filter 0.12s ease, transform 0.12s ease;
|
|
1662
1829
|
-webkit-tap-highlight-color: transparent;
|
|
1663
1830
|
}
|
|
1664
1831
|
|
|
1665
|
-
.number-line-counter-btn:hover:not(:disabled)
|
|
1666
|
-
background: var(--exercise-accent, #705DC0);
|
|
1667
|
-
color: white;
|
|
1668
|
-
}
|
|
1832
|
+
.number-line-counter-btn:hover:not(:disabled) { filter: brightness(0.94); }
|
|
1669
1833
|
|
|
1670
|
-
.number-line-counter-btn:active:not(:disabled) {
|
|
1671
|
-
|
|
1672
|
-
}
|
|
1834
|
+
.number-line-counter-btn:active:not(:disabled) { transform: scale(0.93); }
|
|
1835
|
+
|
|
1836
|
+
.number-line-counter-btn:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
1673
1837
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1838
|
+
/* ── Icon pseudo-elements (horizontal bar shared; vertical bar on + only) ── */
|
|
1839
|
+
|
|
1840
|
+
.number-line-counter-btn::before,
|
|
1841
|
+
.number-line-counter-btn::after {
|
|
1842
|
+
content: '';
|
|
1843
|
+
position: absolute;
|
|
1844
|
+
left: 50%;
|
|
1845
|
+
top: 50%;
|
|
1846
|
+
background: currentColor;
|
|
1847
|
+
border-radius: 999px;
|
|
1848
|
+
transform: translate(-50%, -50%);
|
|
1677
1849
|
}
|
|
1678
1850
|
|
|
1851
|
+
.number-line-counter-btn::before { width: 29px; height: 7px; }
|
|
1852
|
+
|
|
1853
|
+
.number-line-counter-btn[aria-label='Increase']::after { width: 7px; height: 29px; }
|
|
1854
|
+
|
|
1679
1855
|
/* ========================================
|
|
1680
1856
|
ACCESSIBILITY — FOCUS-VISIBLE RINGS (item 6)
|
|
1681
1857
|
======================================== */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mathscan/math-exercise-engine",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "A DSL parser and validator for math exercises - transforms text-based exercise definitions into structured AST and JSON",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|