@react-fabric/form 1.0.0-beta.47 → 1.0.0-beta.49

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 (65) hide show
  1. package/dist/cjs/builder/FormField.js +7 -1
  2. package/dist/cjs/builder/components/SchemaField.js +2 -1
  3. package/dist/cjs/input/AvatarInput.js +8 -7
  4. package/dist/cjs/input/DateInput.js +2 -4
  5. package/dist/cjs/input/File.js +1 -3
  6. package/dist/cjs/input/Input.js +2 -4
  7. package/dist/cjs/input/Number.js +1 -3
  8. package/dist/cjs/input/Password.js +1 -3
  9. package/dist/cjs/input/Search.js +3 -5
  10. package/dist/cjs/input/Switch.js +2 -1
  11. package/dist/cjs/input/Textarea.js +4 -3
  12. package/dist/cjs/internal/FieldWrapper.js +6 -0
  13. package/dist/cjs/select/AutoComplete.js +3 -2
  14. package/dist/cjs/select/List.js +3 -1
  15. package/dist/cjs/select/Select.js +3 -1
  16. package/dist/cjs/select/useSelect.js +2 -1
  17. package/dist/cjs/types/schema.js +1 -0
  18. package/dist/cjs/utils/eventHandlers.js +11 -5
  19. package/dist/esm/builder/FormField.js +7 -1
  20. package/dist/esm/builder/components/SchemaField.js +2 -1
  21. package/dist/esm/input/AvatarInput.js +8 -7
  22. package/dist/esm/input/DateInput.js +3 -5
  23. package/dist/esm/input/File.js +3 -5
  24. package/dist/esm/input/Input.js +4 -6
  25. package/dist/esm/input/Number.js +3 -5
  26. package/dist/esm/input/Password.js +3 -5
  27. package/dist/esm/input/Search.js +5 -7
  28. package/dist/esm/input/Switch.js +2 -1
  29. package/dist/esm/input/Textarea.js +5 -4
  30. package/dist/esm/internal/FieldWrapper.js +6 -0
  31. package/dist/esm/select/AutoComplete.js +3 -2
  32. package/dist/esm/select/List.js +3 -1
  33. package/dist/esm/select/Select.js +3 -1
  34. package/dist/esm/select/useSelect.js +2 -1
  35. package/dist/esm/types/schema.js +1 -0
  36. package/dist/esm/utils/eventHandlers.js +11 -5
  37. package/dist/types/form/Form.d.ts +5 -1
  38. package/dist/types/input/AvatarInput.d.ts +6 -3
  39. package/dist/types/internal/FieldWrapper.d.ts +1 -1
  40. package/dist/types/select/List.d.ts +1 -1
  41. package/dist/types/select/Select.d.ts +1 -1
  42. package/dist/types/select/useSelect.d.ts +2 -1
  43. package/dist/types/types/index.d.ts +4 -0
  44. package/dist/types/types/schema.d.ts +2 -2
  45. package/dist/types/utils/eventHandlers.d.ts +1 -1
  46. package/package.json +9 -9
  47. package/src/builder/FormField.tsx +8 -1
  48. package/src/builder/components/SchemaField.tsx +2 -1
  49. package/src/form/Form.tsx +7 -1
  50. package/src/input/AvatarInput.tsx +11 -7
  51. package/src/input/DateInput.tsx +3 -6
  52. package/src/input/File.tsx +2 -6
  53. package/src/input/Input.tsx +3 -7
  54. package/src/input/Number.tsx +2 -6
  55. package/src/input/Password.tsx +2 -6
  56. package/src/input/Search.tsx +4 -8
  57. package/src/input/Textarea.tsx +6 -4
  58. package/src/internal/FieldWrapper.tsx +4 -0
  59. package/src/select/AutoComplete.tsx +1 -0
  60. package/src/select/List.tsx +2 -0
  61. package/src/select/Select.tsx +2 -0
  62. package/src/select/useSelect.tsx +4 -1
  63. package/src/types/index.ts +4 -0
  64. package/src/types/schema.ts +2 -2
  65. package/src/utils/eventHandlers.ts +9 -3
@@ -28,14 +28,13 @@ import {
28
28
  useCallback,
29
29
  useDeferredValue,
30
30
  useEffect,
31
- useMemo,
32
31
  useRef,
33
32
  useState,
34
33
  type ChangeEvent,
35
34
  } from "react";
