### GlobalFormaProvider Setup for Ehfuse Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Illustrates the necessary setup for using Ehfuse Forma hooks, specifically `useModal`. The application must be wrapped with `GlobalFormaProvider` at the top level to ensure context is available. ```typescript import { GlobalFormaProvider } from "@ehfuse/forma"; function App() { return ( ); } ``` -------------------------------- ### Forma: Performance Tip - Memoization Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Provides a performance optimization strategy for Forma forms using `useMemo`. This example demonstrates how to memoize expensive calculations that depend on form values, ensuring they are only recomputed when necessary. ```tsx import { useMemo } from "react"; // Assuming calculateExpensiveValue is a defined function const expensiveValue = useMemo(() => { return calculateExpensiveValue(form.useFormValue("data")); }, [form.useFormValue("data")]); ``` -------------------------------- ### Install Forma NPM Package Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Installs the Forma NPM package using either npm or yarn. This is the first step for integrating Forma into your project. ```bash npm install @ehfuse/forma # or yarn add @ehfuse/forma ``` -------------------------------- ### Install Forma Package Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Provides the npm command to install the Forma package, a necessary first step for migration. ```bash npm install @ehfuse/forma ``` -------------------------------- ### Shopping Cart Example with Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Illustrates a practical application of Forma for managing a shopping cart's state. It demonstrates how to add items, update the total, and efficiently subscribe to changes in the cart's item count. ```typescript // Basic shopping cart component function ShoppingCart() { const cart = useGlobalFormaState({ stateId: "shopping-cart", initialValues: { items: [], total: 0, }, }); // ✅ Recommended: .length subscription (re-renders only when array length changes) const itemCount = cart.useValue("items.length"); const total = cart.useValue("total"); return (

Shopping Cart ({itemCount})

