{"id":46064219,"url":"https://github.com/zettersten/blazorfastaddtocart","last_synced_at":"2026-03-01T12:02:58.922Z","repository":{"id":324253457,"uuid":"1096546533","full_name":"Zettersten/BlazorFastAddToCart","owner":"Zettersten","description":"A high-performance Blazor component for animating items into a cart with customizable easing functions","archived":false,"fork":false,"pushed_at":"2026-01-12T14:16:14.000Z","size":9250,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-12T20:57:48.743Z","etag":null,"topics":["add-to-cart","animation","blazor","blazor-server","blazor-webassembly","dotnet"],"latest_commit_sha":null,"homepage":"https://zettersten.github.io/BlazorFastAddToCart/","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Zettersten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-14T15:29:34.000Z","updated_at":"2026-01-12T14:16:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Zettersten/BlazorFastAddToCart","commit_stats":null,"previous_names":["zettersten/blazorfastaddtocart"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Zettersten/BlazorFastAddToCart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zettersten%2FBlazorFastAddToCart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zettersten%2FBlazorFastAddToCart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zettersten%2FBlazorFastAddToCart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zettersten%2FBlazorFastAddToCart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Zettersten","download_url":"https://codeload.github.com/Zettersten/BlazorFastAddToCart/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zettersten%2FBlazorFastAddToCart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29969243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T11:43:06.159Z","status":"ssl_error","status_checked_at":"2026-03-01T11:43:03.887Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["add-to-cart","animation","blazor","blazor-server","blazor-webassembly","dotnet"],"created_at":"2026-03-01T12:02:58.186Z","updated_at":"2026-03-01T12:02:58.875Z","avatar_url":"https://github.com/Zettersten.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blazor Fast Add To Cart\n\n[![NuGet](https://img.shields.io/nuget/v/BlazorFastAddToCart.svg)](https://www.nuget.org/packages/BlazorFastAddToCart/)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/Zettersten/BlazorFastAddToCart)\n\nA high-performance Blazor component that animates items flying into a shopping cart (or any destination) with customizable easing functions. Optimized for AOT compilation, trimming-friendly, and designed for both Blazor Server and WebAssembly hosting models.\n\n## 🚀 Live Demo\n\n**[View the interactive demo](https://zettersten.github.io/BlazorFastAddToCart/)**\n\n![Sample 1](https://github.com/Zettersten/BlazorFastAddToCart/blob/main/sample-1.gif?raw=true)\n\n## ✨ Features\n\n- **High Performance**: Allocation-conscious cubic bezier easing (passes control points to JS to avoid per-click easing-string formatting and regex parsing)\n- **Customizable Animations**: Independent easing functions for X, Y, and scale transformations\n- **Multiple Items**: Animate multiple items with staggered timing using the `Count` parameter\n- **Custom Triggers**: Specify which element triggers the animation with the `Trigger` parameter\n- **Progress Tracking**: Track animation progress in real-time with `OnAnimationProgress`\n- **Accessibility**: Respects `prefers-reduced-motion` and provides fallback feedback\n- **Concurrent Animations**: Supports multiple simultaneous animations without conflicts\n- **Flexible Content**: Works with images, buttons, divs, or any HTML content\n- **Blazor Server \u0026 WASM**: Compatible with both hosting models\n- **Trimming-Friendly**: Fully compatible with .NET trimming and AOT compilation\n- **Type-Safe**: Strongly-typed easing functions with compile-time constants\n\n## 📦 Installation\n\nInstall the package via NuGet Package Manager:\n\n```bash\ndotnet add package BlazorFastAddToCart\n```\n\nOr via Package Manager Console:\n\n```powershell\nInstall-Package BlazorFastAddToCart\n```\n\nOr add directly to your `.csproj`:\n\n```xml\n\u003cPackageReference Include=\"BlazorFastAddToCart\" Version=\"1.0.0\" /\u003e\n```\n\n## 🎯 Quick Start\n\n### 1. Add Namespace\n\nAdd the namespace to your `_Imports.razor` file:\n\n```razor\n@using BlazorFastAddToCart\n```\n\n### 2. Basic Usage\n\nWrap any content you want to animate with the `AddToCart` component:\n\n```razor\n\u003c!-- Cart destination --\u003e\n\u003cdiv id=\"cart\" class=\"cart-icon\"\u003e🛒\u003c/div\u003e\n\n\u003c!-- Product with animation --\u003e\n\u003cAddToCart Destination=\"#cart\"\u003e\n    \u003cimg src=\"product.jpg\" alt=\"Product\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### 3. With Event Callback\n\nHandle when the animation completes:\n\n```razor\n\u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"HandleAddToCart\"\u003e\n    \u003cbutton class=\"btn btn-primary\"\u003eAdd to Cart\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private void HandleAddToCart()\n    {\n        // Update cart count, make API call, etc.\n        cartCount++;\n    }\n}\n```\n\n## 📚 Component Parameters\n\n### `Destination` (Required)\n\n**Type**: `string`  \n**Default**: None (required)\n\nCSS selector for the destination element where the animation should end. Can be an ID selector (`#cart`), class selector (`.cart-icon`), or any valid CSS selector.\n\n```razor\n\u003cAddToCart Destination=\"#shopping-cart\"\u003e\n    \u003c!-- content --\u003e\n\u003c/AddToCart\u003e\n```\n\n### `Speed`\n\n**Type**: `double`  \n**Default**: `0.6`\n\nAnimation duration in seconds. Lower values = faster animation.\n\n```razor\n\u003c!-- Fast animation (0.5 seconds) --\u003e\n\u003cAddToCart Destination=\"#cart\" Speed=\"0.5\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n\n\u003c!-- Slow animation (2 seconds) --\u003e\n\u003cAddToCart Destination=\"#cart\" Speed=\"2.0\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n**Note**: The default value of `0.6` seconds provides a smooth, fast animation. For typical e-commerce use cases, values between `0.5` and `1.5` seconds work best.\n\n### `EasingX`\n\n**Type**: `CubicBezier`  \n**Default**: `CubicBezier.CartX`\n\nEasing function for horizontal (X-axis) movement. Controls how the item accelerates/decelerates horizontally.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" EasingX=\"@CubicBezier.EaseOut\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### `EasingY`\n\n**Type**: `CubicBezier`  \n**Default**: `CubicBezier.CartY`\n\nEasing function for vertical (Y-axis) movement. Controls how the item accelerates/decelerates vertically.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" EasingY=\"@CubicBezier.EaseInOut\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### `EasingScale`\n\n**Type**: `CubicBezier`  \n**Default**: `CubicBezier.CartScale`\n\nEasing function for scale transformation. Controls how the item scales down during the animation.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" EasingScale=\"@CubicBezier.EaseIn\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### `OnBeforeAnimation`\n\n**Type**: `EventCallback`  \n**Default**: `null`\n\nCallback invoked before the animation starts. Use this to prepare data, update UI state, perform validation, or execute any logic that should happen before the animation begins. This callback fires once per click, even when `Count \u003e 1`.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" OnBeforeAnimation=\"PrepareAnimation\" OnAnimationComplete=\"HandleAddToCart\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private async Task PrepareAnimation()\n    {\n        // Prepare data, update UI, or perform validation before animation starts\n        await ValidateItemAsync();\n        StateHasChanged();\n    }\n}\n```\n\n### `OnAnimationComplete`\n\n**Type**: `EventCallback`  \n**Default**: `null`\n\nCallback invoked when the animation completes. Use this to update cart counts, make API calls, or perform other actions. When using `Count \u003e 1`, this callback fires only once after all animations complete.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"HandleAddToCart\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private async Task HandleAddToCart()\n    {\n        cartCount++;\n        await AddItemToCartAsync(productId);\n        StateHasChanged();\n    }\n}\n```\n\n### `Count`\n\n**Type**: `int`  \n**Default**: `1`\n\nNumber of items to animate. When set to a value greater than 1, multiple animations will be triggered with staggered timing. All animations complete before `OnAnimationComplete` fires once.\n\n```razor\n\u003c!-- Add 10 items with staggered animations --\u003e\n\u003cAddToCart Destination=\"#cart\" Count=\"10\" OnAnimationComplete=\"HandleBulkAdd\"\u003e\n    \u003cbutton\u003eAdd 10 Items\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private void HandleBulkAdd()\n    {\n        // This fires once after all 10 animations complete\n        cartCount += 10;\n    }\n}\n```\n\n### `Trigger`\n\n**Type**: `string?`  \n**Default**: `null`\n\nCSS selector for the specific element that should trigger the animation. When provided, only clicks on the matching element will trigger the animation. Useful when you want to animate a specific part of your content (like a button) rather than the entire wrapped content.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" Trigger=\".add-to-cart-btn\"\u003e\n    \u003cdiv class=\"product-card\"\u003e\n        \u003cimg src=\"product.jpg\" /\u003e\n        \u003ch3\u003eProduct Name\u003c/h3\u003e\n        \u003c!-- Only clicking this button triggers animation --\u003e\n        \u003cbutton class=\"add-to-cart-btn\"\u003eAdd to Cart\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/AddToCart\u003e\n```\n\nThe selector can be:\n- A class selector: `\".add-to-cart-btn\"`\n- An ID selector: `\"#product-button\"`\n- Any valid CSS selector: `\"button[type='submit']\"`\n\nIf `null`, the entire wrapped content acts as the trigger.\n\n### `OnAnimationProgress`\n\n**Type**: `EventCallback\u003cdouble\u003e`  \n**Default**: `null`\n\nCallback invoked during animation to report progress. Progress ranges from `0.0` (start) to `1.0` (complete). Updates are throttled to reduce callback frequency. When using `Count \u003e 1`, progress represents the overall progress across all animations.\n\n```razor\n\u003cAddToCart Destination=\"#cart\" \n           Count=\"5\"\n           OnAnimationProgress=\"HandleProgress\"\n           OnAnimationComplete=\"HandleComplete\"\u003e\n    \u003cbutton\u003eAdd Items\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private double progress = 0.0;\n\n    private void HandleProgress(double progressValue)\n    {\n        progress = progressValue; // 0.0 to 1.0\n        StateHasChanged();\n    }\n\n    private void HandleComplete()\n    {\n        progress = 0.0; // Reset for next animation\n    }\n}\n```\n\n### `ChildContent`\n\n**Type**: `RenderFragment`  \n**Default**: `null`\n\nThe content to wrap and animate. Can be any HTML element, image, button, or complex markup.\n\n```razor\n\u003cAddToCart Destination=\"#cart\"\u003e\n    \u003c!-- Any content here --\u003e\n    \u003cdiv class=\"product-card\"\u003e\n        \u003cimg src=\"product.jpg\" /\u003e\n        \u003ch3\u003eProduct Name\u003c/h3\u003e\n        \u003cbutton\u003eAdd to Cart\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/AddToCart\u003e\n```\n\n## 🎨 Easing Functions\n\nThe component includes a comprehensive set of predefined easing functions via the `CubicBezier` struct. The predefined `CubicBezier` values are allocation-free; `ToCssString()` allocates the returned string and is meant for display/debugging.\n\n### Standard Easing Functions\n\n```csharp\nCubicBezier.Linear      // Linear interpolation (no easing)\nCubicBezier.Ease        // Default easing (slow start, fast middle, slow end)\nCubicBezier.EaseIn      // Slow start\nCubicBezier.EaseOut     // Slow end\nCubicBezier.EaseInOut   // Slow start and end\n```\n\n### Quadratic Easing\n\n```csharp\nCubicBezier.EaseInQuad\nCubicBezier.EaseOutQuad\nCubicBezier.EaseInOutQuad\n```\n\n### Cubic Easing\n\n```csharp\nCubicBezier.EaseInCubic\nCubicBezier.EaseOutCubic\nCubicBezier.EaseInOutCubic\n```\n\n### Quartic Easing\n\n```csharp\nCubicBezier.EaseInQuart\nCubicBezier.EaseOutQuart\nCubicBezier.EaseInOutQuart\n```\n\n### Quintic Easing\n\n```csharp\nCubicBezier.EaseInQuint\nCubicBezier.EaseOutQuint\nCubicBezier.EaseInOutQuint\n```\n\n### Bouncy/Elastic Easing\n\n```csharp\nCubicBezier.EaseInBack   // Bounces backward at start\nCubicBezier.EaseOutBack  // Bounces forward at end\nCubicBezier.EaseInOutBack // Bounces at both ends\n```\n\n### Custom Cart Easing (Default)\n\nThese are optimized specifically for shopping cart animations:\n\n```csharp\nCubicBezier.CartX      // Default X-axis easing (slight overshoot)\nCubicBezier.CartY      // Default Y-axis easing (bouncy arc)\nCubicBezier.CartScale  // Default scale easing (smooth shrink)\n```\n\n### Creating Custom Easing Functions\n\nYou can create custom easing functions by instantiating `CubicBezier` with your own control points:\n\n```razor\n@code {\n    // Custom easing: fast start, slow end with overshoot\n    private CubicBezier customEasing = new CubicBezier(0.68f, -0.55f, 0.265f, 1.55f);\n}\n\n\u003cAddToCart Destination=\"#cart\" EasingX=\"@customEasing\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n```\n\nThe `CubicBezier` constructor takes four float parameters: `(x1, y1, x2, y2)` representing the control points of the cubic bezier curve. Values typically range from 0 to 1, but can exceed 1 for overshoot effects.\n\n## 💡 Usage Examples\n\n### Example 1: Simple Product Card\n\n```razor\n\u003cdiv class=\"product-grid\"\u003e\n    @foreach (var product in products)\n    {\n        \u003cdiv class=\"product-card\"\u003e\n            \u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"() =\u003e AddToCart(product.Id)\"\u003e\n                \u003cdiv class=\"product-image\"\u003e\n                    \u003cimg src=\"@product.ImageUrl\" alt=\"@product.Name\" /\u003e\n                \u003c/div\u003e\n                \u003cdiv class=\"product-info\"\u003e\n                    \u003ch3\u003e@product.Name\u003c/h3\u003e\n                    \u003cp class=\"price\"\u003e$@product.Price\u003c/p\u003e\n                    \u003cbutton class=\"btn-add-to-cart\"\u003eAdd to Cart\u003c/button\u003e\n                \u003c/div\u003e\n            \u003c/AddToCart\u003e\n        \u003c/div\u003e\n    }\n\u003c/div\u003e\n\n@code {\n    private List\u003cProduct\u003e products = new();\n    private int cartCount = 0;\n\n    private void AddToCart(int productId)\n    {\n        cartCount++;\n        // Add product to cart via API, etc.\n    }\n}\n```\n\n### Example 2: Custom Speed and Easing\n\n```razor\n\u003cAddToCart \n    Destination=\"#cart\" \n    Speed=\"0.8\"\n    EasingX=\"@CubicBezier.EaseOutBack\"\n    EasingY=\"@CubicBezier.EaseInOut\"\n    EasingScale=\"@CubicBezier.EaseIn\"\n    OnAnimationComplete=\"HandleAddToCart\"\u003e\n    \u003cimg src=\"product.jpg\" alt=\"Product\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 3: Dynamic Speed Based on Distance\n\n```razor\n@code {\n    private double CalculateSpeed(Product product)\n    {\n        // Calculate speed based on product position or other factors\n        var baseSpeed = 0.6;\n        var distanceFactor = CalculateDistanceToCart(product);\n        return baseSpeed + (distanceFactor * 0.1);\n    }\n}\n\n\u003cAddToCart Destination=\"#cart\" Speed=\"@CalculateSpeed(product)\"\u003e\n    \u003cimg src=\"@product.ImageUrl\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 4: Multiple Destinations\n\n```razor\n\u003c!-- Wishlist --\u003e\n\u003cdiv id=\"wishlist\"\u003e❤️\u003c/div\u003e\n\n\u003c!-- Cart --\u003e\n\u003cdiv id=\"cart\"\u003e🛒\u003c/div\u003e\n\n\u003c!-- Product with conditional destination --\u003e\n\u003cAddToCart Destination=\"@(isWishlist ? \"#wishlist\" : \"#cart\")\" \n           OnAnimationComplete=\"HandleAction\"\u003e\n    \u003cimg src=\"product.jpg\" /\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private bool isWishlist = false;\n\n    private void HandleAction()\n    {\n        if (isWishlist)\n            AddToWishlist();\n        else\n            AddToCart();\n    }\n}\n```\n\n### Example 5: Async Operations\n\n```razor\n\u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"HandleAddToCartAsync\"\u003e\n    \u003cbutton class=\"btn-primary\"\u003eAdd to Cart\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private async Task HandleAddToCartAsync()\n    {\n        try\n        {\n            await cartService.AddItemAsync(productId);\n            cartCount = await cartService.GetItemCountAsync();\n            StateHasChanged();\n            \n            // Show success notification\n            toastService.ShowSuccess(\"Item added to cart!\");\n        }\n        catch (Exception ex)\n        {\n            toastService.ShowError(\"Failed to add item to cart.\");\n        }\n    }\n}\n```\n\n### Example 6: Image-Only Animation\n\n```razor\n\u003c!-- Simple image animation --\u003e\n\u003cAddToCart Destination=\"#cart\"\u003e\n    \u003cimg src=\"product.jpg\" alt=\"Product\" class=\"product-thumbnail\" /\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 7: Complex Nested Content\n\n```razor\n\u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"UpdateCart\"\u003e\n    \u003cdiv class=\"product-card\"\u003e\n        \u003cdiv class=\"product-badge\"\u003eNew\u003c/div\u003e\n        \u003cimg src=\"product.jpg\" alt=\"Product\" /\u003e\n        \u003cdiv class=\"product-overlay\"\u003e\n            \u003ch3\u003eProduct Name\u003c/h3\u003e\n            \u003cp\u003e$99.99\u003c/p\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 8: Conditional Rendering\n\n```razor\n@if (product.InStock)\n{\n    \u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"AddToCart\"\u003e\n        \u003cbutton class=\"btn-add-to-cart\"\u003eAdd to Cart\u003c/button\u003e\n    \u003c/AddToCart\u003e\n}\nelse\n{\n    \u003cbutton class=\"btn-disabled\" disabled\u003eOut of Stock\u003c/button\u003e\n}\n```\n\n### Example 9: Using with Forms\n\n```razor\n\u003cEditForm Model=\"@product\" OnValidSubmit=\"HandleSubmit\"\u003e\n    \u003cDataAnnotationsValidator /\u003e\n    \n    \u003cInputNumber @bind-Value=\"product.Quantity\" /\u003e\n    \n    \u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"SubmitForm\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn-primary\"\u003eAdd to Cart\u003c/button\u003e\n    \u003c/AddToCart\u003e\n\u003c/EditForm\u003e\n\n@code {\n    private Product product = new();\n    \n    private void SubmitForm()\n    {\n        // Form validation happens before animation\n        // This callback fires after animation completes\n    }\n}\n```\n\n### Example 10: Creative Non-Ecommerce Uses\n\n```razor\n\u003c!-- Star Collector Game --\u003e\n\u003cAddToCart Destination=\"#star-collection\" OnAnimationComplete=\"CollectStar\"\u003e\n    \u003cdiv class=\"star\"\u003e⭐\u003c/div\u003e\n\u003c/AddToCart\u003e\n\n\u003c!-- Message Sender --\u003e\n\u003cAddToCart Destination=\"#inbox\" OnAnimationComplete=\"SendMessage\"\u003e\n    \u003cdiv class=\"message-bubble\"\u003eHello!\u003c/div\u003e\n\u003c/AddToCart\u003e\n\n\u003c!-- Energy Transfer --\u003e\n\u003cAddToCart Destination=\"#battery\" OnAnimationComplete=\"TransferEnergy\"\u003e\n    \u003cdiv class=\"energy-source\"\u003e⚡\u003c/div\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 11: Multiple Items with Count\n\n```razor\n\u003cAddToCart Destination=\"#cart\" Count=\"10\" OnAnimationComplete=\"HandleBulkAdd\"\u003e\n    \u003cbutton class=\"btn-primary\"\u003eAdd 10 Items\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private void HandleBulkAdd()\n    {\n        // Fires once after all 10 animations complete\n        cartCount += 10;\n        StateHasChanged();\n    }\n}\n```\n\n### Example 12: Custom Trigger Element\n\n```razor\n\u003cAddToCart Destination=\"#cart\" Trigger=\".add-to-cart-btn\"\u003e\n    \u003cdiv class=\"product-card\"\u003e\n        \u003cimg src=\"product.jpg\" /\u003e\n        \u003ch3\u003eProduct Name\u003c/h3\u003e\n        \u003cp\u003e$99.99\u003c/p\u003e\n        \u003c!-- Only this button triggers the animation --\u003e\n        \u003cbutton class=\"add-to-cart-btn\"\u003eAdd to Cart\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/AddToCart\u003e\n```\n\n### Example 13: Progress Tracking\n\n```razor\n\u003cAddToCart Destination=\"#cart\" \n           Count=\"5\"\n           OnAnimationProgress=\"UpdateProgress\"\n           OnAnimationComplete=\"HandleComplete\"\u003e\n    \u003cbutton\u003eAdd 5 Items\u003c/button\u003e\n\u003c/AddToCart\u003e\n\n\u003cdiv class=\"progress-bar\"\u003e\n    \u003cdiv class=\"progress-fill\" style=\"width: @($\"{progress * 100}%\")\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n\n@code {\n    private double progress = 0.0;\n\n    private void UpdateProgress(double progressValue)\n    {\n        progress = progressValue; // 0.0 to 1.0\n        StateHasChanged();\n    }\n\n    private void HandleComplete()\n    {\n        progress = 0.0;\n        StateHasChanged();\n    }\n}\n```\n\n### Example 14: Combining All Features\n\n```razor\n\u003cAddToCart Destination=\"#cart\" \n           Count=\"@quantity\"\n           Trigger=\".add-to-cart-btn\"\n           Speed=\"0.8\"\n           OnAnimationProgress=\"HandleProgress\"\n           OnAnimationComplete=\"HandleComplete\"\u003e\n    \u003cdiv class=\"product-card\"\u003e\n        \u003cimg src=\"@product.ImageUrl\" /\u003e\n        \u003ch3\u003e@product.Name\u003c/h3\u003e\n        \u003cp\u003e$@product.Price\u003c/p\u003e\n        \u003cbutton class=\"add-to-cart-btn\"\u003eAdd @quantity to Cart\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/AddToCart\u003e\n\n@code {\n    private int quantity = 5;\n    private double progress = 0.0;\n\n    private void HandleProgress(double p) =\u003e progress = p;\n    \n    private async Task HandleComplete()\n    {\n        await cartService.AddItemsAsync(productId, quantity);\n        progress = 0.0;\n        StateHasChanged();\n    }\n}\n```\n\n## 🎯 Advanced Usage\n\n### Handling Multiple Rapid Clicks\n\nThe component supports concurrent animations, so users can rapidly click multiple items without issues:\n\n```razor\n\u003c!-- All items can animate simultaneously --\u003e\n@foreach (var product in products)\n{\n    \u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"() =\u003e AddToCart(product.Id)\"\u003e\n        \u003cimg src=\"@product.ImageUrl\" /\u003e\n    \u003c/AddToCart\u003e\n}\n```\n\n### Performance Optimization\n\nFor large product lists, consider using virtualization:\n\n```razor\n\u003cVirtualize Items=\"@products\" Context=\"product\"\u003e\n    \u003cAddToCart Destination=\"#cart\" OnAnimationComplete=\"() =\u003e AddToCart(product.Id)\"\u003e\n        \u003cdiv class=\"product-card\"\u003e\n            \u003cimg src=\"@product.ImageUrl\" /\u003e\n        \u003c/div\u003e\n    \u003c/AddToCart\u003e\n\u003c/Virtualize\u003e\n```\n\n### CSS Styling\n\nThe component uses `display: contents` by default, so it doesn't add extra DOM elements. Style your content directly:\n\n```css\n/* Style the content inside AddToCart */\n.product-card {\n    border: 1px solid #ddd;\n    border-radius: 8px;\n    padding: 1rem;\n    transition: transform 0.2s;\n}\n\n.product-card:hover {\n    transform: scale(1.05);\n}\n\n.product-card img {\n    width: 100%;\n    height: auto;\n    border-radius: 4px;\n}\n```\n\n## ♿ Accessibility\n\nThe component automatically respects user preferences:\n\n- **Reduced Motion**: If `prefers-reduced-motion: reduce` is detected, animations are skipped and a visual feedback (ping effect) is shown instead\n- **High Contrast**: Supports high contrast mode with appropriate outlines\n- **Dark Mode**: Optimized for dark color schemes\n- **Print Styles**: Animations are hidden when printing\n\nNo additional configuration needed - these features work automatically!\n\n## 🔧 Browser Compatibility\n\n- Chrome/Edge (latest)\n- Firefox (latest)\n- Safari (latest)\n- All modern browsers with CSS transform and requestAnimationFrame support\n\n## ⚡ Performance Considerations\n\n- **Low Allocation**: Easing control points are passed to JS (avoids per-click easing-string formatting in .NET and regex parsing in JS). `CubicBezier.ToCssString()` is intended for display/debugging and allocates the returned string.\n- **Concurrent Animations**: Multiple animations can run simultaneously without performance degradation\n- **GPU Acceleration**: Uses CSS transforms for hardware-accelerated animations\n- **AOT Compatible**: Fully compatible with .NET AOT compilation\n- **Trimming-Friendly**: No reflection or dynamic code generation\n\n## 🧪 Testing\n\nThe solution includes bUnit tests covering:\n\n- Component rendering\n- Event callbacks\n- JS interop initialization / invocations\n\nRun tests locally:\n\n```bash\ndotnet test\n```\n\n## 📝 Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md).\n\n## 📖 API Reference\n\n### `AddToCart` Component\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `Destination` | `string` | Yes | - | CSS selector for animation destination |\n| `Speed` | `double` | No | `0.6` | Animation duration in seconds |\n| `EasingX` | `CubicBezier` | No | `CubicBezier.CartX` | Horizontal movement easing |\n| `EasingY` | `CubicBezier` | No | `CubicBezier.CartY` | Vertical movement easing |\n| `EasingScale` | `CubicBezier` | No | `CubicBezier.CartScale` | Scale transformation easing |\n| `OnBeforeAnimation` | `EventCallback` | No | `null` | Callback before animation starts (fires once per click) |\n| `OnAnimationComplete` | `EventCallback` | No | `null` | Callback when animation completes (fires once for multiple animations) |\n| `Count` | `int` | No | `1` | Number of items to animate with staggered timing |\n| `Trigger` | `string?` | No | `null` | CSS selector for specific trigger element |\n| `OnAnimationProgress` | `EventCallback\u003cdouble\u003e` | No | `null` | Callback for progress updates (0.0 to 1.0) |\n| `ChildContent` | `RenderFragment` | No | `null` | Content to animate |\n\n### `CubicBezier` Struct\n\nRepresents a cubic bezier easing function with compile-time constants.\n\n**Constructor:**\n```csharp\npublic CubicBezier(float x1, float y1, float x2, float y2)\n```\n\n**Methods:**\n```csharp\nstring ToCssString() // Converts to CSS cubic-bezier() string\n```\n\n**Static Properties:** See [Easing Functions](#-easing-functions) section above.\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## 📄 License\n\nMIT License - see LICENSE file for details.\n\n## 🙏 Acknowledgments\n\nInspired by modern e-commerce animations and optimized for Blazor applications.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzettersten%2Fblazorfastaddtocart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzettersten%2Fblazorfastaddtocart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzettersten%2Fblazorfastaddtocart/lists"}