suprform 1.0.1 → 1.0.2

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,222 @@
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
21
  ```bash
19
- npm install suprform
22
+ npm install suprform react-hook-form react react-dom
20
23
  ```
21
24
 
22
- ## Quick Start
25
+ ## Quick Start with SuprForm.Control
26
+
27
+ The easiest way to get started—use the composable `SuprForm.Control` component with your own UI components:
23
28
 
24
29
  ```tsx
25
- import { useForm, required, email } from 'suprform';
30
+ import SuprForm from 'suprform';
26
31
 
27
32
  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
- });
33
+ return (
34
+ <SuprForm
35
+ onSubmit={(values) => {
36
+ console.log('Form submitted:', values);
37
+ }}
38
+ >
39
+ <SuprForm.Control
40
+ name='email'
41
+ label='Email Address'
42
+ rules={{
43
+ required: 'Email is required',
44
+ pattern: {
45
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
46
+ message: 'Invalid email address',
47
+ },
48
+ }}
49
+ >
50
+ <input type='email' placeholder='you@example.com' />
51
+ </SuprForm.Control>
52
+
53
+ <SuprForm.Control
54
+ name='password'
55
+ label='Password'
56
+ rules={{
57
+ required: 'Password is required',
58
+ minLength: { value: 8, message: 'Password must be at least 8 characters' },
59
+ }}
60
+ >
61
+ <input type='password' placeholder='••••••••' />
62
+ </SuprForm.Control>
63
+
64
+ <button type='submit'>Login</button>
65
+ </SuprForm>
66
+ );
67
+ }
68
+ ```
69
+
70
+ **That's it!** `SuprForm.Control` automatically:
71
+
72
+ - Renders a label above the input
73
+ - Validates on blur and change
74
+ - Displays error messages below the input
75
+ - Manages field state (touched, dirty, value, etc.)
76
+
77
+ Works with any input component—plain HTML, styled divs, Material-UI inputs, custom components, etc.
37
78
 
38
- // Register fields with validators
39
- form.registerField('email', {
40
- validators: [{ rule: required('Email is required') }, { rule: email('Invalid email format') }],
41
- });
79
+ ## Advanced Example: Custom UI Components
42
80
 
43
- form.registerField('password', {
44
- validators: [{ rule: required('Password is required') }],
45
- });
81
+ Since SuprForm is **design system agnostic**, use it with your favorite component library:
46
82
 