Total: ${total}

); } // Product addition component function ProductList() { const cart = useGlobalFormaState({ stateId: "shopping-cart", }); const addToCart = (product) => { const currentItems = cart.getValues().items || []; cart.setValue("items", [...currentItems, product]); // Update total const newTotal = currentItems.reduce((sum, item) => sum + item.price, 0) + product.price; cart.setValue("total", newTotal); }; return ( ); } ``` -------------------------------- ### Reusability Example (TypeScript/JSX) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Illustrates how actions defined in the 'Actions' structure can be called from multiple UI elements, such as buttons and input fields, promoting code reuse and a consistent user experience. ```typescript // Same action can be called from multiple places e.key === "Enter" && state.actions.addTodo()} /> ``` -------------------------------- ### Testability of Actions Independently (Test) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Demonstrates the testability of individual actions using a testing framework. This example shows how to create a mock context and assert the outcome of an action, such as adding a todo item. ```Test // Actions independently testable test("addTodo should add new todo", () => { const context = createMockContext(); actions.addTodo(context); expect(context.values.todos.length).toBe(1); }); ``` -------------------------------- ### Complete Global Form with Validation and Submission - TypeScript Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates a complete global form setup using useGlobalForm in TypeScript. It includes initial values, validation logic, submission handlers, and completion callbacks. This example shows how to define and use the form within a single component. ```typescript function GlobalFormExample() { const form = useGlobalForm({ formId: "user-form", initialValues: { name: "", email: "", age: 0 }, onValidate: async (values) => { // Name validation if (!values.name.trim()) { alert("Please enter your name."); return false; } // Email validation if (!values.email.includes("@")) { alert("Please enter a valid email."); return false; } return true; }, onSubmit: async (values) => { console.log("Global form submission:", values); await api.submitUser(values); }, onComplete: (values) => { alert("Submission completed!"); }, }); return (
); } ``` -------------------------------- ### Multi-Step Form: Quick Submit Button Example Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates how a separate component can trigger the form submission process for a globally managed form. It accesses the form state using the `formId` and calls the `submit` method, leveraging handlers registered in other components. ```typescript // 💡 Pro tip: Can submit from other components too! function QuickSubmitButton() { const form = useGlobalForm({ formId: "user-registration", // Same ID // No handlers - automatically uses handlers registered in FinalStep }); return ( ); } ``` -------------------------------- ### Testability Example (TypeScript) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Highlights the testability advantage of the 'Actions' structure. Actions can be tested independently of the UI components, making unit testing more straightforward and robust. ```typescript // Actions can be tested independently test("addTodo should add new todo", () => { const context = createMockContext(); actions.addTodo(context); expect(context.values.todos.length).toBe(1); }); ``` -------------------------------- ### Logic Encapsulation Example (TypeScript/JSX) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Demonstrates the difference in structure for adding a todo item between a basic scattered approach and the organized 'Actions' structure. The 'Actions' approach centralizes logic within the state management system. ```typescript // ❌ Basic structure: logic scattered in component const addTodo = () => { if (!newTodoText.trim()) return; const todos = state.getValues().todos; state.setValue("todos", [ ...todos, { id: Date.now(), text: newTodoText, completed: false }, ]); state.setValue("newTodoText", ""); }; // ✅ Actions structure: logic organized in one place state.actions.addTodo(); ``` -------------------------------- ### useFormaState Basic Usage Example in TypeScript Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates the basic usage of the useFormaState hook for managing form state, including individual field subscriptions, checking field existence, getting field values, subscribing to global state changes, and performing actions like removing fields and resetting state. It utilizes React's useEffect for global subscriptions. ```typescript import { useFormaState } from "forma"; import React from "react"; // Basic usage function MyComponent() { const state = useFormaState({ user: { name: "", email: "" }, settings: { theme: "light", notifications: true }, }); // Individual field subscription (re-renders only when that field changes) const userName = state.useValue("user.name"); const theme = state.useValue("settings.theme"); // Using new API methods const hasUserEmail = state.hasField("user.email"); const userEmailValue = state.getValue("user.email"); // Non-reactive // Subscribe to global state changes React.useEffect(() => { const unsubscribe = state.subscribe((values) => { console.log("Global state changed:", values); }); return unsubscribe; }, [state]); return (
state.setValue("user.name", e.target.value)} /> {hasUserEmail &&

Email field exists

}
); } ``` -------------------------------- ### Dynamic State Management with Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Shows how to dynamically switch between different global states using Forma by updating the stateId. This is useful for managing distinct sets of data or configurations, such as user sessions. ```typescript function DynamicStateManager() { const [stateId, setStateId] = useState("session-1"); const state = useGlobalFormaState({ stateId, initialValues: { data: {}, metadata: { created: Date.now() } }, }); const switchSession = (newId: string) => { setStateId(newId); // Switch to different global state }; return (
Current session: {stateId}
{/* Displays state of currently selected session */}
); } ``` -------------------------------- ### Basic Global State Usage with Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates how to set up and use global state across multiple components using Forma's GlobalFormaProvider and useGlobalFormaState hooks. It shows how components can share and update the same state based on a stateId. ```typescript import { useGlobalFormaState, GlobalFormaProvider } from "@ehfuse/forma"; // App.tsx function App() { return ( ); } // User profile component function UserProfile() { const state = useGlobalFormaState({ stateId: "user-data", initialValues: { user: { name: "", email: "" }, preferences: { theme: "light", language: "en" }, }, }); const userName = state.useValue("user.name"); const userEmail = state.useValue("user.email"); return (
state.setValue("user.name", e.target.value)} placeholder="Name" /> state.setValue("user.email", e.target.value)} placeholder="Email" />
); } // User settings component (shares same state) function UserSettings() { const state = useGlobalFormaState({ stateId: "user-data", // Share state with same ID // initialValues omitted - already created in UserProfile (ignored even if provided) }); const theme = state.useValue("preferences.theme"); const language = state.useValue("preferences.language"); const userName = state.useValue("user.name"); // Value entered from other component return (

User: {userName}

); } ``` -------------------------------- ### useFormaState Array State Management Example in TypeScript Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Illustrates how to manage array state using the useFormaState hook. This example demonstrates subscribing to specific array elements, the array's length for add/remove operations, and updating individual items within the array. It highlights how changes to array content versus array structure trigger different subscription updates. ```typescript // Array state management function TodoList() { const state = useFormaState({ todos: [ { id: 1, text: "Learn React", completed: false }, { id: 2, text: "Build app", completed: false }, ], }); // Subscribe to specific todo item const firstTodo = state.useValue("todos.0.text"); // Subscribe only to array length (re-renders only when items are added/removed) const todoCount = state.useValue("todos.length"); const addTodo = () => { const todos = state.getValues().todos; state.setValue("todos", [ ...todos, { id: Date.now(), text: "New todo", completed: false }, ]); // When todos array changes, todos.length subscribers are automatically notified }; const updateTodo = (index: number, newText: string) => { // Only array content changes (length stays same) - todos.length subscribers are not notified state.setValue(`todos.${index}.text`, newText); }; const removeTodo = (index: number) => { state.removeField(`todos.${index}`); }; return (

