@paragrav/rhf-utils 0.0.146 → 0.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.
package/README.md CHANGED
@@ -59,7 +59,7 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
59
59
  devTool: import.meta.env.DEV && { placement: 'top-right' },
60
60
  },
61
61
 
62
- // default form props
62
+ // global default native form props
63
63
  form: {
64
64
  noValidate: true,
65
65
  className: 'my-form-class',
@@ -88,7 +88,7 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
88
88
  // form-level control of your own hooks/behaviors via custom option props
89
89
  // (see "Extend RhfUtilsFormOptions" section for more info)
90
90
  useMyOptionalFormHook({
91
- enabled: !!options?.enableMyOptionalFormHook,
91
+ enabled: !!options.enableMyOptionalFormHook,
92
92
  });
93
93
 
94
94
  return (
@@ -161,7 +161,7 @@ Currently, only `zod` is supported.
161
161
  event, // SubmitEvent
162
162
  ) => {
163
163
  await loginService(data);
164
- props.onSuccess();
164
+ handleSuccess();
165
165
  }}
166
166
  // handle error declaratively (i.e., no throw/catch)
167
167
  onSubmitError={({
@@ -169,7 +169,7 @@ Currently, only `zod` is supported.
169
169
  context, // UseRhfUtilsFormOnSubmitErrorContext (id, ref, rhf context, utils options, `FormSubmitFieldErrors` from `onSubmitErrorUnknown`)
170
170
  event, // SubmitEvent
171
171
  }) => {
172
- props.onError(error);
172
+ handleError(error);
173
173
  }}
174
174
  // fields
175
175
  Children={({
@@ -193,6 +193,9 @@ Currently, only `zod` is supported.
193
193
  )}
194
194
  />
195
195
 
196
+ <button type="button" onClick={handleCancel}>
197
+ Cancel
198
+ </button>
196
199
  <button type="submit">Login</button>
197
200
  </>
198
201
  )}
@@ -217,12 +220,25 @@ Currently, only `zod` is supported.
217
220
 
218
221
  `Children` prop takes a component which is rendered as a child of the form (and, if supplied, of `RhfUtilsClientConfig.FormChildrenWrapper`). It receives `UseRhfUtilsFormChildrenProps` as props, including a type-safe `Controller` component.
219
222
 
220
- If you prefer to define your `Children` component as standalone:
223
+ If you prefer to define your `Children` component as standalone, you will need to specify any dependencies as `props` (e.g., `onCancel` callback):
221
224
 
222
225
  ```tsx
223
- const Children: RhfUtilsUseFormChildrenZodFC<typeof schema> = ({...}) => { };
226
+ const Children: RhfUtilsUseFormChildrenZodFC<typeof schema, { onCancel: () => void }> = ({...}) => {};
224
227
 
225
- function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema>) { }
228
+ function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema, { onCancel: () => void }>) {}
229
+ ```
230
+
231
+ And pass dependencies manually:
232
+
233
+ ```tsx
234
+ <RhfUtilsZodForm
235
+ Children={(rhfUtilsZodFormChildrenProps) => (
236
+ <Children
237
+ {...rhfUtilsZodFormChildrenProps}
238
+ props={{ onCancel: handleCancel }}
239
+ />
240
+ )}
241
+ />
226
242
  ```
227
243
 
228
244
  ## Form Component Hierarchy
@@ -1,28 +1,28 @@
1
- import { jsx as i, Fragment as B, jsxs as Z } from "react/jsx-runtime";
1
+ import { jsx as i, Fragment as Z, jsxs as L } from "react/jsx-runtime";
2
2
  import a from "react";
3
3
  import { c as C } from "./createContext.mjs";