36
35
  import { InputWrapper } from "../internal/InputWrapper";
37
36
  import { type InputProps } from "../types";
38
- import { handleEnter } from "../utils";
37
+ import { useHandleEnter } from "../utils";
39
38
 
40
39
  export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
41
40
  /**
@@ -87,10 +86,7 @@ export const Search = ({
87
86
  250,
88
87
  );
89
88
 
90
- const handleEnterPressed = useMemo(
91
- () => handleEnter(handleSearch),
92
- [handleSearch],
93
- );
89
+ const handleEnterPressed = useHandleEnter(handleSearch);
94
90
 
95
91
  useEffect(() => {
96
92
  setActualValue(deferred ?? "");
@@ -103,8 +99,8 @@ export const Search = ({
103
99
  setActualValue(value ?? "");
104
100
  onChange?.(value ?? null);
105
101
 
106
- // value was cleared so force fire onSearch
107
- if (searchOnChange) {
102
+ // when e is undefined value was cleared so force fire onSearch
103
+ if (!e || searchOnChange) {
108
104
  handleSearch();
109
105
  }
110
106
  },
@@ -32,7 +32,7 @@ import {
32
32
  } from "react";
33
33
  import { InputWrapper } from "../internal/InputWrapper";
34
34
  import { type InputProps } from "../types";
35
- import { handleEnter } from "../utils";
35
+ import { useHandleEnter } from "../utils";
36
36
 
37
37
  export interface TextareaProps
38
38
  extends InputProps,
@@ -102,6 +102,10 @@ export const Textarea = ({
102
102
  }
103
103
  }, [actualValue, variableRows, rows, maxRows]);
104
104
 
105
+ const handleEnterPressed = useHandleEnter(onEnterPressed, {
106
+ preventDefault: !!onEnterPressed,
107
+ });
108
+
105
109
  return (
106
110
  <InputWrapper
107
111
  showClear={!!actualValue && !disabled && !readOnly}
@@ -133,9 +137,7 @@ export const Textarea = ({
133
137
  onBlur={onBlur}
134
138
  onFocus={onFocus}
135
139
  onChange={handleChange}
136
- onKeyDown={handleEnter(onEnterPressed, {
137
- preventDefault: !!onEnterPressed,
138
- })}
140
+ onKeyDown={handleEnterPressed}
139
141
  />
140
142
  </InputWrapper>
141
143
  );
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  import classNames from "classnames";
25
+ import { ErrorIcon } from "./ErrorIcon";
25
26
 
26
27
  export const FieldWrapper = ({
27
28
  label,
@@ -35,6 +36,8 @@ export const FieldWrapper = ({
35
36
  children,
36
37
  listing,
37
38
  className,
39
+ invalid,
40
+ error,
38
41
  "data-inner": isInner,
39
42
  }: KeyValue) => {
40
43
  return (
@@ -72,6 +75,7 @@ export const FieldWrapper = ({
72
75
  ✽
73
76
  </span>
74
77
  )}
78
+ <ErrorIcon invalid={invalid} error={error} />
75
79
  <div className="flex-1" />
76
80
  {appendLabel && <span className="flex-content">{appendLabel}</span>}
77
81
  </div>
@@ -293,6 +293,7 @@ export const AutoComplete = ({
293
293
  data-testid={name}
294
294
  name={name}
295
295
  size={1}
296
+ ref={ref}
296
297
  onInput={onInput}
297
298
  autoFocus={autoFocus}
298
299
  rows={!multiple && expandOnEdit && state.open ? 5 : 1}
@@ -53,6 +53,7 @@ export const List = <T extends AnyObject = string>({
53
53
  groupProperty,
54
54
  labelProperty,
55
55
  valueProperty,
56
+ sortProperty,
56
57
  multiple,
57
58
  allowCreate,
58
59
  searchable,
@@ -100,6 +101,7 @@ export const List = <T extends AnyObject = string>({
100
101
  groupProperty,
101
102
  labelProperty,
102
103
  valueProperty,
104
+ sortProperty,
103
105
  allowCreate,
104
106
  createOption,
105
107
  matcher,
@@ -61,6 +61,7 @@ export const Select = <T extends AnyObject = string>({
61
61
  groupProperty,
62
62
  labelProperty = "label" as AnyObject,
63
63
  valueProperty = "id" as AnyObject,
64
+ sortProperty,
64
65
  multiple,
65
66
  searchable,
66
67
  allowCreate,
@@ -93,6 +94,7 @@ export const Select = <T extends AnyObject = string>({
93
94
  groupProperty,
94
95
  labelProperty,
95
96
  valueProperty,
97
+ sortProperty,
96
98
  allowCreate,
97
99
  createOption,
98
100
  matcher,
@@ -83,6 +83,7 @@ export const useSelect = ({
83
83
  groupProperty = "",
84
84
  valueProperty = "id",
85
85
  labelProperty = "label",
86
+ sortProperty,
86
87
  createOption = makeOption,
87
88
  matcher,
88
89
  onQuery,
@@ -97,6 +98,7 @@ export const useSelect = ({
97
98
  groupProperty?: AnyObject;
98
99
  valueProperty?: AnyObject;
99
100
  labelProperty?: AnyObject;
101
+ sortProperty?: AnyObject;
100
102
  autoComplete?: boolean;
101
103
  matcher?: (item: AnyObject, query: string) => boolean;
102
104
  createOption?: (query: string) => AnyObject;
@@ -226,7 +228,8 @@ export const useSelect = ({
226
228
  if (autoComplete && action.query !== undefined) {
227
229
  optionList = dedupe([action.query, ...optionList]);
228
230
  }
229
- optionList = optionList.sort(compareValues("asc", labelProperty));
231
+ if (sortProperty)
232
+ optionList = optionList.sort(compareValues("asc", sortProperty));
230
233
  const grouped = groupBy(optionList, groupProperty, "");
231
234
  if (action.open) newState.open = true;
232
235
  newState.items = [];
@@ -150,6 +150,10 @@ export interface BaseSelectProps<T extends AnyObject = string> {
150
150
  * value property name
151
151
  */