First todo: {firstTodo}

Total todos: {todoCount}

); } ``` -------------------------------- ### Basic Form Setup: Redux Forms vs. Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Compares the basic setup for creating a contact form using Redux Forms and Forma. Redux Forms requires explicit Field components, while Forma utilizes a `useForm` hook for a more streamlined approach. ```typescript import { Field, reduxForm } from "redux-form"; let ContactForm = (props) => { const { handleSubmit } = props; return (
); }; ContactForm = reduxForm({ form: "contact", })(ContactForm); ``` ```typescript import { useForm } from "@ehfuse/forma"; function ContactForm() { const form = useForm({ initialValues: { name: "", email: "" }, onSubmit: (values) => { console.log(values); }, }); return (
); } ``` -------------------------------- ### TanStack Form Initialization Source: https://github.com/ehfuse/forma/blob/main/docs/en/library-comparison.md An example of initializing a form using TanStack Form, a modern form library. It shows the basic setup with default values. ```typescript // TanStack Form const form = useForm({ defaultValues: { name: "" }, }); ``` -------------------------------- ### Efficient Array Length Subscription in TSX Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Demonstrates smart subscription to array length for performance optimization. The 'Smart subscription' example efficiently updates a counter only when items are added or removed. The 'Inefficient' example shows how subscribing to the entire array and then accessing its length can lead to unnecessary re-renders on every todo change. ```tsx // ✅ Smart subscription: update counter only on add/remove const todoCount = state.useValue("todos.length"); // ❌ Inefficient: re-render on every todo change const todoCount = state.useValue("todos").length; ``` -------------------------------- ### Computed Values Example (TypeScript/JSX) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Shows how computed values like filtered todos and counts can be managed as getters within the 'Actions' structure, simplifying data retrieval and ensuring consistency across the application. ```typescript // Manage filtering, counting, etc. logic as getters const filteredTodos = state.actions.getFilteredTodos(); const completedCount = state.actions.getCompletedCount(); const remainingCount = state.actions.getRemainingCount(); ``` -------------------------------- ### Basic Form Management with useForm (TypeScript) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates basic form management using the `useForm` hook. It initializes form values, defines an onSubmit handler, and includes an onValidate function. Individual field values can be subscribed to for performance optimization. ```typescript const form = useForm({ initialValues: { name: "", email: "", age: 0, }, onSubmit: async (values) => { await api.submitUser(values); }, onValidate: async (values) => { return values.email.includes("@"); }, }); // Individual field subscription (performance optimization) const name = form.useFormValue("name"); const email = form.useFormValue("email"); ``` -------------------------------- ### Real-world Example: Bulk Checkbox Selection with setBatch Source: https://github.com/ehfuse/forma/blob/main/docs/en/performance-guide.md Demonstrates a practical use case for setBatch by updating the 'checked' status of 100 checkboxes simultaneously. This highlights the efficiency of batching updates for numerous similar fields. ```tsx function selectAllCheckboxes() { const updates: Record = {}; // Select 100 checkboxes at once Array.from({ length: 100 }, (_, i) => { updates[`items.${i}.checked`] = true; }); state.setBatch(updates); // → Individual setValue: immediate listener execution for each field // → setBatch: collects all changes and executes listeners once at the end } ``` -------------------------------- ### Forma Error Handling Example Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Shows how error feedback is handled in Forma via the `onValidate` callback, compared to directly accessing error objects in older libraries. ```typescript // Old way: { errors.name && Name is required; } ``` ```typescript // New way: // Validation feedback through onValidate callback const form = useForm({ onValidate: (values) => { if (!values.name) { alert("Name is required"); // or set error state return false; } return true; }, }); ``` -------------------------------- ### Dependency Injection via Currying for Actions (JS) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md An advanced pattern demonstrating how currying can be used to inject external dependencies like API functions, configuration, or mock data into Actions, enhancing flexibility and testability. ```JS // Example: Auth Actions with API Dependencies (Conceptual) const createAuthActions = (apiClient) => ({ login: async (username, password) => { const user = await apiClient.post('/login', { username, password }); // ... other logic return user; }, // ... other auth actions }); // Usage with injected API client const authActions = createAuthActions(myApiClient); // Usage in tests with mock API client const mockApiClient = { post: jest.fn() }; const testAuthActions = createAuthActions(mockApiClient); ``` -------------------------------- ### Nested Object Handling with useForm (TypeScript) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Illustrates how to manage nested objects within a form using the `useForm` hook. It shows how to initialize deeply nested values and access them using dot notation for field subscriptions. ```typescript const form = useForm({ initialValues: { user: { profile: { name: "", settings: { theme: "light", }, }, }, }, }); // Access nested objects with dot notation const name = form.useFormValue("user.profile.name"); const theme = form.useFormValue("user.profile.settings.theme"); ``` -------------------------------- ### Reusability of Actions in Multiple UI Elements (TSX) Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Illustrates how a single action, like `addTodo`, can be invoked from various UI components, such as buttons and input fields, showcasing the reusability benefit of the Actions pattern. ```tsx // Same action callable from multiple places e.key === "Enter" && state.actions.addTodo()} /> ``` -------------------------------- ### Responsive Navigation with useBreakpoint Hook Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Shows how to use the `useBreakpoint` hook from `@ehfuse/forma` to conditionally render different navigation elements based on screen size. It displays a horizontal navigation for larger screens (smUp) and a hamburger menu for smaller screens. ```typescript import { useBreakpoint } from "@ehfuse/forma"; function ResponsiveNavigation() { const { smUp } = useBreakpoint(); return (
{smUp ? ( // Desktop: Horizontal navigation ) : ( // Mobile: Hamburger menu )}
); } ``` -------------------------------- ### Dynamic Import of Minified Forma Bundle Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Demonstrates dynamically importing the minified Forma bundle using `await import()`. This technique is ideal for code splitting, allowing the Forma library to be loaded on demand, improving initial page load performance. ```tsx // Lazy load minified bundle const { useForm } = await import("@ehfuse/forma/min"); ``` -------------------------------- ### Dynamic Component Sizing (ImageGallery Example) Source: https://github.com/ehfuse/forma/blob/main/docs/en/API.md Demonstrates how to dynamically size components based on screen breakpoints using the useBreakpoint hook. This approach allows for responsive UIs but should be used judiciously due to potential re-renders on window resize. ```APIDOC ## Dynamic Component Sizing ### Description Dynamically sizes components based on screen breakpoints. Re-renders occur on window resize. Use only when necessary for performance, preferring CSS media queries when possible. Initial value is 0px during server-side rendering. ### Usage Example ```typescript function ImageGallery() { const { xs, sm, md, lg } = useBreakpoint(); const columns = xs ? 1 : sm ? 2 : md ? 3 : lg ? 4 : 5; return ( {images.map((img) => ( {img.title} ))} ); } ``` ### Important Notes * Re-renders occur on window resize. * Use only when necessary for performance (prefer CSS media queries when possible). * Initial value is 0px during server-side rendering. ### Related Links * [Detailed Breakpoint Examples →](./examples.md#usebreakpoint-examples) ``` -------------------------------- ### Product Page Layouts with useBreakpoint Hook Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates adapting a product page layout based on screen size using the `useBreakpoint` hook. It defines different rendering logic for extra-small (xs), small (sm), and medium-up (mdUp) breakpoints, allowing for mobile, tablet, and desktop views with varying component arrangements. ```typescript import { useBreakpoint } from "@ehfuse/forma"; function ProductPage() { const { xs, sm, mdUp } = useBreakpoint(); // Use different layouts based on screen size if (xs) { return (
); } if (sm) { return (
); } // Desktop (md and up) return (
); } ``` -------------------------------- ### Testing Forma Actions with Mocked Dependencies Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/todoapp-example.md Demonstrates how to leverage the currying pattern for effective unit testing of Forma actions. By injecting mock API functions, developers can isolate the logic within the actions and assert their behavior without making actual API calls. ```tsx // Easily inject mock API in tests const mockApi = { login: jest.fn().mockResolvedValue({ success: true }), logout: jest.fn().mockResolvedValue(undefined), }; const form = useForm({ initialValues: testData, actions: { login: AuthActions.login(mockApi.login, mockSetDialog), logout: AuthActions.logout(mockApi.logout), }, }); // Execute Actions and verify mock was called await form.actions.login(); expect(mockApi.login).toHaveBeenCalledWith("user", "pass"); ``` -------------------------------- ### Form Wizard using Ehfust Forma with Multiple Steps Source: https://github.com/ehfuse/forma/blob/main/docs/en/useGlobalForm-guide.md This example demonstrates a multi-step form wizard for user registration using Ehfust Forma. It shows how to manage form state across different components (`Step1`, `Step2`, `ReviewStep`) using a shared `formId` and handles navigation and submission. ```typescript // Example of how the steps might be orchestrated function RegistrationWizard() { const [step, setStep] = useState(0); const handleNext = () => setStep(step + 1); const handlePrev = () => setStep(step - 1); const renderStep = () => { switch (step) { case 0: return ; case 1: return ; case 2: return ; default: return ; } }; return (

