react-math-blocks 0.1.0
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/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/index.d.mts +44 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +240 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PrintNum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# react-math-blocks
|
|
2
|
+
|
|
3
|
+
## Live Demo & Full Customization available at [PrintNum.com](https://printnum.com).
|
|
4
|
+
|
|
5
|
+
Lightweight open-source React components for Number Blocks and Ten-Frame visuals.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install react-math-blocks
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { MathBlocks, TenFrame } from "react-math-blocks";
|
|
17
|
+
|
|
18
|
+
export default function Demo() {
|
|
19
|
+
return (
|
|
20
|
+
<div style={{ display: "grid", gap: 24 }}>
|
|
21
|
+
<MathBlocks value={12} layout="array" colorStyle="Rainbow" showCountingDots />
|
|
22
|
+
<TenFrame value={17} colorStyle="Pastel" showCountingDots />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## API
|
|
29
|
+
|
|
30
|
+
### MathBlocks
|
|
31
|
+
|
|
32
|
+
Props:
|
|
33
|
+
- value: number (1 to 100)
|
|
34
|
+
- layout: "auto" | "stack" | "grid" | "ten-frame" | "array"
|
|
35
|
+
- colorStyle: "Rainbow" | "Single Color" | "Warm" | "Cool" | "Pastel" | "B&W (Coloring)"
|
|
36
|
+
- face: "Happy" | "Smile" | "Surprised" | "Thinking"
|
|
37
|
+
- showNumberLabel: boolean
|
|
38
|
+
- showCountingDots: boolean
|
|
39
|
+
- size: number (pixel output size)
|
|
40
|
+
- className: string
|
|
41
|
+
- title: string
|
|
42
|
+
|
|
43
|
+
### TenFrame
|
|
44
|
+
|
|
45
|
+
Convenience wrapper with layout fixed to ten-frame.
|
|
46
|
+
|
|
47
|
+
## Development
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm run typecheck
|
|
51
|
+
npm run build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Publishing
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm login
|
|
58
|
+
npm run build
|
|
59
|
+
npm publish --access public
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type ColorStyle = "Rainbow" | "Single Color" | "Warm" | "Cool" | "Pastel" | "B&W (Coloring)";
|
|
4
|
+
declare function getBlockColor(index: number, style: ColorStyle): string;
|
|
5
|
+
|
|
6
|
+
type LayoutMode = "auto" | "stack" | "grid" | "ten-frame" | "array";
|
|
7
|
+
interface BlockPosition {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
index: number;
|
|
11
|
+
}
|
|
12
|
+
interface LayoutResult {
|
|
13
|
+
positions: BlockPosition[];
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
declare function generateBlockPositions(value: number, layout: LayoutMode): LayoutResult;
|
|
18
|
+
|
|
19
|
+
type FaceStyle = "Happy" | "Smile" | "Surprised" | "Thinking";
|
|
20
|
+
interface MathBlocksProps {
|
|
21
|
+
value: number;
|
|
22
|
+
layout?: LayoutMode;
|
|
23
|
+
colorStyle?: ColorStyle;
|
|
24
|
+
face?: FaceStyle;
|
|
25
|
+
showNumberLabel?: boolean;
|
|
26
|
+
showCountingDots?: boolean;
|
|
27
|
+
size?: number;
|
|
28
|
+
className?: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
}
|
|
31
|
+
interface TenFrameProps {
|
|
32
|
+
value: number;
|
|
33
|
+
colorStyle?: ColorStyle;
|
|
34
|
+
showNumberLabel?: boolean;
|
|
35
|
+
showCountingDots?: boolean;
|
|
36
|
+
className?: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare function MathBlocks({ value, layout, colorStyle, face, showNumberLabel, showCountingDots, size, className, title, }: MathBlocksProps): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare function TenFrame({ value, colorStyle, showNumberLabel, showCountingDots, className, title, }: TenFrameProps): React.JSX.Element;
|
|
43
|
+
|
|
44
|
+
export { type BlockPosition, type ColorStyle, type FaceStyle, type LayoutMode, type LayoutResult, MathBlocks, type MathBlocksProps, TenFrame, type TenFrameProps, generateBlockPositions, getBlockColor };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type ColorStyle = "Rainbow" | "Single Color" | "Warm" | "Cool" | "Pastel" | "B&W (Coloring)";
|
|
4
|
+
declare function getBlockColor(index: number, style: ColorStyle): string;
|
|
5
|
+
|
|
6
|
+
type LayoutMode = "auto" | "stack" | "grid" | "ten-frame" | "array";
|
|
7
|
+
interface BlockPosition {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
index: number;
|
|
11
|
+
}
|
|
12
|
+
interface LayoutResult {
|
|
13
|
+
positions: BlockPosition[];
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
declare function generateBlockPositions(value: number, layout: LayoutMode): LayoutResult;
|
|
18
|
+
|
|
19
|
+
type FaceStyle = "Happy" | "Smile" | "Surprised" | "Thinking";
|
|
20
|
+
interface MathBlocksProps {
|
|
21
|
+
value: number;
|
|
22
|
+
layout?: LayoutMode;
|
|
23
|
+
colorStyle?: ColorStyle;
|
|
24
|
+
face?: FaceStyle;
|
|
25
|
+
showNumberLabel?: boolean;
|
|
26
|
+
showCountingDots?: boolean;
|
|
27
|
+
size?: number;
|
|
28
|
+
className?: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
}
|
|
31
|
+
interface TenFrameProps {
|
|
32
|
+
value: number;
|
|
33
|
+
colorStyle?: ColorStyle;
|
|
34
|
+
showNumberLabel?: boolean;
|
|
35
|
+
showCountingDots?: boolean;
|
|
36
|
+
className?: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare function MathBlocks({ value, layout, colorStyle, face, showNumberLabel, showCountingDots, size, className, title, }: MathBlocksProps): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare function TenFrame({ value, colorStyle, showNumberLabel, showCountingDots, className, title, }: TenFrameProps): React.JSX.Element;
|
|
43
|
+
|
|
44
|
+
export { type BlockPosition, type ColorStyle, type FaceStyle, type LayoutMode, type LayoutResult, MathBlocks, type MathBlocksProps, TenFrame, type TenFrameProps, generateBlockPositions, getBlockColor };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
|
|
5
|
+
// src/colors.ts
|
|
6
|
+
var rainbow = ["#EF4444", "#F97316", "#EAB308", "#22C55E", "#3B82F6", "#8B5CF6", "#EC4899"];
|
|
7
|
+
var warm = ["#EF4444", "#F97316", "#F59E0B", "#EAB308", "#FB923C", "#F87171"];
|
|
8
|
+
var cool = ["#3B82F6", "#06B6D4", "#10B981", "#22C55E", "#6366F1", "#8B5CF6"];
|
|
9
|
+
var pastel = ["#FCA5A5", "#FDBA74", "#FDE047", "#86EFAC", "#93C5FD", "#C4B5FD", "#F9A8D4"];
|
|
10
|
+
function getBlockColor(index, style) {
|
|
11
|
+
switch (style) {
|
|
12
|
+
case "Single Color":
|
|
13
|
+
return "#3B82F6";
|
|
14
|
+
case "Warm":
|
|
15
|
+
return warm[index % warm.length];
|
|
16
|
+
case "Cool":
|
|
17
|
+
return cool[index % cool.length];
|
|
18
|
+
case "Pastel":
|
|
19
|
+
return pastel[index % pastel.length];
|
|
20
|
+
case "B&W (Coloring)":
|
|
21
|
+
return "#FFFFFF";
|
|
22
|
+
case "Rainbow":
|
|
23
|
+
default:
|
|
24
|
+
return rainbow[index % rainbow.length];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/layout.ts
|
|
29
|
+
function generateBlockPositions(value, layout) {
|
|
30
|
+
let normalized = Math.max(1, Math.floor(value));
|
|
31
|
+
if (layout === "auto") {
|
|
32
|
+
if (normalized <= 5) layout = "stack";
|
|
33
|
+
else if (normalized <= 20) layout = "ten-frame";
|
|
34
|
+
else layout = "grid";
|
|
35
|
+
}
|
|
36
|
+
const block = 60;
|
|
37
|
+
const gap = 4;
|
|
38
|
+
const cell = block + gap;
|
|
39
|
+
let cols = 1;
|
|
40
|
+
let rows = 1;
|
|
41
|
+
const positions = [];
|
|
42
|
+
if (layout === "stack") {
|
|
43
|
+
cols = 1;
|
|
44
|
+
rows = normalized;
|
|
45
|
+
for (let i = 0; i < normalized; i++) {
|
|
46
|
+
positions.push({ x: 0, y: (normalized - 1 - i) * cell, index: i });
|
|
47
|
+
}
|
|
48
|
+
} else if (layout === "grid") {
|
|
49
|
+
cols = Math.ceil(Math.sqrt(normalized));
|
|
50
|
+
rows = Math.ceil(normalized / cols);
|
|
51
|
+
for (let i = 0; i < normalized; i++) {
|
|
52
|
+
const c = i % cols;
|
|
53
|
+
const r = Math.floor(i / cols);
|
|
54
|
+
positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });
|
|
55
|
+
}
|
|
56
|
+
} else if (layout === "ten-frame") {
|
|
57
|
+
cols = Math.min(normalized, 5);
|
|
58
|
+
const groupSize = 10;
|
|
59
|
+
rows = 0;
|
|
60
|
+
for (let i = 0; i < normalized; i++) {
|
|
61
|
+
const groupIndex = Math.floor(i / groupSize);
|
|
62
|
+
const indexInGroup = i % groupSize;
|
|
63
|
+
const c = indexInGroup % 5;
|
|
64
|
+
const rInGroup = Math.floor(indexInGroup / 5);
|
|
65
|
+
const r = groupIndex * 3 + rInGroup;
|
|
66
|
+
if (r > rows) rows = r;
|
|
67
|
+
positions.push({ x: c * cell, y: r * cell, index: i });
|
|
68
|
+
}
|
|
69
|
+
rows += 1;
|
|
70
|
+
cols = Math.max(cols, Math.min(normalized, 5));
|
|
71
|
+
} else if (layout === "array") {
|
|
72
|
+
cols = Math.floor(Math.sqrt(normalized));
|
|
73
|
+
while (normalized % cols !== 0 && cols > 1) cols -= 1;
|
|
74
|
+
if (cols === 1 && normalized > 3) cols = Math.ceil(Math.sqrt(normalized));
|
|
75
|
+
rows = Math.ceil(normalized / cols);
|
|
76
|
+
for (let i = 0; i < normalized; i++) {
|
|
77
|
+
const c = i % cols;
|
|
78
|
+
const r = Math.floor(i / cols);
|
|
79
|
+
positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
positions,
|
|
84
|
+
width: cols * cell - gap,
|
|
85
|
+
height: rows * cell - gap
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function MathBlocks({
|
|
89
|
+
value,
|
|
90
|
+
layout = "auto",
|
|
91
|
+
colorStyle = "Rainbow",
|
|
92
|
+
face = "Happy",
|
|
93
|
+
showNumberLabel = true,
|
|
94
|
+
showCountingDots = false,
|
|
95
|
+
size = 320,
|
|
96
|
+
className,
|
|
97
|
+
title
|
|
98
|
+
}) {
|
|
99
|
+
const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));
|
|
100
|
+
const { positions, width, height } = generateBlockPositions(safeValue, layout);
|
|
101
|
+
const view = 800;
|
|
102
|
+
const padding = 120;
|
|
103
|
+
const scale = Math.min((view - padding * 2) / Math.max(width, height), 1.5);
|
|
104
|
+
const contentWidth = width * scale;
|
|
105
|
+
const contentHeight = height * scale;
|
|
106
|
+
const offsetX = (view - contentWidth) / 2;
|
|
107
|
+
const offsetY = (view - contentHeight) / 2;
|
|
108
|
+
const blockSize = 60;
|
|
109
|
+
const topBlock = positions.reduce((prev, curr) => {
|
|
110
|
+
if (curr.y < prev.y) return curr;
|
|
111
|
+
if (curr.y === prev.y && curr.x < prev.x) return curr;
|
|
112
|
+
return prev;
|
|
113
|
+
}, positions[0]);
|
|
114
|
+
const isBW = colorStyle === "B&W (Coloring)";
|
|
115
|
+
const strokeColor = isBW ? "#111827" : "rgba(0,0,0,0.15)";
|
|
116
|
+
const strokeWidth = isBW ? 4 : 2;
|
|
117
|
+
const label = title || `Math blocks ${safeValue}`;
|
|
118
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
119
|
+
"svg",
|
|
120
|
+
{
|
|
121
|
+
viewBox: `0 0 ${view} ${view}`,
|
|
122
|
+
width: size,
|
|
123
|
+
height: size,
|
|
124
|
+
className,
|
|
125
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
126
|
+
role: "img",
|
|
127
|
+
"aria-label": label,
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ jsxRuntime.jsx("title", { children: label }),
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${offsetX}, ${offsetY}) scale(${scale})`, children: [
|
|
131
|
+
positions.map((pos) => {
|
|
132
|
+
const color = getBlockColor(pos.index, colorStyle);
|
|
133
|
+
const isTop = pos.index === topBlock.index;
|
|
134
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${pos.x}, ${pos.y})`, children: [
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
136
|
+
"rect",
|
|
137
|
+
{
|
|
138
|
+
x: 0,
|
|
139
|
+
y: 0,
|
|
140
|
+
width: blockSize,
|
|
141
|
+
height: blockSize,
|
|
142
|
+
rx: 12,
|
|
143
|
+
fill: color,
|
|
144
|
+
stroke: strokeColor,
|
|
145
|
+
strokeWidth
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
!isBW && /* @__PURE__ */ jsxRuntime.jsx(
|
|
149
|
+
"rect",
|
|
150
|
+
{
|
|
151
|
+
x: 0,
|
|
152
|
+
y: 0,
|
|
153
|
+
width: blockSize,
|
|
154
|
+
height: blockSize,
|
|
155
|
+
rx: 12,
|
|
156
|
+
fill: "url(#rmb-highlight)",
|
|
157
|
+
opacity: 0.3
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
showCountingDots && /* @__PURE__ */ jsxRuntime.jsx(
|
|
161
|
+
"circle",
|
|
162
|
+
{
|
|
163
|
+
cx: blockSize / 2,
|
|
164
|
+
cy: blockSize / 2,
|
|
165
|
+
r: 8,
|
|
166
|
+
fill: isBW ? "none" : "rgba(255,255,255,0.6)",
|
|
167
|
+
stroke: isBW ? "#111827" : "none",
|
|
168
|
+
strokeWidth: isBW ? 3 : 0
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
isTop && /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: "translate(10, 15)", children: [
|
|
172
|
+
face === "Happy" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 10, cy: 10, r: 4, fill: "#1F2937" }),
|
|
174
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 30, cy: 10, r: 4, fill: "#1F2937" }),
|
|
175
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 10 20 Q 20 28 30 20", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
176
|
+
] }),
|
|
177
|
+
face === "Smile" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
178
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 8 10 Q 12 6 16 10", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" }),
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 24 10 Q 28 6 32 10", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 14 20 Q 20 26 26 20", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
181
|
+
] }),
|
|
182
|
+
face === "Surprised" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 10, cy: 10, r: 3, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 }),
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 30, cy: 10, r: 3, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 }),
|
|
185
|
+
/* @__PURE__ */ jsxRuntime.jsx("ellipse", { cx: 20, cy: 22, rx: 4, ry: 6, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 })
|
|
186
|
+
] }),
|
|
187
|
+
face === "Thinking" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
188
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 10, cy: 10, r: 3, fill: "#1F2937" }),
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 30, cy: 10, r: 3, fill: "#1F2937" }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 15 22 L 25 22", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
191
|
+
] })
|
|
192
|
+
] })
|
|
193
|
+
] }, pos.index);
|
|
194
|
+
}),
|
|
195
|
+
showNumberLabel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
196
|
+
"text",
|
|
197
|
+
{
|
|
198
|
+
x: topBlock.x + blockSize / 2,
|
|
199
|
+
y: topBlock.y - 12,
|
|
200
|
+
fontSize: 36,
|
|
201
|
+
fontWeight: "bold",
|
|
202
|
+
textAnchor: "middle",
|
|
203
|
+
fill: "#1F2937",
|
|
204
|
+
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
205
|
+
children: safeValue
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
] }),
|
|
209
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "rmb-highlight", x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
210
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.8 }),
|
|
211
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "white", stopOpacity: 0 })
|
|
212
|
+
] }) })
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
function TenFrame({
|
|
218
|
+
value,
|
|
219
|
+
colorStyle = "Pastel",
|
|
220
|
+
showNumberLabel = true,
|
|
221
|
+
showCountingDots = true,
|
|
222
|
+
className,
|
|
223
|
+
title
|
|
224
|
+
}) {
|
|
225
|
+
const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));
|
|
226
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
227
|
+
MathBlocks,
|
|
228
|
+
{
|
|
229
|
+
value: safeValue,
|
|
230
|
+
layout: "ten-frame",
|
|
231
|
+
colorStyle,
|
|
232
|
+
showNumberLabel,
|
|
233
|
+
showCountingDots,
|
|
234
|
+
className,
|
|
235
|
+
title: title || `Ten-frame ${safeValue}`
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
exports.MathBlocks = MathBlocks;
|
|
241
|
+
exports.TenFrame = TenFrame;
|
|
242
|
+
exports.generateBlockPositions = generateBlockPositions;
|
|
243
|
+
exports.getBlockColor = getBlockColor;
|
|
244
|
+
//# sourceMappingURL=index.js.map
|
|
245
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/colors.ts","../src/layout.ts","../src/components/MathBlocks.tsx","../src/components/TenFrame.tsx"],"names":["jsxs","jsx","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["export type ColorStyle =\n | \"Rainbow\"\n | \"Single Color\"\n | \"Warm\"\n | \"Cool\"\n | \"Pastel\"\n | \"B&W (Coloring)\";\n\nconst rainbow = [\"#EF4444\", \"#F97316\", \"#EAB308\", \"#22C55E\", \"#3B82F6\", \"#8B5CF6\", \"#EC4899\"];\nconst warm = [\"#EF4444\", \"#F97316\", \"#F59E0B\", \"#EAB308\", \"#FB923C\", \"#F87171\"];\nconst cool = [\"#3B82F6\", \"#06B6D4\", \"#10B981\", \"#22C55E\", \"#6366F1\", \"#8B5CF6\"];\nconst pastel = [\"#FCA5A5\", \"#FDBA74\", \"#FDE047\", \"#86EFAC\", \"#93C5FD\", \"#C4B5FD\", \"#F9A8D4\"];\n\nexport function getBlockColor(index: number, style: ColorStyle): string {\n switch (style) {\n case \"Single Color\":\n return \"#3B82F6\";\n case \"Warm\":\n return warm[index % warm.length];\n case \"Cool\":\n return cool[index % cool.length];\n case \"Pastel\":\n return pastel[index % pastel.length];\n case \"B&W (Coloring)\":\n return \"#FFFFFF\";\n case \"Rainbow\":\n default:\n return rainbow[index % rainbow.length];\n }\n}\n","export type LayoutMode = \"auto\" | \"stack\" | \"grid\" | \"ten-frame\" | \"array\";\n\nexport interface BlockPosition {\n x: number;\n y: number;\n index: number;\n}\n\nexport interface LayoutResult {\n positions: BlockPosition[];\n width: number;\n height: number;\n}\n\nexport function generateBlockPositions(value: number, layout: LayoutMode): LayoutResult {\n let normalized = Math.max(1, Math.floor(value));\n if (layout === \"auto\") {\n if (normalized <= 5) layout = \"stack\";\n else if (normalized <= 20) layout = \"ten-frame\";\n else layout = \"grid\";\n }\n\n const block = 60;\n const gap = 4;\n const cell = block + gap;\n\n let cols = 1;\n let rows = 1;\n const positions: BlockPosition[] = [];\n\n if (layout === \"stack\") {\n cols = 1;\n rows = normalized;\n for (let i = 0; i < normalized; i++) {\n positions.push({ x: 0, y: (normalized - 1 - i) * cell, index: i });\n }\n } else if (layout === \"grid\") {\n cols = Math.ceil(Math.sqrt(normalized));\n rows = Math.ceil(normalized / cols);\n for (let i = 0; i < normalized; i++) {\n const c = i % cols;\n const r = Math.floor(i / cols);\n positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });\n }\n } else if (layout === \"ten-frame\") {\n cols = Math.min(normalized, 5);\n const groupSize = 10;\n rows = 0;\n for (let i = 0; i < normalized; i++) {\n const groupIndex = Math.floor(i / groupSize);\n const indexInGroup = i % groupSize;\n const c = indexInGroup % 5;\n const rInGroup = Math.floor(indexInGroup / 5);\n const r = groupIndex * 3 + rInGroup;\n if (r > rows) rows = r;\n positions.push({ x: c * cell, y: r * cell, index: i });\n }\n rows += 1;\n cols = Math.max(cols, Math.min(normalized, 5));\n } else if (layout === \"array\") {\n cols = Math.floor(Math.sqrt(normalized));\n while (normalized % cols !== 0 && cols > 1) cols -= 1;\n if (cols === 1 && normalized > 3) cols = Math.ceil(Math.sqrt(normalized));\n rows = Math.ceil(normalized / cols);\n for (let i = 0; i < normalized; i++) {\n const c = i % cols;\n const r = Math.floor(i / cols);\n positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });\n }\n }\n\n return {\n positions,\n width: cols * cell - gap,\n height: rows * cell - gap,\n };\n}\n","import * as React from \"react\";\nimport { getBlockColor } from \"../colors\";\nimport { generateBlockPositions } from \"../layout\";\nimport type { MathBlocksProps } from \"../types\";\n\nexport function MathBlocks({\n value,\n layout = \"auto\",\n colorStyle = \"Rainbow\",\n face = \"Happy\",\n showNumberLabel = true,\n showCountingDots = false,\n size = 320,\n className,\n title,\n}: MathBlocksProps): React.JSX.Element {\n const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));\n const { positions, width, height } = generateBlockPositions(safeValue, layout);\n\n const view = 800;\n const padding = 120;\n const scale = Math.min((view - padding * 2) / Math.max(width, height), 1.5);\n const contentWidth = width * scale;\n const contentHeight = height * scale;\n const offsetX = (view - contentWidth) / 2;\n const offsetY = (view - contentHeight) / 2;\n\n const blockSize = 60;\n const topBlock = positions.reduce((prev, curr) => {\n if (curr.y < prev.y) return curr;\n if (curr.y === prev.y && curr.x < prev.x) return curr;\n return prev;\n }, positions[0]);\n\n const isBW = colorStyle === \"B&W (Coloring)\";\n const strokeColor = isBW ? \"#111827\" : \"rgba(0,0,0,0.15)\";\n const strokeWidth = isBW ? 4 : 2;\n const label = title || `Math blocks ${safeValue}`;\n\n return (\n <svg\n viewBox={`0 0 ${view} ${view}`}\n width={size}\n height={size}\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n role=\"img\"\n aria-label={label}\n >\n <title>{label}</title>\n <g transform={`translate(${offsetX}, ${offsetY}) scale(${scale})`}>\n {positions.map((pos) => {\n const color = getBlockColor(pos.index, colorStyle);\n const isTop = pos.index === topBlock.index;\n\n return (\n <g key={pos.index} transform={`translate(${pos.x}, ${pos.y})`}>\n <rect\n x={0}\n y={0}\n width={blockSize}\n height={blockSize}\n rx={12}\n fill={color}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n />\n\n {!isBW && (\n <rect\n x={0}\n y={0}\n width={blockSize}\n height={blockSize}\n rx={12}\n fill=\"url(#rmb-highlight)\"\n opacity={0.3}\n />\n )}\n\n {showCountingDots && (\n <circle\n cx={blockSize / 2}\n cy={blockSize / 2}\n r={8}\n fill={isBW ? \"none\" : \"rgba(255,255,255,0.6)\"}\n stroke={isBW ? \"#111827\" : \"none\"}\n strokeWidth={isBW ? 3 : 0}\n />\n )}\n\n {isTop && (\n <g transform=\"translate(10, 15)\">\n {face === \"Happy\" && (\n <>\n <circle cx={10} cy={10} r={4} fill=\"#1F2937\" />\n <circle cx={30} cy={10} r={4} fill=\"#1F2937\" />\n <path d=\"M 10 20 Q 20 28 30 20\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n {face === \"Smile\" && (\n <>\n <path d=\"M 8 10 Q 12 6 16 10\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n <path d=\"M 24 10 Q 28 6 32 10\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n <path d=\"M 14 20 Q 20 26 26 20\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n {face === \"Surprised\" && (\n <>\n <circle cx={10} cy={10} r={3} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n <circle cx={30} cy={10} r={3} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n <ellipse cx={20} cy={22} rx={4} ry={6} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n </>\n )}\n {face === \"Thinking\" && (\n <>\n <circle cx={10} cy={10} r={3} fill=\"#1F2937\" />\n <circle cx={30} cy={10} r={3} fill=\"#1F2937\" />\n <path d=\"M 15 22 L 25 22\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n </g>\n )}\n </g>\n );\n })}\n\n {showNumberLabel && (\n <text\n x={topBlock.x + blockSize / 2}\n y={topBlock.y - 12}\n fontSize={36}\n fontWeight=\"bold\"\n textAnchor=\"middle\"\n fill=\"#1F2937\"\n fontFamily=\"ui-sans-serif, system-ui, sans-serif\"\n >\n {safeValue}\n </text>\n )}\n </g>\n\n <defs>\n <linearGradient id=\"rmb-highlight\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"white\" stopOpacity={0.8} />\n <stop offset=\"100%\" stopColor=\"white\" stopOpacity={0} />\n </linearGradient>\n </defs>\n </svg>\n );\n}\n","import * as React from \"react\";\nimport { MathBlocks } from \"./MathBlocks\";\nimport type { TenFrameProps } from \"../types\";\n\nexport function TenFrame({\n value,\n colorStyle = \"Pastel\",\n showNumberLabel = true,\n showCountingDots = true,\n className,\n title,\n}: TenFrameProps): React.JSX.Element {\n const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));\n\n return (\n <MathBlocks\n value={safeValue}\n layout=\"ten-frame\"\n colorStyle={colorStyle}\n showNumberLabel={showNumberLabel}\n showCountingDots={showCountingDots}\n className={className}\n title={title || `Ten-frame ${safeValue}`}\n />\n );\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
// src/colors.ts
|
|
4
|
+
var rainbow = ["#EF4444", "#F97316", "#EAB308", "#22C55E", "#3B82F6", "#8B5CF6", "#EC4899"];
|
|
5
|
+
var warm = ["#EF4444", "#F97316", "#F59E0B", "#EAB308", "#FB923C", "#F87171"];
|
|
6
|
+
var cool = ["#3B82F6", "#06B6D4", "#10B981", "#22C55E", "#6366F1", "#8B5CF6"];
|
|
7
|
+
var pastel = ["#FCA5A5", "#FDBA74", "#FDE047", "#86EFAC", "#93C5FD", "#C4B5FD", "#F9A8D4"];
|
|
8
|
+
function getBlockColor(index, style) {
|
|
9
|
+
switch (style) {
|
|
10
|
+
case "Single Color":
|
|
11
|
+
return "#3B82F6";
|
|
12
|
+
case "Warm":
|
|
13
|
+
return warm[index % warm.length];
|
|
14
|
+
case "Cool":
|
|
15
|
+
return cool[index % cool.length];
|
|
16
|
+
case "Pastel":
|
|
17
|
+
return pastel[index % pastel.length];
|
|
18
|
+
case "B&W (Coloring)":
|
|
19
|
+
return "#FFFFFF";
|
|
20
|
+
case "Rainbow":
|
|
21
|
+
default:
|
|
22
|
+
return rainbow[index % rainbow.length];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/layout.ts
|
|
27
|
+
function generateBlockPositions(value, layout) {
|
|
28
|
+
let normalized = Math.max(1, Math.floor(value));
|
|
29
|
+
if (layout === "auto") {
|
|
30
|
+
if (normalized <= 5) layout = "stack";
|
|
31
|
+
else if (normalized <= 20) layout = "ten-frame";
|
|
32
|
+
else layout = "grid";
|
|
33
|
+
}
|
|
34
|
+
const block = 60;
|
|
35
|
+
const gap = 4;
|
|
36
|
+
const cell = block + gap;
|
|
37
|
+
let cols = 1;
|
|
38
|
+
let rows = 1;
|
|
39
|
+
const positions = [];
|
|
40
|
+
if (layout === "stack") {
|
|
41
|
+
cols = 1;
|
|
42
|
+
rows = normalized;
|
|
43
|
+
for (let i = 0; i < normalized; i++) {
|
|
44
|
+
positions.push({ x: 0, y: (normalized - 1 - i) * cell, index: i });
|
|
45
|
+
}
|
|
46
|
+
} else if (layout === "grid") {
|
|
47
|
+
cols = Math.ceil(Math.sqrt(normalized));
|
|
48
|
+
rows = Math.ceil(normalized / cols);
|
|
49
|
+
for (let i = 0; i < normalized; i++) {
|
|
50
|
+
const c = i % cols;
|
|
51
|
+
const r = Math.floor(i / cols);
|
|
52
|
+
positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });
|
|
53
|
+
}
|
|
54
|
+
} else if (layout === "ten-frame") {
|
|
55
|
+
cols = Math.min(normalized, 5);
|
|
56
|
+
const groupSize = 10;
|
|
57
|
+
rows = 0;
|
|
58
|
+
for (let i = 0; i < normalized; i++) {
|
|
59
|
+
const groupIndex = Math.floor(i / groupSize);
|
|
60
|
+
const indexInGroup = i % groupSize;
|
|
61
|
+
const c = indexInGroup % 5;
|
|
62
|
+
const rInGroup = Math.floor(indexInGroup / 5);
|
|
63
|
+
const r = groupIndex * 3 + rInGroup;
|
|
64
|
+
if (r > rows) rows = r;
|
|
65
|
+
positions.push({ x: c * cell, y: r * cell, index: i });
|
|
66
|
+
}
|
|
67
|
+
rows += 1;
|
|
68
|
+
cols = Math.max(cols, Math.min(normalized, 5));
|
|
69
|
+
} else if (layout === "array") {
|
|
70
|
+
cols = Math.floor(Math.sqrt(normalized));
|
|
71
|
+
while (normalized % cols !== 0 && cols > 1) cols -= 1;
|
|
72
|
+
if (cols === 1 && normalized > 3) cols = Math.ceil(Math.sqrt(normalized));
|
|
73
|
+
rows = Math.ceil(normalized / cols);
|
|
74
|
+
for (let i = 0; i < normalized; i++) {
|
|
75
|
+
const c = i % cols;
|
|
76
|
+
const r = Math.floor(i / cols);
|
|
77
|
+
positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
positions,
|
|
82
|
+
width: cols * cell - gap,
|
|
83
|
+
height: rows * cell - gap
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function MathBlocks({
|
|
87
|
+
value,
|
|
88
|
+
layout = "auto",
|
|
89
|
+
colorStyle = "Rainbow",
|
|
90
|
+
face = "Happy",
|
|
91
|
+
showNumberLabel = true,
|
|
92
|
+
showCountingDots = false,
|
|
93
|
+
size = 320,
|
|
94
|
+
className,
|
|
95
|
+
title
|
|
96
|
+
}) {
|
|
97
|
+
const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));
|
|
98
|
+
const { positions, width, height } = generateBlockPositions(safeValue, layout);
|
|
99
|
+
const view = 800;
|
|
100
|
+
const padding = 120;
|
|
101
|
+
const scale = Math.min((view - padding * 2) / Math.max(width, height), 1.5);
|
|
102
|
+
const contentWidth = width * scale;
|
|
103
|
+
const contentHeight = height * scale;
|
|
104
|
+
const offsetX = (view - contentWidth) / 2;
|
|
105
|
+
const offsetY = (view - contentHeight) / 2;
|
|
106
|
+
const blockSize = 60;
|
|
107
|
+
const topBlock = positions.reduce((prev, curr) => {
|
|
108
|
+
if (curr.y < prev.y) return curr;
|
|
109
|
+
if (curr.y === prev.y && curr.x < prev.x) return curr;
|
|
110
|
+
return prev;
|
|
111
|
+
}, positions[0]);
|
|
112
|
+
const isBW = colorStyle === "B&W (Coloring)";
|
|
113
|
+
const strokeColor = isBW ? "#111827" : "rgba(0,0,0,0.15)";
|
|
114
|
+
const strokeWidth = isBW ? 4 : 2;
|
|
115
|
+
const label = title || `Math blocks ${safeValue}`;
|
|
116
|
+
return /* @__PURE__ */ jsxs(
|
|
117
|
+
"svg",
|
|
118
|
+
{
|
|
119
|
+
viewBox: `0 0 ${view} ${view}`,
|
|
120
|
+
width: size,
|
|
121
|
+
height: size,
|
|
122
|
+
className,
|
|
123
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
124
|
+
role: "img",
|
|
125
|
+
"aria-label": label,
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsx("title", { children: label }),
|
|
128
|
+
/* @__PURE__ */ jsxs("g", { transform: `translate(${offsetX}, ${offsetY}) scale(${scale})`, children: [
|
|
129
|
+
positions.map((pos) => {
|
|
130
|
+
const color = getBlockColor(pos.index, colorStyle);
|
|
131
|
+
const isTop = pos.index === topBlock.index;
|
|
132
|
+
return /* @__PURE__ */ jsxs("g", { transform: `translate(${pos.x}, ${pos.y})`, children: [
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
"rect",
|
|
135
|
+
{
|
|
136
|
+
x: 0,
|
|
137
|
+
y: 0,
|
|
138
|
+
width: blockSize,
|
|
139
|
+
height: blockSize,
|
|
140
|
+
rx: 12,
|
|
141
|
+
fill: color,
|
|
142
|
+
stroke: strokeColor,
|
|
143
|
+
strokeWidth
|
|
144
|
+
}
|
|
145
|
+
),
|
|
146
|
+
!isBW && /* @__PURE__ */ jsx(
|
|
147
|
+
"rect",
|
|
148
|
+
{
|
|
149
|
+
x: 0,
|
|
150
|
+
y: 0,
|
|
151
|
+
width: blockSize,
|
|
152
|
+
height: blockSize,
|
|
153
|
+
rx: 12,
|
|
154
|
+
fill: "url(#rmb-highlight)",
|
|
155
|
+
opacity: 0.3
|
|
156
|
+
}
|
|
157
|
+
),
|
|
158
|
+
showCountingDots && /* @__PURE__ */ jsx(
|
|
159
|
+
"circle",
|
|
160
|
+
{
|
|
161
|
+
cx: blockSize / 2,
|
|
162
|
+
cy: blockSize / 2,
|
|
163
|
+
r: 8,
|
|
164
|
+
fill: isBW ? "none" : "rgba(255,255,255,0.6)",
|
|
165
|
+
stroke: isBW ? "#111827" : "none",
|
|
166
|
+
strokeWidth: isBW ? 3 : 0
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
isTop && /* @__PURE__ */ jsxs("g", { transform: "translate(10, 15)", children: [
|
|
170
|
+
face === "Happy" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
171
|
+
/* @__PURE__ */ jsx("circle", { cx: 10, cy: 10, r: 4, fill: "#1F2937" }),
|
|
172
|
+
/* @__PURE__ */ jsx("circle", { cx: 30, cy: 10, r: 4, fill: "#1F2937" }),
|
|
173
|
+
/* @__PURE__ */ jsx("path", { d: "M 10 20 Q 20 28 30 20", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
174
|
+
] }),
|
|
175
|
+
face === "Smile" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
176
|
+
/* @__PURE__ */ jsx("path", { d: "M 8 10 Q 12 6 16 10", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" }),
|
|
177
|
+
/* @__PURE__ */ jsx("path", { d: "M 24 10 Q 28 6 32 10", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" }),
|
|
178
|
+
/* @__PURE__ */ jsx("path", { d: "M 14 20 Q 20 26 26 20", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
179
|
+
] }),
|
|
180
|
+
face === "Surprised" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
181
|
+
/* @__PURE__ */ jsx("circle", { cx: 10, cy: 10, r: 3, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 }),
|
|
182
|
+
/* @__PURE__ */ jsx("circle", { cx: 30, cy: 10, r: 3, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 }),
|
|
183
|
+
/* @__PURE__ */ jsx("ellipse", { cx: 20, cy: 22, rx: 4, ry: 6, fill: isBW ? "white" : "#1F2937", stroke: "#1F2937", strokeWidth: isBW ? 2 : 0 })
|
|
184
|
+
] }),
|
|
185
|
+
face === "Thinking" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
186
|
+
/* @__PURE__ */ jsx("circle", { cx: 10, cy: 10, r: 3, fill: "#1F2937" }),
|
|
187
|
+
/* @__PURE__ */ jsx("circle", { cx: 30, cy: 10, r: 3, fill: "#1F2937" }),
|
|
188
|
+
/* @__PURE__ */ jsx("path", { d: "M 15 22 L 25 22", fill: "none", stroke: "#1F2937", strokeWidth: 2.5, strokeLinecap: "round" })
|
|
189
|
+
] })
|
|
190
|
+
] })
|
|
191
|
+
] }, pos.index);
|
|
192
|
+
}),
|
|
193
|
+
showNumberLabel && /* @__PURE__ */ jsx(
|
|
194
|
+
"text",
|
|
195
|
+
{
|
|
196
|
+
x: topBlock.x + blockSize / 2,
|
|
197
|
+
y: topBlock.y - 12,
|
|
198
|
+
fontSize: 36,
|
|
199
|
+
fontWeight: "bold",
|
|
200
|
+
textAnchor: "middle",
|
|
201
|
+
fill: "#1F2937",
|
|
202
|
+
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
203
|
+
children: safeValue
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
] }),
|
|
207
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "rmb-highlight", x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
208
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.8 }),
|
|
209
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "white", stopOpacity: 0 })
|
|
210
|
+
] }) })
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
function TenFrame({
|
|
216
|
+
value,
|
|
217
|
+
colorStyle = "Pastel",
|
|
218
|
+
showNumberLabel = true,
|
|
219
|
+
showCountingDots = true,
|
|
220
|
+
className,
|
|
221
|
+
title
|
|
222
|
+
}) {
|
|
223
|
+
const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));
|
|
224
|
+
return /* @__PURE__ */ jsx(
|
|
225
|
+
MathBlocks,
|
|
226
|
+
{
|
|
227
|
+
value: safeValue,
|
|
228
|
+
layout: "ten-frame",
|
|
229
|
+
colorStyle,
|
|
230
|
+
showNumberLabel,
|
|
231
|
+
showCountingDots,
|
|
232
|
+
className,
|
|
233
|
+
title: title || `Ten-frame ${safeValue}`
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export { MathBlocks, TenFrame, generateBlockPositions, getBlockColor };
|
|
239
|
+
//# sourceMappingURL=index.mjs.map
|
|
240
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/colors.ts","../src/layout.ts","../src/components/MathBlocks.tsx","../src/components/TenFrame.tsx"],"names":["jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["export type ColorStyle =\n | \"Rainbow\"\n | \"Single Color\"\n | \"Warm\"\n | \"Cool\"\n | \"Pastel\"\n | \"B&W (Coloring)\";\n\nconst rainbow = [\"#EF4444\", \"#F97316\", \"#EAB308\", \"#22C55E\", \"#3B82F6\", \"#8B5CF6\", \"#EC4899\"];\nconst warm = [\"#EF4444\", \"#F97316\", \"#F59E0B\", \"#EAB308\", \"#FB923C\", \"#F87171\"];\nconst cool = [\"#3B82F6\", \"#06B6D4\", \"#10B981\", \"#22C55E\", \"#6366F1\", \"#8B5CF6\"];\nconst pastel = [\"#FCA5A5\", \"#FDBA74\", \"#FDE047\", \"#86EFAC\", \"#93C5FD\", \"#C4B5FD\", \"#F9A8D4\"];\n\nexport function getBlockColor(index: number, style: ColorStyle): string {\n switch (style) {\n case \"Single Color\":\n return \"#3B82F6\";\n case \"Warm\":\n return warm[index % warm.length];\n case \"Cool\":\n return cool[index % cool.length];\n case \"Pastel\":\n return pastel[index % pastel.length];\n case \"B&W (Coloring)\":\n return \"#FFFFFF\";\n case \"Rainbow\":\n default:\n return rainbow[index % rainbow.length];\n }\n}\n","export type LayoutMode = \"auto\" | \"stack\" | \"grid\" | \"ten-frame\" | \"array\";\n\nexport interface BlockPosition {\n x: number;\n y: number;\n index: number;\n}\n\nexport interface LayoutResult {\n positions: BlockPosition[];\n width: number;\n height: number;\n}\n\nexport function generateBlockPositions(value: number, layout: LayoutMode): LayoutResult {\n let normalized = Math.max(1, Math.floor(value));\n if (layout === \"auto\") {\n if (normalized <= 5) layout = \"stack\";\n else if (normalized <= 20) layout = \"ten-frame\";\n else layout = \"grid\";\n }\n\n const block = 60;\n const gap = 4;\n const cell = block + gap;\n\n let cols = 1;\n let rows = 1;\n const positions: BlockPosition[] = [];\n\n if (layout === \"stack\") {\n cols = 1;\n rows = normalized;\n for (let i = 0; i < normalized; i++) {\n positions.push({ x: 0, y: (normalized - 1 - i) * cell, index: i });\n }\n } else if (layout === \"grid\") {\n cols = Math.ceil(Math.sqrt(normalized));\n rows = Math.ceil(normalized / cols);\n for (let i = 0; i < normalized; i++) {\n const c = i % cols;\n const r = Math.floor(i / cols);\n positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });\n }\n } else if (layout === \"ten-frame\") {\n cols = Math.min(normalized, 5);\n const groupSize = 10;\n rows = 0;\n for (let i = 0; i < normalized; i++) {\n const groupIndex = Math.floor(i / groupSize);\n const indexInGroup = i % groupSize;\n const c = indexInGroup % 5;\n const rInGroup = Math.floor(indexInGroup / 5);\n const r = groupIndex * 3 + rInGroup;\n if (r > rows) rows = r;\n positions.push({ x: c * cell, y: r * cell, index: i });\n }\n rows += 1;\n cols = Math.max(cols, Math.min(normalized, 5));\n } else if (layout === \"array\") {\n cols = Math.floor(Math.sqrt(normalized));\n while (normalized % cols !== 0 && cols > 1) cols -= 1;\n if (cols === 1 && normalized > 3) cols = Math.ceil(Math.sqrt(normalized));\n rows = Math.ceil(normalized / cols);\n for (let i = 0; i < normalized; i++) {\n const c = i % cols;\n const r = Math.floor(i / cols);\n positions.push({ x: c * cell, y: (rows - 1 - r) * cell, index: i });\n }\n }\n\n return {\n positions,\n width: cols * cell - gap,\n height: rows * cell - gap,\n };\n}\n","import * as React from \"react\";\nimport { getBlockColor } from \"../colors\";\nimport { generateBlockPositions } from \"../layout\";\nimport type { MathBlocksProps } from \"../types\";\n\nexport function MathBlocks({\n value,\n layout = \"auto\",\n colorStyle = \"Rainbow\",\n face = \"Happy\",\n showNumberLabel = true,\n showCountingDots = false,\n size = 320,\n className,\n title,\n}: MathBlocksProps): React.JSX.Element {\n const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));\n const { positions, width, height } = generateBlockPositions(safeValue, layout);\n\n const view = 800;\n const padding = 120;\n const scale = Math.min((view - padding * 2) / Math.max(width, height), 1.5);\n const contentWidth = width * scale;\n const contentHeight = height * scale;\n const offsetX = (view - contentWidth) / 2;\n const offsetY = (view - contentHeight) / 2;\n\n const blockSize = 60;\n const topBlock = positions.reduce((prev, curr) => {\n if (curr.y < prev.y) return curr;\n if (curr.y === prev.y && curr.x < prev.x) return curr;\n return prev;\n }, positions[0]);\n\n const isBW = colorStyle === \"B&W (Coloring)\";\n const strokeColor = isBW ? \"#111827\" : \"rgba(0,0,0,0.15)\";\n const strokeWidth = isBW ? 4 : 2;\n const label = title || `Math blocks ${safeValue}`;\n\n return (\n <svg\n viewBox={`0 0 ${view} ${view}`}\n width={size}\n height={size}\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n role=\"img\"\n aria-label={label}\n >\n <title>{label}</title>\n <g transform={`translate(${offsetX}, ${offsetY}) scale(${scale})`}>\n {positions.map((pos) => {\n const color = getBlockColor(pos.index, colorStyle);\n const isTop = pos.index === topBlock.index;\n\n return (\n <g key={pos.index} transform={`translate(${pos.x}, ${pos.y})`}>\n <rect\n x={0}\n y={0}\n width={blockSize}\n height={blockSize}\n rx={12}\n fill={color}\n stroke={strokeColor}\n strokeWidth={strokeWidth}\n />\n\n {!isBW && (\n <rect\n x={0}\n y={0}\n width={blockSize}\n height={blockSize}\n rx={12}\n fill=\"url(#rmb-highlight)\"\n opacity={0.3}\n />\n )}\n\n {showCountingDots && (\n <circle\n cx={blockSize / 2}\n cy={blockSize / 2}\n r={8}\n fill={isBW ? \"none\" : \"rgba(255,255,255,0.6)\"}\n stroke={isBW ? \"#111827\" : \"none\"}\n strokeWidth={isBW ? 3 : 0}\n />\n )}\n\n {isTop && (\n <g transform=\"translate(10, 15)\">\n {face === \"Happy\" && (\n <>\n <circle cx={10} cy={10} r={4} fill=\"#1F2937\" />\n <circle cx={30} cy={10} r={4} fill=\"#1F2937\" />\n <path d=\"M 10 20 Q 20 28 30 20\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n {face === \"Smile\" && (\n <>\n <path d=\"M 8 10 Q 12 6 16 10\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n <path d=\"M 24 10 Q 28 6 32 10\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n <path d=\"M 14 20 Q 20 26 26 20\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n {face === \"Surprised\" && (\n <>\n <circle cx={10} cy={10} r={3} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n <circle cx={30} cy={10} r={3} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n <ellipse cx={20} cy={22} rx={4} ry={6} fill={isBW ? \"white\" : \"#1F2937\"} stroke=\"#1F2937\" strokeWidth={isBW ? 2 : 0} />\n </>\n )}\n {face === \"Thinking\" && (\n <>\n <circle cx={10} cy={10} r={3} fill=\"#1F2937\" />\n <circle cx={30} cy={10} r={3} fill=\"#1F2937\" />\n <path d=\"M 15 22 L 25 22\" fill=\"none\" stroke=\"#1F2937\" strokeWidth={2.5} strokeLinecap=\"round\" />\n </>\n )}\n </g>\n )}\n </g>\n );\n })}\n\n {showNumberLabel && (\n <text\n x={topBlock.x + blockSize / 2}\n y={topBlock.y - 12}\n fontSize={36}\n fontWeight=\"bold\"\n textAnchor=\"middle\"\n fill=\"#1F2937\"\n fontFamily=\"ui-sans-serif, system-ui, sans-serif\"\n >\n {safeValue}\n </text>\n )}\n </g>\n\n <defs>\n <linearGradient id=\"rmb-highlight\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"white\" stopOpacity={0.8} />\n <stop offset=\"100%\" stopColor=\"white\" stopOpacity={0} />\n </linearGradient>\n </defs>\n </svg>\n );\n}\n","import * as React from \"react\";\nimport { MathBlocks } from \"./MathBlocks\";\nimport type { TenFrameProps } from \"../types\";\n\nexport function TenFrame({\n value,\n colorStyle = \"Pastel\",\n showNumberLabel = true,\n showCountingDots = true,\n className,\n title,\n}: TenFrameProps): React.JSX.Element {\n const safeValue = Math.max(1, Math.min(100, Math.floor(value || 1)));\n\n return (\n <MathBlocks\n value={safeValue}\n layout=\"ten-frame\"\n colorStyle={colorStyle}\n showNumberLabel={showNumberLabel}\n showCountingDots={showCountingDots}\n className={className}\n title={title || `Ten-frame ${safeValue}`}\n />\n );\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-math-blocks",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Live Demo & Full Customization available at PrintNum.com. Lightweight React components for Number Blocks and Ten-Frame math visuals.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"math",
|
|
8
|
+
"ten-frame",
|
|
9
|
+
"number-blocks",
|
|
10
|
+
"education",
|
|
11
|
+
"homeschool",
|
|
12
|
+
"teachers"
|
|
13
|
+
],
|
|
14
|
+
"author": "PrintNum",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"homepage": "https://printnum.com",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/printnum/react-math-blocks.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/printnum/react-math-blocks/issues"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"module": "dist/index.mjs",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"require": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": ">=18",
|
|
42
|
+
"react-dom": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/react": "^19.2.2",
|
|
46
|
+
"@types/react-dom": "^19.2.2",
|
|
47
|
+
"tsup": "^8.5.0",
|
|
48
|
+
"typescript": "^5.9.3"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"dev": "tsup --watch",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
55
|
+
}
|
|
56
|
+
}
|