@ehfuse/forma 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +333 -185
  2. package/dist/core/FieldStore.d.ts +41 -0
  3. package/dist/core/FieldStore.d.ts.map +1 -1
  4. package/dist/core/FieldStore.js +121 -7
  5. package/dist/core/FieldStore.js.map +1 -1
  6. package/dist/esm/core/FieldStore.d.ts +41 -0
  7. package/dist/esm/core/FieldStore.d.ts.map +1 -1
  8. package/dist/esm/core/FieldStore.js +121 -7
  9. package/dist/esm/core/FieldStore.js.map +1 -1
  10. package/dist/esm/hooks/useForm.js +6 -3
  11. package/dist/esm/hooks/useForm.js.map +1 -1
  12. package/dist/esm/hooks/useFormaState.d.ts +3 -1
  13. package/dist/esm/hooks/useFormaState.d.ts.map +1 -1
  14. package/dist/esm/hooks/useFormaState.js +31 -3
  15. package/dist/esm/hooks/useFormaState.js.map +1 -1
  16. package/dist/esm/hooks/useGlobalForm.d.ts +8 -12
  17. package/dist/esm/hooks/useGlobalForm.d.ts.map +1 -1
  18. package/dist/esm/hooks/useGlobalForm.js +36 -2
  19. package/dist/esm/hooks/useGlobalForm.js.map +1 -1
  20. package/dist/esm/hooks/useGlobalFormaState.d.ts +8 -72
  21. package/dist/esm/hooks/useGlobalFormaState.d.ts.map +1 -1
  22. package/dist/esm/hooks/useGlobalFormaState.js +8 -2
  23. package/dist/esm/hooks/useGlobalFormaState.js.map +1 -1
  24. package/dist/esm/index.d.ts +1 -1
  25. package/dist/esm/index.d.ts.map +1 -1
  26. package/dist/esm/index.js +2 -44
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/types/form.d.ts +18 -0
  29. package/dist/esm/types/form.d.ts.map +1 -1
  30. package/dist/esm/types/globalForm.d.ts +23 -2
  31. package/dist/esm/types/globalForm.d.ts.map +1 -1
  32. package/dist/esm/types/globalForm.js.map +1 -1
  33. package/dist/hooks/useForm.js +6 -3
  34. package/dist/hooks/useForm.js.map +1 -1
  35. package/dist/hooks/useFormaState.d.ts +3 -1
  36. package/dist/hooks/useFormaState.d.ts.map +1 -1
  37. package/dist/hooks/useFormaState.js +31 -3
  38. package/dist/hooks/useFormaState.js.map +1 -1
  39. package/dist/hooks/useGlobalForm.d.ts +8 -12
  40. package/dist/hooks/useGlobalForm.d.ts.map +1 -1
  41. package/dist/hooks/useGlobalForm.js +36 -2
  42. package/dist/hooks/useGlobalForm.js.map +1 -1
  43. package/dist/hooks/useGlobalFormaState.d.ts +8 -72
  44. package/dist/hooks/useGlobalFormaState.d.ts.map +1 -1
  45. package/dist/hooks/useGlobalFormaState.js +8 -2
  46. package/dist/hooks/useGlobalFormaState.js.map +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +2 -67
  50. package/dist/index.js.map +1 -1
  51. package/dist/types/form.d.ts +18 -0
  52. package/dist/types/form.d.ts.map +1 -1
  53. package/dist/types/globalForm.d.ts +23 -2
  54. package/dist/types/globalForm.d.ts.map +1 -1
  55. package/dist/types/globalForm.js.map +1 -1
  56. package/package.json +4 -10
  57. package/dist/esm/index.min.js +0 -28
  58. package/dist/index.min.js +0 -28
package/README.md CHANGED
@@ -11,61 +11,192 @@ Forma is a high-performance library that makes form and state management in Reac
11
11
 
12
12
  Forma는 React 애플리케이션에서 폼과 상태를 **간편하면서도 강력하게** 관리할 수 있는 고성능 라이브러리입니다. **Zero-Config로 바로 시작**할 수 있으며, 개별 필드 구독을 통한 **선택적 리렌더링**으로 최적의 성능을 제공합니다. 복잡한 설정 없이도 **글로벌 폼 상태 공유**, **Dot Notation 중첩 객체 접근**, **MUI 완전 호환** 등 프로덕션 레벨의 고급 기능들을 손쉽게 사용할 수 있습니다.
13
13
 
