@contember/react-form 1.3.0-alpha.24 → 1.3.0-alpha.26

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 (50) hide show
  1. package/dist/development/components/FormCheckbox.cjs +6 -6
  2. package/dist/development/components/FormCheckbox.cjs.map +1 -1
  3. package/dist/development/components/FormCheckbox.js +6 -6
  4. package/dist/development/components/FormCheckbox.js.map +1 -1
  5. package/dist/development/components/FormInput.cjs +4 -4
  6. package/dist/development/components/FormInput.cjs.map +1 -1
  7. package/dist/development/components/FormInput.js +4 -4
  8. package/dist/development/components/FormInput.js.map +1 -1
  9. package/dist/development/hooks/useFormInputValidationHandler.cjs +15 -8
  10. package/dist/development/hooks/useFormInputValidationHandler.cjs.map +1 -1
  11. package/dist/development/hooks/useFormInputValidationHandler.js +15 -8
  12. package/dist/development/hooks/useFormInputValidationHandler.js.map +1 -1
  13. package/dist/development/internal/useFormInputHandler.cjs +22 -25
  14. package/dist/development/internal/useFormInputHandler.cjs.map +1 -1
  15. package/dist/development/internal/useFormInputHandler.js +22 -25
  16. package/dist/development/internal/useFormInputHandler.js.map +1 -1
  17. package/dist/production/components/FormCheckbox.cjs +5 -5
  18. package/dist/production/components/FormCheckbox.cjs.map +1 -1
  19. package/dist/production/components/FormCheckbox.js +5 -5
  20. package/dist/production/components/FormCheckbox.js.map +1 -1
  21. package/dist/production/components/FormInput.cjs +2 -2
  22. package/dist/production/components/FormInput.cjs.map +1 -1
  23. package/dist/production/components/FormInput.js +2 -2
  24. package/dist/production/components/FormInput.js.map +1 -1
  25. package/dist/production/hooks/useFormInputValidationHandler.cjs +15 -8
  26. package/dist/production/hooks/useFormInputValidationHandler.cjs.map +1 -1
  27. package/dist/production/hooks/useFormInputValidationHandler.js +15 -8
  28. package/dist/production/hooks/useFormInputValidationHandler.js.map +1 -1
  29. package/dist/production/internal/useFormInputHandler.cjs +22 -25
  30. package/dist/production/internal/useFormInputHandler.cjs.map +1 -1
  31. package/dist/production/internal/useFormInputHandler.js +22 -25
  32. package/dist/production/internal/useFormInputHandler.js.map +1 -1
  33. package/dist/types/components/FormError.d.ts.map +1 -1
  34. package/dist/types/components/FormInput.d.ts +3 -0
  35. package/dist/types/components/FormInput.d.ts.map +1 -1
  36. package/dist/types/hooks/useFormInputValidationHandler.d.ts.map +1 -1
  37. package/dist/types/index.d.ts +1 -0
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/internal/useFormInputHandler.d.ts +2 -6
  40. package/dist/types/internal/useFormInputHandler.d.ts.map +1 -1
  41. package/dist/types/tsconfig.tsbuildinfo +1 -1
  42. package/dist/types/types/index.d.ts +7 -0
  43. package/dist/types/types/index.d.ts.map +1 -0
  44. package/package.json +8 -8
  45. package/src/components/FormCheckbox.tsx +5 -5
  46. package/src/components/FormInput.tsx +5 -2
  47. package/src/hooks/useFormInputValidationHandler.tsx +23 -8
  48. package/src/index.ts +1 -0
  49. package/src/internal/useFormInputHandler.ts +26 -31
  50. package/src/types/index.ts +7 -0
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ export type FormInputHandler = {
3
+ parseValue: (value: string) => any;
4
+ formatValue: (value: any) => string;
5
+ defaultInputProps?: React.InputHTMLAttributes<HTMLInputElement>;
6
+ };
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,MAAM,MAAM,gBAAgB,GAAG;IAC9B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;IAClC,WAAW,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAA;IACnC,iBAAiB,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAA;CAC/D,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contember/react-form",
3
3
  "license": "Apache-2.0",
4
- "version": "1.3.0-alpha.24",
4
+ "version": "1.3.0-alpha.26",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/production/index.js",
@@ -40,18 +40,18 @@
40
40
  "directory": "packages/react-form"
41
41
  },
42
42
  "dependencies": {
43
- "@contember/react-binding": "1.3.0-alpha.24",
44
- "@contember/react-utils": "1.3.0-alpha.24",
45
- "@contember/utilities": "1.3.0-alpha.24",
43
+ "@contember/react-binding": "1.3.0-alpha.26",
44
+ "@contember/react-utils": "1.3.0-alpha.26",
45
+ "@contember/utilities": "1.3.0-alpha.26",
46
46
  "@radix-ui/react-slot": "^1.0.2"
47
47
  },
