@react-fabric/form 1.0.0-beta.6 → 1.0.0-beta.60
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/{src/input/ArrayInput.module.css → css/_arrayInput.css} +8 -8
- package/css/_colorPicker.css +65 -0
- package/{src/internal/Field.module.css → css/_field.css} +66 -30
- package/{src/input/File.module.css → css/_file.css} +21 -6
- package/css/styles.css +27 -0
- package/dist/cjs/builder/FileField.js +40 -28
- package/dist/cjs/builder/FormField.js +50 -34
- package/dist/cjs/builder/SchemaEditor.js +72 -0
- package/dist/cjs/builder/components/AddSchemaFields.js +62 -0
- package/dist/cjs/builder/components/SchemaArrayForm.js +145 -0
- package/dist/cjs/builder/components/SchemaField.js +414 -0
- package/dist/cjs/form/Controller.js +46 -1
- package/dist/cjs/form/Form.js +70 -9
- package/dist/cjs/hooks/useFileUploader.js +16 -0
- package/dist/cjs/hooks/useFormBuilder.js +57 -15
- package/dist/cjs/i18n/ar.json.js +5 -4
- package/dist/cjs/i18n/en.json.js +5 -5
- package/dist/cjs/index.js +12 -2
- package/dist/cjs/input/ArrayInput.js +126 -36
- package/dist/cjs/input/AvatarInput.js +43 -23
- package/dist/cjs/input/Checkbox.js +16 -6
- package/dist/cjs/input/ColorInput.js +113 -58
- package/dist/cjs/input/ColorPicker.js +60 -76
- package/dist/cjs/input/DateInput.js +197 -0
- package/dist/cjs/input/Field.js +10 -4
- package/dist/cjs/input/File.js +14 -7
- package/dist/cjs/input/Hidden.js +13 -2
- package/dist/cjs/input/Input.js +24 -10
- package/dist/cjs/input/Number.js +22 -10
- package/dist/cjs/input/Password.js +22 -12
- package/dist/cjs/input/Radio.js +12 -3
- package/dist/cjs/input/RadioGroup.js +10 -1
- package/dist/cjs/input/{Range.js → RangeSlider.js} +16 -8
- package/dist/cjs/input/Search.js +30 -19
- package/dist/cjs/input/Slider.js +12 -6
- package/dist/cjs/input/Switch.js +20 -9
- package/dist/cjs/input/Textarea.js +29 -8
- package/dist/cjs/internal/ErrorIcon.js +1 -1
- package/dist/cjs/internal/FieldWrapper.js +11 -4
- package/dist/cjs/internal/InputWrapper.js +27 -20
- package/dist/cjs/select/AutoComplete.js +21 -11
- package/dist/cjs/select/DualList.js +34 -12
- package/dist/cjs/select/List.js +68 -22
- package/dist/cjs/select/Options.js +49 -42
- package/dist/cjs/select/Select.js +40 -10
- package/dist/cjs/select/useSelect.js +22 -11
- package/dist/cjs/types/schema.js +43 -0
- package/dist/cjs/utils/eventHandlers.js +15 -5
- package/dist/esm/builder/FileField.js +42 -30
- package/dist/esm/builder/FormField.js +50 -34
- package/dist/esm/builder/SchemaEditor.js +72 -0
- package/dist/esm/builder/components/AddSchemaFields.js +62 -0
- package/dist/esm/builder/components/SchemaArrayForm.js +145 -0
- package/dist/esm/builder/components/SchemaField.js +414 -0
- package/dist/esm/form/Controller.js +46 -1
- package/dist/esm/form/Form.js +72 -12
- package/dist/esm/hooks/useFileUploader.js +16 -0
- package/dist/esm/hooks/useFormBuilder.js +55 -13
- package/dist/esm/i18n/ar.json.js +5 -4
- package/dist/esm/i18n/en.json.js +5 -5
- package/dist/esm/index.js +6 -2
- package/dist/esm/input/ArrayInput.js +126 -36
- package/dist/esm/input/AvatarInput.js +44 -24
- package/dist/esm/input/Checkbox.js +16 -6
- package/dist/esm/input/ColorInput.js +115 -60
- package/dist/esm/input/ColorPicker.js +60 -76
- package/dist/esm/input/DateInput.js +197 -0
- package/dist/esm/input/Field.js +11 -5
- package/dist/esm/input/File.js +16 -9
- package/dist/esm/input/Hidden.js +13 -2
- package/dist/esm/input/Input.js +26 -12
- package/dist/esm/input/Number.js +24 -12
- package/dist/esm/input/Password.js +24 -14
- package/dist/esm/input/Radio.js +12 -3
- package/dist/esm/input/RadioGroup.js +11 -2
- package/dist/esm/input/{Range.js → RangeSlider.js} +16 -8
- package/dist/esm/input/Search.js +32 -21
- package/dist/esm/input/Slider.js +12 -6
- package/dist/esm/input/Switch.js +20 -9
- package/dist/esm/input/Textarea.js +30 -9
- package/dist/esm/internal/ErrorIcon.js +1 -1
- package/dist/esm/internal/FieldWrapper.js +11 -4
- package/dist/esm/internal/InputWrapper.js +27 -20
- package/dist/esm/select/AutoComplete.js +21 -11
- package/dist/esm/select/DualList.js +34 -12
- package/dist/esm/select/List.js +69 -23
- package/dist/esm/select/Options.js +49 -42
- package/dist/esm/select/Select.js +40 -10
- package/dist/esm/select/useSelect.js +23 -12
- package/{src/input/ColorPicker.module.css → dist/esm/types/schema.js} +18 -27
- package/dist/esm/utils/eventHandlers.js +15 -5
- package/dist/types/builder/FileField.d.ts +4 -2
- package/dist/types/builder/FormField.d.ts +3 -1
- package/dist/types/builder/SchemaEditor.d.ts +9 -0
- package/dist/types/builder/components/AddSchemaFields.d.ts +2 -0
- package/dist/types/builder/components/SchemaArrayForm.d.ts +2 -0
- package/dist/types/builder/components/SchemaField.d.ts +10 -0
- package/dist/types/form/Controller.d.ts +47 -2
- package/dist/types/form/Form.d.ts +48 -2
- package/dist/types/hooks/useFileUploader.d.ts +16 -0
- package/dist/types/hooks/useFormBuilder.d.ts +32 -1
- package/dist/types/index.d.ts +6 -3
- package/dist/types/input/ArrayInput.d.ts +69 -12
- package/dist/types/input/AvatarInput.d.ts +23 -3
- package/dist/types/input/Checkbox.d.ts +13 -4
- package/dist/types/input/ColorInput.d.ts +15 -2
- package/dist/types/input/ColorPicker.d.ts +11 -1
- package/dist/types/input/DateInput.d.ts +28 -0
- package/dist/types/input/Field.d.ts +5 -1
- package/dist/types/input/File.d.ts +9 -0
- package/dist/types/input/Hidden.d.ts +13 -1
- package/dist/types/input/Input.d.ts +9 -1
- package/dist/types/input/Number.d.ts +9 -1
- package/dist/types/input/Password.d.ts +7 -1
- package/dist/types/input/Radio.d.ts +9 -1
- package/dist/types/input/RadioGroup.d.ts +8 -1
- package/dist/types/input/RangeSlider.d.ts +67 -0
- package/dist/types/input/Search.d.ts +14 -1
- package/dist/types/input/Slider.d.ts +8 -2
- package/dist/types/input/Switch.d.ts +10 -2
- package/dist/types/input/Textarea.d.ts +15 -1
- package/dist/types/internal/FieldWrapper.d.ts +1 -1
- package/dist/types/internal/InputWrapper.d.ts +1 -1
- package/dist/types/ranger/index.d.ts +2 -2
- package/dist/types/select/AutoComplete.d.ts +8 -1
- package/dist/types/select/DualList.d.ts +17 -2
- package/dist/types/select/List.d.ts +9 -1
- package/dist/types/select/Options.d.ts +4 -3
- package/dist/types/select/Select.d.ts +9 -1
- package/dist/types/select/useSelect.d.ts +10 -6
- package/dist/types/types/index.d.ts +34 -5
- package/dist/types/types/schema.d.ts +78 -33
- package/dist/types/utils/eventHandlers.d.ts +2 -2
- package/package.json +22 -20
- package/src/builder/FileField.tsx +62 -30
- package/src/builder/FormField.tsx +52 -32
- package/src/builder/SchemaEditor.tsx +79 -0
- package/src/builder/components/AddSchemaFields.tsx +74 -0
- package/src/builder/components/SchemaArrayForm.tsx +161 -0
- package/src/builder/components/SchemaField.tsx +436 -0
- package/src/form/Controller.tsx +48 -3
- package/src/form/Form.tsx +80 -8
- package/src/hooks/useFileUploader.ts +16 -0
- package/src/hooks/useFormBuilder.tsx +58 -15
- package/src/i18n/ar.json +5 -4
- package/src/i18n/en.json +5 -5
- package/src/index.ts +12 -3
- package/src/input/ArrayInput.tsx +199 -64
- package/src/input/AvatarInput.tsx +67 -19
- package/src/input/Checkbox.tsx +16 -6
- package/src/input/ColorInput.tsx +131 -71
- package/src/input/ColorPicker.tsx +54 -72
- package/src/input/DateInput.tsx +260 -0
- package/src/input/Field.tsx +15 -11
- package/src/input/File.tsx +16 -14
- package/src/input/Hidden.tsx +17 -2
- package/src/input/Input.tsx +27 -13
- package/src/input/Number.tsx +22 -13
- package/src/input/Password.tsx +24 -16
- package/src/input/Radio.tsx +12 -3
- package/src/input/RadioGroup.tsx +12 -3
- package/src/input/{Range.tsx → RangeSlider.tsx} +17 -9
- package/src/input/Search.tsx +33 -22
- package/src/input/Slider.tsx +20 -11
- package/src/input/Switch.tsx +17 -6
- package/src/input/Textarea.tsx +34 -9
- package/src/internal/ErrorIcon.tsx +1 -1
- package/src/internal/FieldWrapper.tsx +8 -4
- package/src/internal/InputWrapper.tsx +49 -27
- package/src/select/AutoComplete.tsx +14 -3
- package/src/select/DualList.tsx +31 -16
- package/src/select/List.tsx +52 -8
- package/src/select/Options.tsx +50 -46
- package/src/select/Select.tsx +25 -5
- package/src/select/useSelect.tsx +26 -9
- package/src/types/index.ts +37 -6
- package/src/types/schema.ts +96 -41
- package/src/utils/eventHandlers.ts +14 -4
- package/dist/cjs/input/ArrayInput.module.css +0 -1
- package/dist/cjs/input/ColorPicker.module.css +0 -1
- package/dist/cjs/input/File.module.css +0 -1
- package/dist/cjs/internal/Field.module.css +0 -1
- package/dist/esm/input/ArrayInput.module.css +0 -1
- package/dist/esm/input/ColorPicker.module.css +0 -1
- package/dist/esm/input/File.module.css +0 -1
- package/dist/esm/internal/Field.module.css +0 -1
- package/dist/types/input/Range.d.ts +0 -59
package/src/input/Password.tsx
CHANGED
|
@@ -28,14 +28,13 @@ import {
|
|
|
28
28
|
useCallback,
|
|
29
29
|
useDeferredValue,
|
|
30
30
|
useEffect,
|
|
31
|
-
useMemo,
|
|
32
31
|
useState,
|
|
33
32
|
type ChangeEvent,
|
|
34
33
|
} from "react";
|
|
35
34
|
import { useTranslation } from "react-i18next";
|
|
36
35
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
37
36
|
import { type InputProps } from "../types";
|
|
38
|
-
import {
|
|
37
|
+
import { useHandleEnter } from "../utils";
|
|
39
38
|
|
|
40
39
|
export interface PasswordProps extends InputProps, RefProp<HTMLInputElement> {
|
|
41
40
|
/**
|
|
@@ -48,6 +47,12 @@ export interface PasswordProps extends InputProps, RefProp<HTMLInputElement> {
|
|
|
48
47
|
strength?: number;
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Password input component with optional strength meter and toggle visibility.
|
|
52
|
+
*
|
|
53
|
+
* @param {PasswordProps} props - The properties for the Password component.
|
|
54
|
+
* @returns {JSX.Element} The rendered Password input component.
|
|
55
|
+
*/
|
|
51
56
|
export const Password = ({
|
|
52
57
|
ref,
|
|
53
58
|
value,
|
|
@@ -58,8 +63,11 @@ export const Password = ({
|
|
|
58
63
|
disabled,
|
|
59
64
|
required,
|
|
60
65
|
placeholder,
|
|
66
|
+
defaultValue,
|
|
61
67
|
autoFocus,
|
|
62
68
|
showToggle,
|
|
69
|
+
onBlur,
|
|
70
|
+
onFocus,
|
|
63
71
|
onChange,
|
|
64
72
|
onEnterPressed,
|
|
65
73
|
...rest
|
|
@@ -68,12 +76,9 @@ export const Password = ({
|
|
|
68
76
|
const [show, setShow] = useState(false);
|
|
69
77
|
|
|
70
78
|
const [actualValue, setActualValue] = useState("");
|
|
71
|
-
const deferred = useDeferredValue(value);
|
|
79
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
72
80
|
|
|
73
|
-
const handleEnterPressed =
|
|
74
|
-
() => handleEnter(onEnterPressed),
|
|
75
|
-
[onEnterPressed],
|
|
76
|
-
);
|
|
81
|
+
const handleEnterPressed = useHandleEnter(onEnterPressed);
|
|
77
82
|
|
|
78
83
|
useEffect(() => {
|
|
79
84
|
setActualValue(deferred ?? "");
|
|
@@ -81,24 +86,25 @@ export const Password = ({
|
|
|
81
86
|
|
|
82
87
|
const handleChange = useCallback(
|
|
83
88
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
84
|
-
const value = e?.target.value;
|
|
89
|
+
const value = e?.target.value ?? defaultValue;
|
|
85
90
|
setActualValue(value ?? "");
|
|
86
|
-
onChange?.(value ??
|
|
91
|
+
onChange?.(value ?? null);
|
|
87
92
|
},
|
|
88
|
-
[onChange],
|
|
93
|
+
[onChange, defaultValue],
|
|
89
94
|
);
|
|
90
95
|
|
|
91
96
|
return (
|
|
92
97
|
<InputWrapper
|
|
93
|
-
showClear={!!actualValue}
|
|
98
|
+
showClear={!!actualValue && !disabled && !readOnly}
|
|
94
99
|
onClear={handleChange}
|
|
95
100
|
invalid={invalid}
|
|
96
101
|
readOnly={readOnly}
|
|
97
102
|
disabled={disabled}
|
|
98
103
|
required={required}
|
|
99
104
|
{...rest}
|
|
100
|
-
|
|
101
|
-
showToggle &&
|
|
105
|
+
actionButton={
|
|
106
|
+
showToggle &&
|
|
107
|
+
actualValue && (
|
|
102
108
|
<Tooltip
|
|
103
109
|
color="warning"
|
|
104
110
|
content={t(show ? "password.hide" : "password.show")}
|
|
@@ -116,7 +122,7 @@ export const Password = ({
|
|
|
116
122
|
}
|
|
117
123
|
>
|
|
118
124
|
<input
|
|
119
|
-
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0"
|
|
125
|
+
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 peer"
|
|
120
126
|
aria-invalid={invalid}
|
|
121
127
|
aria-disabled={disabled}
|
|
122
128
|
aria-readonly={readOnly}
|
|
@@ -129,8 +135,10 @@ export const Password = ({
|
|
|
129
135
|
type={show ? "text" : "password"}
|
|
130
136
|
ref={ref}
|
|
131
137
|
autoComplete="off"
|
|
132
|
-
{
|
|
138
|
+
autoFocus={autoFocus}
|
|
133
139
|
value={actualValue}
|
|
140
|
+
onBlur={onBlur}
|
|
141
|
+
onFocus={onFocus}
|
|
134
142
|
onChange={handleChange}
|
|
135
143
|
onKeyDown={handleEnterPressed}
|
|
136
144
|
/>
|
|
@@ -138,7 +146,7 @@ export const Password = ({
|
|
|
138
146
|
<div
|
|
139
147
|
className={classNames(
|
|
140
148
|
"absolute bottom-px h-[3px] inset-x-0 after:block after:h-full after:bg-dimmed",
|
|
141
|
-
"ltr:bg-
|
|
149
|
+
"ltr:bg-linear-to-r rtl:bg-linear-to-l from-danger-500 via-marigold-500 to-jade-500",
|
|
142
150
|
)}
|
|
143
151
|
style={{
|
|
144
152
|
paddingInlineStart: `${strength > 1 ? 100 : strength * 100}%`,
|
package/src/input/Radio.tsx
CHANGED
|
@@ -69,6 +69,15 @@ export interface RadioProps extends RefProp<HTMLInputElement> {
|
|
|
69
69
|
iconChecked?: string;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Radio input component with custom icons and label.
|
|
74
|
+
*
|
|
75
|
+
* This component renders a radio button with an optional label and custom icons for checked and unchecked states.
|
|
76
|
+
* It supports disabled and invalid states, and allows for custom width.
|
|
77
|
+
*
|
|
78
|
+
* @param {RadioProps} props - The properties for the Radio component.
|
|
79
|
+
* @returns {JSX.Element} The rendered Radio input component.
|
|
80
|
+
*/
|
|
72
81
|
export const Radio = ({
|
|
73
82
|
ref,
|
|
74
83
|
name,
|
|
@@ -104,7 +113,7 @@ export const Radio = ({
|
|
|
104
113
|
disabled
|
|
105
114
|
? "opacity-50 cursor-not-allowed"
|
|
106
115
|
: "hover:opacity-100 cursor-pointer",
|
|
107
|
-
"inline-flex gap-1 py-1 items-center relative cursor-pointer opacity-85 rounded ring-offset-2 has-
|
|
116
|
+
"inline-flex gap-1 py-1 items-center relative cursor-pointer opacity-85 rounded ring-offset-2 has-focus-visible:ring-1",
|
|
108
117
|
)}
|
|
109
118
|
style={{ width }}
|
|
110
119
|
>
|
|
@@ -126,7 +135,7 @@ export const Radio = ({
|
|
|
126
135
|
<Icon
|
|
127
136
|
className={classNames(
|
|
128
137
|
"p-0.5 hidden peer-checked:inline-block",
|
|
129
|
-
icon && !iconChecked && "bg-primary-500 text-white",
|
|
138
|
+
icon && !iconChecked && "bg-primary-500 text-white!",
|
|
130
139
|
)}
|
|
131
140
|
color={invalid ? "danger" : "primary"}
|
|
132
141
|
size="1.25em"
|
|
@@ -139,7 +148,7 @@ export const Radio = ({
|
|
|
139
148
|
icon={iconOff}
|
|
140
149
|
/>
|
|
141
150
|
{label && (
|
|
142
|
-
<span className="flex-initial leading-
|
|
151
|
+
<span className="flex-initial leading-tight truncate">{label}</span>
|
|
143
152
|
)}
|
|
144
153
|
</label>
|
|
145
154
|
);
|
package/src/input/RadioGroup.tsx
CHANGED
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { cloneChildren } from "@react-fabric/core";
|
|
24
25
|
import {
|
|
25
26
|
type ChildrenProp,
|
|
26
27
|
type CssProp,
|
|
27
28
|
} from "@react-fabric/core/dist/types/types";
|
|
28
|
-
import {
|
|
29
|
+
import { cloneElement } from "react";
|
|
29
30
|
import { FieldWrapper } from "../internal/FieldWrapper";
|
|
30
31
|
import { type Radio } from "./Radio";
|
|
31
32
|
|
|
@@ -73,6 +74,14 @@ export interface RadioGroupProps extends ChildrenProp<typeof Radio>, CssProp {
|
|
|
73
74
|
onChange?: (value: AnyObject) => void;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
/**
|
|
78
|
+
* RadioGroup component for rendering a group of radio buttons.
|
|
79
|
+
* It allows for customization of the label, options, and layout.
|
|
80
|
+
* The component supports inline and vertical orientations, and can handle change events.
|
|
81
|
+
*
|
|
82
|
+
* @param {RadioGroupProps} props - The properties for the RadioGroup component.
|
|
83
|
+
* @returns {JSX.Element} The rendered RadioGroup component.
|
|
84
|
+
*/
|
|
76
85
|
export const RadioGroup = ({
|
|
77
86
|
children,
|
|
78
87
|
name,
|
|
@@ -84,8 +93,8 @@ export const RadioGroup = ({
|
|
|
84
93
|
return (
|
|
85
94
|
<FieldWrapper {...rest}>
|
|
86
95
|
<div className={className}>
|
|
87
|
-
{
|
|
88
|
-
cloneElement(child
|
|
96
|
+
{cloneChildren(children, (child: AnyObject) =>
|
|
97
|
+
cloneElement(child, {
|
|
89
98
|
name,
|
|
90
99
|
onChange,
|
|
91
100
|
width: optionWidth,
|
|
@@ -38,7 +38,7 @@ import { type InputProps } from "../types";
|
|
|
38
38
|
export interface RangeProps
|
|
39
39
|
extends Omit<
|
|
40
40
|
InputProps<[number, number]>,
|
|
41
|
-
"placeholder" | "allowClear" | "children"
|
|
41
|
+
"placeholder" | "allowClear" | "children" | "defaultValue"
|
|
42
42
|
> {
|
|
43
43
|
/**
|
|
44
44
|
* min value
|
|
@@ -95,9 +95,17 @@ export interface RangeProps
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
98
|
+
* RangeSlider component for rendering a range slider input.
|
|
99
|
+
* It supports vertical orientation, custom colors, step increments,
|
|
100
|
+
* min/max values, and display of labels and value tooltips.
|
|
101
|
+
* The component uses the Ranger library for handling the slider functionality.
|
|
102
|
+
* It also provides error handling and supports disabled and read-only states.
|
|
103
|
+
* The component is designed to be flexible and customizable, allowing for various configurations.
|
|
104
|
+
*
|
|
105
|
+
* @param {RangeProps} props - The properties for the RangeSlider component.
|
|
106
|
+
* @returns {JSX.Element} The rendered RangeSlider component.
|
|
99
107
|
*/
|
|
100
|
-
export const
|
|
108
|
+
export const RangeSlider = ({
|
|
101
109
|
error,
|
|
102
110
|
name,
|
|
103
111
|
value,
|
|
@@ -141,7 +149,7 @@ export const Range = ({
|
|
|
141
149
|
const handleChange = useCallback(
|
|
142
150
|
(val: [number, number]) => {
|
|
143
151
|
setActualValue(val ?? [min, max]);
|
|
144
|
-
onChange?.(val ??
|
|
152
|
+
onChange?.(val ?? null);
|
|
145
153
|
},
|
|
146
154
|
[onChange, min, max],
|
|
147
155
|
);
|
|
@@ -190,7 +198,7 @@ export const Range = ({
|
|
|
190
198
|
>
|
|
191
199
|
<div
|
|
192
200
|
className={classNames(
|
|
193
|
-
"flex-
|
|
201
|
+
"flex-1 order-3 flex items-center select-none z-0",
|
|
194
202
|
vertical && "flex-col w-8",
|
|
195
203
|
invalid ? "text-danger-500" : "text-primary-600",
|
|
196
204
|
)}
|
|
@@ -201,7 +209,7 @@ export const Range = ({
|
|
|
201
209
|
<div
|
|
202
210
|
ref={rangerInstance.trackElRef}
|
|
203
211
|
className={classNames(
|
|
204
|
-
"flex-
|
|
212
|
+
"flex-1 relative flex items-center",
|
|
205
213
|
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
206
214
|
)}
|
|
207
215
|
style={{ height: vertical ? height : undefined }}
|
|
@@ -210,7 +218,7 @@ export const Range = ({
|
|
|
210
218
|
<div
|
|
211
219
|
key={key}
|
|
212
220
|
className={classNames(
|
|
213
|
-
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-
|
|
221
|
+
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-0 z-1",
|
|
214
222
|
vertical && "left-1/2 -ml-0.5",
|
|
215
223
|
)}
|
|
216
224
|
style={styles}
|
|
@@ -256,8 +264,8 @@ export const Range = ({
|
|
|
256
264
|
: "top-1/2 -translate-y-1/2",
|
|
257
265
|
!vertical &&
|
|
258
266
|
(key === 0
|
|
259
|
-
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-
|
|
260
|
-
: "ms-3 ltr:before:-translate-x-
|
|
267
|
+
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-0.5 rtl:before:-translate-x-0.5 before:end-0"
|
|
268
|
+
: "ms-3 ltr:before:-translate-x-0.5 rtl:before:translate-x-0.5 before:start-0"),
|
|
261
269
|
)}
|
|
262
270
|
data-align={key === 0 ? "start" : "end"}
|
|
263
271
|
style={valueStyles}
|
package/src/input/Search.tsx
CHANGED
|
@@ -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 {
|
|
37
|
+
import { useHandleEnter } from "../utils";
|
|
39
38
|
|
|
40
39
|
export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
41
40
|
/**
|
|
@@ -46,12 +45,25 @@ export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
|
46
45
|
* search on value change
|
|
47
46
|
*/
|
|
48
47
|
searchOnChange?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* hide search action handle
|
|
50
|
+
*/
|
|
51
|
+
hideHandle?: boolean;
|
|
49
52
|
/**
|
|
50
53
|
* search handler
|
|
51
54
|
*/
|
|
52
55
|
onSearch?: (query?: string) => void;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Search input component with optional searching state and search handler.
|
|
60
|
+
* This component allows users to input search queries and trigger a search action.
|
|
61
|
+
* It supports features like searching on value change, showing a search handle,
|
|
62
|
+
* and handling search actions with a debounce mechanism.
|
|
63
|
+
*
|
|
64
|
+
* @param {SearchProps} props - The properties for the Search component.
|
|
65
|
+
* @returns {JSX.Element} The rendered Search input component.
|
|
66
|
+
*/
|
|
55
67
|
export const Search = ({
|
|
56
68
|
ref,
|
|
57
69
|
value,
|
|
@@ -62,18 +74,20 @@ export const Search = ({
|
|
|
62
74
|
required,
|
|
63
75
|
searching,
|
|
64
76
|
placeholder,
|
|
77
|
+
defaultValue,
|
|
65
78
|
autoFocus,
|
|
79
|
+
hideHandle,
|
|
66
80
|
allowClear = true,
|
|
67
|
-
searchOnChange =
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
searchOnChange = false,
|
|
82
|
+
onBlur,
|
|
83
|
+
onFocus,
|
|
70
84
|
onSearch,
|
|
71
85
|
onChange,
|
|
72
86
|
onEnterPressed,
|
|
73
87
|
...rest
|
|
74
88
|
}: SearchProps) => {
|
|
75
89
|
const [actualValue, setActualValue] = useState("");
|
|
76
|
-
const deferred = useDeferredValue(value);
|
|
90
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
77
91
|
|
|
78
92
|
const refValue = useRef("");
|
|
79
93
|
const handleSearch = useDebounce(
|
|
@@ -82,10 +96,7 @@ export const Search = ({
|
|
|
82
96
|
250,
|
|
83
97
|
);
|
|
84
98
|
|
|
85
|
-
const handleEnterPressed =
|
|
86
|
-
() => handleEnter(handleSearch),
|
|
87
|
-
[handleSearch],
|
|
88
|
-
);
|
|
99
|
+
const handleEnterPressed = useHandleEnter(handleSearch);
|
|
89
100
|
|
|
90
101
|
useEffect(() => {
|
|
91
102
|
setActualValue(deferred ?? "");
|
|
@@ -93,36 +104,34 @@ export const Search = ({
|
|
|
93
104
|
|
|
94
105
|
const handleChange = useCallback(
|
|
95
106
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
96
|
-
const value = e?.target.value;
|
|
107
|
+
const value = e?.target.value ?? defaultValue;
|
|
97
108
|
refValue.current = value ?? "";
|
|
98
109
|
setActualValue(value ?? "");
|
|
99
|
-
onChange?.(value ??
|
|
110
|
+
onChange?.(value ?? null);
|
|
100
111
|
|
|
101
|
-
// value was cleared so force fire onSearch
|
|
102
|
-
if (searchOnChange) {
|
|
112
|
+
// when e is undefined value was cleared so force fire onSearch
|
|
113
|
+
if (!e || searchOnChange) {
|
|
103
114
|
handleSearch();
|
|
104
115
|
}
|
|
105
116
|
},
|
|
106
|
-
[onChange, searchOnChange, handleSearch],
|
|
117
|
+
[onChange, searchOnChange, handleSearch, defaultValue],
|
|
107
118
|
);
|
|
108
119
|
|
|
109
120
|
return (
|
|
110
121
|
<InputWrapper
|
|
111
|
-
showClear={!!actualValue}
|
|
122
|
+
showClear={!!actualValue && !disabled && !readOnly}
|
|
112
123
|
onClear={handleChange}
|
|
113
124
|
allowClear={allowClear}
|
|
114
125
|
invalid={invalid}
|
|
115
126
|
readOnly={readOnly}
|
|
116
127
|
disabled={disabled}
|
|
117
128
|
required={required}
|
|
118
|
-
|
|
119
|
-
decorateEnd={
|
|
129
|
+
actionButton={
|
|
120
130
|
<Fragment>
|
|
121
|
-
{decorateEnd}
|
|
122
131
|
{searching && (
|
|
123
132
|
<Icon className="p-2" icon={CoreIcons.spinner} animate="spin" />
|
|
124
133
|
)}
|
|
125
|
-
{!searching && (
|
|
134
|
+
{!searching && !hideHandle && (
|
|
126
135
|
<Button
|
|
127
136
|
tabIndex={-1}
|
|
128
137
|
variant="link"
|
|
@@ -137,7 +146,7 @@ export const Search = ({
|
|
|
137
146
|
{...rest}
|
|
138
147
|
>
|
|
139
148
|
<input
|
|
140
|
-
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0"
|
|
149
|
+
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 peer"
|
|
141
150
|
aria-invalid={invalid}
|
|
142
151
|
aria-disabled={disabled}
|
|
143
152
|
aria-readonly={readOnly}
|
|
@@ -150,8 +159,10 @@ export const Search = ({
|
|
|
150
159
|
type="search"
|
|
151
160
|
ref={ref}
|
|
152
161
|
autoComplete="off"
|
|
153
|
-
{
|
|
162
|
+
autoFocus={autoFocus}
|
|
154
163
|
value={actualValue}
|
|
164
|
+
onBlur={onBlur}
|
|
165
|
+
onFocus={onFocus}
|
|
155
166
|
onChange={handleChange}
|
|
156
167
|
onKeyDown={handleEnterPressed}
|
|
157
168
|
/>
|
package/src/input/Slider.tsx
CHANGED
|
@@ -36,7 +36,10 @@ import { useRanger } from "../ranger";
|
|
|
36
36
|
import { type InputProps } from "../types";
|
|
37
37
|
|
|
38
38
|
export interface SliderProps
|
|
39
|
-
extends Omit<
|
|
39
|
+
extends Omit<
|
|
40
|
+
InputProps<number>,
|
|
41
|
+
"placeholder" | "allowClear" | "children" | "defaultValue"
|
|
42
|
+
> {
|
|
40
43
|
/**
|
|
41
44
|
* min value
|
|
42
45
|
*/
|
|
@@ -96,7 +99,13 @@ export interface SliderProps
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
|
-
*
|
|
102
|
+
* Slider component for rendering a slider input with labels and value display.
|
|
103
|
+
* It supports vertical orientation, custom min/max labels, and step ranges.
|
|
104
|
+
* The component handles value changes, displays tooltips, and integrates with ranger for slider functionality.
|
|
105
|
+
* It also supports deferred value updates for smoother interactions.
|
|
106
|
+
*
|
|
107
|
+
* @param {SliderProps} props - The properties for the Slider component.
|
|
108
|
+
* @returns {JSX.Element} The rendered Slider component.
|
|
100
109
|
*/
|
|
101
110
|
export const Slider = ({
|
|
102
111
|
error,
|
|
@@ -146,7 +155,7 @@ export const Slider = ({
|
|
|
146
155
|
(value: number) => {
|
|
147
156
|
const val = useInfinity && value === max ? Infinity : value;
|
|
148
157
|
setActualValue(val ?? 0);
|
|
149
|
-
onChange?.(val ??
|
|
158
|
+
onChange?.(val ?? null);
|
|
150
159
|
},
|
|
151
160
|
[onChange, max, useInfinity],
|
|
152
161
|
);
|
|
@@ -194,7 +203,7 @@ export const Slider = ({
|
|
|
194
203
|
>
|
|
195
204
|
<div
|
|
196
205
|
className={classNames(
|
|
197
|
-
"flex-
|
|
206
|
+
"flex-1 order-3 flex items-center select-none relative z-0",
|
|
198
207
|
vertical && "flex-col w-8",
|
|
199
208
|
invalid ? "text-danger-500" : "text-primary-600",
|
|
200
209
|
)}
|
|
@@ -205,8 +214,8 @@ export const Slider = ({
|
|
|
205
214
|
<div
|
|
206
215
|
ref={rangerInstance.trackElRef}
|
|
207
216
|
className={classNames(
|
|
208
|
-
"
|
|
209
|
-
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
217
|
+
"relative flex items-center",
|
|
218
|
+
vertical ? "my-2 w-8" : "flex-1 mx-2 h-8",
|
|
210
219
|
)}
|
|
211
220
|
style={{ height: vertical ? height : undefined }}
|
|
212
221
|
>
|
|
@@ -214,7 +223,7 @@ export const Slider = ({
|
|
|
214
223
|
<div
|
|
215
224
|
key={key}
|
|
216
225
|
className={classNames(
|
|
217
|
-
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-
|
|
226
|
+
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-0 z-1",
|
|
218
227
|
vertical && "left-1/2 -ml-0.5",
|
|
219
228
|
)}
|
|
220
229
|
style={styles}
|
|
@@ -253,15 +262,15 @@ export const Slider = ({
|
|
|
253
262
|
{displayValue && (
|
|
254
263
|
<div
|
|
255
264
|
className={classNames(
|
|
256
|
-
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-
|
|
265
|
+
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-5 whitespace-nowrap pointer-events-none",
|
|
257
266
|
"before:absolute before:h-1.5 before:w-1.5 before:z-[-1] before:bg-invert before:top-1/2 before:-translate-y-1/2 before:rotate-45",
|
|
258
267
|
vertical
|
|
259
|
-
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2"
|
|
268
|
+
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2 ltr:before:-translate-x-0.5 rtl:before:translate-x-0.5 before:start-0"
|
|
260
269
|
: "top-1/2 -translate-y-1/2",
|
|
261
270
|
!vertical &&
|
|
262
271
|
(percentage > 50
|
|
263
|
-
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-
|
|
264
|
-
: "ms-3 ltr:before:-translate-x-
|
|
272
|
+
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-0.5 rtl:before:-translate-x-0.5 before:end-0"
|
|
273
|
+
: "ms-3 ltr:before:-translate-x-0.5 rtl:before:translate-x-0.5 before:start-0"),
|
|
265
274
|
)}
|
|
266
275
|
data-align={percentage > 50 ? "start" : "end"}
|
|
267
276
|
style={valueStyles}
|
package/src/input/Switch.tsx
CHANGED
|
@@ -87,6 +87,15 @@ export interface SwitchProps extends RefProp<HTMLInputElement> {
|
|
|
87
87
|
offLabelColor?: string | ColorType;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Switch input component with custom labels and colors.
|
|
92
|
+
* This component renders a switch input with optional labels for the "on" and "off" states,
|
|
93
|
+
* and allows for custom colors for the switch background and labels.
|
|
94
|
+
* It supports disabled and invalid states, and handles change events.
|
|
95
|
+
*
|
|
96
|
+
* @param {SwitchProps} props - The properties for the Switch component.
|
|
97
|
+
* @returns {JSX.Element} The rendered Switch input component.
|
|
98
|
+
*/
|
|
90
99
|
export const Switch = ({
|
|
91
100
|
ref,
|
|
92
101
|
label,
|
|
@@ -102,6 +111,8 @@ export const Switch = ({
|
|
|
102
111
|
onLabelColor,
|
|
103
112
|
offLabelColor,
|
|
104
113
|
defaultColor,
|
|
114
|
+
// @ts-expect-error ignore
|
|
115
|
+
required,
|
|
105
116
|
onChange,
|
|
106
117
|
...rest
|
|
107
118
|
}: SwitchProps) => {
|
|
@@ -127,7 +138,7 @@ export const Switch = ({
|
|
|
127
138
|
disabled
|
|
128
139
|
? "opacity-50 cursor-not-allowed"
|
|
129
140
|
: "hover:opacity-100 cursor-pointer",
|
|
130
|
-
"inline-flex gap-1 py-1 items-center relative cursor-pointer opacity-85 rounded ring-offset-2 has-
|
|
141
|
+
"inline-flex gap-1 py-1 items-center relative cursor-pointer opacity-85 rounded ring-offset-2 has-focus-visible:ring-1",
|
|
131
142
|
)}
|
|
132
143
|
style={{ width }}
|
|
133
144
|
>
|
|
@@ -136,7 +147,7 @@ export const Switch = ({
|
|
|
136
147
|
actualValue && getBgClass(color ? `${color}-500` : "primary-500"),
|
|
137
148
|
!actualValue &&
|
|
138
149
|
(defaultColor ? getBgClass(`${defaultColor}-500`) : "bg-tint-200"),
|
|
139
|
-
"relative grid grid-cols-2 items-center h-
|
|
150
|
+
"relative grid grid-cols-2 items-center h-[1.5em] min-w-[2.5em] cursor-pointer rounded-full p-[0.25em] transition-colors duration-200 ease-in-out",
|
|
140
151
|
)}
|
|
141
152
|
style={{
|
|
142
153
|
backgroundColor: actualValue
|
|
@@ -165,11 +176,11 @@ export const Switch = ({
|
|
|
165
176
|
aria-hidden="true"
|
|
166
177
|
className={classNames(
|
|
167
178
|
!disabled && "shadow-sm",
|
|
168
|
-
actualValue ? "translate-x-
|
|
169
|
-
"pointer-events-none inline-block h-
|
|
179
|
+
actualValue ? "translate-x-full" : "translate-x-0",
|
|
180
|
+
"pointer-events-none inline-block h-[1em] start-[0.25em] absolute rounded-full bg-white ring-0 transition duration-200 ease-in-out",
|
|
170
181
|
)}
|
|
171
182
|
style={{
|
|
172
|
-
width: "calc(50% - 0.
|
|
183
|
+
width: "calc(50% - 0.25em)",
|
|
173
184
|
}}
|
|
174
185
|
/>
|
|
175
186
|
{(!!onLabel || !!offLabel) && (
|
|
@@ -195,7 +206,7 @@ export const Switch = ({
|
|
|
195
206
|
</div>
|
|
196
207
|
<ErrorIcon invalid={invalid} error={error} />
|
|
197
208
|
{label && (
|
|
198
|
-
<span className="flex-initial leading-
|
|
209
|
+
<span className="flex-initial leading-tight truncate">{label}</span>
|
|
199
210
|
)}
|
|
200
211
|
</label>
|
|
201
212
|
);
|
package/src/input/Textarea.tsx
CHANGED
|
@@ -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 {
|
|
35
|
+
import { useHandleEnter } from "../utils";
|
|
36
36
|
|
|
37
37
|
export interface TextareaProps
|
|
38
38
|
extends InputProps,
|
|
@@ -49,8 +49,22 @@ export interface TextareaProps
|
|
|
49
49
|
* increment rows on value change
|
|
50
50
|
*/
|
|
51
51
|
variableRows?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* expandable textarea
|
|
54
|
+
*/
|
|
55
|
+
expandable?: boolean;
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Textarea component that allows users to input multi-line text.
|
|
60
|
+
* It supports features like variable row count, expandable behavior,
|
|
61
|
+
* and handling of focus, blur, and change events.
|
|
62
|
+
* This component is designed to be flexible and user-friendly,
|
|
63
|
+
* providing a clear interface for text input with optional validation and accessibility features.
|
|
64
|
+
*
|
|
65
|
+
* @param {TextareaProps} props - The properties for the Textarea component.
|
|
66
|
+
* @returns {JSX.Element} The rendered Textarea component.
|
|
67
|
+
*/
|
|
54
68
|
export const Textarea = ({
|
|
55
69
|
ref,
|
|
56
70
|
value,
|
|
@@ -60,17 +74,21 @@ export const Textarea = ({
|
|
|
60
74
|
disabled,
|
|
61
75
|
required,
|
|
62
76
|
placeholder,
|
|
77
|
+
defaultValue,
|
|
63
78
|
autoFocus,
|
|
64
79
|
rows = 5,
|
|
65
80
|
maxRows = 12,
|
|
66
81
|
variableRows,
|
|
82
|
+
expandable,
|
|
83
|
+
onBlur,
|
|
84
|
+
onFocus,
|
|
67
85
|
onChange,
|
|
68
86
|
onEnterPressed,
|
|
69
87
|
...rest
|
|
70
88
|
}: TextareaProps) => {
|
|
71
89
|
const [actualValue, setActualValue] = useState("");
|
|
72
90
|
const [fixedRows, setFixedRows] = useState(rows);
|
|
73
|
-
const deferred = useDeferredValue(value);
|
|
91
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
74
92
|
const wrapperRef = useRef(null);
|
|
75
93
|
|
|
76
94
|
useEffect(() => {
|
|
@@ -79,11 +97,11 @@ export const Textarea = ({
|
|
|
79
97
|
|
|
80
98
|
const handleChange = useCallback(
|
|
81
99
|
(e?: ChangeEvent<HTMLTextAreaElement>) => {
|
|
82
|
-
const value = e?.target.value;
|
|
100
|
+
const value = e?.target.value ?? defaultValue;
|
|
83
101
|
setActualValue(value ?? "");
|
|
84
|
-
onChange?.(value ??
|
|
102
|
+
onChange?.(value ?? null);
|
|
85
103
|
},
|
|
86
|
-
[onChange],
|
|
104
|
+
[onChange, defaultValue],
|
|
87
105
|
);
|
|
88
106
|
|
|
89
107
|
useEffect(() => {
|
|
@@ -95,20 +113,25 @@ export const Textarea = ({
|
|
|
95
113
|
}
|
|
96
114
|
}, [actualValue, variableRows, rows, maxRows]);
|
|
97
115
|
|
|
116
|
+
const handleEnterPressed = useHandleEnter(onEnterPressed, {
|
|
117
|
+
preventDefault: !!onEnterPressed,
|
|
118
|
+
});
|
|
119
|
+
|
|
98
120
|
return (
|
|
99
121
|
<InputWrapper
|
|
100
|
-
showClear={!!actualValue}
|
|
122
|
+
showClear={!!actualValue && !disabled && !readOnly}
|
|
101
123
|
onClear={handleChange}
|
|
102
124
|
invalid={invalid}
|
|
103
125
|
readOnly={readOnly}
|
|
104
126
|
disabled={disabled}
|
|
105
127
|
required={required}
|
|
106
128
|
wrapperRef={wrapperRef}
|
|
129
|
+
textareaExpandable={expandable}
|
|
107
130
|
textarea
|
|
108
131
|
{...rest}
|
|
109
132
|
>
|
|
110
133
|
<textarea
|
|
111
|
-
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-
|
|
134
|
+
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-12 resize-none"
|
|
112
135
|
aria-invalid={invalid}
|
|
113
136
|
aria-disabled={disabled}
|
|
114
137
|
aria-readonly={readOnly}
|
|
@@ -120,10 +143,12 @@ export const Textarea = ({
|
|
|
120
143
|
name={name}
|
|
121
144
|
ref={ref}
|
|
122
145
|
autoComplete="off"
|
|
123
|
-
{
|
|
146
|
+
autoFocus={autoFocus}
|
|
124
147
|
value={actualValue}
|
|
148
|
+
onBlur={onBlur}
|
|
149
|
+
onFocus={onFocus}
|
|
125
150
|
onChange={handleChange}
|
|
126
|
-
onKeyDown={
|
|
151
|
+
onKeyDown={handleEnterPressed as any}
|
|
127
152
|
/>
|
|
128
153
|
</InputWrapper>
|
|
129
154
|
);
|