14
- ## Key Features
15
-
16
- - 🎯 **Complete Zero-Config**: Start immediately without any configuration
17
- - ✅ **Individual Field Subscription**: Optimized performance through selective re-rendering per field
18
- - 🌟 **Global State Subscription**: Subscribe to entire state with `useValue("*")` pattern for optimal performance
19
- - ✅ **General State Management**: Efficient management of non-form states with `useFormaState`
20
- - 🎭 **Modal Stack Management**: Mobile-friendly modal handling with back button support via `useModal`
21
- - 📱 **Responsive Breakpoint Management**: Screen size detection and adaptive UI with `useBreakpoint`
22
- - ✅ **Dot Notation Optimization**: Access nested objects like `user.profile.name`
23
- - ✅ **Full MUI Compatibility**: Perfect integration with Material-UI components
24
- - ✅ **Global Form State**: Share form state across multiple components
25
- - ✅ **Form Registration System**: Register existing forms as global
26
- - ✅ **Full TypeScript Support**: Strong type safety
27
- - ✅ **React 19 Optimized**: Utilizing latest React features
28
-
29
- ## 주요 특징
30
-
31
- - 🎯 **완전한 Zero-Config**: 설정 없이 바로 사용 가능한 개발 경험
32
- - ✅ **개별 필드 구독**: 필드별 선택적 리렌더링으로 최적화된 성능
33
- - 🌟 **전체 상태 구독**: `useValue("*")` 패턴으로 전체 상태를 한 번에 구독하여 최적 성능 제공
34
- - ✅ **범용 상태 관리**: `useFormaState`로 외 일반 상태도 효율적 관리
35
- - 🎭 **모달 스택 관리**: `useModal`로 뒤로가기 지원하는 모바일 친화적 모달 처리
36
- - 📱 **반응형 브레이크포인트 관리**: `useBreakpoint`로 화면 크기 감지 및 적응형 UI 구현
37
- - ✅ **Dot Notation 최적화**: `user.profile.name` 형태의 중첩 객체 접근
38
- - ✅ **MUI 완전 호환**: Material-UI 컴포넌트와 완벽한 통합
39
- - ✅ **글로벌 폼 상태**: 여러 컴포넌트 간 폼 상태 공유
40
- - ✅ **폼 등록 시스템**: 기존 폼을 글로벌로 등록 가능
41
- - ✅ **TypeScript 완전 지원**: 강력한 타입 안전성
42
- - ✅ **React 19 최적화**: 최신 React 기능 활용
14
+ ## Why Forma? | 왜 Forma인가?
15
+
16
+ Forma는 단순한 폼 라이브러리가 아닙니다. **React 상태 관리의 패러다임을 바꾸는** 혁신적인 솔루션입니다.
17
+
18
+ ### 🚀 The Ultimate State Management Solution | 최강의 상태 관리 솔루션
19
+
20
+ #### 1. **Watch + Actions = No More useEffect & useState & Context**
21
+
22
+ **useEffect, useState, Context 지옥에서 탈출하세요**
23
+
24
+ ```tsx
25
+ // Traditional: useEffect + useState + Context + Props Drilling
26
+ const AuthContext = createContext(null);
27
+
28
+ function App() {
29
+ const [logined, setLogined] = useState(false);
30
+ const [syncInterval, setSyncInterval] = useState(null);
31
+
32
+ useEffect(() => {
33
+ if (logined) {
34
+ const interval = setInterval(() => syncData(), 5000);
35
+ setSyncInterval(interval);
36
+ } else {
37
+ if (syncInterval) clearInterval(syncInterval);
38
+ setSyncInterval(null);
39
+ }
40
+ }, [logined]);
41
+
42
+ // Props drilling or Context Provider needed
43
+ return (
44
+ <AuthContext.Provider value={{ logined, setLogined }}>
45
+ <Header />
46
+ <Main />
47
+ <Footer />
48
+ </AuthContext.Provider>
49
+ );
50
+ }
51
+
52
+ // ✅ Forma: Clean and declarative
53
+ const state = useGlobalFormaState({
54
+ stateId: "auth",
55
+ initialValues: {
56
+ logined: false,
57
+ user: { name: "", email: "" },
58
+ syncInterval: null,
59
+ },
60
+ actions: {
61
+ startSync: (ctx) => {
62
+ const interval = setInterval(() => syncData(), 5000);
63
+ ctx.setValue("syncInterval", interval);
64
+ },
65
+ stopSync: (ctx) => {
66
+ const interval = ctx.getValue("syncInterval");
67
+ if (interval) clearInterval(interval);
68
+ ctx.setValue("syncInterval", null);
69
+ },
70
+ },
71
+ watch: {
72
+ logined: (ctx, value) => {
73
+ value ? ctx.actions.startSync(ctx) : ctx.actions.stopSync(ctx);
74
+ },
75
+ "user.email": (ctx, value) => {
76
+ console.log("Email changed:", value);
77
+ },
78
+ },
79
+ });
80
+ ```
81
+
82
+ **Benefits | 이점:**
83
+
84
+ - 🧹 **No useEffect clutter** | useEffect 없이 깔끔한 코드
85
+ - � **No Context needed** | Context API 불필요
86
+ - 🎯 **No Props Drilling** | Props 전달 지옥 탈출
87
+ - �📦 **Modular logic** | 로직을 별도 파일로 분리 가능
88
+ - 🧪 **Easy testing** | actions/watch 단독 테스트 용이
89
+ - 🎯 **Better code cohesion** | 높은 코드 응집도
90
+
91
+ #### 2. **Surgical Re-rendering**
92
+
93
+ **수술적 정밀도의 리렌더링**
94
+
95
+ ```tsx
96
+ // ❌ Redux/Context: Entire component re-renders
97
+ const { user, todos, settings } = useStore(); // or useContext(AppContext)
98
+ // All fields change = entire component re-renders
99
+
100
+ // ✅ Forma: Only what you need
101
+ const userName = state.useValue("user.name"); // Only this field
102
+ const todoCount = state.useValue("todos.length"); // Only array length
103
+ const theme = state.useValue("settings.theme"); // Only theme
104
+ // Each component subscribes to ONLY what it needs
105
+ ```
106
+
107
+ **Performance | 성능:**
108
+
109
+ - ⚡ **10-100x faster** than Redux for large forms | 대규모 폼에서 Redux 대비 10-100배 빠름
110
+ - 🎯 **Field-level optimization** | 필드 단위 최적화
111
+ - 📊 **No selectors needed** | 셀렉터 불필요
112
+ - 🔥 **Zero wasted renders** | 불필요한 렌더링 제로
113
+
114
+ #### 3. **Form + State + Global Access in One**
115
+
116
+ **폼, 상태, 글로벌 접근을 하나로**
117
+
118
+ ```tsx
119
+ // ❌ Traditional: Multiple libraries + Context boilerplate
120
+ import { useForm } from "react-hook-form";
121
+ import { create } from "zustand";
122
+ import { createContext, useContext } from "react";
123
+
124
+ // Context setup, Provider wrapping, Props drilling...
125
+ const FormContext = createContext(null);
126
+
127
+ function App() {
128
+ const form = useForm();
129
+ return (
130
+ <FormContext.Provider value={form}>
131
+ <Header />
132
+ <MainContent />
133
+ </FormContext.Provider>
134
+ );
135
+ }
136
+
137
+ // ✅ Forma: One library, zero boilerplate
138
+ import { useGlobalForm, useGlobalFormaState } from "@ehfuse/forma";
139
+
140
+ function Header() {
141
+ // Access anywhere, no Provider needed!
142
+ const state = useGlobalFormaState<AuthState>({ stateId: "auth" });
143
+ const userName = state.useValue("user.name");
144
+ }
145
+
146
+ function MainContent() {
147
+ // Same state, no props drilling
148
+ const state = useGlobalFormaState<AuthState>({ stateId: "auth" });
149
+ }
150
+ ```
151
+
152
+ **All-in-One | 올인원:**
153
+
154
+ - 📝 **Form management** | 폼 관리
155
+ - 🌐 **Global state (no Context!)** | 전역 상태 (Context 불필요!)
156
+ - 🚫 **No Props Drilling** | Props 전달 불필요
157
+ - 👀 **Reactive watch** | 반응형 감시
158
+ - 🎬 **Actions system** | 액션 시스템
159
+ - 🎭 **Modal management** | 모달 관리
160
+ - 📱 **Breakpoint detection** | 반응형 감지
161
+
162
+ ## Key Features | 주요 특징
163
+
164
+ - 🎯 **Zero-Config**: Start immediately | 설정 없이 즉시 시작
165
+ - 👀 **Watch System**: Replace useEffect with declarative watchers | useEffect를 선언적 watcher로 대체
166
+ - � **Actions Pattern**: Modular business logic | 모듈화된 비즈니스 로직
167
+ - ✅ **Individual Field Subscription**: Surgical re-rendering | 수술적 리렌더링
168
+ - 🌟 **Dot Notation**: Deep nested access `user.profile.name` | 깊은 중첩 접근
169
+ - 🌐 **Global State Sharing**: Share across components | 컴포넌트 간 공유
170
+ - 🎭 **Modal Stack**: Mobile-friendly with back button | 뒤로가기 지원 모달
171
+ - 📱 **Breakpoint Management**: Responsive UI made easy | 반응형 UI 간편화
172
+ - ✅ **Full MUI Compatibility**: Perfect Material-UI integration | MUI 완벽 통합
173
+ - ✅ **TypeScript Native**: Full type safety | 완전한 타입 안전성
43
174
 