47
- const emailState = form.getFieldState('email');
48
- const emailHandlers = form.getFieldHandlers('email');
83
+ ```tsx
84
+ import SuprForm from 'suprform';
85
+ import { TextField, Button } from '@mui/material'; // or your own
49
86
 
87
+ function SignupForm() {
50
88
  return (
51
- <form
52
- onSubmit={(e) => {
53
- e.preventDefault();
54
- form.submitForm();
89
+ <SuprForm
90
+ onSubmit={(values) => {
91
+ console.log('User signed up:', values);
55
92
  }}
56
93
  >
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>
94
+ <SuprForm.Control
95
+ name='username'
96
+ label='Username'
97
+ rules={{
98
+ required: 'Username is required',
99
+ minLength: { value: 3, message: 'Min 3 characters' },
100
+ pattern: {
101
+ value: /^[a-zA-Z0-9_]+$/,
102
+ message: 'Only letters, numbers, and underscores',
103
+ },
104
+ }}
105
+ >
106
+ <TextField variant='outlined' fullWidth />
107
+ </SuprForm.Control>
108
+
109
+ <SuprForm.Control
110
+ name='email'
111
+ label='Email'
112
+ rules={{
113
+ required: 'Email is required',
114
+ pattern: {
115
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
116
+ message: 'Invalid email',
117
+ },
118
+ }}
119
+ >
120
+ <TextField type='email' variant='outlined' fullWidth />
121
+ </SuprForm.Control>
122
+
123
+ <Button variant='contained' type='submit'>
124
+ Sign Up
125
+ </Button>
126
+ </SuprForm>
127
+ );
128
+ }
129
+ ```
130
+
131
+ ## Styling
132
+
133
+ Since SuprForm is **design system agnostic**, styling is completely in your control. Here are the CSS classes generated:
134
+
135
+ ```css
136
+ /* Wrapper for the entire field */
137
+ .controlled-field {
138
+ /* Your styles */
139
+ }
140
+
141
+ /* Label element */
142
+ .controlled-field-label {
143
+ /* Your styles */
144
+ }
145
+
146
+ /* Error message container */
147
+ .controlled-field-error {
148
+ /* Defaults to red, 14px font, margin-top 4px */
149
+ /* Override with your own styles */
150
+ }
151
+ ```
152
+
153
+ **Example with Tailwind CSS:**
154
+
155
+ ```tsx
156
+ <SuprForm.Control
157
+ name='email'
158
+ label='Email'
159
+ rules={{ required: 'Email is required' }}
160
+ className='mb-4'
161
+ >
162
+ <input
163
+ type='email'
164
+ className='w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2'
165
+ />
166
+ </SuprForm.Control>
167
+ ```
168
+
169
+ **Example with styled-components:**
170
+
171
+ ```tsx
172
+ import styled from 'styled-components';
173
+
174
+ const StyledField = styled.div`
175
+ margin-bottom: 1.5rem;
176
+
177
+ label {
178
+ display: block;
179
+ font-weight: 600;
180
+ margin-bottom: 0.5rem;
181
+ }
182
+
183
+ input {
184
+ width: 100%;
185
+ padding: 0.75rem;
186
+ border: 1px solid #ddd;
187
+ border-radius: 4px;
188
+
189
+ &:focus {
190
+ outline: none;
191
+ border-color: #0066cc;
192
+ box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
193
+ }
194
+ }
195
+
196
+ .controlled-field-error {
197
+ color: #d32f2f;
198
+ font-size: 0.875rem;
199
+ margin-top: 0.5rem;
200
+ }
201
+ `;
202
+
203
+ function EmailField() {
204
+ return (
205
+ <SuprForm.Control
206
+ name='email'
207
+ label='Email'
208
+ rules={{ required: 'Email is required' }}
209
+ className={StyledField}
210
+ >
211
+ <input type='email' />
212
+ </SuprForm.Control>
71
213
  );
72
214
  }
73
215
  ```
74
216
 
75
217
  ## Publishing
76
218
 
77
- To publish a new version to the npm registry:
219
+ To publish a new version to npm:
78
220
 
79
221
  1. Ensure you are logged in to npm:
80
222
 
@@ -82,150 +224,128 @@ To publish a new version to the npm registry:
82
224
  npm login
83
225
  ```
84
226
 
85
- 2. Build the package (also runs automatically via `prepublishOnly`):
227
+ 2. Build the package (runs automatically via `prepublishOnly`):
86
228
 
87
229
  ```bash
88
230
  npm run build
89
231
  ```
90
232
 
91
- 3. Bump the version in `package.json` and publish:
233
+ 3. Bump the version and publish:
92
234
 
93
235
  ```bash
94
236
  npm version patch # or minor/major
95
- npm publish --access public
237
+ npm publish --access public --otp=XXXXXX
96
238
  ```
97
239
 
240
+ (Replace `XXXXXX` with your 2FA code if you have 2FA enabled.)
241
+
98
242
  The published package contains only the compiled `dist/` files with ESM/CJS builds and TypeScript declarations.
99
243
 
100
- ## Using useField Hook
244
+ ## Validation Rules
101
245
 
102
- For simpler field management, use the `useField` hook:
246
+ All validation rules come from **react-hook-form**. Pass them directly to the `rules` prop:
103
247
 
104
248
  ```tsx