User Registration

{renderStep()}
); } ``` -------------------------------- ### Migration from Formik to Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/library-comparison.md Illustrates migrating from Formik to Forma. The example demonstrates how to initialize form values and handle input changes using Forma's `useForm` and `handleFormChange`, compared to Formik's `values` and `setFieldValue`. ```typescript // Before (Formik) {({ values, setFieldValue }) => ( setFieldValue("name", e.target.value)} /> )} ; // After (Forma) const form = useForm({ initialValues: { name: "" } }); const name = form.useFormValue("name"); return ; ``` -------------------------------- ### FormaJS 'watch' Usage Example with Async Operations (TypeScript) Source: https://github.com/ehfuse/forma/blob/main/docs/API-en.md This example showcases an asynchronous usage of the FormaJS `watch` feature, specifically synchronizing user data based on a 'logined' state. It demonstrates how to use `async/await` within a watch handler to perform operations like starting and stopping data synchronization intervals. The example also shows how to manage interval IDs within the state using `setValue` and `getValue` from the `ActionContext`. ```typescript // Automatically sync data based on login state const appState = useGlobalFormaState({ stateId: "app", initialValues: { logined: false, syncInterval: null }, watch: { logined: async (context, value) => { if (value) { // Start data synchronization on login const intervalId = setInterval(async () => { await syncUserData(); }, 5000); context.setValue("syncInterval", intervalId); } else { // Stop synchronization on logout const intervalId = context.getValue("syncInterval"); if (intervalId) { clearInterval(intervalId); context.setValue("syncInterval", null); } } }, }, }); ``` -------------------------------- ### Global State Management with Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Illustrates Forma's built-in global state management capabilities, contrasting it with the need for external state management solutions in previous setups. ```typescript // Need external state management for form sharing const [formData, setFormData] = useState({}); ``` ```typescript // Built-in global form state const form = useGlobalForm({ formId: "shared-form" }); ``` -------------------------------- ### Declare useFormaState with Basic Usage Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Shows basic usage of the `useFormaState` hook by providing initial values for nested objects. This is a straightforward way to initialize state with predefined structures. ```tsx import { useFormaState } from "@/forma"; // 2. Basic usage - with initial values const state = useFormaState({ user: { name: "", email: "" }, settings: { theme: "light" }, }); ``` -------------------------------- ### Declare useFormaState with Options Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Demonstrates using `useFormaState` with an options object, including an `onChange` callback to log state changes and `deepEquals` set to `true` for deep comparison of state updates. This allows for more control over state update behavior and event handling. ```tsx import { useFormaState } from "@/forma"; // 4. Use with options const stateWithOptions = useFormaState( { data: {}, }, { onChange: (values) => console.log("State changed:", values), deepEquals: true, // Enable deep equality check } ); ``` -------------------------------- ### Form Hooks: useForm, useGlobalForm, and useFormaState in React Source: https://github.com/ehfuse/forma/blob/main/docs/en/performance-guide.md Demonstrates the distinct use cases for useForm (single component), useGlobalForm (multi-component/page forms), and useFormaState (general state management). Includes examples of basic state access and optimization for complex data structures with useFormaState. ```tsx import { useForm, useGlobalForm, useFormaState } from '@forma/react'; // ✅ Single component form → useForm function ContactForm() { const form = useForm({ initialValues: { name: "", email: "" }, }); } // ✅ Multi-component/page form → useGlobalForm function MultiStepForm() { const form = useGlobalForm({ formId: "user-registration", }); } // ✅ General state management (not form) → useFormaState function UserDashboard() { const state = useFormaState({ user: { name: "John Doe", status: "online" }, theme: "dark", }); const userName = state.useValue("user.name"); const theme = state.useValue("theme"); return (
Hello, {userName}! Theme: {theme}
); } // ✅ Complex array/object state → useFormaState (individual subscriptions) function TodoManager() { const state = useFormaState({ todos: [ { id: 1, text: "Learn React", completed: false }, { id: 2, text: "Try Forma", completed: true }, ], filter: "all", }); // ❌ Whole array subscription - re-renders on all todo changes // const todos = state.useValue("todos"); // ✅ Individual todo item subscription (performance optimization) const firstTodo = state.useValue("todos.0.text"); const secondCompleted = state.useValue("todos.1.completed"); return (
First: {firstTodo}
); } ``` -------------------------------- ### Declare useFormaState with Dynamic Object Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Illustrates initializing `useFormaState` with an empty object and specifying a generic type `Record`. This allows for dynamic addition of properties to the state object after its initial declaration. ```tsx import { useFormaState } from "@/forma"; // 3. Start with an empty object (dynamic field addition) const dynamicState = useFormaState>(); ``` -------------------------------- ### Import Forma Core Hooks (Standard) Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Imports the main hooks provided by the Forma library for form management and state. These are essential for building forms and managing their state within React applications. ```tsx import { useForm, useFormaState, GlobalFormProvider, useGlobalForm, } from "@ehfuse/forma"; ``` -------------------------------- ### Automatic Memory Cleanup with Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Explains how Forma automatically cleans up global state when it's no longer referenced by any components. The `autoCleanup: true` option ensures that memory is managed efficiently, preventing leaks. ```typescript // Component A mounts → reference count: 1 function ComponentA() { const state = useGlobalFormaState({ stateId: "shared", autoCleanup: true, }); return
{state.useValue("data")}
; } // Component B mounts → reference count: 2 function ComponentB() { const state = useGlobalFormaState({ stateId: "shared", // Same ID autoCleanup: true, }); return
{state.useValue("data")}
; } // Component A unmounts → reference count: 1 (state preserved) // Component B unmounts → reference count: 0 → 🗑️ Automatic cleanup! ``` -------------------------------- ### Global Form Registration and Access with useRegisterGlobalForm Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Demonstrates how to register a local form instance as a global form using `useRegisterGlobalForm` and access it from other components using `useGlobalForm`. This facilitates state management and data sharing between different parts of the application, enabling components to interact with a shared form state. ```typescript import { useForm, useRegisterGlobalForm } from "@ehfuse/forma"; function MyComponent() { // Create local form const form = useForm<{ name: string; email: string }>({ initialValues: { name: "", email: "" }, onSubmit: async (values) => console.log(values), }); // Register as global form useRegisterGlobalForm("shared-form", form); return ( ); } // Access from another component function AnotherComponent() { const form = useGlobalForm<{ name: string; email: string }>({ formId: "shared-form", }); return