44
175
  ## Documentation | 문서
45
176
 
46
177
  ### English
47
178
 
48
- - **[Getting Started Guide](./docs/getting-started-en.md)** - Step-by-step tutorial and examples
49
- - **[API Reference](./docs/API-en.md)** - Complete API documentation with examples
50
- - **[Examples Collection](./docs/examples-en.md)** - Practical usage examples and patterns
51
- - **[Performance Guide](./docs/performance-guide-en.md)** - Performance optimization techniques
52
- - **[Performance Warnings](./docs/performance-warnings-en.md)** - Anti-patterns and common pitfalls
53
- - **[Migration Guide](./docs/migration-en.md)** - Migrate from other form libraries
54
- - **[useGlobalForm Guide](./docs/useGlobalForm-guide-en.md)** - Global form state management
55
- - **[Global Hooks Comparison](./docs/global-hooks-comparison-en.md)** - useGlobalForm vs useGlobalFormaState
56
- - **[Library Comparison](./docs/library-comparison-en.md)** - Forma vs other libraries
179
+ - **[Getting Started Guide](./docs/en/getting-started.md)** - Step-by-step tutorial and examples
180
+ - **[API Reference](./docs/en/API.md)** - Complete API documentation with examples
181
+ - **[Examples Collection](./docs/en/examples.md)** - Practical usage examples and patterns
182
+ - **[Performance Guide](./docs/en/performance-guide.md)** - Performance optimization techniques
183
+ - **[Performance Warnings](./docs/en/performance-warnings.md)** - Anti-patterns and common pitfalls
184
+ - **[Migration Guide](./docs/en/migration.md)** - Migrate from other form libraries
185
+ - **[useGlobalForm Guide](./docs/en/useGlobalForm-guide.md)** - Global form state management
186
+ - **[Global Hooks Comparison](./docs/en/global-hooks-comparison.md)** - useGlobalForm vs useGlobalFormaState
187
+ - **[Library Comparison](./docs/en/library-comparison.md)** - Forma vs other libraries
57
188
 