105
- import { useForm, useField, required } from 'suprform';
106
-
107
- function TextField({ name, label, form }) {
108
- const { field, meta } = useField({ name, form });
249
+ <SuprForm.Control
250
+ name='age'
251
+ rules={{
252
+ required: 'Age is required',
253
+ min: { value: 18, message: 'Must be 18 or older' },
254
+ max: { value: 120, message: 'Please enter a valid age' },
255
+ }}
256
+ >
257
+ <input type='number' />
258
+ </SuprForm.Control>
259
+ ```
109
260
 
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
- }
261
+ ### Common Rules
122
262
 
123
- function MyForm() {
124
- const form = useForm({
125
- initialValues: { name: '', email: '' },
126
- onSubmit: (values) => console.log(values),
127
- });
263
+ - `required` / `required: "message"` - Field must not be empty
264
+ - `minLength: { value: 5, message: "..." }` - Minimum string length
265
+ - `maxLength: { value: 20, message: "..." }` - Maximum string length
266
+ - `min: { value: 0, message: "..." }` - Minimum numeric value
267
+ - `max: { value: 100, message: "..." }` - Maximum numeric value
268
+ - `pattern: { value: /regex/, message: "..." }` - Match a regex pattern
269
+ - `validate: (value) => true || "error message"` - Custom synchronous validation
270
+ - `validate: async (value) => true || "error message"` - Custom async validation
128
271
 
129
- form.registerField('name', {
130
- validators: [{ rule: required() }],
131
- });
272
+ ### Custom Validation Example
132
273
 
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
- }
274
+ ```tsx
275
+ <SuprForm.Control
276
+ name='password'
277
+ rules={{
278
+ required: 'Password is required',
279
+ minLength: { value: 8, message: 'Must be at least 8 characters' },
280
+ validate: async (value) => {
281
+ const isCommon = await checkIfPasswordIsCommon(value);
282
+ return !isCommon || 'This password is too common';
283
+ },
284
+ }}
285
+ >
286
+ <input type='password' />
287
+ </SuprForm.Control>
145
288
  ```
146
289
 
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
290
+ ## API Reference
158
291
 
159
- ## Custom Validators
292
+ ### SuprForm Component
160
293
 
161
- Create custom validators easily:
294
+ The root form wrapper (powered by `FormProvider` from react-hook-form).
162
295
 
163
- ```tsx
164
- import { ValidationRule } from 'suprform';
296
+ **Props:**
165
297
 
166
- const isStrongPassword: ValidationRule = (value: string) => {
167
- if (!value) return undefined;
298
+ - `children` - Form fields and elements
299
+ - `onSubmit` - Handler called with form values when form is valid
300
+ - `className` - CSS class for the `<form>` element
301
+ - `style` - Inline styles for the `<form>` element
302
+ - `formOptions` - Options passed to react-hook-form's `useForm()` hook
168
303
 
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);
304
+ **Example:**
173
305
 
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
- });
306
+ ```tsx
307
+ <SuprForm
308
+ onSubmit={(values) => console.log(values)}
309
+ formOptions={{
310
+ mode: 'onBlur', // Validate on blur instead of on change
311
+ reValidateMode: 'onChange',
312
+ }}
313
+ >
314
+ {/* controls */}
315
+ </SuprForm>
185
316
  ```
186
317
 
187
- ## API Reference
318
+ ### SuprForm.Control Component
188
319
 
189
- ### useForm(config)
320
+ Composable field control component that wraps your input elements.
190
321
 
191
- Creates a form instance with state management and validation.
322
+ **Props:**
192
323
 
193
- **Parameters:**
324
+ - `name` - Field name (must match form values)
325
+ - `label` - Optional label text (rendered above input with `htmlFor` linking)
326
+ - `children` - Your input component (any React element)
327
+ - `rules` - Validation rules (react-hook-form's `RegisterOptions`)
328
+ - `className` - CSS class for the wrapper div
194
329
 
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)
330
+ **Example:**
199
331
 
200
- **Returns:**
332
+ ```tsx
333
+ <SuprForm.Control
334
+ name='email'
335
+ label='Email'
336
+ rules={{ required: 'Email is required' }}
337
+ className='form-field'
338
+ >
339
+ <input type='email' />
340
+ </SuprForm.Control>
341
+ ```
342
+
343
+ **Automatic Features:**
201
344
 
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
345
+ - Renders `<label>` when `label` prop is provided
346
+ - Displays error message below input (in red, styled as `.controlled-field-error`)
347
+ - Injects `name`, `value`, `onChange`, `onBlur`, and `error` props to child input
348
+ - Handles field state automatically (touched, dirty, valid)
229
349
  - `defaultValue` - Default field value
230
350
  - `validators` - Array of validators
231
351
 
@@ -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"}