@mathscan/math-exercise-engine 1.2.8 → 1.2.10

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/style.css CHANGED
@@ -2626,6 +2626,28 @@ th.exercise-table-cell.exercise-table-cell--last-row:last-child {
2626
2626
  transform: translateY(-50%);
2627
2627
  }
2628
2628
 
2629
+ /**
2630
+ * GEOMETRY widget — the wrapper this package owns. Everything inside it is
2631
+ * rendered by @mathscan/geometry-engine, which ships no stylesheet of its own
2632
+ * and sizes its canvas from the box it is given.
2633
+ */
2634
+
2635
+ .geometry-widget {
2636
+ width: 100%;
2637
+ max-width: 100%;
2638
+ margin: 0;
2639
+ }
2640
+
2641
+ /* Reserves the canvas box while the engine's React entry is still loading, so
2642
+ the exercise does not jump when the canvas appears. */
2643
+
2644
+ .geometry-widget__loading {
2645
+ width: 100%;
2646
+ aspect-ratio: 1 / 1;
2647
+ border-radius: 8px;
2648
+ background: var(--exercise-bg, transparent);
2649
+ }
2650
+
2629
2651
  /**
2630
2652
  * Button & Action Styles
2631
2653
  *
@@ -2767,8 +2789,22 @@ th.exercise-table-cell.exercise-table-cell--last-row:last-child {
2767
2789
 
2768
2790
  /* ── Root container ─────────────────────────────────────────────────────────── */
2769
2791
 