48
48
  "peerDependencies": {
49
- "react": "^17 || ^18",
50
- "react-dom": "^17 || ^18"
49
+ "react": "^18 || ^19",
50
+ "react-dom": "^18 || ^19"
51
51
  },
52
52
  "devDependencies": {
53
- "react": "^18.2.0",
54
- "react-dom": "^18.2.0"
53
+ "react": "^18.3.1",
54
+ "react-dom": "^18.3.1"
55
55
  },
56
56
  "stableVersion": "0.0.0"
57
57
  }
@@ -28,15 +28,15 @@ export const FormCheckbox = Component<FormCheckboxProps>(({ field, isNonbearing,
28
28
  if (!checkboxRef) {
29
29
  return
30
30
  }
31
- (ref as any).current = checkboxRef
32
- if (value === null) {
33
- checkboxRef.indeterminate = true
34
- }
31
+ checkboxRef.indeterminate = value === null
35
32
  }, [checkboxRef, ref, value])
36
33
 
37
34
  return (
38
35
  <SlotInput
39
- ref={setCheckboxRef}
36
+ ref={it => {
37
+ (ref as any).current = checkboxRef
38
+ setCheckboxRef(it)
39
+ }}
40
40
  type="checkbox"
41
41
  checked={accessor.value === true}
42
42
  data-state={value === null ? 'indeterminate' : (value ? 'checked' : 'unchecked')}
@@ -6,6 +6,7 @@ import { dataAttribute } from '@contember/utilities'
6
6
  import { useFormInputHandler } from '../internal/useFormInputHandler'
7
7
  import { useFormError, useFormFieldId } from '../contexts'
8
8
  import { useFormInputValidationHandler } from '../hooks/useFormInputValidationHandler'
9
+ import { FormInputHandler } from '../types'
9
10
 
10
11
  type InputProps = React.JSX.IntrinsicElements['input']
11
12
  const SlotInput = Slot as ComponentType<InputProps>
@@ -15,13 +16,15 @@ export interface FormInputProps {
15
16
  isNonbearing?: boolean
16
17
  defaultValue?: OptionallyVariableFieldValue
17
18
  children: React.ReactElement
19
+ formatValue?: FormInputHandler['formatValue']
20
+ parseValue?: FormInputHandler['parseValue']
18
21
  }
19
22
 
20
- export const FormInput = Component<FormInputProps>(({ field, isNonbearing, defaultValue, ...props }) => {
23
+ export const FormInput = Component<FormInputProps>(({ field, isNonbearing, defaultValue, formatValue: formatValueIn, parseValue: parseValueIn, ...props }) => {
21
24
  const id = useFormFieldId()
22
25
  const accessor = useField(field)
23
26
  const errors = useFormError() ?? accessor.errors?.errors ?? []
24
- const { parseValue, formatValue, defaultInputProps } = useFormInputHandler(accessor)
27
+ const { parseValue, formatValue, defaultInputProps } = useFormInputHandler(accessor, { formatValue: formatValueIn, parseValue: parseValueIn })
25
28
  const accessorGetter = accessor.getAccessor
26
29
  const { ref, onFocus, onBlur } = useFormInputValidationHandler(accessor)
27
30
 
@@ -17,17 +17,32 @@ export const useFormInputValidationHandler = (field: FieldAccessor<any>) => {
17
17
  if (!inputRef.current) {
18
18
  return
19
19
  }
20
+
20
21
  const input = inputRef.current
21
22
  const valid = input.validity?.valid
23
+
22
24
  const message = valid ? undefined : input?.validationMessage
23
- if (message !== validationMessage.current) {
24
- validationMessage.current = message
25
- if (!message || !focus) {
26
- accessorGetter().clearErrors()
27
- }
28
- if (!focus && message) {
29
- accessorGetter().addError(message)
30
- }
25
+ const previousMessage = validationMessage.current
26
+ validationMessage.current = message
27
+
28
+ // if there is no message, we want to clear the error
29
+ if (!message) {
30
+ accessorGetter().clearErrors()
31
+ return
32
+ }
33
+ if (message === previousMessage) {
34
+ return
35
+ }
36
+ // if the input is not touched, we don't want to show the error message
37
+ if (!field.isTouched) {
38
+ return
39
+ }
40
+
41
+ // if the input is not focused, we want to show the error message
42
+ // also, even the input is focused, we want to replace the previous message
43
+ if (!focus || !!previousMessage) {
44
+ accessorGetter().clearErrors()
45
+ accessorGetter().addError(message)
31
46
  }
32
47
  })
33
48
 
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './components'
2
2
  export * from './hooks'
3
3
  export * from './contexts'
4
+ export * from './types'
@@ -1,26 +1,35 @@
1
1
  import { FieldAccessor, SchemaColumn, SchemaKnownColumnType } from '@contember/react-binding'
2
- import * as React from 'react'
3
2
  import { useMemo } from 'react'
3
+ import { FormInputHandler } from '../types'
4
4
 
5
- export const useFormInputHandler = (field: FieldAccessor) => {
5
+ export const useFormInputHandler = (field: FieldAccessor, { formatValue, parseValue }: Partial<FormInputHandler>): FormInputHandler => {
6
6
  return useMemo(() => {
7
7
  const schema = field.schema
8
8
  const columnType = schema.type
9
- const handlerFactory = ColumnTypeHandlerFactories[columnType as SchemaKnownColumnType]
10
- if (!handlerFactory) {
11
- throw new Error(`Column type ${columnType} is not supported yet`)
9
+ const handlerFactory = ColumnTypeHandlerFactories[columnType as SchemaKnownColumnType] ?? defaultHandlerFactory
10
+ const handler = handlerFactory(schema, field.getAccessor)
11
+ return {
12
+ defaultInputProps: handler.defaultInputProps,
13
+ formatValue: formatValue ?? handler.formatValue,
14
+ parseValue: parseValue ?? handler.parseValue,
12
15
  }
13
- return handlerFactory(schema, field.getAccessor)
14
- }, [field.getAccessor, field.schema])
16
+ }, [field.getAccessor, field.schema, formatValue, parseValue])
15
17
  }
16
18
 
17
- type ColumnTypeHandlerFactory = (column: SchemaColumn, getAccessor: FieldAccessor.GetFieldAccessor) => {
18
- parseValue: (value: string) => any
19
- formatValue: (value: any) => string
20
- defaultInputProps?: React.InputHTMLAttributes<HTMLInputElement>
21
- }
19
+ type ColumnTypeHandlerFactory = (column: SchemaColumn, getAccessor: FieldAccessor.GetFieldAccessor) => FormInputHandler
20
+
21
+ const defaultHandlerFactory: ColumnTypeHandlerFactory = (schema, field) => ({
22
+ parseValue: (value: string) => {
23
+ if (value === '' && schema.nullable && field().valueOnServer === null) {
24
+ return null
25
+ }
26
+ return value
27
+ },
28
+ formatValue: (value: string | null) => value ?? '',
29
+ })
22
30
 
23
- const ColumnTypeHandlerFactories: Record<SchemaKnownColumnType, ColumnTypeHandlerFactory> = {
31
+ const ColumnTypeHandlerFactories: Record<SchemaKnownColumnType, ColumnTypeHandlerFactory | undefined> = {
32
+ String: defaultHandlerFactory,
24
33
  Integer: () => ({
25
34
  parseValue: (value: string) => {
26
35
  if (value === '') {
@@ -51,15 +60,7 @@ const ColumnTypeHandlerFactories: Record<SchemaKnownColumnType, ColumnTypeHandle
51
60
  type: 'number',
52
61
  },
53
62
  }),
54
- String: (schema, field) => ({
55
- parseValue: (value: string) => {
56
- if (value === '' && schema.nullable && field().valueOnServer === null) {
57
- return null
58
- }
59
- return value
60
- },
61
- formatValue: (value: string | null) => value ?? '',
62
- }),
63
+
63
64
  Date: () => ({
64
65
  parseValue: (value: string) => {
65
66
  if (value === '') {
@@ -93,15 +94,9 @@ const ColumnTypeHandlerFactories: Record<SchemaKnownColumnType, ColumnTypeHandle
93
94
  type: 'datetime-local',
94
95
  },
95
96
  }),
96
- Bool: () => {
97
- throw new Error('Boolean column type is not supported yet')
98
- },
99
- Enum: () => {
100
- throw new Error('Enum column type is not supported yet')
101
- },
102
- Uuid: () => {
103
- throw new Error('UUID column type is not supported yet')
104
- },
97
+ Bool: undefined,
98
+ Enum: undefined,
99
+ Uuid: undefined,
105
100
  }
106
101
 
107
102
  const toLocalDate = (date: Date) => {
@@ -0,0 +1,7 @@
1
+ import * as React from 'react'
2
+
3
+ export type FormInputHandler = {
4
+ parseValue: (value: string) => any
5
+ formatValue: (value: any) => string
6
+ defaultInputProps?: React.InputHTMLAttributes<HTMLInputElement>
7
+ }