58
189
  ### 한국어 (Korean)
59
190
 
60
- - **[시작 가이드](./docs/getting-started-ko.md)** - 단계별 튜토리얼과 예제
61
- - **[API 레퍼런스](./docs/API-ko.md)** - 완전한 API 문서와 예제
62
- - **[예제 모음](./docs/examples-ko.md)** - 실용적인 사용 예제와 패턴
63
- - **[성능 최적화 가이드](./docs/performance-guide-ko.md)** - 성능 최적화 기법
64
- - **[성능 최적화 주의사항](./docs/performance-warnings-ko.md)** - 안티패턴과 일반적인 함정
65
- - **[마이그레이션 가이드](./docs/migration-ko.md)** - 다른 폼 라이브러리에서 이전
66
- - **[useGlobalForm 가이드](./docs/useGlobalForm-guide-ko.md)** - 글로벌 폼 상태 관리
67
- - **[글로벌 훅 비교](./docs/global-hooks-comparison-ko.md)** - useGlobalForm vs useGlobalFormaState
68
- - **[라이브러리 비교](./docs/library-comparison-ko.md)** - Forma vs 다른 라이브러리
191
+ - **[시작 가이드](./docs/ko/getting-started.md)** - 단계별 튜토리얼과 예제
192
+ - **[API 레퍼런스](./docs/ko/API.md)** - 완전한 API 문서와 예제
193
+ - **[예제 모음](./docs/ko/examples.md)** - 실용적인 사용 예제와 패턴
194
+ - **[성능 최적화 가이드](./docs/ko/performance-guide.md)** - 성능 최적화 기법
195
+ - **[성능 최적화 주의사항](./docs/ko/performance-warnings.md)** - 안티패턴과 일반적인 함정
196
+ - **[마이그레이션 가이드](./docs/ko/migration.md)** - 다른 폼 라이브러리에서 이전
197
+ - **[useGlobalForm 가이드](./docs/ko/useGlobalForm-guide.md)** - 글로벌 폼 상태 관리
198
+ - **[글로벌 훅 비교](./docs/ko/global-hooks-comparison.md)** - useGlobalForm vs useGlobalFormaState
199
+ - **[라이브러리 비교](./docs/ko/library-comparison.md)** - Forma vs 다른 라이브러리
69
200
 
