#!/usr/bin/env node /** * Generate SVG examples and README content for AbacusReact * * This script creates actual SVG files using react-dom/server and * generates a balanced README with usage examples. */ const fs = require("fs").promises; const path = require("path"); const React = require("react"); const { renderToStaticMarkup } = require("react-dom/server"); // Setup comprehensive DOM globals for React Spring and dependencies const { JSDOM } = require("jsdom"); if (typeof global.window === "undefined") { const dom = new JSDOM("
", { url: "http://localhost", pretendToBeVisual: true, resources: "usable", }); global.window = dom.window; global.document = dom.window.document; global.navigator = dom.window.navigator; global.HTMLElement = dom.window.HTMLElement; global.SVGElement = dom.window.SVGElement; global.Element = dom.window.Element; global.requestAnimationFrame = dom.window.requestAnimationFrame || function (cb) { return setTimeout(cb, 16); }; global.cancelAnimationFrame = dom.window.cancelAnimationFrame || function (id) { return clearTimeout(id); }; // Add customElements for number-flow compatibility global.customElements = { define: function () {}, get: function () { return undefined; }, whenDefined: function () { return Promise.resolve(); }, }; // Add ResizeObserver mock global.ResizeObserver = class ResizeObserver { observe() {} unobserve() {} disconnect() {} }; // Mock React Spring to return static components but preserve all SVG elements const createAnimatedComponent = (tag) => { // Return a React component that forwards props to the base element return React.forwardRef((props, ref) => { return React.createElement(tag, { ...props, ref }); }); }; const mockAnimated = { div: createAnimatedComponent("div"), svg: createAnimatedComponent("svg"), g: createAnimatedComponent("g"), circle: createAnimatedComponent("circle"), rect: createAnimatedComponent("rect"), path: createAnimatedComponent("path"), text: createAnimatedComponent("text"), polygon: createAnimatedComponent("polygon"), line: createAnimatedComponent("line"), foreignObject: createAnimatedComponent("foreignObject"), }; // Mock @react-spring/web with better stubs require.cache[require.resolve("@react-spring/web")] = { exports: { useSpring: () => [ { x: 0, y: 0 }, { start: () => {}, set: () => {} }, ], useSpringValue: () => ({ start: () => {}, get: () => 0, to: () => {} }), animated: mockAnimated, config: { default: {}, slow: {}, wobbly: {}, stiff: {} }, to: (springs, fn) => (fn ? fn(springs) : springs), }, }; // Mock @use-gesture/react with proper signatures require.cache[require.resolve("@use-gesture/react")] = { exports: { useDrag: () => () => ({}), useGesture: () => () => ({}), }, }; // Mock @number-flow/react with aggressive SVG text replacement require.cache[require.resolve("@number-flow/react")] = { exports: { __esModule: true, default: ({ children, value, format, style, ...props }) => { // Use value if provided, otherwise fallback to children const displayValue = value !== undefined ? value : children; // Return raw text content - React will render this as a text node return String(displayValue); }, }, }; } // Import our component after setting up globals - use source directly const { AbacusReact } = require("./src/AbacusReact.tsx"); // Key example configurations for different use cases const examples = [ { name: "basic-usage", title: "Basic Usage", description: "Simple abacus showing a number", code: `