2792
+ /* CSS-only scroll shadows (Lea Verou): edge-pinned radial gradients revealed by
2793
+ `local`-attached cover gradients that scroll away with the content. */
2794
+
2770
2795
  .chart-scroll {
2771
2796
  width: 100%;
2797
+ overflow-x: auto;
2798
+ -webkit-overflow-scrolling: touch;
2799
+ background:
2800
+ linear-gradient(to right, var(--exercise-bg, #fff) 30%, transparent),
2801
+ linear-gradient(to left, var(--exercise-bg, #fff) 30%, transparent) 100% 0,
2802
+ radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.15), transparent),
2803
+ radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.15), transparent) 100% 0;
2804
+ background-repeat: no-repeat;
2805
+ background-color: var(--exercise-bg, #fff);
2806
+ background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
2807
+ background-attachment: local, local, scroll, scroll;
2772
2808
  }
2773
2809
 
2774
2810
  .chart {
@@ -3474,6 +3510,120 @@ th.exercise-table-cell.exercise-table-cell--last-row:last-child {
3474
3510
  width: 1px;
3475
3511
  }
3476
3512
 
3513
+ /* ═══════════════════════════════════════════════════════════════════════════
3514
+ GROUPED-BAR CHART (.chart--grouped-bar)
3515
+ Two nesting levels: .chart-groups > .chart-group (cluster) > .chart-bar-wrapper.
3516
+ Bars inside a cluster reuse every bar-chart rule and var untouched; the only
3517
+ new spacing is the cluster gap (--chart-group-gap vs --chart-bar-gap).
3518
+ ═══════════════════════════════════════════════════════════════════════════ */
3519
+
3520
+ .chart-groups {
3521
+ position: absolute;
3522
+ inset: 0;
3523
+ display: flex;
3524
+ align-items: flex-end;
3525
+ justify-content: center;
3526
+ padding-inline: var(--chart-group-gap);
3527
+ gap: var(--chart-group-gap);
3528
+ }
3529
+
3530
+ .chart-group {
3531
+ flex: 0 0 var(--chart-group-width);
3532
+ width: var(--chart-group-width);
3533
+ display: flex;
3534
+ align-items: flex-end;
3535
+ justify-content: center;
3536
+ gap: var(--chart-bar-gap);
3537
+ height: 100%;
3538
+ }
3539
+
3540
+ /* Series declared but absent from this GROUP: holds the slot, paints nothing. */
3541
+
3542
+ .chart-group-bar-gap {
3543
+ flex: 0 0 var(--chart-bar-slot-width);
3544
+ width: var(--chart-bar-slot-width);
3545
+ height: 100%;
3546
+ }
3547
+
3548
+ /* Category label row: bar-chart's .chart-axis-x widened from a bar to a cluster. */
3549
+
3550
+ .chart--grouped-bar .chart-axis-x {
3551
+ padding-inline: var(--chart-group-gap);
3552
+ gap: var(--chart-group-gap);
3553
+ }
3554
+
3555
+ .chart--grouped-bar .chart-axis-tick-x {
3556
+ flex: 0 0 var(--chart-group-width);
3557
+ }
3558
+
3559
+ /* ── Horizontal ─────────────────────────────────────────────────────────────── */
3560
+
3561
+ .chart--horizontal .chart-groups {
3562
+ flex-direction: column;
3563
+ align-items: flex-start;
3564
+ justify-content: flex-start;
3565
+ padding-inline: 0;
3566
+ padding-block: var(--chart-group-gap);
3567
+ }
3568
+
3569
+ .chart--horizontal .chart-group {
3570
+ flex: 0 0 var(--chart-group-width);
3571
+ height: var(--chart-group-width);
3572
+ width: 100%;
3573
+ /* Column, not row: each bar needs the full plot width to fill from 0. */
3574
+ flex-direction: column;
3575
+ align-items: flex-start;
3576
+ justify-content: flex-start;
3577
+ }
3578
+
3579
+ .chart--horizontal .chart-group-bar-gap {
3580
+ flex: 0 0 var(--chart-bar-slot-width);
3581
+ width: 100%;
3582
+ height: var(--chart-bar-slot-width);
3583
+ }
3584
+
3585
+ .chart--grouped-bar.chart--horizontal .chart-axis-y--categories {
3586
+ padding-block: var(--chart-group-gap);
3587
+ gap: var(--chart-group-gap);
3588
+ }
3589
+
3590
+ .chart--grouped-bar.chart--horizontal .chart-bar-y-label {
3591
+ flex: 0 0 var(--chart-group-width);
3592
+ height: var(--chart-group-width);
3593
+ }
3594
+
3595
+ /* ── Legend ─────────────────────────────────────────────────────────────────── */
3596
+
3597
+ /* Explicit cell: grid auto-placement would float it above the chart. */
3598
+
3599
+ .chart-legend {
3600
+ display: flex;
3601
+ flex-wrap: wrap;
3602
+ justify-content: center;
3603
+ gap: 0.4rem 1rem;
3604
+ padding-top: 0.6rem;
3605
+ grid-column: 3;
3606
+ grid-row: 5;
3607
+ }
3608
+
3609
+ .chart-legend-item {
3610
+ display: flex;
3611
+ align-items: center;
3612
+ gap: 0.4rem;
3613
+ }
3614
+
3615
+ .chart-legend-swatch {
3616
+ width: 0.85rem;
3617
+ height: 0.85rem;
3618
+ border-radius: 3px;
3619
+ flex: 0 0 auto;
3620
+ }
3621
+
3622
+ .chart-legend-label {
3623
+ font-size: var(--chart-label-font-size);
3624
+ color: var(--exercise-text-primary, #1f2937);
3625
+ }
3626
+
3477
3627
  /* Responsive Overrides - must be last */
3478
3628
 
3479
3629
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mathscan/math-exercise-engine",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
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",
@@ -18,6 +18,7 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "build": "vite build",
21
+ "check:geometry-isolation": "node --no-warnings --experimental-loader ./scripts/geometry-validation-isolation-loader.mjs ./scripts/check-geometry-validation-isolation.mjs && node ./scripts/check-geometry-bundle-isolation.mjs",
21
22
  "dev": "vite build --watch",
22
23
  "playground": "vite --open /playground/grid-symmetry-builder/",
23
24
  "demo": "node examples/demo.mjs",
@@ -31,7 +32,7 @@
31
32
  "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"*.{json,md}\"",
32
33
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"*.{json,md}\"",
33
34
  "typecheck": "tsc --noEmit",
34
- "prepublishOnly": "pnpm run build"
35
+ "prepublishOnly": "pnpm run build && pnpm run check:geometry-isolation"
35
36
  },
36
37
  "keywords": [
37
38
  "math",
@@ -48,14 +49,17 @@
48
49
  "dependencies": {
49
50
  "@dnd-kit/core": "^6.3.1",
50
51
  "@dnd-kit/utilities": "^3.2.2",
52
+ "@mathscan/geometry-engine": "0.1.4",
51
53
  "chevrotain": "^11.0.3",
52
54
  "lodash": "^4.17.21",
53
55
  "mathjs": "^12.4.0",
54
56
  "zod": "^3.22.4"
55
57
  },
56
58
  "peerDependencies": {
57
- "react": "^18.0.0 || ^19.0.0",
58
- "react-dom": "^18.0.0 || ^19.0.0"
59
+ "konva": "^10.3.0",
60
+ "react": "^19.2.0",
61
+ "react-dom": "^19.2.0",
62
+ "react-konva": "^19.2.5"
59
63
  },
60
64
  "peerDependenciesMeta": {
61
65
  "react": {
@@ -63,6 +67,12 @@
63
67
  },
64
68
  "react-dom": {
65
69
  "optional": true
70
+ },
71
+ "konva": {
72
+ "optional": true
73
+ },
74
+ "react-konva": {
75
+ "optional": true
66
76
  }
67
77
  },
68
78
  "devDependencies": {
@@ -89,7 +99,7 @@
89
99
  "vitest": "^4.0.17"
90
100
  },
91
101
  "engines": {
92
- "node": ">=18.0.0"
102
+ "node": "^20.19.0 || >=22.12.0"
93
103
  },
94
104
  "packageManager": "pnpm@8.15.0"
95
105
  }