@react-fabric/form 1.0.0-beta.6 → 1.0.0-beta.61
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 +63 -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 +71 -13
- package/dist/cjs/hooks/useFileUploader.js +16 -0
- package/dist/cjs/hooks/useFormBuilder.js +67 -18
- 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 +128 -38
- package/dist/cjs/input/AvatarInput.js +43 -23
- package/dist/cjs/input/Checkbox.js +18 -8
- package/dist/cjs/input/ColorInput.js +114 -59
- 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 +15 -8
- 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 +23 -13
- package/dist/cjs/input/Radio.js +14 -5
- package/dist/cjs/input/RadioGroup.js +10 -1
- package/dist/cjs/input/{Range.js → RangeSlider.js} +16 -8
- package/dist/cjs/input/Search.js +32 -22
- 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 +2 -2
- package/dist/cjs/internal/FieldWrapper.js +11 -4
- package/dist/cjs/internal/InputWrapper.js +29 -22
- package/dist/cjs/select/AutoComplete.js +22 -13
- package/dist/cjs/select/DualList.js +34 -12
- package/dist/cjs/select/List.js +49 -21
- package/dist/cjs/select/Options.js +49 -42
- package/dist/cjs/select/Select.js +21 -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 +63 -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 +73 -16
- package/dist/esm/hooks/useFileUploader.js +16 -0
- package/dist/esm/hooks/useFormBuilder.js +65 -16
- 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 +128 -38
- package/dist/esm/input/AvatarInput.js +43 -23
- package/dist/esm/input/Checkbox.js +19 -9
- package/dist/esm/input/ColorInput.js +116 -61
- 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 +18 -11
- 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 +26 -16
- package/dist/esm/input/Radio.js +15 -6
- package/dist/esm/input/RadioGroup.js +11 -2
- package/dist/esm/input/{Range.js → RangeSlider.js} +16 -8
- package/dist/esm/input/Search.js +35 -25
- 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 +3 -3
- package/dist/esm/internal/FieldWrapper.js +11 -4
- package/dist/esm/internal/InputWrapper.js +30 -23
- package/dist/esm/select/AutoComplete.js +23 -14
- package/dist/esm/select/DualList.js +35 -13
- package/dist/esm/select/List.js +50 -22
- package/dist/esm/select/Options.js +49 -42
- package/dist/esm/select/Select.js +22 -11
- 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 +49 -6
- package/dist/types/hooks/useFileUploader.d.ts +16 -0
- package/dist/types/hooks/useFormBuilder.d.ts +38 -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 +21 -7
- 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 +38 -10
- 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 +56 -30
- package/src/builder/FormField.tsx +52 -32
- package/src/builder/SchemaEditor.tsx +79 -0
- package/src/builder/components/AddSchemaFields.tsx +75 -0
- package/src/builder/components/SchemaArrayForm.tsx +155 -0
- package/src/builder/components/SchemaField.tsx +435 -0
- package/src/form/Controller.tsx +48 -3
- package/src/form/Form.tsx +84 -13
- package/src/hooks/useFileUploader.ts +16 -0
- package/src/hooks/useFormBuilder.tsx +70 -19
- 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 +195 -66
- package/src/input/AvatarInput.tsx +66 -18
- package/src/input/Checkbox.tsx +22 -9
- package/src/input/ColorInput.tsx +128 -72
- 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 +18 -16
- 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 +28 -18
- package/src/input/Radio.tsx +15 -6
- package/src/input/RadioGroup.tsx +12 -3
- package/src/input/{Range.tsx → RangeSlider.tsx} +17 -9
- package/src/input/Search.tsx +36 -25
- 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 +3 -3
- package/src/internal/FieldWrapper.tsx +8 -4
- package/src/internal/InputWrapper.tsx +56 -30
- package/src/select/AutoComplete.tsx +16 -6
- package/src/select/DualList.tsx +40 -22
- package/src/select/List.tsx +52 -8
- package/src/select/Options.tsx +50 -46
- package/src/select/Select.tsx +29 -10
- package/src/select/useSelect.tsx +26 -9
- package/src/types/index.ts +42 -10
- 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
|
@@ -21,21 +21,20 @@
|
|
|
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 { Button,
|
|
24
|
+
import { Button, Tooltip } from "@react-fabric/core";
|
|
25
25
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
26
|
import classNames from "classnames";
|
|
27
27
|
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")}
|
|
@@ -108,7 +114,9 @@ export const Password = ({
|
|
|
108
114
|
color="warning"
|
|
109
115
|
variant="link"
|
|
110
116
|
aria-label={t(show ? "password.hide" : "password.show")}
|
|
111
|
-
icon={
|
|
117
|
+
icon={
|
|
118
|
+
show ? "icon-[mdi--eye-off-outline]" : "icon-[mdi--eye-outline]"
|
|
119
|
+
}
|
|
112
120
|
onClick={() => setShow(!show)}
|
|
113
121
|
/>
|
|
114
122
|
</Tooltip>
|
|
@@ -116,7 +124,7 @@ export const Password = ({
|
|
|
116
124
|
}
|
|
117
125
|
>
|
|
118
126
|
<input
|
|
119
|
-
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0"
|
|
127
|
+
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 peer"
|
|
120
128
|
aria-invalid={invalid}
|
|
121
129
|
aria-disabled={disabled}
|
|
122
130
|
aria-readonly={readOnly}
|
|
@@ -129,8 +137,10 @@ export const Password = ({
|
|
|
129
137
|
type={show ? "text" : "password"}
|
|
130
138
|
ref={ref}
|
|
131
139
|
autoComplete="off"
|
|
132
|
-
{
|
|
140
|
+
autoFocus={autoFocus}
|
|
133
141
|
value={actualValue}
|
|
142
|
+
onBlur={onBlur}
|
|
143
|
+
onFocus={onFocus}
|
|
134
144
|
onChange={handleChange}
|
|
135
145
|
onKeyDown={handleEnterPressed}
|
|
136
146
|
/>
|
|
@@ -138,7 +148,7 @@ export const Password = ({
|
|
|
138
148
|
<div
|
|
139
149
|
className={classNames(
|
|
140
150
|
"absolute bottom-px h-[3px] inset-x-0 after:block after:h-full after:bg-dimmed",
|
|
141
|
-
"ltr:bg-
|
|
151
|
+
"ltr:bg-linear-to-r rtl:bg-linear-to-l from-danger-500 via-marigold-500 to-jade-500",
|
|
142
152
|
)}
|
|
143
153
|
style={{
|
|
144
154
|
paddingInlineStart: `${strength > 1 ? 100 : strength * 100}%`,
|
package/src/input/Radio.tsx
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
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 {
|
|
24
|
+
import { Icon } from "@react-fabric/core";
|
|
25
25
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
26
|
import classNames from "classnames";
|
|
27
27
|
import { useCallback, useMemo, type ChangeEvent } from "react";
|
|
@@ -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,
|
|
@@ -84,10 +93,10 @@ export const Radio = ({
|
|
|
84
93
|
...rest
|
|
85
94
|
}: RadioProps) => {
|
|
86
95
|
const iconOn = useMemo(
|
|
87
|
-
() => iconChecked ?? icon ??
|
|
96
|
+
() => iconChecked ?? icon ?? "icon-[mdi--radiobox-marked]",
|
|
88
97
|
[icon, iconChecked],
|
|
89
98
|
);
|
|
90
|
-
const iconOff = useMemo(() => icon ??
|
|
99
|
+
const iconOff = useMemo(() => icon ?? "icon-[mdi--radiobox-blank]", [icon]);
|
|
91
100
|
|
|
92
101
|
const handleChange = useCallback(
|
|
93
102
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
@@ -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
|
@@ -21,21 +21,20 @@
|
|
|
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 { Button,
|
|
24
|
+
import { Button, Icon, useDebounce } from "@react-fabric/core";
|
|
25
25
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
26
|
import {
|
|
27
27
|
Fragment,
|
|
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,42 +104,40 @@ 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
|
-
<Icon className="p-2" icon=
|
|
132
|
+
<Icon className="p-2" icon="icon-[svg-spinners--eclipse]" />
|
|
124
133
|
)}
|
|
125
|
-
{!searching && (
|
|
134
|
+
{!searching && !hideHandle && (
|
|
126
135
|
<Button
|
|
127
136
|
tabIndex={-1}
|
|
128
137
|
variant="link"
|
|
129
138
|
aria-label="search"
|
|
130
139
|
disabled={!actualValue}
|
|
131
|
-
icon=
|
|
140
|
+
icon="icon-[mdi--magnify]"
|
|
132
141
|
onClick={handleSearch}
|
|
133
142
|
/>
|
|
134
143
|
)}
|
|
@@ -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
|
);
|