diff --git a/packages/abacus-react/README.md b/packages/abacus-react/README.md index 7f1b2f07..c0b5583c 100644 --- a/packages/abacus-react/README.md +++ b/packages/abacus-react/README.md @@ -6,12 +6,12 @@ A comprehensive React component for rendering interactive Soroban (Japanese abac - 🎯 **Interactive beads** - Click to toggle or use directional gestures - 🎨 **Complete visual customization** - Style every element individually -- 🎓 **Tutorial system** - Built-in overlay and guidance capabilities -- ⚡ **React Spring animations** - Smooth bead movements and transitions - 📱 **Responsive scaling** - Configurable scale factor for different sizes - 🌈 **Multiple color schemes** - Monochrome, place-value, alternating, heaven-earth -- 🔧 **Developer-friendly** - Comprehensive hooks and callback system - 🎭 **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 ## Installation @@ -24,97 +24,145 @@ pnpm add @soroban/abacus-react yarn add @soroban/abacus-react ``` -## Basic Usage +## Quick Start + + +### Basic Usage + +Simple abacus showing a number + +![Basic Usage](./examples/basic-usage.svg) ```tsx -import { AbacusReact } from '@soroban/abacus-react'; + +``` -function MyApp() { - return ( - - ); +### Interactive Mode + +Clickable abacus with animations + +![Interactive Mode](./examples/interactive.svg) + +```tsx + console.log('New value:', newValue), + onBeadClick: (event) => console.log('Bead clicked:', event) + }} +/> +``` + +### Custom Styling + +Personalized colors and highlights + +![Custom Styling](./examples/custom-styling.svg) + +```tsx + +``` + +### Tutorial System + +Educational guidance with tooltips + +![Tutorial System](./examples/tutorial-mode.svg) + +```tsx +Click this bead!, + offset: { x: 0, y: -30 } + }]} + callbacks={{ + onBeadClick: (event) => { + if (event.columnIndex === 0 && event.beadType === 'earth' && event.position === 1) { + console.log('Correct!'); + } + } + }} +/> +``` + + +## Core API + +### Basic Props + +```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 + scaleFactor?: number; // 0.5 - 3.0, size multiplier + + // Appearance + beadShape?: 'diamond' | 'square' | 'circle'; + colorScheme?: 'monochrome' | 'place-value' | 'alternating' | 'heaven-earth'; + colorPalette?: 'default' | 'colorblind' | 'mnemonic' | 'grayscale' | 'nature'; + hideInactiveBeads?: boolean; // Hide/show inactive beads + + // Interaction + interactive?: boolean; // Enable user interactions + animated?: boolean; // Enable animations + gestures?: boolean; // Enable drag gestures } ``` -## Advanced Tutorial System - -Build interactive educational experiences with precise bead targeting and overlay positioning: +### Event Callbacks ```tsx -import { AbacusReact, BeadClickEvent } from '@soroban/abacus-react'; +interface AbacusCallbacks { + onValueChange?: (newValue: number) => void; + onBeadClick?: (event: BeadClickEvent) => void; + onBeadHover?: (event: BeadClickEvent) => void; + onBeadLeave?: (event: BeadClickEvent) => void; + onColumnClick?: (columnIndex: number) => void; + onNumeralClick?: (columnIndex: number, value: number) => void; + onBeadRef?: (bead: BeadConfig, element: SVGElement | null) => void; +} -function TutorialExample() { - const [step, setStep] = useState(0); - const [beadRefs, setBeadRefs] = useState(new Map()); - - const handleBeadClick = (event: BeadClickEvent) => { - // Validate clicks against tutorial targets - if (event.columnIndex === 0 && event.beadType === 'earth') { - setStep(step + 1); - } - }; - - const handleBeadRef = (bead: BeadConfig, element: SVGElement | null) => { - // Collect references to individual beads for precise positioning - const key = `${bead.columnIndex}-${bead.type}-${bead.position}`; - if (element) { - beadRefs.set(key, element); - } - }; - - return ( - Click this bead!, - offset: { x: 0, y: -20 } - }]} - - // Enhanced callbacks - callbacks={{ - onBeadClick: handleBeadClick, - onBeadRef: handleBeadRef - }} - /> - ); +interface BeadClickEvent { + columnIndex: number; // 0, 1, 2... + beadType: 'heaven' | 'earth'; // Type of bead + position: number; // Position within type (0-3 for earth) + active: boolean; // Current state + value: number; // Numeric value (1 or 5) + bead: BeadConfig; // Full bead configuration } ``` -## Customization API +## Advanced Customization ### Granular Styling @@ -133,9 +181,6 @@ const customStyles = { 0: { // Hundreds column heavenBeads: { fill: '#e74c3c' }, earthBeads: { fill: '#2ecc71' } - }, - 2: { // Ones column - numerals: { color: '#9b59b6', fontWeight: 'bold' } } }, @@ -163,12 +208,56 @@ const customStyles = { ``` +### Tutorial and Overlay System + +Create interactive educational experiences: + +```tsx +const overlays = [ + { + id: 'welcome-tooltip', + type: 'tooltip', + target: { + type: 'bead', + columnIndex: 0, + beadType: 'earth', + beadPosition: 0 + }, + content: ( +
+ Click me to start! +
+ ), + offset: { x: 0, y: -30 } + } +]; + + { + if (event.columnIndex === 0 && event.beadType === 'earth' && event.position === 0) { + console.log('Tutorial step completed!'); + } + } + }} +/> +``` + ### Bead Reference System Access individual bead DOM elements for advanced positioning: ```tsx -function AdvancedTutorial() { +function AdvancedExample() { const beadRefs = useRef(new Map()); const handleBeadRef = (bead: BeadConfig, element: SVGElement | null) => { @@ -191,155 +280,6 @@ function AdvancedTutorial() { } ``` -### Overlay System - -Inject custom UI elements positioned relative to abacus components: - -```tsx -const overlays = [ - { - id: 'welcome-tooltip', - type: 'tooltip', - target: { - type: 'bead', - columnIndex: 0, - beadType: 'earth', - beadPosition: 0 - }, - content: ( -
- Click me to start! - {/* CSS arrow pointing to target */} -
-
- ), - offset: { x: 0, y: -30 }, - visible: true - }, - - { - id: 'column-label', - type: 'highlight', - target: { type: 'column', columnIndex: 2 }, - content:
Ones column
, - offset: { x: 0, y: -80 } - }, - - { - id: 'coordinate-marker', - type: 'custom', - target: { type: 'coordinates', x: 100, y: 50 }, - content:
Custom position
- } -]; - - -``` - -## Event Callbacks - -### Enhanced Bead Events - -Get detailed information about every interaction: - -```tsx -const handleBeadClick = (event: BeadClickEvent) => { - console.log('Bead clicked:', { - columnIndex: event.columnIndex, // 0, 1, 2... - beadType: event.beadType, // 'heaven' | 'earth' - position: event.position, // 0-3 for earth beads - active: event.active, // Current state - value: event.value, // Numeric value (1 or 5) - bead: event.bead // Full bead config - }); - - // Tutorial validation example - if (event.columnIndex === targetColumn && event.beadType === targetType) { - advanceToNextStep(); - } -}; - -const callbacks = { - onBeadClick: handleBeadClick, - onBeadHover: (event) => showHoverTooltip(event), - onBeadLeave: (event) => hideHoverTooltip(event), - onValueChange: (newValue) => updateDisplay(newValue), - onColumnClick: (columnIndex) => highlightColumn(columnIndex), - onNumeralClick: (columnIndex, value) => editColumnValue(columnIndex, value), - onBeadRef: (bead, element) => storeBeadReference(bead, element) -}; - - -``` - -## Configuration Options - -### Display Configuration - -```tsx -interface AbacusConfig { - // Basic setup - value?: number; // 0-99999, value to display - columns?: number | 'auto'; // Number of columns or auto-calculate - showEmptyColumns?: boolean; // Show leading zero columns - showNumbers?: boolean; // Show place value numbers - - // Visual appearance - beadShape?: 'diamond' | 'square' | 'circle'; - colorScheme?: 'monochrome' | 'place-value' | 'alternating' | 'heaven-earth'; - colorPalette?: 'default' | 'colorblind' | 'mnemonic' | 'grayscale' | 'nature'; - scaleFactor?: number; // 0.5 - 3.0, size multiplier - hideInactiveBeads?: boolean; // Hide/show inactive beads - - // Interaction - interactive?: boolean; // Enable user interactions - gestures?: boolean; // Enable drag gestures - animated?: boolean; // Enable animations - - // Advanced customization - customStyles?: AbacusCustomStyles; // Granular styling - overlays?: AbacusOverlay[]; // UI overlays - callbacks?: AbacusCallbacks; // Event handlers - - // Tutorial features - highlightColumns?: number[]; // Highlight specific columns - highlightBeads?: BeadTarget[]; // Highlight specific beads - disabledColumns?: number[]; // Disable interactions - disabledBeads?: BeadTarget[]; // Disable specific beads -} -``` - -### Highlighting and Disabling - -```tsx -// Highlight specific elements for tutorials - -``` - ## Hooks ### useAbacusDimensions @@ -352,13 +292,6 @@ import { useAbacusDimensions } from '@soroban/abacus-react'; function MyComponent() { const dimensions = useAbacusDimensions(3, 1.2); // 3 columns, 1.2x scale - console.log('Abacus size:', { - width: dimensions.width, // Total width in pixels - height: dimensions.height, // Total height in pixels - rodSpacing: dimensions.rodSpacing, // Distance between columns - beadSize: dimensions.beadSize // Individual bead size - }); - return (
@@ -367,25 +300,6 @@ function MyComponent() { } ``` -## TypeScript Support - -Full TypeScript definitions included: - -```tsx -import { - AbacusReact, - AbacusConfig, - BeadConfig, - BeadClickEvent, - AbacusCustomStyles, - AbacusOverlay, - AbacusCallbacks, - useAbacusDimensions -} from '@soroban/abacus-react'; - -// All interfaces fully typed for excellent developer experience -``` - ## Educational Use Cases ### Interactive Math Lessons @@ -399,30 +313,17 @@ function MathLesson() {

Add {problem.a} + {problem.b}

- {step === 'show-first' && ( - This represents {problem.a}
- }]} - /> - )} - - {step === 'add-second' && ( - { - if (value === problem.a + problem.b) { - celebrate(); - } + { + if (value === problem.a + problem.b) { + celebrate(); } - }} - /> - )} + } + }} + />
); } @@ -455,10 +356,29 @@ function AbacusQuiz() { } ``` +## TypeScript Support + +Full TypeScript definitions included: + +```tsx +import { + AbacusReact, + AbacusConfig, + BeadConfig, + BeadClickEvent, + AbacusCustomStyles, + AbacusOverlay, + AbacusCallbacks, + useAbacusDimensions +} from '@soroban/abacus-react'; + +// All interfaces fully typed for excellent developer experience +``` + ## Contributing Contributions welcome! Please see our contributing guidelines and feel free to submit issues or pull requests. ## License -MIT License - see LICENSE file for details. \ No newline at end of file +MIT License - see LICENSE file for details. diff --git a/packages/abacus-react/examples/README.md b/packages/abacus-react/examples/README.md new file mode 100644 index 00000000..b703f596 --- /dev/null +++ b/packages/abacus-react/examples/README.md @@ -0,0 +1,29 @@ +# AbacusReact Examples + +Generated SVG examples demonstrating various features of the AbacusReact component. + +## Files + +- **basic-usage.svg** - Simple abacus showing a number +- **interactive.svg** - Clickable abacus with animations +- **custom-styling.svg** - Personalized colors and highlights +- **tutorial-mode.svg** - Educational guidance with tooltips + +## Usage in Documentation + +These SVG files can be embedded directly in markdown: + +```markdown +![Basic Usage](./examples/basic-usage.svg) +``` + +Or referenced in HTML: + +```html +Basic AbacusReact Usage +``` + +--- + +_Generated automatically by generate-examples.js using react-dom/server_ +_Last updated: 2025-09-19T19:39:30.261Z_ diff --git a/packages/abacus-react/examples/basic-usage.svg b/packages/abacus-react/examples/basic-usage.svg new file mode 100644 index 00000000..a72d8ea0 --- /dev/null +++ b/packages/abacus-react/examples/basic-usage.svg @@ -0,0 +1,20 @@ + + + + + + Basic Usage + + + Simple abacus showing a number + + + (SSR placeholder - use Storybook for interactive preview) + + \ No newline at end of file diff --git a/packages/abacus-react/examples/custom-styling.svg b/packages/abacus-react/examples/custom-styling.svg new file mode 100644 index 00000000..d6514c4b --- /dev/null +++ b/packages/abacus-react/examples/custom-styling.svg @@ -0,0 +1,38 @@ + + + + + + Custom Styling + + + Personalized colors and highlights + + + (SSR placeholder - use Storybook for interactive preview) + + \ No newline at end of file diff --git a/packages/abacus-react/examples/interactive.svg b/packages/abacus-react/examples/interactive.svg new file mode 100644 index 00000000..70124f6f --- /dev/null +++ b/packages/abacus-react/examples/interactive.svg @@ -0,0 +1,20 @@ + + + + + + Interactive Mode + + + Clickable abacus with animations + + + (SSR placeholder - use Storybook for interactive preview) + + \ No newline at end of file diff --git a/packages/abacus-react/examples/tutorial-mode.svg b/packages/abacus-react/examples/tutorial-mode.svg new file mode 100644 index 00000000..da21d6b3 --- /dev/null +++ b/packages/abacus-react/examples/tutorial-mode.svg @@ -0,0 +1,20 @@ + + + + + + Tutorial System + + + Educational guidance with tooltips + + + (SSR placeholder - use Storybook for interactive preview) + + \ No newline at end of file