feat(abacus-react): comprehensive README overhaul with current capabilities
- Complete documentation of interactive features and tutorial system - Detailed examples for all major use cases and APIs - Place-value based targeting system documentation - Progressive tutorial steps and directional gesture guides - Granular styling customization examples - Educational use case implementations - Full TypeScript interface documentation - Accessibility and color scheme information - Live Storybook documentation links 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
176a1961d0
commit
0ce351e572
|
|
@ -1,18 +1,21 @@
|
|||
# @soroban/abacus-react
|
||||
|
||||
A comprehensive React component for rendering interactive Soroban (Japanese abacus) visualizations with advanced customization and tutorial capabilities.
|
||||
A comprehensive React component for rendering interactive Soroban (Japanese abacus) visualizations with advanced tutorial capabilities, directional gestures, and complete visual customization.
|
||||
|
||||
## Features
|
||||
|
||||
- 🎯 **Interactive beads** - Click to toggle or use directional gestures
|
||||
- 🎨 **Complete visual customization** - Style every element individually
|
||||
- 📱 **Responsive scaling** - Configurable scale factor for different sizes
|
||||
- 🎯 **Interactive beads** - Click to toggle or use directional drag gestures
|
||||
- 🎨 **Complete visual customization** - Style every element individually with granular control
|
||||
- 📱 **Responsive scaling** - Configurable scale factor for different display sizes
|
||||
- 🌈 **Multiple color schemes** - Monochrome, place-value, alternating, heaven-earth
|
||||
- 🎭 **Flexible shapes** - Diamond, square, or circle beads
|
||||
- ⚡ **React Spring animations** - Smooth bead movements and transitions
|
||||
- 🔧 **Developer-friendly** - Comprehensive hooks and callback system
|
||||
- 🎓 **Tutorial system** - Built-in overlay and guidance capabilities
|
||||
- 🧩 **Framework-free SVG** - Complete control over rendering
|
||||
- 🎭 **Flexible bead shapes** - Diamond, square, or circle beads
|
||||
- ⚡ **React Spring animations** - Smooth bead movements and state transitions
|
||||
- 🔧 **Developer-friendly** - Comprehensive hooks, callbacks, and ref system
|
||||
- 🎓 **Tutorial system** - Built-in overlay system with tooltips and highlights
|
||||
- 🧩 **Framework-free SVG** - Complete control over rendering and styling
|
||||
- 🏗️ **Type-safe APIs** - Full TypeScript support with branded types
|
||||
- 📐 **Precise positioning** - Place-value based bead targeting system
|
||||
- 🎮 **Directional gestures** - Natural drag interactions for bead manipulation
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -40,14 +43,13 @@ The package is published to both npm and GitHub Packages simultaneously for redu
|
|||
|
||||
## Quick Start
|
||||
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Simple abacus showing a number
|
||||
|
||||
<img src="https://raw.githubusercontent.com/antialias/soroban-abacus-flashcards/main/packages/abacus-react/examples/basic-usage.svg" alt="Basic Usage">
|
||||
Simple static abacus display:
|
||||
|
||||
```tsx
|
||||
import { AbacusReact } from '@soroban/abacus-react';
|
||||
|
||||
<AbacusReact
|
||||
value={123}
|
||||
columns={3}
|
||||
|
|
@ -58,9 +60,7 @@ Simple abacus showing a number
|
|||
|
||||
### Interactive Mode
|
||||
|
||||
Clickable abacus with animations
|
||||
|
||||
<img src="https://raw.githubusercontent.com/antialias/soroban-abacus-flashcards/main/packages/abacus-react/examples/interactive.svg" alt="Interactive Mode">
|
||||
Clickable abacus with animations and callbacks:
|
||||
|
||||
```tsx
|
||||
<AbacusReact
|
||||
|
|
@ -68,6 +68,7 @@ Clickable abacus with animations
|
|||
columns={3}
|
||||
interactive={true}
|
||||
animated={true}
|
||||
gestures={true}
|
||||
showNumbers={true}
|
||||
callbacks={{
|
||||
onValueChange: (newValue) => console.log('New value:', newValue),
|
||||
|
|
@ -78,9 +79,7 @@ Clickable abacus with animations
|
|||
|
||||
### Custom Styling
|
||||
|
||||
Personalized colors and highlights
|
||||
|
||||
<img src="https://raw.githubusercontent.com/antialias/soroban-abacus-flashcards/main/packages/abacus-react/examples/custom-styling.svg" alt="Custom Styling">
|
||||
Personalized colors and visual themes:
|
||||
|
||||
```tsx
|
||||
<AbacusReact
|
||||
|
|
@ -88,22 +87,23 @@ Personalized colors and highlights
|
|||
columns={3}
|
||||
colorScheme="place-value"
|
||||
beadShape="circle"
|
||||
colorPalette="nature"
|
||||
customStyles={{
|
||||
heavenBeads: { fill: '#ff6b35' },
|
||||
earthBeads: { fill: '#3498db' },
|
||||
numerals: { color: '#2c3e50', fontWeight: 'bold' }
|
||||
heavenBeads: { fill: '#2ecc71', stroke: '#27ae60' },
|
||||
earthBeads: { fill: '#3498db', stroke: '#2980b9' },
|
||||
numerals: { color: '#2c3e50', fontWeight: 'bold' },
|
||||
reckoningBar: { stroke: '#34495e', strokeWidth: 3 }
|
||||
}}
|
||||
highlightBeads={[
|
||||
{ columnIndex: 1, beadType: 'heaven' }
|
||||
{ placeValue: 2, beadType: 'heaven' }, // Hundreds place heaven bead
|
||||
{ placeValue: 0, beadType: 'earth', position: 1 } // Ones place, second earth bead
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### Tutorial System
|
||||
|
||||
Educational guidance with tooltips
|
||||
|
||||
<img src="https://raw.githubusercontent.com/antialias/soroban-abacus-flashcards/main/packages/abacus-react/examples/tutorial-mode.svg" alt="Tutorial System">
|
||||
Educational guidance with interactive overlays:
|
||||
|
||||
```tsx
|
||||
<AbacusReact
|
||||
|
|
@ -111,34 +111,58 @@ Educational guidance with tooltips
|
|||
columns={2}
|
||||
interactive={true}
|
||||
overlays={[{
|
||||
id: 'tip',
|
||||
id: 'tutorial-tip',
|
||||
type: 'tooltip',
|
||||
target: { type: 'bead', columnIndex: 0, beadType: 'earth', beadPosition: 1 },
|
||||
content: <div>Click this bead!</div>,
|
||||
target: {
|
||||
type: 'bead',
|
||||
columnIndex: 0,
|
||||
beadType: 'earth',
|
||||
beadPosition: 1
|
||||
},
|
||||
content: (
|
||||
<div style={{
|
||||
background: '#333',
|
||||
color: 'white',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
Click this bead to add 1!
|
||||
</div>
|
||||
),
|
||||
offset: { x: 0, y: -30 }
|
||||
}]}
|
||||
stepBeadHighlights={[{
|
||||
placeValue: 0,
|
||||
beadType: 'earth',
|
||||
position: 1,
|
||||
stepIndex: 0,
|
||||
direction: 'activate',
|
||||
order: 1
|
||||
}]}
|
||||
showDirectionIndicators={true}
|
||||
callbacks={{
|
||||
onBeadClick: (event) => {
|
||||
if (event.columnIndex === 0 && event.beadType === 'earth' && event.position === 1) {
|
||||
console.log('Correct!');
|
||||
if (event.placeValue === 0 && event.beadType === 'earth' && event.position === 1) {
|
||||
console.log('Tutorial step completed!');
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
## Core API
|
||||
|
||||
### Basic Props
|
||||
### AbacusConfig Interface
|
||||
|
||||
```tsx
|
||||
interface AbacusConfig {
|
||||
// Display
|
||||
value?: number; // 0-99999, number to display
|
||||
columns?: number | 'auto'; // Number of columns or auto-calculate
|
||||
showNumbers?: boolean; // Show place value numbers
|
||||
showNumbers?: boolean; // Show place value numbers below
|
||||
scaleFactor?: number; // 0.5 - 3.0, size multiplier
|
||||
showEmptyColumns?: boolean; // Display columns with value 0
|
||||
|
||||
// Appearance
|
||||
beadShape?: 'diamond' | 'square' | 'circle';
|
||||
|
|
@ -148,12 +172,21 @@ interface AbacusConfig {
|
|||
|
||||
// Interaction
|
||||
interactive?: boolean; // Enable user interactions
|
||||
animated?: boolean; // Enable animations
|
||||
gestures?: boolean; // Enable drag gestures
|
||||
animated?: boolean; // Enable React Spring animations
|
||||
gestures?: boolean; // Enable directional drag gestures
|
||||
|
||||
// Advanced
|
||||
customStyles?: AbacusCustomStyles; // Granular styling control
|
||||
callbacks?: AbacusCallbacks; // Event handlers
|
||||
overlays?: AbacusOverlay[]; // Tutorial overlay system
|
||||
highlightBeads?: BeadHighlight[]; // Highlight specific beads
|
||||
stepBeadHighlights?: StepBeadHighlight[]; // Progressive tutorial highlighting
|
||||
showDirectionIndicators?: boolean; // Show movement direction indicators
|
||||
disabledBeads?: BeadHighlight[]; // Disable specific bead interactions
|
||||
}
|
||||
```
|
||||
|
||||
### Event Callbacks
|
||||
### Event System
|
||||
|
||||
```tsx
|
||||
interface AbacusCallbacks {
|
||||
|
|
@ -161,117 +194,211 @@ interface AbacusCallbacks {
|
|||
onBeadClick?: (event: BeadClickEvent) => void;
|
||||
onBeadHover?: (event: BeadClickEvent) => void;
|
||||
onBeadLeave?: (event: BeadClickEvent) => void;
|
||||
onColumnClick?: (columnIndex: number) => void;
|
||||
onNumeralClick?: (columnIndex: number, value: number) => void;
|
||||
onColumnClick?: (columnIndex: number, event: React.MouseEvent) => void;
|
||||
onNumeralClick?: (columnIndex: number, value: number, event: React.MouseEvent) => void;
|
||||
onBeadRef?: (bead: BeadConfig, element: SVGElement | null) => void;
|
||||
}
|
||||
|
||||
interface BeadClickEvent {
|
||||
columnIndex: number; // 0, 1, 2...
|
||||
bead: BeadConfig; // Complete bead configuration
|
||||
columnIndex: number; // 0, 1, 2... (array index)
|
||||
placeValue: ValidPlaceValues; // 0=ones, 1=tens, 2=hundreds...
|
||||
beadType: 'heaven' | 'earth'; // Type of bead
|
||||
position: number; // Position within type (0-3 for earth)
|
||||
active: boolean; // Current state
|
||||
active: boolean; // Current activation state
|
||||
value: number; // Numeric value (1 or 5)
|
||||
bead: BeadConfig; // Full bead configuration
|
||||
event: React.MouseEvent; // Original mouse event
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Customization
|
||||
## Advanced Features
|
||||
|
||||
### Granular Styling
|
||||
### Place-Value Based Targeting
|
||||
|
||||
Target beads by mathematical place value instead of visual column position:
|
||||
|
||||
```tsx
|
||||
// Target beads by place value (recommended)
|
||||
const placeValueHighlights = [
|
||||
{ placeValue: 0, beadType: 'earth', position: 2 }, // Ones place, 3rd earth bead
|
||||
{ placeValue: 1, beadType: 'heaven' }, // Tens place, heaven bead
|
||||
{ placeValue: 2, beadType: 'earth', position: 0 } // Hundreds place, 1st earth bead
|
||||
];
|
||||
|
||||
// Legacy column-index targeting (still supported)
|
||||
const columnHighlights = [
|
||||
{ columnIndex: 2, beadType: 'earth', position: 2 }, // Rightmost column
|
||||
{ columnIndex: 1, beadType: 'heaven' }, // Middle column
|
||||
{ columnIndex: 0, beadType: 'earth', position: 0 } // Leftmost column
|
||||
];
|
||||
|
||||
<AbacusReact highlightBeads={placeValueHighlights} />
|
||||
```
|
||||
|
||||
### Progressive Tutorial Steps
|
||||
|
||||
Create multi-step interactive tutorials:
|
||||
|
||||
```tsx
|
||||
const tutorialSteps = [
|
||||
{
|
||||
placeValue: 0,
|
||||
beadType: 'earth',
|
||||
position: 0,
|
||||
stepIndex: 0,
|
||||
direction: 'activate',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
placeValue: 0,
|
||||
beadType: 'earth',
|
||||
position: 1,
|
||||
stepIndex: 1,
|
||||
direction: 'activate',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
placeValue: 1,
|
||||
beadType: 'heaven',
|
||||
stepIndex: 2,
|
||||
direction: 'activate',
|
||||
order: 1
|
||||
}
|
||||
];
|
||||
|
||||
<AbacusReact
|
||||
stepBeadHighlights={tutorialSteps}
|
||||
currentStep={currentStepIndex}
|
||||
showDirectionIndicators={true}
|
||||
interactive={true}
|
||||
/>
|
||||
```
|
||||
|
||||
### Granular Style Customization
|
||||
|
||||
Target any visual element with precise control:
|
||||
|
||||
```tsx
|
||||
const customStyles = {
|
||||
const advancedStyles = {
|
||||
// Global defaults
|
||||
heavenBeads: { fill: '#ff6b35' },
|
||||
earthBeads: { fill: '#3498db' },
|
||||
heavenBeads: { fill: '#e74c3c', stroke: '#c0392b' },
|
||||
earthBeads: { fill: '#3498db', stroke: '#2980b9' },
|
||||
activeBeads: { opacity: 1.0 },
|
||||
inactiveBeads: { opacity: 0.3 },
|
||||
|
||||
// Column-specific overrides
|
||||
// Column-specific overrides (by array index)
|
||||
columns: {
|
||||
0: { // Hundreds column
|
||||
heavenBeads: { fill: '#e74c3c' },
|
||||
earthBeads: { fill: '#2ecc71' }
|
||||
0: { // Leftmost column (highest place value)
|
||||
heavenBeads: { fill: '#f39c12' },
|
||||
earthBeads: { fill: '#e67e22' },
|
||||
backgroundGlow: { fill: '#fff3cd', opacity: 0.3 }
|
||||
}
|
||||
},
|
||||
|
||||
// Individual bead targeting
|
||||
// Individual bead targeting (by array index)
|
||||
beads: {
|
||||
1: { // Middle column
|
||||
heaven: { fill: '#f39c12' },
|
||||
heaven: { fill: '#9b59b6' },
|
||||
earth: {
|
||||
0: { fill: '#1abc9c' }, // First earth bead
|
||||
3: { fill: '#e67e22' } // Fourth earth bead
|
||||
1: { fill: '#16a085' }, // Second earth bead
|
||||
2: { fill: '#17a2b8' }, // Third earth bead
|
||||
3: { fill: '#138496' } // Fourth earth bead
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// UI elements
|
||||
reckoningBar: { stroke: '#34495e', strokeWidth: 3 },
|
||||
columnPosts: { stroke: '#7f8c8d' },
|
||||
columnPosts: { stroke: '#7f8c8d', strokeWidth: 2 },
|
||||
numerals: {
|
||||
color: '#2c3e50',
|
||||
fontSize: '14px',
|
||||
fontFamily: 'monospace'
|
||||
fontSize: '16px',
|
||||
fontFamily: 'monospace',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
};
|
||||
|
||||
<AbacusReact customStyles={customStyles} />
|
||||
<AbacusReact customStyles={advancedStyles} />
|
||||
```
|
||||
|
||||
### Tutorial and Overlay System
|
||||
### Overlay System
|
||||
|
||||
Create interactive educational experiences:
|
||||
Create rich interactive educational experiences:
|
||||
|
||||
```tsx
|
||||
const overlays = [
|
||||
const educationalOverlays = [
|
||||
{
|
||||
id: 'welcome-tooltip',
|
||||
id: 'value-explanation',
|
||||
type: 'tooltip',
|
||||
target: {
|
||||
type: 'bead',
|
||||
columnIndex: 0,
|
||||
beadType: 'earth',
|
||||
beadPosition: 0
|
||||
},
|
||||
target: { type: 'bead', columnIndex: 0, beadType: 'heaven' },
|
||||
content: (
|
||||
<div style={{
|
||||
background: '#333',
|
||||
color: 'white',
|
||||
padding: '8px',
|
||||
borderRadius: '4px'
|
||||
}}>
|
||||
Click me to start!
|
||||
<div className="tutorial-tooltip">
|
||||
<h4>Heaven Bead</h4>
|
||||
<p>Worth 5 in this place value</p>
|
||||
<button onClick={() => nextStep()}>Got it!</button>
|
||||
</div>
|
||||
),
|
||||
offset: { x: 0, y: -30 }
|
||||
offset: { x: 0, y: -40 }
|
||||
},
|
||||
{
|
||||
id: 'direction-arrow',
|
||||
type: 'arrow',
|
||||
target: { type: 'bead', columnIndex: 1, beadType: 'earth', beadPosition: 0 },
|
||||
content: <div className="arrow-down">⬇</div>,
|
||||
offset: { x: 0, y: -20 }
|
||||
}
|
||||
];
|
||||
|
||||
<AbacusReact
|
||||
overlays={overlays}
|
||||
highlightBeads={[
|
||||
{ columnIndex: 0, beadType: 'earth', position: 0 }
|
||||
]}
|
||||
overlays={educationalOverlays}
|
||||
interactive={true}
|
||||
callbacks={{
|
||||
onBeadClick: (event) => {
|
||||
if (event.columnIndex === 0 && event.beadType === 'earth' && event.position === 0) {
|
||||
console.log('Tutorial step completed!');
|
||||
}
|
||||
}
|
||||
onBeadClick: handleTutorialProgression
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Dimension Calculation Hook
|
||||
|
||||
Get exact sizing information for layout planning:
|
||||
|
||||
```tsx
|
||||
import { useAbacusDimensions } from '@soroban/abacus-react';
|
||||
|
||||
function ResponsiveAbacusContainer() {
|
||||
const dimensions = useAbacusDimensions(
|
||||
5, // columns
|
||||
1.2, // scale factor
|
||||
true // show numbers
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
border: '1px solid #ccc',
|
||||
padding: '10px'
|
||||
}}
|
||||
>
|
||||
<AbacusReact
|
||||
columns={5}
|
||||
scaleFactor={1.2}
|
||||
showNumbers={true}
|
||||
value={12345}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Bead Reference System
|
||||
|
||||
Access individual bead DOM elements for advanced positioning:
|
||||
|
||||
```tsx
|
||||
function AdvancedExample() {
|
||||
function AdvancedPositioning() {
|
||||
const beadRefs = useRef(new Map<string, SVGElement>());
|
||||
|
||||
const handleBeadRef = (bead: BeadConfig, element: SVGElement | null) => {
|
||||
|
|
@ -279,92 +406,16 @@ function AdvancedExample() {
|
|||
if (element) {
|
||||
beadRefs.current.set(key, element);
|
||||
|
||||
// Now you can position tooltips, highlights, etc. precisely
|
||||
// Position custom elements relative to beads
|
||||
const rect = element.getBoundingClientRect();
|
||||
console.log(`Bead at column ${bead.columnIndex} is at:`, rect);
|
||||
console.log(`Bead at column ${bead.columnIndex} positioned at:`, rect);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AbacusReact
|
||||
callbacks={{ onBeadRef: handleBeadRef }}
|
||||
// ... other props
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Hooks
|
||||
|
||||
### useAbacusDimensions
|
||||
|
||||
Get exact sizing information for layout planning:
|
||||
|
||||
```tsx
|
||||
import { useAbacusDimensions } from '@soroban/abacus-react';
|
||||
|
||||
function MyComponent() {
|
||||
const dimensions = useAbacusDimensions(3, 1.2); // 3 columns, 1.2x scale
|
||||
|
||||
return (
|
||||
<div style={{ width: dimensions.width, height: dimensions.height }}>
|
||||
<AbacusReact columns={3} scaleFactor={1.2} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Educational Use Cases
|
||||
|
||||
### Interactive Math Lessons
|
||||
|
||||
```tsx
|
||||
function MathLesson() {
|
||||
const [problem, setProblem] = useState({ a: 23, b: 45 });
|
||||
const [step, setStep] = useState('show-first');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Add {problem.a} + {problem.b}</h3>
|
||||
|
||||
<AbacusReact
|
||||
value={step === 'show-first' ? problem.a : 0}
|
||||
interactive={step === 'add-second'}
|
||||
callbacks={{
|
||||
onValueChange: (value) => {
|
||||
if (value === problem.a + problem.b) {
|
||||
celebrate();
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Assessment Tools
|
||||
|
||||
```tsx
|
||||
function AbacusQuiz() {
|
||||
const [answers, setAnswers] = useState([]);
|
||||
|
||||
const checkAnswer = (event: BeadClickEvent) => {
|
||||
const isCorrect = validateBeadClick(event, expectedAnswer);
|
||||
recordAnswer(event, isCorrect);
|
||||
|
||||
if (isCorrect) {
|
||||
showSuccessFeedback();
|
||||
} else {
|
||||
showHint(event);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AbacusReact
|
||||
interactive={true}
|
||||
callbacks={{ onBeadClick: checkAnswer }}
|
||||
customStyles={getAnswerHighlighting(answers)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -372,7 +423,7 @@ function AbacusQuiz() {
|
|||
|
||||
## TypeScript Support
|
||||
|
||||
Full TypeScript definitions included:
|
||||
Full TypeScript definitions with branded types for enhanced type safety:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
|
|
@ -383,15 +434,134 @@ import {
|
|||
AbacusCustomStyles,
|
||||
AbacusOverlay,
|
||||
AbacusCallbacks,
|
||||
useAbacusDimensions
|
||||
useAbacusDimensions,
|
||||
PlaceValueBead,
|
||||
ColumnIndexBead,
|
||||
StepBeadHighlight,
|
||||
PlaceValue,
|
||||
ColumnIndex,
|
||||
ValidPlaceValues,
|
||||
EarthBeadPosition
|
||||
} from '@soroban/abacus-react';
|
||||
|
||||
// All interfaces fully typed for excellent developer experience
|
||||
// Branded types prevent mixing place values and column indices
|
||||
const placeValue: ValidPlaceValues = 2; // hundreds place
|
||||
const earthPosition: EarthBeadPosition = 3; // fourth earth bead
|
||||
|
||||
// Type-safe bead specification
|
||||
const bead: PlaceValueBead = {
|
||||
placeValue: 1, // tens place
|
||||
beadType: 'earth',
|
||||
position: 2 // third earth bead
|
||||
};
|
||||
```
|
||||
|
||||
## Educational Use Cases
|
||||
|
||||
### Interactive Math Lessons
|
||||
|
||||
```tsx
|
||||
function AdditionLesson() {
|
||||
const [problem] = useState({ a: 23, b: 45 });
|
||||
const [step, setStep] = useState('show-first');
|
||||
const [userValue, setUserValue] = useState(0);
|
||||
|
||||
const checkAnswer = (newValue: number) => {
|
||||
setUserValue(newValue);
|
||||
if (newValue === problem.a + problem.b) {
|
||||
setStep('completed');
|
||||
showCelebration();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="math-lesson">
|
||||
<h3>Add {problem.a} + {problem.b}</h3>
|
||||
|
||||
<AbacusReact
|
||||
value={step === 'show-first' ? problem.a : userValue}
|
||||
columns={3}
|
||||
interactive={step === 'user-input'}
|
||||
animated={true}
|
||||
showNumbers={true}
|
||||
callbacks={{ onValueChange: checkAnswer }}
|
||||
highlightBeads={step === 'hint' ? getHintBeads() : []}
|
||||
/>
|
||||
|
||||
{step === 'completed' && (
|
||||
<div className="success">
|
||||
🎉 Correct! {problem.a} + {problem.b} = {problem.a + problem.b}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Assessment and Quizzing
|
||||
|
||||
```tsx
|
||||
function AbacusQuiz() {
|
||||
const [answers, setAnswers] = useState<BeadClickEvent[]>([]);
|
||||
const [feedback, setFeedback] = useState<string>('');
|
||||
|
||||
const validateAnswer = (event: BeadClickEvent) => {
|
||||
const isCorrect = checkBeadClick(event, expectedAnswer);
|
||||
|
||||
setAnswers(prev => [...prev, event]);
|
||||
|
||||
if (isCorrect) {
|
||||
setFeedback('Correct! Well done.');
|
||||
advanceToNextQuestion();
|
||||
} else {
|
||||
setFeedback('Try again. Remember: this bead represents...');
|
||||
showHint(event);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="abacus-quiz">
|
||||
<AbacusReact
|
||||
value={currentQuestionValue}
|
||||
interactive={true}
|
||||
callbacks={{ onBeadClick: validateAnswer }}
|
||||
customStyles={getAnswerHighlighting(answers)}
|
||||
overlays={currentHints}
|
||||
/>
|
||||
<div className="feedback">{feedback}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Color Schemes and Accessibility
|
||||
|
||||
### Built-in Color Schemes
|
||||
|
||||
- **`monochrome`** - Single color for all beads
|
||||
- **`place-value`** - Different colors for each place value column
|
||||
- **`alternating`** - Alternating colors between columns
|
||||
- **`heaven-earth`** - Different colors for heaven vs earth beads
|
||||
|
||||
### Accessibility Palettes
|
||||
|
||||
- **`colorblind`** - High contrast, colorblind-friendly palette
|
||||
- **`grayscale`** - Monochrome grayscale for maximum compatibility
|
||||
- **`mnemonic`** - Colors that aid memory and learning
|
||||
- **`nature`** - Earth-tone palette for reduced eye strain
|
||||
|
||||
```tsx
|
||||
<AbacusReact
|
||||
colorScheme="place-value"
|
||||
colorPalette="colorblind"
|
||||
value={12345}
|
||||
columns={5}
|
||||
/>
|
||||
```
|
||||
|
||||
## Publishing and Versioning
|
||||
|
||||
This package uses [semantic-release](https://semantic-release.gitbook.io/) for automated publishing to npm. Versions are determined by conventional commit messages:
|
||||
This package uses [semantic-release](https://semantic-release.gitbook.io/) for automated publishing. Versions are determined by conventional commit messages:
|
||||
|
||||
### Commit Message Format
|
||||
|
||||
|
|
@ -399,18 +569,18 @@ Use these prefixes for commits that affect the `packages/abacus-react` directory
|
|||
|
||||
```bash
|
||||
# New features (minor version bump)
|
||||
feat(abacus-react): add new bead animation system
|
||||
feat(abacus-react): add gesture recognition system
|
||||
|
||||
# Bug fixes (patch version bump)
|
||||
fix(abacus-react): resolve gesture detection issue
|
||||
fix(abacus-react): resolve animation timing issues
|
||||
|
||||
# Performance improvements (patch version bump)
|
||||
perf(abacus-react): optimize bead rendering
|
||||
perf(abacus-react): optimize bead rendering performance
|
||||
|
||||
# Breaking changes (major version bump)
|
||||
feat(abacus-react)!: change callback signature
|
||||
feat(abacus-react)!: redesign callback API
|
||||
# or
|
||||
feat(abacus-react): redesign API
|
||||
feat(abacus-react): change component interface
|
||||
|
||||
BREAKING CHANGE: callback functions now receive different parameters
|
||||
```
|
||||
|
|
@ -438,10 +608,15 @@ pnpm storybook
|
|||
pnpm release:dry-run
|
||||
```
|
||||
|
||||
## Live Documentation
|
||||
|
||||
- **Storybook**: [Component examples and documentation](https://antialias.github.io/soroban-abacus-flashcards/abacus-react/)
|
||||
- **Source Code**: [GitHub Repository](https://github.com/antialias/soroban-abacus-flashcards/tree/main/packages/abacus-react)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions welcome! Please see our contributing guidelines and feel free to submit issues or pull requests.
|
||||
Contributions welcome! Please see our [contributing guidelines](../../CONTRIBUTING.md) and feel free to submit issues or pull requests.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
MIT License - see [LICENSE](../../LICENSE) file for details.
|
||||
Loading…
Reference in New Issue