152
152
  valueProperty?: keyof T;
153
+ /**
154
+ * value property name
155
+ */
156
+ sortProperty?: keyof T | true;
153
157
  /**
154
158
  * searchable list
155
159
  */
@@ -29,6 +29,7 @@ export enum DATA_TYPES {
29
29
  COLOR = "color",
30
30
  BOOL = "bool",
31
31
  DATE = "date",
32
+ DATETIME = "datetime",
32
33
  STRING = "string",
33
34
  NUMBER = "number",
34
35
  RANGE = "range",
@@ -84,8 +85,7 @@ export interface RangeSchema extends BaseSchema {
84
85
  }
85
86
 
86
87
  export interface DateSchema extends BaseSchema {
87
- datatype: DATA_TYPES.DATE;
88
- type?: "date" | "datetime";
88
+ datatype: DATA_TYPES.DATE | DATA_TYPES.DATETIME;
89
89
  min?: DateLike;
90
90
  max?: DateLike;
91
91
  }
@@ -23,19 +23,25 @@
23
23
 
24
24
  /* istanbul ignore file */
25
25
 
26
- import { debounce } from "@react-fabric/utilities";
26
+ import { useFloatingTree } from "@floating-ui/react";
27
+ import { useDebounce } from "@react-fabric/core";
27
28
  import { type KeyboardEvent, type MouseEvent } from "react";
28
29
 
29
30
  /** ***************** common handler for enter press *******************/
30
- export const handleEnter = (
31
+ export const useHandleEnter = (
31
32
  callback?: (e: KeyboardEvent) => void,
32
33
  {
33
34
  stopPropagation = false,
34
35
  preventDefault = false,
35
36
  }: { stopPropagation?: boolean; preventDefault?: boolean } = {},
36
37
  ) => {
37
- const cbHandle = debounce(callback ?? (() => undefined), 100);
38
+ const cbHandle = useDebounce(callback ?? (() => undefined), [callback], 100);
39
+ const tree = useFloatingTree();
38
40
  return (e: KeyboardEvent) => {
41
+ // prevent propagation of event if input within dropdown (work around for floating-ui typeahead)
42
+ if (tree && e.key !== "Escape") {
43
+ e?.stopPropagation();
44
+ }
39
45
  if (
40
46
  !e.shiftKey &&
41
47
  !e.altKey &&