4
- import { zodResolver as I } from "@hookform/resolvers/zod";
5
- import { useFormContext as b, Controller as L, get as z, useFormState as x, FormProvider as A, useForm as $ } from "react-hook-form";
6
- import { i as O, _ as H, u as g } from "./useFlatFieldErrorsContext.mjs";
7
- import { flatten as Q } from "flat";
4
+ import { zodResolver as z } from "@hookform/resolvers/zod";
5
+ import { useFormContext as b, Controller as I, get as A, useFormState as x, FormProvider as $, useForm as H } from "react-hook-form";
6
+ import { i as y, _ as Q, u as g } from "./useFlatFieldErrorsContext.mjs";
7
+ import { flatten as G } from "flat";
8
8
  const {
9
- Provider: G,
9
+ Provider: J,
10
10
  useMaybe: _
11
- } = C(), J = a.lazy(
11
+ } = C(), K = a.lazy(
12
12
  () => import("@hookform/devtools").then((r) => ({
13
13
  default: r.DevTool
14
14
  }))
15
- ), K = ({ enabled: r, props: t }) => {
15
+ ), X = ({ enabled: r, props: t }) => {
16
16
  if (!r) return null;
17
17
  const { control: e } = b();
18
- return /* @__PURE__ */ i(a.Suspense, { fallback: null, children: /* @__PURE__ */ i(J, { control: e, ...t }) });
18
+ return /* @__PURE__ */ i(a.Suspense, { fallback: null, children: /* @__PURE__ */ i(K, { control: e, ...t }) });
19
19
  };
20
20
  class F extends Error {
21
21
  constructor(t, e) {
22
22
  super(e), this.errors = t;
23
23
  }
24
24
  }