Name: {form.useFormValue("name")}

; } ``` -------------------------------- ### Automatic Memory Cleanup: Enabled by Default Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Illustrates the `autoCleanup` option in `useGlobalForm`. When `autoCleanup` is true (the default), the form state is automatically managed and cleaned up, which is suitable for transient forms like multi-step wizards. ```typescript // Automatic cleanup in multi-step forms function Step1() { const form = useGlobalForm({ formId: "wizard-form", autoCleanup: true, // Default - automatic cleanup }); return ; } function Step2() { const form = useGlobalForm({ formId: "wizard-form", // Share same form autoCleanup: true, }); return ; } ``` -------------------------------- ### Multi-Step User Registration Form Example Source: https://github.com/ehfuse/forma/blob/main/docs/en/useGlobalForm-guide.md A foundational component for a multi-step user registration wizard. This component (`PersonalInfoStep`) uses `useGlobalForm` to manage form state across different steps of the registration process. ```tsx // Step 1: Personal Information function PersonalInfoStep({ onNext }) { const form = useGlobalForm({ formId: "registration-wizard", initialValues: { personal: { firstName: "", lastName: "", email: "" }, address: { street: "", city: "", zipCode: "" }, preferences: { newsletter: false, theme: "light" } } }); const firstName = form.useFormValue("personal.firstName"); const lastName = form.useFormValue("personal.lastName"); const email = form.useFormValue("personal.email"); // ... rest of the component logic for input fields and navigation buttons ... } ``` -------------------------------- ### Forma Field Binding Example Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Demonstrates the difference in field binding syntax between older libraries like React Hook Form and Forma. Forma uses `name`, `value`, and `onChange` attributes directly. ```typescript // Old way (React Hook Form): ``` ```typescript // New way (Forma): ``` -------------------------------- ### TypeScript Migration: Formik to Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/API.md Provides a TypeScript example of migrating from Formik to Forma. It compares the initialization and value access methods, showing how to set initial values and retrieve form field values in both Formik and Forma. ```typescript // Formik const formik = useFormik({ initialValues: { name: "" } }); const name = formik.values.name; // Forma const form = useForm({ initialValues: { name: "" } }); const name = form.useFormValue("name"); ``` -------------------------------- ### Forma: Resetting and Updating Form Initial Values Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Shows how to reset form values using `setInitialFormValues`, update a single field with `setFormValue`, and update multiple fields simultaneously with `setValues` after a form has been initialized. ```tsx import { useGlobalForm } from "forma"; interface UserForm { name: string; email: string; } const form = useGlobalForm({ formId: "user-registration", initialValues: { name: "", email: "" }, }); // Reset form values later function resetFormValues() { form.setInitialFormValues({ name: "john", email: "john@example.com", }); } // Update a specific field function updateName() { form.setFormValue("name", "jane"); } // Update multiple fields at once function updateMultiple() { form.setValues({ name: "bob", email: "bob@example.com", }); } ``` -------------------------------- ### Basic Form Usage: React Hook Form vs Forma Source: https://github.com/ehfuse/forma/blob/main/docs/en/migration.md Compares the basic form setup between React Hook Form and Forma. Shows how to initialize forms, handle input changes, and submit data. Forma uses a single `useForm` hook with explicit `onSubmit` and `onValidate` callbacks, while React Hook Form uses `handleSubmit` and `register`. ```typescript import { useForm } from "react-hook-form"; function MyForm() { const { register, handleSubmit, watch, formState: { errors }, } = useForm({ defaultValues: { name: "", email: "" }, }); const name = watch("name"); const onSubmit = (data) => { console.log(data); }; return (
); } ``` ```typescript import { useForm } from "@ehfuse/forma"; function MyForm() { const form = useForm({ initialValues: { name: "", email: "" }, onSubmit: (values) => { console.log(values); }, onValidate: (values) => { return values.name && values.email; // Simple validation }, }); const name = form.useFormValue("name"); return (
); } ``` -------------------------------- ### Conditional Component Rendering with useBreakpoint Source: https://github.com/ehfuse/forma/blob/main/docs/en/examples/basic-example.md Conditionally renders components like video controls, playlists, and recommended videos based on screen size breakpoints (smUp, mdUp). This enables showing or hiding specific UI elements to optimize user experience on different devices. For example, basic controls might appear on small screens, while playlists and recommendations appear on larger ones. ```typescript import { useBreakpoint } from "@ehfuse/forma"; function VideoPlayer() { const { smUp, mdUp } = useBreakpoint(); return (
{/* Basic controls only on small screens */} {smUp && } {/* Playlist from medium size */} {mdUp && } {/* Recommended videos on large screens */} {mdUp && }
); } ``` -------------------------------- ### Forma MUI: Integrating DatePicker Component Source: https://github.com/ehfuse/forma/blob/main/docs/en/getting-started.md Demonstrates how to integrate Material-UI's `DatePicker` component with Forma. It shows setting initial values for a 'birthDate' field and handling date changes using `useFormValue` and `handleDatePickerChange`. ```tsx import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { useForm } from "forma"; interface BirthDateForm { birthDate: string; } function FormWithDate() { const form = useForm({ initialValues: { birthDate: "" }, }); const birthDate = form.useFormValue("birthDate"); return ( ); } ```