react-server-actions 1.0.4 → 1.0.5
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 +310 -67
- package/dist/client/helpers.js +2 -2
- package/dist/client/helpers.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,75 @@
|
|
|
1
|
-
#
|
|
1
|
+
# React Server Actions
|
|
2
2
|
|
|
3
|
-
A lightweight library for handling
|
|
3
|
+
A lightweight library for handling server actions in React and Next.js applications using server side zod validation and native html client side validation.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Intro
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
React Server Actions represent a groundbreaking advancement in how we handle server-side operations in React applications. However, while the APIs provided by the React team are powerful, developers often face challenges in establishing consistent patterns for handling responses, validation, and error management. This is where this library comes in.
|
|
8
|
+
|
|
9
|
+
React Server Actions was born out of the need to address these gaps in the implementation of React's new server actions feature. Rather than replacing the native functionality, this library builds upon it by providing a structured approach to server actions. The core idea is to establish a well-defined shape for server action responses, making them predictable and easier to work with.
|
|
10
|
+
|
|
11
|
+
This is how we define a server action with the help of react-server-actions library.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
export const zodSchema = z.object({
|
|
15
|
+
name: z.string().min(1),
|
|
16
|
+
...
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
'use server';
|
|
8
22
|
|
|
9
|
-
|
|
23
|
+
// the action wrapper will take care of validate data and will wrap the response into a ActionResult type!
|
|
24
|
+
export const someAction = action(zodSchema, async (data) => {
|
|
25
|
+
// data is already validated and is typed
|
|
26
|
+
return {
|
|
27
|
+
something: 'whatever',
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
By providing this structure, the library enables developers to create more robust client-side components that can confidently interact with server actions. It combines the power of Zod for server-side validation with native HTML validation attributes, creating a seamless development experience while maintaining type safety throughout the application. The result is a more organized and maintainable codebase that follows best practices for handling server-client interactions.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
'use client'
|
|
36
|
+
export default function Form() {
|
|
37
|
+
const [state, action, pending] = useActionState(someAction, initialState());
|
|
38
|
+
|
|
39
|
+
console.log(state.formData?.name); // state will be always of type ActionResult
|
|
40
|
+
console.log(state.invalid?.name); // it will contain the data and eventually the validation problems
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Form state={state} action={action} schema={schema}>
|
|
44
|
+
<FormField
|
|
45
|
+
name="name"
|
|
46
|
+
render={(field) => (
|
|
47
|
+
<div>
|
|
48
|
+
<label htmlFor={field.input.id} className={field.invalid ? 'text-red-500' : ''}>Name</label>
|
|
49
|
+
<input {...field.input} type="text" />
|
|
50
|
+
{field.invalid && <p className="text-red-500">{field.invalid}</p>}
|
|
51
|
+
</div>
|
|
52
|
+
)}
|
|
53
|
+
/>
|
|
54
|
+
</Form>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// The ActionResult type
|
|
61
|
+
export type ActionResult<Schema> = {
|
|
62
|
+
success: boolean;
|
|
63
|
+
formData: z.infer<Schema> | undefined; // Data submitted
|
|
64
|
+
successData: any; // Data returned from the user
|
|
65
|
+
invalid: [key in keyof Partial<z.TypeOf<Schema>>]: string[] | undefined; // Validation fields
|
|
66
|
+
error: string | undefined;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
10
69
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
### Server-Side Features
|
|
14
73
|
|
|
15
74
|
#### Structured Action Responses
|
|
16
75
|
|
|
@@ -33,7 +92,7 @@ A lightweight library for handling form actions in Next.js applications using na
|
|
|
33
92
|
|
|
34
93
|
#### Form State Management
|
|
35
94
|
|
|
36
|
-
-
|
|
95
|
+
- Form data persistence between submissions
|
|
37
96
|
- Ability to reset form data after successful submission
|
|
38
97
|
- State management utilities for handling loading and error states
|
|
39
98
|
|
|
@@ -41,56 +100,119 @@ A lightweight library for handling form actions in Next.js applications using na
|
|
|
41
100
|
|
|
42
101
|
#### Framework Agnostic
|
|
43
102
|
|
|
103
|
+
- Use React standard hook useActionState
|
|
44
104
|
- Works with any form management library of your choice
|
|
45
105
|
- Native support for React Hook Form, Formik, or plain HTML forms
|
|
46
106
|
- Zero client-side dependencies required
|
|
47
107
|
|
|
48
108
|
#### Native HTML Validation
|
|
49
109
|
|
|
50
|
-
- Automatic HTML5 validation attributes from Zod schemas
|
|
110
|
+
- Automatic HTML5 validation attributes inferred from Zod schemas
|
|
51
111
|
- Client-side validation before server submission
|
|
52
112
|
- Improved user experience with instant feedback
|
|
53
113
|
- Accessibility-friendly validation messages
|
|
54
114
|
|
|
55
115
|
## Installation
|
|
56
116
|
|
|
57
|
-
bash
|
|
58
|
-
npm install
|
|
117
|
+
```bash
|
|
118
|
+
npm install react-server-actions
|
|
119
|
+
```
|
|
59
120
|
|
|
60
121
|
## Basic Usage
|
|
61
122
|
|
|
62
123
|
### 1. Define your schema and action
|
|
63
124
|
|
|
64
|
-
|
|
125
|
+
Define your zod schema and create a server action. The server action must be wrapped into the `action` method to be sure that it will return a correct `ActionResult` type.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
65
128
|
import { z } from 'zod';
|
|
66
|
-
import { createAction } from 'next-native-actions';
|
|
67
129
|
const userSchema = z.object({
|
|
68
|
-
name: z.string().min(2),
|
|
69
|
-
email: z.string().email(),
|
|
70
|
-
age: z.number().min(18)
|
|
130
|
+
name: z.string().min(2),
|
|
131
|
+
email: z.string().email(),
|
|
132
|
+
age: z.number().min(18),
|
|
71
133
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { userSchema } from './schema';
|
|
138
|
+
import { action } from 'react-server-actions';
|
|
139
|
+
export const createUser = action(userSchema, async (data) => {
|
|
140
|
+
// Your server logic here
|
|
141
|
+
return { success: true, data };
|
|
75
142
|
});
|
|
143
|
+
```
|
|
76
144
|
|
|
77
145
|
### 2. Use in your form component
|
|
78
146
|
|
|
79
|
-
|
|
147
|
+
Connect the server action with the React hook `useStateAction`.
|
|
148
|
+
For having a correct initial data we provide a `initialState` method
|
|
149
|
+
After that you will have a typed `state` with all the informations about data submitted and validation state.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
'use client';
|
|
153
|
+
import { useActionState } from 'react';
|
|
154
|
+
import { createUser } from './action';
|
|
155
|
+
import { initialState } from 'react-server-actions';
|
|
156
|
+
export function UserForm() {
|
|
157
|
+
const [state, action, pending] = useActionState(createUser, initialData({
|
|
158
|
+
// can be an object that satisfies userSchema or undefined
|
|
159
|
+
...
|
|
160
|
+
}));
|
|
161
|
+
...
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 3. Define the form
|
|
166
|
+
|
|
167
|
+
You can now create the form with native `<form>` or with any other library, taking advantage of having a structured and typed `state`.
|
|
168
|
+
This library will, anyway, provide two useful component:
|
|
169
|
+
|
|
170
|
+
- `<Form>` component - it will provide the ability to reset the form on successful submission, define a `onSuccess` and `onError` callback
|
|
171
|
+
- `<FormField>` component - it will provide a render method, which will expose a `field` property with the correct informations to build your inputs. **It will also inject the HTML5 validation rule based on the zod schema**!
|
|
172
|
+
- Inside the `render` method of the `<FormField>` component you can use whatever ui library you want.
|
|
173
|
+
- The `field` property will have this structure
|
|
174
|
+
```typescript
|
|
175
|
+
{
|
|
176
|
+
invalid: string[] | undefined;
|
|
177
|
+
value: any;
|
|
178
|
+
input: {
|
|
179
|
+
id: string;
|
|
180
|
+
name: string;
|
|
181
|
+
'aria-invalid': boolean;
|
|
182
|
+
autoComplete: 'on' | 'off' | undefined;
|
|
183
|
+
defaultValue?: string;
|
|
184
|
+
...html5ValidationRules (like required, min, etc...)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
80
190
|
'use client';
|
|
81
|
-
import {
|
|
191
|
+
import { useActionState } from 'react';
|
|
192
|
+
import { createUser } from './action'
|
|
82
193
|
export function UserForm() {
|
|
83
|
-
const
|
|
84
|
-
return (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
194
|
+
const [state, action, pending] = useActionState(createUser);
|
|
195
|
+
return (
|
|
196
|
+
<Form state={state} action={action} schema={userSchema}>
|
|
197
|
+
|
|
198
|
+
<FormField
|
|
199
|
+
name="name"
|
|
200
|
+
render={(field) => (
|
|
201
|
+
<div>
|
|
202
|
+
<label htmlFor={field.input.id} className={field.invalid ? 'text-red-500' : ''}>
|
|
203
|
+
Name
|
|
204
|
+
</label>
|
|
205
|
+
<input {...field.input} type="text" />
|
|
206
|
+
{field.invalid && <p className="text-red-500">{field.invalid}</p>}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
/>
|
|
210
|
+
|
|
211
|
+
<button type="submit" disabled={pending}>Save</button>
|
|
212
|
+
</Form>
|
|
213
|
+
);
|
|
93
214
|
}
|
|
215
|
+
```
|
|
94
216
|
|
|
95
217
|
## Advanced Features
|
|
96
218
|
|
|
@@ -98,50 +220,131 @@ return (
|
|
|
98
220
|
|
|
99
221
|
The library works seamlessly with popular form management libraries:
|
|
100
222
|
|
|
101
|
-
|
|
102
|
-
// With React Hook Form
|
|
103
|
-
import { useForm } from 'react-hook-form';
|
|
104
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
105
|
-
export function UserFormWithRHF() {
|
|
106
|
-
const form = useForm({
|
|
107
|
-
resolver: zodResolver(userSchema)
|
|
108
|
-
});
|
|
109
|
-
// ... rest of your form implementation
|
|
110
|
-
}
|
|
223
|
+
** Docs still missing **
|
|
111
224
|
|
|
112
|
-
###
|
|
225
|
+
### Build your component around the library
|
|
113
226
|
|
|
114
|
-
|
|
115
|
-
'use client';
|
|
116
|
-
export function UserForm() {
|
|
117
|
-
const { action, isLoading, error } = useAction(createUser);
|
|
118
|
-
return (
|
|
119
|
-
|
|
120
|
-
<form action={action}>
|
|
121
|
-
{error && <div className="error">{error.message}</div>}
|
|
122
|
-
{/ form fields /}
|
|
123
|
-
</form>
|
|
124
|
-
);
|
|
125
|
-
}
|
|
227
|
+
** Docs still missing **
|
|
126
228
|
|
|
127
|
-
|
|
229
|
+
If you want to create your custom components around react-server-action library you can use the provided `useField` hook.
|
|
128
230
|
|
|
129
|
-
|
|
231
|
+
The `<Form>` and `<FormField>` components are providing a context in which you can call the `useField` for getting all the required information about a single field you need to build a component.
|
|
130
232
|
|
|
131
|
-
|
|
233
|
+
For example, we can recreate the standard Shadcn Form components in this way:
|
|
132
234
|
|
|
133
|
-
|
|
235
|
+
```typescript
|
|
236
|
+
"use client";
|
|
134
237
|
|
|
135
|
-
|
|
136
|
-
|
|
238
|
+
import { useField } from "@native-actions/client";
|
|
239
|
+
import React from "react";
|
|
240
|
+
|
|
241
|
+
export function FormLabel({ children }: { children: React.ReactNode }) {
|
|
242
|
+
const field = useField();
|
|
243
|
+
return (
|
|
244
|
+
<label
|
|
245
|
+
className={`text-sm font-medium leading-none ${field.invalid && "text-destructive"}`}
|
|
246
|
+
htmlFor={field.input.id}
|
|
247
|
+
>
|
|
248
|
+
{children}
|
|
249
|
+
</label>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function FormDescription({ children }: { children: React.ReactNode }) {
|
|
254
|
+
const field = useField();
|
|
255
|
+
return (
|
|
256
|
+
<p
|
|
257
|
+
id={field.input.id + "-description"}
|
|
258
|
+
className="text-sm text-muted-foreground"
|
|
259
|
+
>
|
|
260
|
+
{children}
|
|
261
|
+
</p>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function FormMessage({ children }: { children?: React.ReactNode }) {
|
|
266
|
+
const field = useField();
|
|
267
|
+
const error = field.invalid || children;
|
|
268
|
+
if (!error) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
return (
|
|
272
|
+
<p
|
|
273
|
+
id={field.input.id + "-message"}
|
|
274
|
+
className={`text-sm font-medium ${error && "text-destructive"}`}
|
|
275
|
+
>
|
|
276
|
+
{error}
|
|
277
|
+
</p>
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
And them can use them inside the form for having a better developer experience
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
export default function ShadcnForm() {
|
|
286
|
+
const [state, action, pending] = useActionState(formAction, initialState(undefined));
|
|
287
|
+
return (
|
|
288
|
+
<Form state={state} action={action} schema={schema} className="space-y-4">
|
|
289
|
+
<FormField
|
|
290
|
+
name="name"
|
|
291
|
+
render={(field) => (
|
|
292
|
+
<div className="flex flex-col space-y-2">
|
|
293
|
+
<FormLabel>Name</FormLabel>
|
|
294
|
+
<FormDescription>Insert your name</FormDescription>
|
|
295
|
+
<Input {...field.input} />
|
|
296
|
+
<FormMessage />
|
|
297
|
+
</div>
|
|
298
|
+
)}
|
|
299
|
+
/>
|
|
300
|
+
...
|
|
301
|
+
</Form>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Error Handling
|
|
137
307
|
|
|
138
|
-
|
|
308
|
+
In the `ActionResult` object there is an `error` property exposed. This property will be sent back only in case of an error during the action execution.
|
|
309
|
+
You can handle this error state in several ways
|
|
139
310
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
311
|
+
```typescript
|
|
312
|
+
'use client';
|
|
313
|
+
import { useActionState } from 'react';
|
|
314
|
+
import { createUser } from './action'
|
|
315
|
+
export function UserForm() {
|
|
316
|
+
const [state, action, pending] = useActionState(createUser);
|
|
317
|
+
useEffect(() => {
|
|
318
|
+
// You can subscribe to state variable
|
|
319
|
+
if (state.error) {
|
|
320
|
+
console.log(state.error);
|
|
321
|
+
}
|
|
322
|
+
}, [state]);
|
|
323
|
+
return (
|
|
324
|
+
<Form state={state} action={action} schema={userSchema} onError={(err) => {
|
|
325
|
+
// You can use the <Form> onError callback
|
|
326
|
+
toast.error(err);
|
|
327
|
+
}}>
|
|
328
|
+
// You can render some component if state error is present
|
|
329
|
+
{state.error && <p>An error occurred: {state.error}</p>}
|
|
330
|
+
<FormField
|
|
331
|
+
name="name"
|
|
332
|
+
render={(field) => (
|
|
333
|
+
<div>
|
|
334
|
+
<label htmlFor={field.input.id} className={field.invalid ? 'text-red-500' : ''}>
|
|
335
|
+
Name
|
|
336
|
+
</label>
|
|
337
|
+
<input {...field.input} type="text" />
|
|
338
|
+
{field.invalid && <p className="text-red-500">{field.invalid}</p>}
|
|
339
|
+
</div>
|
|
340
|
+
)}
|
|
341
|
+
/>
|
|
342
|
+
|
|
343
|
+
<button type="submit" disabled={pending}>Save</button>
|
|
344
|
+
</Form>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
```
|
|
145
348
|
|
|
146
349
|
## TypeScript Support
|
|
147
350
|
|
|
@@ -152,6 +355,46 @@ The library is written in TypeScript and provides full type safety:
|
|
|
152
355
|
- Proper error typing
|
|
153
356
|
- IDE autocompletion support
|
|
154
357
|
|
|
358
|
+
## Caveats
|
|
359
|
+
|
|
360
|
+
### datetime-local input type
|
|
361
|
+
|
|
362
|
+
In the standard html (as the time of writing) we have two kinds of date input
|
|
363
|
+
|
|
364
|
+
- `<input type="date">` which represent a yyyy-MM-dd date
|
|
365
|
+
- `<input type="datetime-local">` which represent a yyyy-MM-ddTHH:mm
|
|
366
|
+
Since from a zod rule like `z.coerce.date()` we cannot know if the user is using a `<input type="date">` or `<input type="datetime-local">` we are, by default, assuming you are using a type="date" field.
|
|
367
|
+
So, inside the `render` method of the `<FormField>` component, we are returning a yyyy-MM-dd formatted string inside the `field.input.defaultValue`
|
|
368
|
+
|
|
369
|
+
So this will work
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
<FormField
|
|
373
|
+
name="dateField"
|
|
374
|
+
render={(field) => (
|
|
375
|
+
<input {...field.input} type="date" />
|
|
376
|
+
)}
|
|
377
|
+
/>
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Instead for working with `datetime-local` inputs we are exposing a helper method to retrieve the defaultValue to assing to the input to be sure that we will not loose the field state across submits
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import { datetimeToInputDefaultValue } from 'react-server-actions';
|
|
384
|
+
...
|
|
385
|
+
<FormField
|
|
386
|
+
name="dateField"
|
|
387
|
+
render={(field) => (
|
|
388
|
+
<input {...field.input} type="datetime-local" defaultValue={field.value ? datetimeToInputDefaultValue(field.value) : ''} />
|
|
389
|
+
)}
|
|
390
|
+
/>
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### select defaultValue
|
|
394
|
+
|
|
395
|
+
In react 19 there is an open issue https://github.com/facebook/react/issues/30580 that prevents the defaultValue to correctly set the select value.
|
|
396
|
+
According to this comment https://github.com/facebook/react/issues/30580#issuecomment-2537962675 there is a workaround by setting the 'key' attribute of the select.
|
|
397
|
+
|
|
155
398
|
## Contributing
|
|
156
399
|
|
|
157
400
|
Contributions are welcome! Please read our contributing guidelines before submitting a pull request.
|
package/dist/client/helpers.js
CHANGED
|
@@ -37,10 +37,10 @@ export function getZodValidationAttributes(schema, path, options) {
|
|
|
37
37
|
attrs.type = 'text';
|
|
38
38
|
if (def.checks) {
|
|
39
39
|
for (const check of def.checks) {
|
|
40
|
-
if (check.kind === '
|
|
40
|
+
if (check.kind === 'minlength') {
|
|
41
41
|
attrs.minLength = check.value;
|
|
42
42
|
}
|
|
43
|
-
if (check.kind === '
|
|
43
|
+
if (check.kind === 'maxlength') {
|
|
44
44
|
attrs.maxLength = check.value;
|
|
45
45
|
}
|
|
46
46
|
if (check.kind === 'email') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/client/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAoB,EACpB,IAAc,EACd,OAEC;IAKD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC;IACxB,IAAI,IAAI,GAAsD,QAAQ,CAAC;IACvE,MAAM,KAAK,GAA8C,EAAE,CAAC;IAE5D,sDAAsD;IACtD,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAuB,CAAC,CAAC;QACnD,OAAO,KAAK;YACV,CAAC,CAAC,0BAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClD,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,iEAAiE;IACjE,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,CAAC,WAAW,CAAC;IACvD,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,CAAC,WAAW,CAAC;IAEvD,+FAA+F;IAC/F,IAAI,cAAc,IAAI,cAAc,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,0BAA0B,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACnE,OAAO,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;QACjC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IAEtB,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACjC,IAAI,GAAG,QAAQ,CAAC;QAChB,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC;QACpB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/client/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAoB,EACpB,IAAc,EACd,OAEC;IAKD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC;IACxB,IAAI,IAAI,GAAsD,QAAQ,CAAC;IACvE,MAAM,KAAK,GAA8C,EAAE,CAAC;IAE5D,sDAAsD;IACtD,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAuB,CAAC,CAAC;QACnD,OAAO,KAAK;YACV,CAAC,CAAC,0BAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClD,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,iEAAiE;IACjE,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,CAAC,WAAW,CAAC;IACvD,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,CAAC,WAAW,CAAC;IAEvD,+FAA+F;IAC/F,IAAI,cAAc,IAAI,cAAc,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,0BAA0B,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACnE,OAAO,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;QACjC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IAEtB,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACjC,IAAI,GAAG,QAAQ,CAAC;QAChB,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC;QACpB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC/B,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;gBAChC,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC/B,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;gBAChC,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC3B,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC;gBACvB,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IACE,GAAG,CAAC,QAAQ,KAAK,WAAW;QAC5B,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,WAAW,CAAC,EAC1E,CAAC;QACD,IAAI,GAAG,QAAQ,CAAC;QAChB,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC;QACtB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACpD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;gBAC1B,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;gBAC1B,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IACE,GAAG,CAAC,QAAQ,KAAK,SAAS;QAC1B,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,EACxE,CAAC;QACD,IAAI,GAAG,MAAM,CAAC;QACd,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC;QACpB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACpD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACtD,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBACzB,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IACE,GAAG,CAAC,QAAQ,KAAK,YAAY;QAC7B,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,YAAY,CAAC,EAC3E,CAAC;QACD,IAAI,GAAG,SAAS,CAAC;QACjB,KAAK,CAAC,IAAI,GAAG,UAAU,CAAC;IAC1B,CAAC;IAED,IACE,GAAG,CAAC,QAAQ,KAAK,SAAS;QAC1B,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,EACxE,CAAC;QACD,IAAI,GAAG,MAAM,CAAC;QACd,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC;IACvB,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,IAAU,EAAE,EAAE;IACpD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACnD,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,GAAG,KAAK,CAAC;SACrE,WAAW,EAAE;SACb,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,IAAU,EAAE,EAAE;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACnD,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,GAAG,KAAK,CAAC;SACrE,WAAW,EAAE;SACb,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC"}
|