suprform 1.0.1 → 1.0.3

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.
package/README.md CHANGED
@@ -1,80 +1,221 @@
1
1
  # suprform
2
2
 
3
- A headless React form library for managing complex state, validation, and error handling with a clean, scalable architecture.
3
+ A lightweight, **design system agnostic** React form library built as a powerful wrapper on top of **[react-hook-form](https://react-hook-form.com)**. Manage complex forms, validation, and error handling with a clean, composable API—no UI components bundled, complete control over your design.
4
4
 
5
- ## Features
5
+ > **What is SuprForm?** A thin, type-safe layer on top of `react-hook-form` that adds intuitive field management, built-in validation rules, and automatic error display—while staying completely design-system agnostic.
6
6
 
7
- - 🎨 **Headless Architecture** - Complete control over your UI and styling
8
- - 🔒 **TypeScript First** - Full type safety and IntelliSense support
9
- - **Flexible Validation** - Built-in validators and custom validation rules
10
- - 🎯 **Field-Level Control** - Manage individual fields with ease
11
- - 📊 **Form State Management** - Track dirty, touched, valid states automatically
12
- - **Async Validation** - Support for asynchronous validation
13
- - 📦 **Zero Dependencies** - Only requires React as peer dependency
14
- - 🧪 **Well Tested** - Comprehensive test suite included
7
+ ## Key Highlights
8
+
9
+ - 🎨 **Design System Agnostic** - Works with any UI framework (Material-UI, Tailwind, custom components, etc.) or plain HTML
10
+ - 🪝 **Built on react-hook-form** - Leverages the performance and flexibility of the most popular form library
11
+ - 🔒 **TypeScript First** - Full type safety and IntelliSense support with complete type inference
12
+ - **Seamless Validation** - Declarative validation rules with built-in validators and custom rule support
13
+ - 🎯 **Field-Level Control** - Granular control over individual fields with automatic state tracking
14
+ - 📊 **Automatic State Management** - Tracks dirty, touched, valid, error, and submission states
15
+ - ⚡ **Async Validation** - Native support for asynchronous validation (API calls, etc.)
16
+ - 🧪 **Well Tested** - Comprehensive test suite with full coverage
17
+ - 📦 **Minimal Footprint** - Only requires React as a peer dependency
15
18
 
16
19
  ## Installation
17
20
 
18
- ```bash
21
+ ````bash
19
22
  npm install suprform
20
- ```
21
23
 
22
- ## Quick Start
24
+ ## Quick Start with SuprForm.Control
25
+
26
+ The easiest way to get started—use the composable `SuprForm.Control` component with your own UI components:
23
27
 
24
28
  ```tsx
25
- import { useForm, required, email } from 'suprform';
29
+ import SuprForm from 'suprform';
26
30
 
27
31
  function LoginForm() {
28
- const form = useForm({
29
- initialValues: {
30
- email: '',
31
- password: '',
32
- },
33
- onSubmit: async (values) => {
34
- console.log('Form submitted:', values);
35
- },
36
- });
32
+ return (
33
+ <SuprForm
34
+ onSubmit={(values) => {
35
+ console.log('Form submitted:', values);
36
+ }}
37
+ >
38
+ <SuprForm.Control
39
+ name='email'
40
+ label='Email Address'
41
+ rules={{
42
+ required: 'Email is required',
43
+ pattern: {
44
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
45
+ message: 'Invalid email address',
46
+ },
47
+ }}
48
+ >
49
+ <input type='email' placeholder='you@example.com' />
50
+ </SuprForm.Control>
51
+
52
+ <SuprForm.Control
53
+ name='password'
54
+ label='Password'
55
+ rules={{
56
+ required: 'Password is required',
57
+ minLength: { value: 8, message: 'Password must be at least 8 characters' },
58
+ }}
59
+ >
60
+ <input type='password' placeholder='••••••••' />
61
+ </SuprForm.Control>
62
+
63
+ <button type='submit'>Login</button>
64
+ </SuprForm>
65
+ );
66
+ }
67
+ ````
68
+
69
+ **That's it!** `SuprForm.Control` automatically:
37
70
 
38
- // Register fields with validators
39
- form.registerField('email', {
40
- validators: [{ rule: required('Email is required') }, { rule: email('Invalid email format') }],
41
- });
71
+ - Renders a label above the input
72
+ - Validates on blur and change
73
+ - Displays error messages below the input
74
+ - Manages field state (touched, dirty, value, etc.)
42
75
 
43
- form.registerField('password', {
44
- validators: [{ rule: required('Password is required') }],
45
- });
76
+ Works with any input component—plain HTML, styled divs, Material-UI inputs, custom components, etc.
46
77
 
47
- const emailState = form.getFieldState('email');
48
- const emailHandlers = form.getFieldHandlers('email');
78
+ ## Advanced Example: Custom UI Components
49
79
 
80
+ Since SuprForm is **design system agnostic**, use it with your favorite component library:
81
+
82
+ ```tsx
83
+ import SuprForm from 'suprform';
84
+ import { TextField, Button } from '@mui/material'; // or your own
85
+
86
+ function SignupForm() {
50
87
  return (
51
- <form
52
- onSubmit={(e) => {
53
- e.preventDefault();
54
- form.submitForm();
88
+ <SuprForm
89
+ onSubmit={(values) => {
90
+ console.log('User signed up:', values);
55
91
  }}
56
92
  >
57
- <div>
58
- <input
59
- type='email'
60
- value={emailState.value || ''}
61
- onChange={(e) => emailHandlers.onChange(e.target.value)}
62
- onBlur={emailHandlers.onBlur}
63
- />
64
- {emailState.touched && emailState.error && <span>{emailState.error}</span>}
65
- </div>
66
-
67
- <button type='submit' disabled={!form.isValid || form.submitting}>
68
- {form.submitting ? 'Submitting...' : 'Login'}
69
- </button>
70
- </form>
93
+ <SuprForm.Control
94
+ name='username'
95
+ label='Username'
96
+ rules={{
97
+ required: 'Username is required',
98
+ minLength: { value: 3, message: 'Min 3 characters' },
99
+ pattern: {
100
+ value: /^[a-zA-Z0-9_]+$/,
101
+ message: 'Only letters, numbers, and underscores',
102
+ },
103
+ }}
104
+ >
105
+ <TextField variant='outlined' fullWidth />
106
+ </SuprForm.Control>
107
+
108
+ <SuprForm.Control
109
+ name='email'
110
+ label='Email'
111
+ rules={{
112
+ required: 'Email is required',
113
+ pattern: {
114
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
115
+ message: 'Invalid email',
116
+ },
117
+ }}
118
+ >
119
+ <TextField type='email' variant='outlined' fullWidth />
120
+ </SuprForm.Control>
121
+
122
+ <Button variant='contained' type='submit'>
123
+ Sign Up
124
+ </Button>
125
+ </SuprForm>
126
+ );
127
+ }
128
+ ```
129
+
130
+ ## Styling
131
+
132
+ Since SuprForm is **design system agnostic**, styling is completely in your control. Here are the CSS classes generated:
133
+
134
+ ```css
135
+ /* Wrapper for the entire field */
136
+ .controlled-field {
137
+ /* Your styles */
138
+ }
139
+
140
+ /* Label element */
141
+ .controlled-field-label {
142
+ /* Your styles */
143
+ }
144
+
145
+ /* Error message container */
146
+ .controlled-field-error {
147
+ /* Defaults to red, 14px font, margin-top 4px */
148
+ /* Override with your own styles */
149
+ }
150
+ ```
151
+
152
+ **Example with Tailwind CSS:**
153
+
154
+ ```tsx
155
+ <SuprForm.Control
156
+ name='email'
157
+ label='Email'
158
+ rules={{ required: 'Email is required' }}
159
+ className='mb-4'
160
+ >
161
+ <input
162
+ type='email'
163
+ className='w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2'
164
+ />
165
+ </SuprForm.Control>
166
+ ```
167
+
168
+ **Example with styled-components:**
169
+
170
+ ```tsx
171
+ import styled from 'styled-components';
172
+
173
+ const StyledField = styled.div`
174
+ margin-bottom: 1.5rem;
175
+
176
+ label {
177
+ display: block;
178
+ font-weight: 600;
179
+ margin-bottom: 0.5rem;
180
+ }
181
+
182
+ input {
183
+ width: 100%;
184
+ padding: 0.75rem;
185
+ border: 1px solid #ddd;
186
+ border-radius: 4px;
187
+
188
+ &:focus {
189
+ outline: none;
190
+ border-color: #0066cc;
191
+ box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
192
+ }
193
+ }
194
+
195
+ .controlled-field-error {
196
+ color: #d32f2f;
197
+ font-size: 0.875rem;
198
+ margin-top: 0.5rem;
199
+ }
200
+ `;
201
+
202
+ function EmailField() {
203
+ return (
204
+ <SuprForm.Control
205
+ name='email'
206
+ label='Email'
207
+ rules={{ required: 'Email is required' }}
208
+ className={StyledField}
209
+ >
210
+ <input type='email' />
211
+ </SuprForm.Control>
71
212
  );
72
213
  }
73
214
  ```
74
215
 
75
216
  ## Publishing
76
217
 
77
- To publish a new version to the npm registry:
218
+ To publish a new version to npm:
78
219
 
79
220
  1. Ensure you are logged in to npm:
80
221
 
@@ -82,150 +223,128 @@ To publish a new version to the npm registry:
82
223
  npm login
83
224
  ```
84
225
 
85
- 2. Build the package (also runs automatically via `prepublishOnly`):
226
+ 2. Build the package (runs automatically via `prepublishOnly`):
86
227
 
87
228
  ```bash
88
229
  npm run build
89
230
  ```
90
231
 
91
- 3. Bump the version in `package.json` and publish:
232
+ 3. Bump the version and publish:
92
233
 
93
234
  ```bash
94
235
  npm version patch # or minor/major
95
- npm publish --access public
236
+ npm publish --access public --otp=XXXXXX
96
237
  ```
97
238
 
239
+ (Replace `XXXXXX` with your 2FA code if you have 2FA enabled.)
240
+
98
241
  The published package contains only the compiled `dist/` files with ESM/CJS builds and TypeScript declarations.
99
242
 
100
- ## Using useField Hook
243
+ ## Validation Rules
101
244
 
102
- For simpler field management, use the `useField` hook:
245
+ All validation rules come from **react-hook-form**. Pass them directly to the `rules` prop:
103
246
 
104
247
  ```tsx
105
- import { useForm, useField, required } from 'suprform';
106
-
107
- function TextField({ name, label, form }) {
108
- const { field, meta } = useField({ name, form });
248
+ <SuprForm.Control
249
+ name='age'
250
+ rules={{
251
+ required: 'Age is required',
252
+ min: { value: 18, message: 'Must be 18 or older' },
253
+ max: { value: 120, message: 'Please enter a valid age' },
254
+ }}
255
+ >
256
+ <input type='number' />
257
+ </SuprForm.Control>
258
+ ```
109
259
 
110
- return (
111
- <div>
112
- <label>{label}</label>
113
- <input
114
- value={field.value || ''}
115
- onChange={(e) => field.onChange(e.target.value)}
116
- onBlur={field.onBlur}
117
- />
118
- {meta.touched && meta.error && <span>{meta.error}</span>}
119
- </div>
120
- );
121
- }
260
+ ### Common Rules
122
261
 
123
- function MyForm() {
124
- const form = useForm({
125
- initialValues: { name: '', email: '' },
126
- onSubmit: (values) => console.log(values),
127
- });
262
+ - `required` / `required: "message"` - Field must not be empty
263
+ - `minLength: { value: 5, message: "..." }` - Minimum string length
264
+ - `maxLength: { value: 20, message: "..." }` - Maximum string length
265
+ - `min: { value: 0, message: "..." }` - Minimum numeric value
266
+ - `max: { value: 100, message: "..." }` - Maximum numeric value
267
+ - `pattern: { value: /regex/, message: "..." }` - Match a regex pattern
268
+ - `validate: (value) => true || "error message"` - Custom synchronous validation
269
+ - `validate: async (value) => true || "error message"` - Custom async validation
128
270
 
129
- form.registerField('name', {
130
- validators: [{ rule: required() }],
131
- });
271
+ ### Custom Validation Example
132
272
 
133
- return (
134
- <form
135
- onSubmit={(e) => {
136
- e.preventDefault();
137
- form.submitForm();
138
- }}
139
- >
140
- <TextField name='name' label='Name' form={form} />
141
- <button type='submit'>Submit</button>
142
- </form>
143
- );
144
- }
273
+ ```tsx
274
+ <SuprForm.Control
275
+ name='password'
276
+ rules={{
277
+ required: 'Password is required',
278
+ minLength: { value: 8, message: 'Must be at least 8 characters' },
279
+ validate: async (value) => {
280
+ const isCommon = await checkIfPasswordIsCommon(value);
281
+ return !isCommon || 'This password is too common';
282
+ },
283
+ }}
284
+ >
285
+ <input type='password' />
286
+ </SuprForm.Control>
145
287
  ```
146
288
 
147
- ## Built-in Validators
148
-
149
- - `required(message?)` - Validates that a field is not empty
150
- - `minLength(min, message?)` - Validates minimum string length
151
- - `maxLength(max, message?)` - Validates maximum string length
152
- - `email(message?)` - Validates email format
153
- - `pattern(regex, message?)` - Validates against a regex pattern
154
- - `min(value, message?)` - Validates minimum numeric value
155
- - `max(value, message?)` - Validates maximum numeric value
156
- - `matches(fieldName, message?)` - Validates that a field matches another field
157
- - `combine(...validators)` - Combines multiple validators
289
+ ## API Reference
158
290
 
159
- ## Custom Validators
291
+ ### SuprForm Component
160
292
 
161
- Create custom validators easily:
293
+ The root form wrapper (powered by `FormProvider` from react-hook-form).
162
294
 
163
- ```tsx
164
- import { ValidationRule } from 'suprform';
295
+ **Props:**
165
296
 
166
- const isStrongPassword: ValidationRule = (value: string) => {
167
- if (!value) return undefined;
297
+ - `children` - Form fields and elements
298
+ - `onSubmit` - Handler called with form values when form is valid
299
+ - `className` - CSS class for the `<form>` element
300
+ - `style` - Inline styles for the `<form>` element
301
+ - `formOptions` - Options passed to react-hook-form's `useForm()` hook
168
302
 
169
- const hasUpperCase = /[A-Z]/.test(value);
170
- const hasLowerCase = /[a-z]/.test(value);
171
- const hasNumbers = /\d/.test(value);
172
- const hasSpecialChar = /[!@#$%^&*]/.test(value);
303
+ **Example:**
173
304
 
174
- if (!hasUpperCase || !hasLowerCase || !hasNumbers || !hasSpecialChar) {
175
- return 'Password must contain uppercase, lowercase, numbers, and special characters';
176
- }
177
-
178
- return undefined;
179
- };
180
-
181
- // Use in your form
182
- form.registerField('password', {
183
- validators: [{ rule: isStrongPassword }],
184
- });
305
+ ```tsx
306
+ <SuprForm
307
+ onSubmit={(values) => console.log(values)}
308
+ formOptions={{
309
+ mode: 'onBlur', // Validate on blur instead of on change
310
+ reValidateMode: 'onChange',
311
+ }}
312
+ >
313
+ {/* controls */}
314
+ </SuprForm>
185
315
  ```
186
316
 
187
- ## API Reference
317
+ ### SuprForm.Control Component
188
318
 
189
- ### useForm(config)
319
+ Composable field control component that wraps your input elements.
190
320
 
191
- Creates a form instance with state management and validation.
321
+ **Props:**
192
322
 
193
- **Parameters:**
323
+ - `name` - Field name (must match form values)
324
+ - `label` - Optional label text (rendered above input with `htmlFor` linking)
325
+ - `children` - Your input component (any React element)
326
+ - `rules` - Validation rules (react-hook-form's `RegisterOptions`)
327
+ - `className` - CSS class for the wrapper div
194
328
 
195
- - `config.initialValues` - Initial form values
196
- - `config.onSubmit` - Submit handler function
197
- - `config.validateOnChange` - Validate fields on change (default: true)
198
- - `config.validateOnBlur` - Validate fields on blur (default: true)
329
+ **Example:**
199
330
 
200
- **Returns:**
331
+ ```tsx
332
+ <SuprForm.Control
333
+ name='email'
334
+ label='Email'
335
+ rules={{ required: 'Email is required' }}
336
+ className='form-field'
337
+ >
338
+ <input type='email' />
339
+ </SuprForm.Control>
340
+ ```
341
+
342
+ **Automatic Features:**
201
343
 
202
- - `values` - Current form values
203
- - `errors` - Field errors
204
- - `touched` - Touched field states
205
- - `dirty` - Whether form has been modified
206
- - `submitting` - Whether form is being submitted
207
- - `submitCount` - Number of submission attempts
208
- - `isValid` - Whether form is valid
209
- - `setFieldValue(name, value)` - Set a field value
210
- - `setFieldError(name, error)` - Set a field error
211
- - `setFieldTouched(name, touched)` - Set field touched state
212
- - `resetForm()` - Reset form to initial state
213
- - `validateField(name)` - Validate a single field
214
- - `validateForm()` - Validate all fields
215
- - `submitForm()` - Submit the form
216
- - `getFieldState(name)` - Get field state
217
- - `getFieldHandlers(name)` - Get field handlers
218
- - `registerField(name, config)` - Register a field
219
- - `unregisterField(name)` - Unregister a field
220
-
221
- ### useField(props)
222
-
223
- Hook for managing individual fields.
224
-
225
- **Parameters:**
226
-
227
- - `name` - Field name
228
- - `form` - Form instance from useForm
344
+ - Renders `<label>` when `label` prop is provided
345
+ - Displays error message below input (in red, styled as `.controlled-field-error`)
346
+ - Injects `name`, `value`, `onChange`, `onBlur`, and `error` props to child input
347
+ - Handles field state automatically (touched, dirty, valid)
229
348
  - `defaultValue` - Default field value
230
349
  - `validators` - Array of validators
231
350
 
@@ -1 +1 @@
1
- {"version":3,"file":"SuprForm.d.ts","sourceRoot":"","sources":["../../../src/components/form/SuprForm.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAKL,WAAW,EACX,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAwB,MAAM,QAAQ,CAAC;AAE/E,KAAK,YAAY,GAAG,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,EACjE,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,KAC/B,YAAY,CAAC;AAElB,KAAK,iBAAiB,GAAG,YAAY,GAAG;IACtC,OAAO,EAAE,CACP,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAE/D,KAAK,EAAE,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,KACzC,YAAY,CAAC;CACnB,CAAC;AAEF,QAAA,MAAM,QAAQ,EAAE,iBA0Bf,CAAC;AAsEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"SuprForm.d.ts","sourceRoot":"","sources":["../../../src/components/form/SuprForm.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAKL,WAAW,EACX,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAwB,MAAM,QAAQ,CAAC;AAE/E,KAAK,YAAY,GAAG,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,EACjE,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,KAC/B,YAAY,CAAC;AAElB,KAAK,iBAAiB,GAAG,YAAY,GAAG;IACtC,OAAO,EAAE,CACP,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAE/D,KAAK,EAAE,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,KACzC,YAAY,CAAC;CACnB,CAAC;AAEF,QAAA,MAAM,QAAQ,EAAE,iBA0Bf,CAAC;AAgGF,eAAe,QAAQ,CAAC"}
@@ -12,10 +12,15 @@ export interface FormControlProps<TFieldValues extends FieldValues = FieldValues
12
12
  rules?: RegisterOptions<TFieldValues, TName>;
13
13
  name: TName;
14
14
  label?: string;
15
+ className?: string;
16
+ id?: string;
15
17
  }
16
18
  export interface ControlledFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> {
17
19
  field: ControllerRenderProps<TFieldValues, TName>;
18
20
  fieldState: ControllerFieldState;
19
21
  children: ReactElement<any>;
22
+ className?: string;
23
+ label?: string;
24
+ id?: string;
20
25
  }
21
26
  //# sourceMappingURL=type.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/components/form/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,YAAY,EACb,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW;IAC3E,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC;IAE/D,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB,CACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC;IAE/D,KAAK,EAAE,qBAAqB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;CAC7B"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/components/form/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,YAAY,EACb,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW;IAC3E,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC;IAE/D,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB,CACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC;IAE/D,KAAK,EAAE,qBAAqB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACb"}