70
201
  ### Links | 링크
71
202
 
@@ -90,154 +221,102 @@ yarn add @ehfuse/forma
90
221
 
91
222
  ## Quick Start | 빠른 시작
92
223
 
93
- ### Zero-Config Usage | Zero-Config 사용법
94
-
95
- **Start immediately without any configuration!**
96
- **설정 없이 바로 시작하세요!**
97
-
98
- ```tsx
99
- import { useForm, useFormaState } from "@ehfuse/forma";
100
-
101
- function ZeroConfigForm() {
102
- // Zero-Config: Start without any parameters
103
- // Zero-Config: 매개변수 없이 바로 사용
104
- const form = useForm<{ name: string; email: string }>();
105
-
106
- return (
107
- <div>
108
- <input
109
- placeholder="Name"
110
- value={form.useFormValue("name")}
111
- onChange={(e) => form.setFormValue("name", e.target.value)}
112
- />
113
- <input
114
- placeholder="Email"
115
- value={form.useFormValue("email")}
116
- onChange={(e) => form.setFormValue("email", e.target.value)}
117
- />
118
- <button onClick={() => console.log(form.getFormValues())}>
119
- Log Values
120
- </button>
121
- </div>
122
- );
123
- }
124
-
125
- function ZeroConfigState() {
126
- // Zero-Config: General state without configuration
127
- // Zero-Config: 일반 상태도 설정 없이 사용
128
- const state = useFormaState<{ count: number }>();
129
-
130
- return (
131
- <div>
132
- <p>Count: {state.useValue("count") || 0}</p>
133
- <button
134
- onClick={() =>
135
- state.setValue("count", (state.getValue("count") || 0) + 1)
136
- }
137
- >
138
- Increment
139
- </button>
140
- </div>
141
- );
142
- }
224
+ ```bash
225
+ npm install @ehfuse/forma
143
226
  ```
144
227
 
145
- ### Form State Management | 상태 관리
228
+ ### Real-World Example: Todo App with Watch | 실전 예제: Watch를 활용한 Todo 앱
146
229
 
147
230
  ```tsx