25
- const X = (r, t) => {
25
+ const Y = (r, t) => {
26
26
  Object.entries(t).forEach(([e, o]) => {
27
27
  r.setError(e, {
28
28
  type: "FormSubmitFieldError",
@@ -30,11 +30,11 @@ const X = (r, t) => {
30
30
  ...o
31
31
  });
32
32
  });
33
- }, Y = ({
33
+ }, rr = ({
34
34
  children: r
35
- }) => /* @__PURE__ */ i(B, { children: r });
36
- function rr(r) {
37
- return /* @__PURE__ */ i(L, { ...r });
35
+ }) => /* @__PURE__ */ i(Z, { children: r });
36
+ function O(r) {
37
+ return /* @__PURE__ */ i(I, { ...r });
38
38
  }
39
39
  function er({
40
40
  formId: r,
@@ -66,15 +66,15 @@ function er({
66
66
  },
67
67
  f
68
68
  ), P = (h, f) => {
69
- var y;
69
+ var R;
70
70
  const E = h instanceof F ? (
71
71
  // consumer can manually throw FormSubmitError (e.g., manual validation)
72
72
  h.errors
73
73
  ) : (
74
74
  // if error is not FormSubmitError, consumer can provide global handler
75
- (y = d == null ? void 0 : d.onSubmitErrorUnknown) == null ? void 0 : y.call(d, h)
75
+ (R = d == null ? void 0 : d.onSubmitErrorUnknown) == null ? void 0 : R.call(d, h)
76
76
  );
77
- E && X(m, E), o == null || o(
77
+ E && Y(m, E), o == null || o(
78
78
  h,
79
79
  {
80
80
  formId: r,
@@ -85,29 +85,36 @@ function er({
85
85
  },
86
86
  f
87
87
  );
88
- }, R = {
88
+ }, V = {
89
89
  formId: r,
90
90
  formRef: t,
91
91
  context: m,
92
92
  utils: u,
93
- Controller: rr,
93
+ Controller: O,
94
94
  FormSubmitError: F
95
- }, V = R, N = (d == null ? void 0 : d.FormComponent) ?? "form", q = (d == null ? void 0 : d.FormChildrenWrapper) ?? Y;
95
+ }, N = {
96
+ formId: r,
97
+ formRef: t,
98
+ context: m,
99
+ utils: u,
100
+ Controller: O,
101
+ FormSubmitError: F
102
+ }, q = (d == null ? void 0 : d.FormComponent) ?? "form", B = (d == null ? void 0 : d.FormChildrenWrapper) ?? rr;
96
103
  return /* @__PURE__ */ i(
97
- N,
104
+ q,
98
105
  {
99
106
  ...l,
100
107
  ref: t,
101
108
  onSubmit: (h) => void c(h),
102
- children: /* @__PURE__ */ Z(q, { ...V, children: [
109
+ children: /* @__PURE__ */ L(B, { ...N, children: [
103
110
  /* @__PURE__ */ i(
104
- K,
111
+ X,
105
112
  {
106
113
  enabled: !!(u != null && u.devTool),
107
114
  props: typeof (u == null ? void 0 : u.devTool) == "object" ? u.devTool : void 0
108
115
  }
109
116
  ),
110
- /* @__PURE__ */ i(n, { ...R })
117
+ /* @__PURE__ */ i(n, { ...V })
111
118
  ] })
112
119
  }
113
120
  );
@@ -149,7 +156,7 @@ const v = (r) => (t) => (
149
156
  ir(t)
150
157
  )(r), ar = ([r]) => j(r), mr = v(
151
158
  ar
152
- ), hr = (r) => Q(r), cr = (r) => {
159
+ ), hr = (r) => G(r), cr = (r) => {
153
160
  const t = hr(r), e = Object.keys(t);
154
161
  return Object.fromEntries(
155
162
  e.reduce(
@@ -159,7 +166,7 @@ const v = (r) => (t) => (
159
166
  ""
160
167
  );
161
168
  if (n === s) return o;
162
- const l = z(r, n, void 0);
169
+ const l = A(r, n, void 0);
163
170
  return l && o.push([n, l]), o;
164
171
  },
165
172
  []
@@ -176,10 +183,10 @@ const v = (r) => (t) => (
176
183
  roots: mr(o),
177
184
  orphans: s,
178
185
  // computed
179
- hasErrors: !O(e),
180
- hasOrphans: !O(s)
186
+ hasErrors: !y(e),
187
+ hasOrphans: !y(s)
181
188
  };
182
- return /* @__PURE__ */ i(H, { value: n, children: t });
189
+ return /* @__PURE__ */ i(Q, { value: n, children: t });
183
190
  }, br = (r, t, e, o = "debug") => {
184
191
  console[o](r, { values: t, errors: e });
185
192
  }, Er = (r) => {
@@ -311,7 +318,7 @@ function gr({
311
318
  utils: o,
312
319
  children: s
313
320
  }) {
314
- return /* @__PURE__ */ i(A, { ...e, children: /* @__PURE__ */ i(Fr, { formRef: t, children: /* @__PURE__ */ i(
321
+ return /* @__PURE__ */ i($, { ...e, children: /* @__PURE__ */ i(Fr, { formRef: t, children: /* @__PURE__ */ i(
315
322
  xr,
316
323
  {
317
324
  formId: r,
@@ -331,7 +338,7 @@ const w = ({
331
338
  form: l,
332
339
  utils: u
333
340
  }) => {
334
- const m = a.useId(), d = $({
341
+ const m = a.useId(), d = H({
335
342
  ...n,
336
343
  defaultValues: r
337
344
  }), c = a.useRef(null);
@@ -436,26 +443,26 @@ const _r = (r, ...t) => (
436
443
  }
437
444
  );
438
445
  };
439
- }, jr = kr(I), {
446
+ }, jr = kr(z), {
440
447
  Provider: wr,
441
448
  useRequired: D
442
- } = C(), Ir = ({
449
+ } = C(), Lr = ({
443
450
  config: r,
444
451
  children: t
445
452
  }) => {
446
453
  const [e] = a.useState(r), [o] = a.useState(
447
454
  () => jr(e ?? {})
448
455
  );
449
- return /* @__PURE__ */ i(G, { value: e, children: /* @__PURE__ */ i(wr, { value: o, children: t }) });
456
+ return /* @__PURE__ */ i(J, { value: e, children: /* @__PURE__ */ i(wr, { value: o, children: t }) });
450
457
  };
451
- function Lr({
458
+ function zr({
452
459
  schema: r,
453
460
  ...t
454
461
  }) {
455
462
  const { FormWithProviders: e } = D();
456
463
  return /* @__PURE__ */ i(e, { schema: r, ...t });
457
464
  }
458
- const zr = (r, t) => D().useForm(r, t), Ar = () => {
465
+ const Ir = (r, t) => D().useForm(r, t), Ar = () => {
459
466
  const r = g();
460
467
  return a.useMemo(() => !r.hasErrors || !r.hasOrphans ? !1 : Object.keys(r.orphans).length === Object.keys(r.all).length, [r]);
461
468
  }, $r = ({ path: r }) => {
@@ -474,11 +481,11 @@ const zr = (r, t) => D().useForm(r, t), Ar = () => {
474
481
  };
475
482
  export {
476
483
  F as FormSubmitError,
477
- Ir as RhfUtilsClientForZodContextProvider,
484
+ Lr as RhfUtilsClientForZodContextProvider,
478
485
  $r as RhfUtilsNonFieldErrorMarker,
479
- Lr as RhfUtilsZodForm,
486
+ zr as RhfUtilsZodForm,
480
487
  g as useFlatFieldErrorsContext,
481
488
  Ar as useFlatFieldErrorsContextHasOnlyOrphans,
482
489
  Zr as useRhfUtilsContext,
483
- zr as useRhfUtilsZodForm
490
+ Ir as useRhfUtilsZodForm
484
491
  };
@@ -67,4 +67,4 @@ export type RhfUtilsClientConfig = {
67
67
  /**
68
68
  * Non-schema-typed version of `UseRhfUtilsFormChildrenProps` for global config.
69
69
  */
70
- export type RhfUtilsFormChildrenWrapperProps = React.PropsWithChildren<UseRhfUtilsFormChildrenProps>;
70
+ export type RhfUtilsFormChildrenWrapperProps = React.PropsWithChildren<Pick<UseRhfUtilsFormChildrenProps, 'formId' | 'formRef' | 'context' | 'utils' | 'Controller' | 'FormSubmitError'>>;
@@ -1,25 +1,20 @@
1
1
  import { default as React } from 'react';
2
2
  import { Resolver } from 'react-hook-form';
3
3
  import { RhfUtilsClientConfig } from './config/RhfUtilsClientConfig';
4
- import { FormWithProvidersProps } from '../form/FormWithProviders';
5
4
  import { SafeFieldValues } from '../form/SafeFieldValues';
6
5
  import { UseRhfUtilsFormProps } from '../form/UseRhfUtilsFormProps';
7
6
  import { UseRhfUtilsFormReturn } from '../form/UseRhfUtilsFormReturn';
8
7
  /**
9
8
  * Generic object schema type.
10
9
  */
11
- export type ObjectSchema<TInputKey extends string, TOutputKey extends string> = {
12
- [key in TInputKey]: SafeFieldValues;
13
- } & {
14
- [key in TOutputKey]: SafeFieldValues;
15
- };
10
+ export type ObjectSchema<TInputKey extends string, TOutputKey extends string> = Record<TInputKey, SafeFieldValues> & Record<TOutputKey, SafeFieldValues>;
16
11
  export type CreateRhfUtilsClient<TObjectSchema extends ObjectSchema<TObjectSchemaInputKey, TObjectSchemaOutputKey>, TObjectSchemaInputKey extends string, TObjectSchemaOutputKey extends string> = {
17
12
  useForm: <TSchema extends TObjectSchema, TSchemaInput extends SafeFieldValues = TSchema[TObjectSchemaInputKey], TSchemaOutput extends SafeFieldValues = TSchema[TObjectSchemaOutputKey]>(schema: TSchema, form: UseRhfUtilsFormProps<TSchemaInput, TSchemaOutput>) => UseRhfUtilsFormReturn<TSchemaInput, TSchemaOutput> & {
18
13
  FormWithProviders: React.FC<React.PropsWithChildren>;
19
14
  };
20
- FormWithProviders: <TSchema extends TObjectSchema, TSchemaInput extends SafeFieldValues = TSchema[TObjectSchemaInputKey], TSchemaOutput extends SafeFieldValues = TSchema[TObjectSchemaOutputKey]>(props: {
15
+ FormWithProviders: <TSchema extends TObjectSchema, TSchemaInput extends SafeFieldValues = TSchema[TObjectSchemaInputKey], TSchemaOutput extends SafeFieldValues = TSchema[TObjectSchemaOutputKey]>(props: React.PropsWithChildren<{
21
16
  schema: TSchema;
22
- } & FormWithProvidersProps<TSchemaInput, TSchemaOutput>) => JSX.Element;
17
+ } & UseRhfUtilsFormProps<TSchemaInput, TSchemaOutput>>) => JSX.Element;
23
18
  };
24
19
  /**
25
20
  * ...
@@ -9,4 +9,4 @@ import { ZodTypeFieldValues } from './ZodTypeFieldValues';
9
9
  * const Children: RhfUtilsUseFormChildrenZodFC<typeof schema> = () => {};
10
10
  * ```
11
11
  */
12
- export type RhfUtilsUseFormChildrenZodFC<TSchema extends ZodTypeFieldValues> = React.FC<RhfUtilsUseFormChildrenZodProps<TSchema>>;
12
+ export type RhfUtilsUseFormChildrenZodFC<TSchema extends ZodTypeFieldValues, TChildrenProps> = React.FC<RhfUtilsUseFormChildrenZodProps<TSchema, TChildrenProps>>;
@@ -1,4 +1,4 @@
1
1
  import { UseRhfUtilsFormChildrenProps } from '../../form/UseRhfUtilsFormChildrenProps';
2
2
  import { zodTypeInput, zodTypeOutput } from './consts';
3
3
  import { ZodTypeFieldValues } from './ZodTypeFieldValues';
4
- export type RhfUtilsUseFormChildrenZodProps<TSchema extends ZodTypeFieldValues> = UseRhfUtilsFormChildrenProps<TSchema[typeof zodTypeInput], TSchema[typeof zodTypeOutput]>;
4
+ export type RhfUtilsUseFormChildrenZodProps<TSchema extends ZodTypeFieldValues, TChildrenProps = undefined> = UseRhfUtilsFormChildrenProps<TSchema[typeof zodTypeInput], TSchema[typeof zodTypeOutput], TChildrenProps>;
@@ -1,6 +1,6 @@
1
1
  import { SafeFieldValues } from './SafeFieldValues';
2
2
  import { UseRhfUtilsFormProps } from './UseRhfUtilsFormProps';
3
- export type FormWithProvidersProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = React.PropsWithChildren<UseRhfUtilsFormProps<TFieldValues, TTransformedValues>>;
3
+ type Props<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = React.PropsWithChildren<UseRhfUtilsFormProps<TFieldValues, TTransformedValues>>;
4
4
  /**
5
5
  * Form providers (with utils) with immediate descendent {@link Form}.
6
6
  * (Syntactic sugar for {@link useRhfUtilsForm}. Use this for most applications.)
@@ -8,5 +8,5 @@ export type FormWithProvidersProps<TFieldValues extends SafeFieldValues, TTransf
8
8
  * Use {@link useRhfUtilsForm} if you need to specific nesting hierarchy.
9
9
  * (e.g., wrapping `<tr>` with provider and nesting `<form>` within `<td>` to appease HTML rules.)
10
10
  */
11
- declare function FormWithProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>(props: FormWithProvidersProps<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
11
+ declare function FormWithProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>(props: Props<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
12
12
  export default FormWithProviders;
@@ -9,11 +9,15 @@ import { SafeFieldValues } from './SafeFieldValues';
9
9
  *
10
10
  * Consider keeping shape in line with `UseRhfUtilsFormOnSubmitProps` and `UseRhfUtilsFormReturn`.
11
11
  */
12
- export type UseRhfUtilsFormChildrenProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = SafeFieldValues> = {
12
+ export type UseRhfUtilsFormChildrenProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = SafeFieldValues, TProps = undefined> = {
13
13
  formId: string;
14
14
  formRef: React.RefObject<HTMLFormElement>;
15
15
  context: UseFormReturn<TFieldValues, unknown, TTransformedValues>;
16
16
  utils?: RhfUtilsFormOptions;
17
17
  Controller: typeof _Controller<TFieldValues>;
18
18
  FormSubmitError: typeof FormSubmitError<TFieldValues>;
19
- };
19
+ } & (TProps extends undefined ? {
20
+ props?: undefined;
21
+ } : {
22
+ props: TProps;
23
+ });
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@paragrav/rhf-utils",
3
3
  "author": "paragrav.dev",
4
4
  "license": "MIT",
5
- "version": "0.0.146",
5
+ "version": "0.1.0",
6
6
  "description": "Integration utilities for react-hook-form.",
7
7
  "type": "module",
8
8
  "sideEffects": false,
@@ -37,6 +37,23 @@
37
37
  }
38
38
  }
39
39
  },
40
+ "scripts": {
41
+ "build": "vite build",
42
+ "build:dev": "vite build --config vite.config.dev.ts",
43
+ "dev": "vite --config vite.config.dev.ts --force",
44
+ "lint": "eslint --ignore-path ./.gitignore --ext ts,tsx --report-unused-disable-directives --max-warnings 0 .",
45
+ "postpack": "clean-package restore",
46
+ "preinstall": "npx only-allow pnpm",
47
+ "prepack": "clean-package",
48
+ "prepare": "husky",
49
+ "prepublishOnly": "pnpm build",
50
+ "preview": "vite preview --config vite.config.dev.ts",
51
+ "test": "vitest run",
52
+ "test:ct": "playwright test -c playwright-ct.config.ts",
53
+ "test:ct:ui": "playwright test -c playwright-ct.config.ts --ui",
54
+ "tsc": "tsc",
55
+ "validate": "cross-env CI=1 pnpm install && pnpm tsc && pnpm lint && pnpm test && pnpm test:ct"
56
+ },
40
57
  "peerDependencies": {
41
58
  "@hookform/devtools": "4",
42
59
  "@hookform/resolvers": "3",
@@ -48,7 +65,43 @@
48
65
  "react-hook-form": "7",
49
66
  "zod": "3"
50
67
  },
68
+ "devDependencies": {
69
+ "@playwright/experimental-ct-react": "^1.48.2",
70
+ "@playwright/test": "^1.48.2",
71
+ "@rollup/plugin-typescript": "^12.1.1",
72
+ "@types/node": "^20.17.6",
73
+ "@types/react": "^18.3.12",
74
+ "@types/react-dom": "^18.3.1",
75
+ "@typescript-eslint/eslint-plugin": "^8.13.0",
76
+ "@typescript-eslint/parser": "^8.13.0",
77
+ "@vitejs/plugin-react": "^4.3.3",
78
+ "clean-package": "^2.2.0",
79
+ "cross-env": "^7.0.3",
80
+ "eslint": "^8.57.1",
81
+ "eslint-config-prettier": "^9.1.0",
82
+ "eslint-import-resolver-typescript": "^3.6.3",
83
+ "eslint-plugin-import": "^2.31.0",
84
+ "eslint-plugin-react": "^7.37.2",
85
+ "eslint-plugin-react-hooks": "^4.6.2",
86
+ "eslint-plugin-simple-import-sort": "^12.1.1",
87
+ "happy-dom": "^15.11.0",
88
+ "husky": "^9.1.6",
89
+ "lint-staged": "^15.2.10",
90
+ "prettier": "^3.3.3",
91
+ "rollup": "^4.24.4",
92
+ "terser": "^5.36.0",
93
+ "typescript": "^5.6.3",
94
+ "vite": "^5.4.10",
95
+ "vite-plugin-dts": "^4.3.0",
96
+ "vite-tsconfig-paths": "^5.1.0",
97
+ "vitest": "^2.1.4"
98
+ },
51
99
  "resolutions": {},
100
+ "engines": {
101
+ "node": ">=20.14",
102
+ "pnpm": ">=9.12.2"
103
+ },
104
+ "packageManager": "pnpm@9.12.2",
52
105
  "repository": {
53
106
  "type": "git",
54
107
  "url": "git+https://github.com/paragrav/rhf-utils.git"
@@ -67,4 +120,4 @@
67
120
  "utils",
68
121
  "zod"
69
122
  ]
70
- }
123
+ }