148
- import { useForm } from "@ehfuse/forma";
149
-
150
- function MyForm() {
151
- const form = useForm({
152
- initialValues: { name: "", email: "" },
153
- onValidate: async (values) => {
154
- // Name validation
155
- // 이름 검증
156
- if (!values.name.trim()) {
157
- alert("Please enter your name.");
158
- return false;
159
- }
160
-
161
- // Email validation
162
- // 이메일 검증
163
- if (!values.email.includes("@")) {
164
- alert("Please enter a valid email address.");
165
- return false;
166
- }
167
-
168
- return true; // Validation passed
231
+ import { useGlobalFormaState } from "@ehfuse/forma";
232
+
233
+ // 🎯 Separate actions file for better organization
234
+ // 액션을 별도 파일로 분리하여 코드 응집도 향상
235
+ const todoActions = {
236
+ addTodo: (ctx, text: string) => {
237
+ const todos = ctx.values.todos;
238
+ ctx.setValue("todos", [
239
+ ...todos,
240
+ {
241
+ id: Date.now(),
242
+ text,
243
+ completed: false,
244
+ },
245
+ ]);
246
+ },
247
+
248
+ toggleTodo: (ctx, id: number) => {
249
+ const todos = ctx.values.todos.map((t) =>
250
+ t.id === id ? { ...t, completed: !t.completed } : t
251
+ );
252
+ ctx.setValue("todos", todos);
253
+ },
254
+
255
+ // Auto-save to localStorage
256
+ saveToStorage: (ctx) => {
257
+ localStorage.setItem("todos", JSON.stringify(ctx.values.todos));
258
+ },
259
+ };
260
+
261
+ function TodoApp() {
262
+ const state = useGlobalFormaState({
263
+ stateId: "todo-app",
264
+ initialValues: {
265
+ todos: [],
266
+ filter: "all",
267
+ lastSync: null,
169
268
  },
170
- onSubmit: async (values) => {
171
- console.log("Submit:", values);
269
+ actions: todoActions,
270
+ watch: {
271
+ // 👀 Auto-save when todos change (replaces useEffect!)
272
+ // todos 변경 시 자동 저장 (useEffect 불필요!)
273
+ todos: (ctx, value) => {
274
+ ctx.actions.saveToStorage(ctx);
275
+ ctx.setValue("lastSync", new Date().toISOString());
276
+ },
277
+
278
+ // 🎯 Log filter changes
279
+ filter: (ctx, value, prevValue) => {
280
+ console.log(`Filter changed: ${prevValue} → ${value}`);
281
+ },
172
282
  },
173
283
  });
174
284
 
175
- return (
176
- <form onSubmit={form.submit}>
177
- <input
178
- name="name"
179
- value={form.useFormValue("name")}
180
- onChange={form.handleFormChange}
181
- />
182
- <input
183
- name="email"
184
- value={form.useFormValue("email")}
185
- onChange={form.handleFormChange}
186
- />
187
- <button type="submit">Submit</button>
188
- </form>
189
- );
190
- }
191
- ```
192
-
193
- ### General State Management | 일반 상태 관리
194
-
195
- ```tsx
196
- import { useFormaState } from "@ehfuse/forma";
197
-
198
- function UserDashboard() {
199
- const state = useFormaState({
200
- todos: [
201
- { id: 1, text: "Learn React", completed: false },
202
- { id: 2, text: "Build app", completed: false },
203
- ],
204
- filter: "all",
205
- });
206
-
207
- // Individual field subscription - re-renders only when that field changes
208
- // 개별 필드 구독 - 해당 필드가 변경될 때만 리렌더링
209
- const filter = state.useValue("filter");
210
-
211
- // ✅ Subscribe only to array length (re-renders only when items are added/removed)
212
- // ✅ 배열 길이만 구독 (항목 추가/삭제 시에만 리렌더링)
285
+ // ✅ Surgical re-rendering: Only subscribes to what's needed
286
+ // 수술적 리렌더링: 필요한 것만 구독
213
287
  const todosLength = state.useValue("todos.length");
214
-
215
- // Subscribe to specific todo text (utilizing dot notation)
216
- // ✅ 특정 할 일의 텍스트만 구독 (dot notation 활용)
217
- const firstTodoText = state.useValue("todos.0.text");
218
-
219
- const addTodo = () => {
220
- const todos = state.getValues().todos;
221
- state.setValue("todos", [
222
- ...todos,
223
- { id: Date.now(), text: "New todo", completed: false },
224
- ]);
225
- };
288
+ const filter = state.useValue("filter");
289
+ const lastSync = state.useValue("lastSync");
226
290
 
227
291
  return (
228
292
  <div>
229
- <p>Filter: {filter}</p>
230
- <p>First Todo: {firstTodoText}</p>
231
- <p>Total Count: {todosLength}</p>
232
- <button onClick={addTodo}>Add Todo</button>
233
- <button onClick={() => state.setValue("filter", "completed")}>
234
- Show Completed
293
+ <h1>Todos ({todosLength})</h1>
294
+ <p>Last synced: {lastSync}</p>
295
+
296
+ <button onClick={() => state.actions.addTodo(state, "New Task")}>
297
+ Add Todo
235
298
  </button>
299
+
300
+ <select
301
+ value={filter}
302
+ onChange={(e) => state.setValue("filter", e.target.value)}
303
+ >
304
+ <option value="all">All</option>
305
+ <option value="active">Active</option>
306
+ <option value="completed">Completed</option>
307
+ </select>
236
308
  </div>
237
309
  );
238
310
  }
239
311
  ```
240
312
 
313
+ **What you gain | 얻는 것:**
314
+
315
+ - 🧹 **No useEffect** - Watch handles all side effects | useEffect 제거 - Watch가 모든 부수효과 처리
316
+ - 📦 **Modular actions** - Easy to test and maintain | 모듈화된 액션 - 테스트와 유지보수 용이
317
+ - ⚡ **Optimized rendering** - Only `todosLength`, `filter`, `lastSync` trigger re-renders | 최적화된 렌더링
318
+ - 🔄 **Automatic persistence** - Watch auto-saves changes | 자동 저장 - Watch가 변경사항 자동 저장
319
+
241
320
  ---
242
321
 
243
322
  ## When to choose Forma?
@@ -314,19 +393,88 @@ Forma는 **폼 상태 관리에 특화**된 라이브러리로 특정 시나리
314
393
 
315
394
  ---
316
395
 
317
- ## Core Performance Principles | 핵심 성능 원칙
396
+ ## Architecture Benefits | 아키텍처 이점
397
+
398
+ ### 📁 Clean Separation of Concerns | 관심사의 명확한 분리
318
399
 
319
400
  ```tsx
320
- // Efficient: Individual field subscription
321
- // 효율적: 개별 필드 구독
322
- const userName = form.useFormValue("user.name");
323
- const userEmail = form.useFormValue("user.email");
401
+ // actions.ts - Business logic isolated
402
+ // actions.ts - 비즈니스 로직 분리
403
+ export const authActions = {
404
+ login: async (ctx, credentials) => {
405
+ const user = await api.login(credentials);
406
+ ctx.setValues({ logined: true, user, token: user.token });
407
+ },
408
+ logout: (ctx) => {
409
+ ctx.setValues({ logined: false, user: null, token: null });
410
+ },
411
+ startSync: (ctx) => {
412
+ /* ... */
413
+ },
414
+ stopSync: (ctx) => {
415
+ /* ... */
416
+ },
417
+ };
418
+
419
+ // watch.ts - Side effects isolated
420
+ // watch.ts - 부수효과 분리
421
+ export const authWatch = {
422
+ logined: (ctx, value) => {
423
+ value ? ctx.actions.startSync(ctx) : ctx.actions.stopSync(ctx);
424
+ },
425
+ "user.preferences": (ctx, value) => {
426
+ localStorage.setItem("prefs", JSON.stringify(value));
427
+ },
428
+ };
429
+
430
+ // component.tsx - Pure UI
431
+ // component.tsx - 순수 UI
432
+ function AuthApp() {
433
+ const state = useGlobalFormaState({
434
+ stateId: "auth",
435
+ actions: authActions,
436
+ watch: authWatch,
437
+ });
438
+
439
+ // Clean, declarative UI
440
+ // 깔끔한 선언적 UI
441
+ return <LoginForm onSubmit={state.actions.login} />;
442
+ }
443
+ ```
324
444
 
325
- // When user.name changes → Only userName field re-renders
326
- // user.name 변경 시 → userName 필드만 리렌더링
445
+ **Benefits | 이점:**
446
+
447
+ - 🧪 **Testable**: Test actions/watch independently | 독립적 테스트 가능
448
+ - 📦 **Reusable**: Share logic across projects | 프로젝트 간 로직 공유
449
+ - 🔍 **Maintainable**: Easy to locate and update logic | 로직 위치 파악 및 수정 용이
450
+ - 👥 **Team-friendly**: Clear code organization | 명확한 코드 구조
451
+
452
+ ### ⚡ Performance Comparison | 성능 비교
453
+
454
+ ```tsx
455
+ // ❌ Redux: Entire component re-renders
456
+ const state = useSelector((state) => state); // Everything triggers re-render
457
+ // 전체 컴포넌트 리렌더링
458
+
459
+ // ❌ Context: All consumers re-render
460
+ const { user, todos, settings } = useContext(AppContext);
461
+ // 모든 컨슈머 리렌더링
462
+
463
+ // ✅ Forma: Surgical precision
464
+ const userName = state.useValue("user.name"); // Only this
465
+ const todoCount = state.useValue("todos.length"); // Only this
466
+ const theme = state.useValue("settings.theme"); // Only this
467
+ // 수술적 정밀도
327
468
  ```
328
469
 
329
- **[View Detailed Performance Guide](./docs/performance-guide-en.md)**
470
+ **Real-world impact | 실제 영향:**
471
+
472
+ - 📊 **50+ fields**: 10-100x faster than Redux | Redux 대비 10-100배 빠름
473
+ - ⚡ **Real-time forms**: Smooth 60fps performance | 부드러운 60fps 성능
474
+ - 📱 **Mobile**: Better battery life | 배터리 수명 향상
475
+ - 🎯 **Zero wasted renders**: Every render is intentional | 모든 렌더링이 의도적
476
+
477
+ **[View Detailed Performance Guide](./docs/en/performance-guide.md)** | **[성능 가이드 보기](./docs/ko/performance-guide.md)**
330
478
 
331
479
  ---
332
480
 
@@ -33,11 +33,16 @@
33
33
  *
34
34
  * @template T 폼 데이터의 타입 / Form data type
35
35
  */
36
+ /**
37
+ * Watch 콜백 타입 / Watch callback type
38
+ */
39
+ type WatchCallback = (value: any, prevValue: any) => void;
36
40
  export declare class FieldStore<T extends Record<string, any>> {
37
41
  private fields;
38
42
  private dotNotationListeners;
39
43
  private initialValues;
40
44
  private globalListeners;
45
+ private watchers;
41
46
  constructor(initialValues: T);
42
47
  /**
43
48
  * 특정 필드 값 가져오기 / Get specific field value
@@ -130,9 +135,45 @@ export declare class FieldStore<T extends Record<string, any>> {
130
135
  * 초기값으로 리셋 / Reset to initial values
131
136
  */
132
137
  reset(): void;
138
+ /**
139
+ * 필드 변경 감시 / Watch field changes
140
+ * @param path 감시할 필드 경로 (dot notation 지원) / Field path to watch (supports dot notation)
141
+ * @param callback 변경 시 실행할 콜백 / Callback to execute on change
142
+ * @param options 옵션 / Options
143
+ * @returns cleanup 함수 / Cleanup function
144
+ */
145
+ watch(path: string, callback: WatchCallback, options?: {
146
+ immediate?: boolean;
147
+ }): () => void;
148
+ /**
149
+ * Watcher 알림 실행 / Notify watchers
150
+ * @param path 변경된 필드 경로 / Changed field path
151
+ * @param value 새 값 / New value
152
+ * @param prevValue 이전 값 / Previous value
153
+ */
154
+ private notifyWatchers;
155
+ /**
156
+ * 와일드카드 패턴 매칭 / Wildcard pattern matching
157
+ * @param path 실제 경로 / Actual path (e.g., "todos.0.completed")
158
+ * @param pattern 와일드카드 패턴 / Wildcard pattern (e.g., "todos.*.completed")
159
+ * @returns 매칭 여부 / Whether path matches pattern
160
+ */
161
+ private matchesWildcard;
162
+ /**
163
+ * 특정 path에 watcher가 등록되어 있는지 확인 / Check if watcher is registered for specific path
164
+ * @param path 확인할 경로 / Path to check
165
+ * @returns watcher 등록 여부 / Whether watcher is registered
166
+ */
167
+ hasWatcher(path: string): boolean;
168
+ /**
169
+ * 등록된 모든 watcher path 목록 반환 (디버깅용) / Return all registered watcher paths (for debugging)
170
+ * @returns watcher path 배열 / Array of watcher paths
171
+ */
172
+ getWatchedPaths(): string[];
133
173
  /**
134
174
  * 리소스 정리 / Clean up resources
135
175
  */
136
176
  destroy(): void;
137
177
  }
178
+ export {};
138
179
  //# sourceMappingURL=FieldStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FieldStore.d.ts","sourceRoot":"","sources":["../../core/FieldStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH;;;;;;GAMG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACjD,OAAO,CAAC,MAAM,CACA;IACd,OAAO,CAAC,oBAAoB,CAA2C;IACvE,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,eAAe,CAAyB;gBAEpC,aAAa,EAAE,CAAC;IAW5B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,GAAG;IA8B1C;;;;;;OAMG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI;IAuD3D;;;;;OAKG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI;IAOpC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG;IA2JhD;;;OAGG;IACH,SAAS,IAAI,CAAC;IAUd;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IA4B/B;;;OAGG;IACH,gBAAgB,CAAC,gBAAgB,EAAE,CAAC;IAyBpC;;;OAGG;IACH,UAAU,IAAI,OAAO;IAkBrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAU/B;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAyC/B;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAYzD;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IA2CnC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IA4B5C;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAsF7B;;OAEG;IACH,KAAK;IA6DL;;OAEG;IACH,OAAO;CAKV"}
1
+ {"version":3,"file":"FieldStore.d.ts","sourceRoot":"","sources":["../../core/FieldStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH;;;;;;GAMG;AACH;;GAEG;AACH,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,KAAK,IAAI,CAAC;AAE1D,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACjD,OAAO,CAAC,MAAM,CACA;IACd,OAAO,CAAC,oBAAoB,CAA2C;IACvE,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAA8C;gBAElD,aAAa,EAAE,CAAC;IAW5B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,GAAG;IA8B1C;;;;;;OAMG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI;IAuD3D;;;;;OAKG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI;IAOpC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG;IA0KhD;;;OAGG;IACH,SAAS,IAAI,CAAC;IAUd;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IA4C/B;;;OAGG;IACH,gBAAgB,CAAC,gBAAgB,EAAE,CAAC;IAyBpC;;;OAGG;IACH,UAAU,IAAI,OAAO;IAkBrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAU/B;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAyC/B;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAYzD;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IA2CnC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IA4B5C;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAsF7B;;OAEG;IACH,KAAK;IA6DL;;;;;;OAMG;IACH,KAAK,CACD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAClC,MAAM,IAAI;IAuBb;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAoCtB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;OAGG;IACH,eAAe,IAAI,MAAM,EAAE;IAI3B;;OAEG;IACH,OAAO;CAMV"}