@react-fabric/form 1.0.0-beta.8 → 1.0.1
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 +95 -0
- package/{src/internal/Field.module.css → css/_field.css} +94 -33
- package/{src/input/File.module.css → css/_file.css} +21 -6
- package/css/styles.css +27 -0
- package/dist/cjs/builder/FileField.js +107 -78
- package/dist/cjs/builder/FormField.js +60 -39
- package/dist/cjs/builder/SchemaEditor.js +72 -0
- package/dist/cjs/builder/components/AddSchemaFields.js +64 -0
- package/dist/cjs/builder/components/SchemaArrayForm.js +146 -0
- package/dist/cjs/builder/components/SchemaField.js +423 -0
- package/dist/cjs/form/Controller.js +66 -19
- package/dist/cjs/form/Form.js +97 -39
- package/dist/cjs/form/useForm.js +32 -0
- package/dist/cjs/hooks/useFileUploader.js +74 -45
- package/dist/cjs/hooks/useFormBuilder.js +85 -31
- package/dist/cjs/i18n/{ar.json.js → ar/form.json.js} +5 -4
- package/dist/cjs/i18n/{en.json.js → en/form.json.js} +5 -5
- package/dist/cjs/i18n/index.js +4 -4
- package/dist/cjs/index.js +41 -2
- package/dist/cjs/input/ArrayInput.js +259 -135
- package/dist/cjs/input/AvatarInput.js +99 -63
- package/dist/cjs/input/Checkbox.js +24 -25
- package/dist/cjs/input/ColorInput.js +138 -81
- package/dist/cjs/input/ColorPicker.js +78 -95
- package/dist/cjs/input/DateInput.js +192 -0
- package/dist/cjs/input/Field.js +21 -20
- package/dist/cjs/input/File.js +85 -80
- package/dist/cjs/input/Hidden.js +27 -13
- package/dist/cjs/input/Input.js +49 -48
- package/dist/cjs/input/Number.js +46 -44
- package/dist/cjs/input/Password.js +51 -49
- package/dist/cjs/input/Radio.js +26 -16
- package/dist/cjs/input/RadioGroup.js +26 -11
- package/dist/cjs/input/{Range.js → RangeSlider.js} +61 -66
- package/dist/cjs/input/Search.js +58 -64
- package/dist/cjs/input/Slider.js +57 -66
- package/dist/cjs/input/Switch.js +29 -27
- package/dist/cjs/input/Textarea.js +65 -53
- package/dist/cjs/internal/ErrorIcon.js +9 -9
- package/dist/cjs/internal/FieldWrapper.js +23 -13
- package/dist/cjs/internal/InputWrapper.js +85 -87
- package/dist/cjs/ranger/index.js +7 -7
- package/dist/cjs/ranger/utils.js +9 -4
- package/dist/cjs/select/AutoComplete.js +93 -76
- package/dist/cjs/select/DualList.js +235 -154
- package/dist/cjs/select/List.js +122 -89
- package/dist/cjs/select/Options.js +58 -54
- package/dist/cjs/select/Select.js +119 -89
- package/dist/cjs/select/helpers.js +5 -5
- package/dist/cjs/select/useSelect.js +83 -58
- package/dist/cjs/types/schema.js +43 -0
- package/dist/cjs/utils/eventHandlers.js +16 -6
- package/dist/cjs/utils/getColor.js +6 -6
- package/dist/cjs/utils/getProps.js +49 -0
- package/dist/esm/builder/FileField.js +109 -80
- package/dist/esm/builder/FormField.js +60 -39
- package/dist/esm/builder/SchemaEditor.js +72 -0
- package/dist/esm/builder/components/AddSchemaFields.js +64 -0
- package/dist/esm/builder/components/SchemaArrayForm.js +146 -0
- package/dist/esm/builder/components/SchemaField.js +423 -0
- package/dist/esm/form/Controller.js +66 -19
- package/dist/esm/form/Form.js +97 -39
- package/dist/esm/form/useForm.js +32 -0
- package/dist/esm/hooks/useFileUploader.js +75 -46
- package/dist/esm/hooks/useFormBuilder.js +84 -30
- package/dist/esm/i18n/{ar.json.js → ar/form.json.js} +5 -4
- package/dist/esm/i18n/{en.json.js → en/form.json.js} +5 -5
- package/dist/esm/i18n/index.js +2 -2
- package/dist/esm/index.js +36 -1
- package/dist/esm/input/ArrayInput.js +260 -136
- package/dist/esm/input/AvatarInput.js +99 -63
- package/dist/esm/input/Checkbox.js +26 -27
- package/dist/esm/input/ColorInput.js +141 -84
- package/dist/esm/input/ColorPicker.js +80 -97
- package/dist/esm/input/DateInput.js +192 -0
- package/dist/esm/input/Field.js +21 -20
- package/dist/esm/input/File.js +89 -84
- package/dist/esm/input/Hidden.js +28 -14
- package/dist/esm/input/Input.js +51 -50
- package/dist/esm/input/Number.js +48 -46
- package/dist/esm/input/Password.js +54 -52
- package/dist/esm/input/Radio.js +27 -17
- package/dist/esm/input/RadioGroup.js +27 -12
- package/dist/esm/input/{Range.js → RangeSlider.js} +62 -67
- package/dist/esm/input/Search.js +61 -67
- package/dist/esm/input/Slider.js +58 -67
- package/dist/esm/input/Switch.js +31 -29
- package/dist/esm/input/Textarea.js +67 -55
- package/dist/esm/internal/ErrorIcon.js +11 -11
- package/dist/esm/internal/FieldWrapper.js +23 -13
- package/dist/esm/internal/InputWrapper.js +88 -90
- package/dist/esm/ranger/index.js +7 -7
- package/dist/esm/ranger/utils.js +9 -4
- package/dist/esm/select/AutoComplete.js +95 -78
- package/dist/esm/select/DualList.js +233 -152
- package/dist/esm/select/List.js +125 -92
- package/dist/esm/select/Options.js +58 -54
- package/dist/esm/select/Select.js +122 -92
- package/dist/esm/select/helpers.js +5 -5
- package/dist/esm/select/useSelect.js +84 -59
- package/{src/input/ColorPicker.module.css → dist/esm/types/schema.js} +18 -27
- package/dist/esm/utils/eventHandlers.js +16 -6
- package/dist/esm/utils/getColor.js +6 -6
- package/dist/esm/utils/getProps.js +49 -0
- package/dist/types/builder/FileField.d.ts +7 -4
- package/dist/types/builder/FormField.d.ts +4 -2
- package/dist/types/builder/SchemaEditor.d.ts +6 -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 +12 -0
- package/dist/types/form/Controller.d.ts +45 -3
- package/dist/types/form/Form.d.ts +38 -7
- package/dist/types/form/useForm.d.ts +6 -0
- package/dist/types/hooks/useFileUploader.d.ts +24 -3
- package/dist/types/hooks/useFormBuilder.d.ts +41 -3
- package/dist/types/index.d.ts +32 -2
- package/dist/types/input/ArrayInput.d.ts +68 -13
- package/dist/types/input/AvatarInput.d.ts +23 -6
- package/dist/types/input/Checkbox.d.ts +12 -10
- package/dist/types/input/ColorInput.d.ts +15 -5
- package/dist/types/input/ColorPicker.d.ts +10 -2
- package/dist/types/input/DateInput.d.ts +21 -0
- package/dist/types/input/Field.d.ts +9 -36
- package/dist/types/input/File.d.ts +16 -4
- package/dist/types/input/Hidden.d.ts +7 -6
- package/dist/types/input/Input.d.ts +11 -4
- package/dist/types/input/Number.d.ts +9 -4
- package/dist/types/input/Password.d.ts +9 -4
- package/dist/types/input/Radio.d.ts +9 -4
- package/dist/types/input/RadioGroup.d.ts +14 -6
- package/dist/types/input/{Range.d.ts → RangeSlider.d.ts} +11 -6
- package/dist/types/input/Search.d.ts +14 -4
- package/dist/types/input/Slider.d.ts +9 -6
- package/dist/types/input/Switch.d.ts +13 -8
- package/dist/types/input/Textarea.d.ts +15 -4
- package/dist/types/internal/ErrorIcon.d.ts +4 -1
- package/dist/types/internal/FieldWrapper.d.ts +10 -1
- package/dist/types/internal/InputWrapper.d.ts +19 -1
- package/dist/types/ranger/index.d.ts +7 -3
- package/dist/types/ranger/utils.d.ts +2 -2
- package/dist/types/select/AutoComplete.d.ts +7 -2
- package/dist/types/select/DualList.d.ts +11 -37
- package/dist/types/select/List.d.ts +7 -2
- package/dist/types/select/Options.d.ts +8 -7
- package/dist/types/select/Select.d.ts +7 -2
- package/dist/types/select/helpers.d.ts +2 -2
- package/dist/types/select/useSelect.d.ts +10 -28
- package/dist/types/types/index.d.ts +73 -39
- package/dist/types/types/schema.d.ts +78 -32
- package/dist/types/utils/eventHandlers.d.ts +4 -4
- package/dist/types/utils/getColor.d.ts +4 -4
- package/dist/types/utils/getProps.d.ts +26 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/package.json +25 -25
- package/src/builder/FileField.tsx +73 -56
- package/src/builder/FormField.tsx +66 -58
- package/src/builder/SchemaEditor.tsx +78 -0
- package/src/builder/components/AddSchemaFields.tsx +64 -0
- package/src/builder/components/SchemaArrayForm.tsx +146 -0
- package/src/builder/components/SchemaField.tsx +405 -0
- package/src/form/Controller.tsx +61 -24
- package/src/form/Form.tsx +74 -50
- package/src/form/useForm.ts +53 -0
- package/src/hooks/useFileUploader.ts +115 -84
- package/src/hooks/useFormBuilder.tsx +80 -41
- package/src/i18n/{ar.json → ar/form.json} +5 -4
- package/src/i18n/{en.json → en/form.json} +5 -5
- package/src/i18n/index.ts +2 -2
- package/src/index.ts +34 -20
- package/src/input/ArrayInput.tsx +255 -173
- package/src/input/AvatarInput.tsx +82 -39
- package/src/input/Checkbox.tsx +30 -54
- package/src/input/ColorInput.tsx +146 -105
- package/src/input/ColorPicker.tsx +76 -102
- package/src/input/DateInput.tsx +225 -0
- package/src/input/Field.tsx +23 -65
- package/src/input/File.tsx +76 -98
- package/src/input/Hidden.tsx +36 -24
- package/src/input/Input.tsx +55 -53
- package/src/input/Number.tsx +49 -54
- package/src/input/Password.tsx +61 -66
- package/src/input/Radio.tsx +28 -37
- package/src/input/RadioGroup.tsx +30 -25
- package/src/input/{Range.tsx → RangeSlider.tsx} +81 -109
- package/src/input/Search.tsx +64 -77
- package/src/input/Slider.tsx +80 -109
- package/src/input/Switch.tsx +39 -53
- package/src/input/Textarea.tsx +72 -59
- package/src/internal/ErrorIcon.tsx +22 -21
- package/src/internal/FieldWrapper.tsx +33 -23
- package/src/internal/InputWrapper.tsx +132 -143
- package/src/ranger/index.tsx +37 -117
- package/src/ranger/utils.ts +12 -11
- package/src/select/AutoComplete.tsx +113 -123
- package/src/select/DualList.tsx +218 -204
- package/src/select/List.tsx +130 -97
- package/src/select/Options.tsx +59 -57
- package/src/select/Select.tsx +148 -122
- package/src/select/helpers.ts +13 -8
- package/src/select/useSelect.tsx +110 -127
- package/src/types/index.ts +76 -45
- package/src/types/schema.ts +97 -40
- package/src/utils/eventHandlers.ts +24 -26
- package/src/utils/getColor.ts +9 -8
- package/src/utils/getProps.ts +47 -0
- package/src/utils/index.ts +1 -0
- 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/src/input/Search.tsx
CHANGED
|
@@ -21,23 +21,14 @@
|
|
|
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,
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
Fragment,
|
|
28
|
-
useCallback,
|
|
29
|
-
useDeferredValue,
|
|
30
|
-
useEffect,
|
|
31
|
-
useMemo,
|
|
32
|
-
useRef,
|
|
33
|
-
useState,
|
|
34
|
-
type ChangeEvent,
|
|
35
|
-
} from "react";
|
|
24
|
+
import { Button, Icon, useControlledValue, useDebounce } from "@react-fabric/core";
|
|
25
|
+
import type { RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
|
+
import { Fragment, useCallback, useId, useRef } from "react";
|
|
36
27
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
28
|
+
import type { InputProps, WrapperProps } from "../types";
|
|
29
|
+
import { getWrapperProps, useHandleEnter } from "../utils";
|
|
39
30
|
|
|
40
|
-
export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
31
|
+
export interface SearchProps extends InputProps, WrapperProps, RefProp<HTMLInputElement> {
|
|
41
32
|
/**
|
|
42
33
|
* is searching
|
|
43
34
|
*/
|
|
@@ -46,98 +37,92 @@ export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
|
46
37
|
* search on value change
|
|
47
38
|
*/
|
|
48
39
|
searchOnChange?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* hide search action handle
|
|
42
|
+
*/
|
|
43
|
+
hideHandle?: boolean;
|
|
49
44
|
/**
|
|
50
45
|
* search handler
|
|
51
46
|
*/
|
|
52
47
|
onSearch?: (query?: string) => void;
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Search input component with optional searching state and search handler.
|
|
52
|
+
* This component allows users to input search queries and trigger a search action.
|
|
53
|
+
* It supports features like searching on value change, showing a search handle,
|
|
54
|
+
* and handling search actions with a debounce mechanism.
|
|
55
|
+
*/
|
|
56
|
+
export function Search(props: SearchProps) {
|
|
57
|
+
const {
|
|
58
|
+
value,
|
|
59
|
+
defaultValue,
|
|
60
|
+
onSearch,
|
|
61
|
+
onChange,
|
|
62
|
+
onBlur,
|
|
63
|
+
onFocus,
|
|
64
|
+
hideHandle,
|
|
65
|
+
disabled,
|
|
66
|
+
readOnly,
|
|
67
|
+
invalid,
|
|
68
|
+
searching,
|
|
69
|
+
searchOnChange,
|
|
70
|
+
placeholder,
|
|
71
|
+
name,
|
|
72
|
+
autoFocus,
|
|
73
|
+
allowClear,
|
|
74
|
+
ref,
|
|
75
|
+
} = props;
|
|
77
76
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
() => onSearch?.(refValue.current),
|
|
81
|
-
[onSearch],
|
|
82
|
-
250,
|
|
83
|
-
);
|
|
77
|
+
const id = useId();
|
|
78
|
+
const { currentValue, updateValue } = useControlledValue(value, defaultValue);
|
|
84
79
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
[handleSearch],
|
|
88
|
-
);
|
|
80
|
+
const valueRef = useRef("");
|
|
81
|
+
const handleSearch = useDebounce(() => onSearch?.(valueRef.current), [onSearch], 250);
|
|
89
82
|
|
|
90
|
-
|
|
91
|
-
setActualValue(deferred ?? "");
|
|
92
|
-
}, [deferred]);
|
|
83
|
+
const handleEnterPressed = useHandleEnter(handleSearch);
|
|
93
84
|
|
|
94
85
|
const handleChange = useCallback(
|
|
95
|
-
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
96
|
-
const value = e?.target.value;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
onChange?.(value
|
|
86
|
+
(e?: React.ChangeEvent<HTMLInputElement>) => {
|
|
87
|
+
const value = e?.target.value ?? defaultValue;
|
|
88
|
+
valueRef.current = value ?? "";
|
|
89
|
+
updateValue(value);
|
|
90
|
+
onChange?.(value);
|
|
100
91
|
|
|
101
|
-
// value was cleared so force fire onSearch
|
|
102
|
-
if (searchOnChange) {
|
|
92
|
+
// when e is undefined value was cleared so force fire onSearch
|
|
93
|
+
if (!e || searchOnChange) {
|
|
103
94
|
handleSearch();
|
|
104
95
|
}
|
|
105
96
|
},
|
|
106
|
-
[onChange, searchOnChange, handleSearch],
|
|
97
|
+
[defaultValue, updateValue, onChange, searchOnChange, handleSearch],
|
|
107
98
|
);
|
|
108
99
|
|
|
109
100
|
return (
|
|
110
101
|
<InputWrapper
|
|
111
|
-
|
|
102
|
+
id={id}
|
|
103
|
+
showClear={allowClear && (currentValue ?? "") !== (defaultValue ?? "") && !disabled && !readOnly}
|
|
112
104
|
onClear={handleChange}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
disabled={disabled}
|
|
117
|
-
required={required}
|
|
118
|
-
decorateStart={decorateStart}
|
|
119
|
-
decorateEnd={
|
|
105
|
+
hasStepper
|
|
106
|
+
{...getWrapperProps(props)}
|
|
107
|
+
actionButton={
|
|
120
108
|
<Fragment>
|
|
121
|
-
{
|
|
122
|
-
{searching && (
|
|
123
|
-
<Icon className="p-2" icon={CoreIcons.spinner} animate="spin" />
|
|
124
|
-
)}
|
|
125
|
-
{!searching && (
|
|
109
|
+
{searching && <Icon className="p-2" icon="icon-[svg-spinners--eclipse]" />}
|
|
110
|
+
{!searching && !hideHandle && (
|
|
126
111
|
<Button
|
|
127
112
|
tabIndex={-1}
|
|
128
113
|
variant="link"
|
|
129
114
|
aria-label="search"
|
|
130
|
-
disabled={!
|
|
131
|
-
icon=
|
|
115
|
+
disabled={!currentValue}
|
|
116
|
+
icon="icon-[mdi--magnify]"
|
|
132
117
|
onClick={handleSearch}
|
|
133
118
|
/>
|
|
134
119
|
)}
|
|
135
120
|
</Fragment>
|
|
136
121
|
}
|
|
137
|
-
{...rest}
|
|
138
122
|
>
|
|
139
123
|
<input
|
|
140
|
-
|
|
124
|
+
id={id}
|
|
125
|
+
className="appearance-none bg-transparent py-1 px-4 not-first:ps-2 not-last:pe-2 flex-1 border-none outline-none ring-0 peer"
|
|
141
126
|
aria-invalid={invalid}
|
|
142
127
|
aria-disabled={disabled}
|
|
143
128
|
aria-readonly={readOnly}
|
|
@@ -151,10 +136,12 @@ export const Search = ({
|
|
|
151
136
|
ref={ref}
|
|
152
137
|
autoComplete="off"
|
|
153
138
|
{...{ autoFocus }}
|
|
154
|
-
value={
|
|
139
|
+
value={currentValue ?? ""}
|
|
140
|
+
onBlur={onBlur}
|
|
141
|
+
onFocus={onFocus}
|
|
155
142
|
onChange={handleChange}
|
|
156
143
|
onKeyDown={handleEnterPressed}
|
|
157
144
|
/>
|
|
158
145
|
</InputWrapper>
|
|
159
146
|
);
|
|
160
|
-
}
|
|
147
|
+
}
|
package/src/input/Slider.tsx
CHANGED
|
@@ -21,22 +21,15 @@
|
|
|
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 { Format } from "@react-fabric/utilities";
|
|
25
|
-
import
|
|
26
|
-
import {
|
|
27
|
-
Fragment,
|
|
28
|
-
useCallback,
|
|
29
|
-
useDeferredValue,
|
|
30
|
-
useEffect,
|
|
31
|
-
useMemo,
|
|
32
|
-
useState,
|
|
33
|
-
} from "react";
|
|
24
|
+
import { Format, cn } from "@react-fabric/utilities";
|
|
25
|
+
import { Fragment, useCallback, useDeferredValue, useEffect, useMemo, useState } from "react";
|
|
34
26
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
35
27
|
import { useRanger } from "../ranger";
|
|
36
|
-
import {
|
|
28
|
+
import type { InputProps, WrapperProps } from "../types";
|
|
29
|
+
import { getWrapperProps } from "../utils";
|
|
37
30
|
|
|
38
31
|
export interface SliderProps
|
|
39
|
-
extends Omit<InputProps<number>, "placeholder" | "allowClear" | "children"
|
|
32
|
+
extends Omit<InputProps<number>, "placeholder" | "allowClear" | "children" | "defaultValue">, WrapperProps {
|
|
40
33
|
/**
|
|
41
34
|
* min value
|
|
42
35
|
*/
|
|
@@ -72,11 +65,11 @@ export interface SliderProps
|
|
|
72
65
|
/**
|
|
73
66
|
* custom min label
|
|
74
67
|
*/
|
|
75
|
-
minLabel?: string;
|
|
68
|
+
minLabel?: string | React.ReactElement;
|
|
76
69
|
/**
|
|
77
70
|
* custom max label
|
|
78
71
|
*/
|
|
79
|
-
maxLabel?: string;
|
|
72
|
+
maxLabel?: string | React.ReactElement;
|
|
80
73
|
/**
|
|
81
74
|
* step ranges
|
|
82
75
|
*/
|
|
@@ -96,36 +89,32 @@ export interface SliderProps
|
|
|
96
89
|
}
|
|
97
90
|
|
|
98
91
|
/**
|
|
99
|
-
*
|
|
92
|
+
* Slider component for rendering a slider input with labels and value display.
|
|
93
|
+
* It supports vertical orientation, custom min/max labels, and step ranges.
|
|
94
|
+
* The component handles value changes, displays tooltips, and integrates with ranger for slider functionality.
|
|
95
|
+
* It also supports deferred value updates for smoother interactions.
|
|
100
96
|
*/
|
|
101
|
-
export
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
onBlur,
|
|
123
|
-
onChange,
|
|
124
|
-
onEnterPressed,
|
|
125
|
-
onFocus,
|
|
126
|
-
onSlide,
|
|
127
|
-
...rest
|
|
128
|
-
}: SliderProps) => {
|
|
97
|
+
export function Slider(props: SliderProps) {
|
|
98
|
+
const {
|
|
99
|
+
value,
|
|
100
|
+
showLabels,
|
|
101
|
+
showValue,
|
|
102
|
+
onChange,
|
|
103
|
+
onSlide,
|
|
104
|
+
ranges,
|
|
105
|
+
useInfinity,
|
|
106
|
+
invalid,
|
|
107
|
+
step = 1,
|
|
108
|
+
min = 0,
|
|
109
|
+
max = 100,
|
|
110
|
+
height = 192,
|
|
111
|
+
vertical,
|
|
112
|
+
minLabel,
|
|
113
|
+
maxLabel,
|
|
114
|
+
format,
|
|
115
|
+
color,
|
|
116
|
+
} = props;
|
|
117
|
+
|
|
129
118
|
const [actualValue, setActualValue] = useState<number>(0);
|
|
130
119
|
const [displayValue, setDisplayValue] = useState(false);
|
|
131
120
|
const deferred = useDeferredValue(value);
|
|
@@ -134,11 +123,12 @@ export const Slider = ({
|
|
|
134
123
|
const maxValue = useMemo(() => ranges?.slice(-1)[0] ?? max, [max, ranges]);
|
|
135
124
|
|
|
136
125
|
useEffect(() => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
);
|
|
126
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect
|
|
127
|
+
setActualValue(useInfinity && deferred === Infinity ? max : (deferred ?? min));
|
|
140
128
|
}, [deferred, min, max, useInfinity]);
|
|
129
|
+
|
|
141
130
|
useEffect(() => {
|
|
131
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect
|
|
142
132
|
setDisplayValue(!!showValue);
|
|
143
133
|
}, [showValue]);
|
|
144
134
|
|
|
@@ -146,7 +136,7 @@ export const Slider = ({
|
|
|
146
136
|
(value: number) => {
|
|
147
137
|
const val = useInfinity && value === max ? Infinity : value;
|
|
148
138
|
setActualValue(val ?? 0);
|
|
149
|
-
onChange?.(val ??
|
|
139
|
+
onChange?.(val ?? null);
|
|
150
140
|
},
|
|
151
141
|
[onChange, max, useInfinity],
|
|
152
142
|
);
|
|
@@ -183,18 +173,10 @@ export const Slider = ({
|
|
|
183
173
|
});
|
|
184
174
|
|
|
185
175
|
return (
|
|
186
|
-
<InputWrapper
|
|
187
|
-
{...rest}
|
|
188
|
-
noOutline
|
|
189
|
-
error={error}
|
|
190
|
-
invalid={invalid}
|
|
191
|
-
isDisabled={disabled}
|
|
192
|
-
isReadOnly={readOnly}
|
|
193
|
-
canClear={!!actualValue}
|
|
194
|
-
>
|
|
176
|
+
<InputWrapper {...getWrapperProps(props)} borderless focusRing>
|
|
195
177
|
<div
|
|
196
|
-
className={
|
|
197
|
-
"flex-
|
|
178
|
+
className={cn(
|
|
179
|
+
"flex-1 order-3 flex items-center select-none relative z-0",
|
|
198
180
|
vertical && "flex-col w-8",
|
|
199
181
|
invalid ? "text-danger-500" : "text-primary-600",
|
|
200
182
|
)}
|
|
@@ -204,17 +186,14 @@ export const Slider = ({
|
|
|
204
186
|
{showLabels && (vertical ? maxDisplay : minDisplay)}
|
|
205
187
|
<div
|
|
206
188
|
ref={rangerInstance.trackElRef}
|
|
207
|
-
className={
|
|
208
|
-
"flex-auto relative flex items-center",
|
|
209
|
-
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
210
|
-
)}
|
|
189
|
+
className={cn("relative flex items-center", vertical ? "my-2 w-8" : "flex-1 mx-2 h-8")}
|
|
211
190
|
style={{ height: vertical ? height : undefined }}
|
|
212
191
|
>
|
|
213
|
-
{rangerInstance.ticks.map(({
|
|
192
|
+
{rangerInstance.ticks.map(({ key, styles }) => (
|
|
214
193
|
<div
|
|
215
194
|
key={key}
|
|
216
|
-
className={
|
|
217
|
-
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-
|
|
195
|
+
className={cn(
|
|
196
|
+
"absolute inline-block h-1 w-1 rounded-sm bg-invert opacity-30 leading-0 z-1",
|
|
218
197
|
vertical && "left-1/2 -ml-0.5",
|
|
219
198
|
)}
|
|
220
199
|
style={styles}
|
|
@@ -223,60 +202,52 @@ export const Slider = ({
|
|
|
223
202
|
{rangerInstance.segments.map(({ key, styles, active }) => (
|
|
224
203
|
<div
|
|
225
204
|
key={key}
|
|
226
|
-
className={
|
|
205
|
+
className={cn(
|
|
227
206
|
"absolute",
|
|
228
|
-
active
|
|
229
|
-
|
|
230
|
-
: "bg-invert opacity-5 z-0",
|
|
231
|
-
vertical
|
|
232
|
-
? "-bottom-1 left-1/2 -translate-x-1/2"
|
|
233
|
-
: "top-1/2 -translate-y-1/2",
|
|
207
|
+
active ? "bg-current z-1 opacity-90" : "bg-invert opacity-5 z-0",
|
|
208
|
+
vertical ? "-bottom-1 left-1/2 -translate-x-1/2" : "top-1/2 -translate-y-1/2",
|
|
234
209
|
!vertical && (active ? "h-1" : "h-0.5"),
|
|
235
210
|
vertical && (active ? "w-1" : "w-0.5"),
|
|
236
211
|
)}
|
|
237
212
|
style={styles}
|
|
238
213
|
/>
|
|
239
214
|
))}
|
|
240
|
-
{rangerInstance.handles.map(
|
|
241
|
-
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
vertical && "left-1/2 -ml-1.5",
|
|
249
|
-
)}
|
|
250
|
-
{...props}
|
|
251
|
-
style={styles}
|
|
252
|
-
/>
|
|
253
|
-
{displayValue && (
|
|
254
|
-
<div
|
|
255
|
-
className={classNames(
|
|
256
|
-
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-[5] whitespace-nowrap",
|
|
257
|
-
"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
|
-
vertical
|
|
259
|
-
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2"
|
|
260
|
-
: "top-1/2 -translate-y-1/2",
|
|
261
|
-
!vertical &&
|
|
262
|
-
(percentage > 50
|
|
263
|
-
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-[0.125rem] rtl:before:-translate-x-[0.125rem] before:end-0"
|
|
264
|
-
: "ms-3 ltr:before:-translate-x-[0.125rem] rtl:before:translate-x-[0.125rem] before:start-0"),
|
|
265
|
-
)}
|
|
266
|
-
data-align={percentage > 50 ? "start" : "end"}
|
|
267
|
-
style={valueStyles}
|
|
268
|
-
>
|
|
269
|
-
{value === Infinity || (useInfinity && value === max)
|
|
270
|
-
? maxLabel ?? "∞"
|
|
271
|
-
: Format.number(value, format)}
|
|
272
|
-
</div>
|
|
215
|
+
{rangerInstance.handles.map(({ key, value, props, styles, percentage, valueStyles }) => (
|
|
216
|
+
<Fragment key={key}>
|
|
217
|
+
<button
|
|
218
|
+
type="button"
|
|
219
|
+
className={cn(
|
|
220
|
+
"bg-current cursor-pointer appearance-none h-3 w-3 rounded-full z-3 absolute",
|
|
221
|
+
"focus:ring-2 focus:ring-offset-2",
|
|
222
|
+
vertical && "left-1/2 -ml-1.5",
|
|
273
223
|
)}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
224
|
+
{...props}
|
|
225
|
+
style={styles}
|
|
226
|
+
/>
|
|
227
|
+
{displayValue && (
|
|
228
|
+
<div
|
|
229
|
+
className={cn(
|
|
230
|
+
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-5 whitespace-nowrap pointer-events-none",
|
|
231
|
+
"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",
|
|
232
|
+
vertical
|
|
233
|
+
? "inset-e-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:inset-s-0"
|
|
234
|
+
: "top-1/2 -translate-y-1/2",
|
|
235
|
+
!vertical &&
|
|
236
|
+
(percentage > 50
|
|
237
|
+
? "-ms-3 ltr:-translate-x-full rtl:translate-x-full ltr:before:translate-x-0.5 rtl:before:-translate-x-0.5 before:inset-e-0"
|
|
238
|
+
: "ms-3 ltr:before:-translate-x-0.5 rtl:before:translate-x-0.5 before:inset-s-0"),
|
|
239
|
+
)}
|
|
240
|
+
data-align={percentage > 50 ? "start" : "end"}
|
|
241
|
+
style={valueStyles}
|
|
242
|
+
>
|
|
243
|
+
{value === Infinity || (useInfinity && value === max) ? (maxLabel ?? "∞") : Format.number(value, format)}
|
|
244
|
+
</div>
|
|
245
|
+
)}
|
|
246
|
+
</Fragment>
|
|
247
|
+
))}
|
|
277
248
|
</div>
|
|
278
249
|
{showLabels && (vertical ? minDisplay : maxDisplay)}
|
|
279
250
|
</div>
|
|
280
251
|
</InputWrapper>
|
|
281
252
|
);
|
|
282
|
-
}
|
|
253
|
+
}
|
package/src/input/Switch.tsx
CHANGED
|
@@ -21,19 +21,10 @@
|
|
|
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 {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from "
|
|
28
|
-
import classNames from "classnames";
|
|
29
|
-
import {
|
|
30
|
-
Fragment,
|
|
31
|
-
useCallback,
|
|
32
|
-
useDeferredValue,
|
|
33
|
-
useEffect,
|
|
34
|
-
useState,
|
|
35
|
-
type ChangeEvent,
|
|
36
|
-
} from "react";
|
|
24
|
+
import { useControlledValue } from "@react-fabric/core";
|
|
25
|
+
import type { ColorUnion, RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
|
+
import { cn } from "@react-fabric/utilities";
|
|
27
|
+
import { Fragment, useCallback } from "react";
|
|
37
28
|
import { ErrorIcon } from "../internal/ErrorIcon";
|
|
38
29
|
import { getBgClass, getColor, getColorClass } from "../utils";
|
|
39
30
|
|
|
@@ -41,7 +32,7 @@ export interface SwitchProps extends RefProp<HTMLInputElement> {
|
|
|
41
32
|
/**
|
|
42
33
|
* Switch label
|
|
43
34
|
*/
|
|
44
|
-
label?:
|
|
35
|
+
label?: React.ReactElement | string;
|
|
45
36
|
/**
|
|
46
37
|
* checked
|
|
47
38
|
*/
|
|
@@ -72,22 +63,28 @@ export interface SwitchProps extends RefProp<HTMLInputElement> {
|
|
|
72
63
|
/**
|
|
73
64
|
* cutom Switch icon
|
|
74
65
|
*/
|
|
75
|
-
color?:
|
|
66
|
+
color?: ColorUnion;
|
|
76
67
|
/**
|
|
77
68
|
* cutom Switch icon
|
|
78
69
|
*/
|
|
79
|
-
defaultColor?:
|
|
70
|
+
defaultColor?: ColorUnion;
|
|
80
71
|
|
|
81
72
|
name?: string;
|
|
82
73
|
|
|
83
74
|
onLabel?: string;
|
|
84
|
-
onLabelColor?:
|
|
75
|
+
onLabelColor?: ColorUnion;
|
|
85
76
|
|
|
86
77
|
offLabel?: string;
|
|
87
|
-
offLabelColor?:
|
|
78
|
+
offLabelColor?: ColorUnion;
|
|
88
79
|
}
|
|
89
80
|
|
|
90
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Switch input component with custom labels and colors.
|
|
83
|
+
* This component renders a switch input with optional labels for the "on" and "off" states,
|
|
84
|
+
* and allows for custom colors for the switch background and labels.
|
|
85
|
+
* It supports disabled and invalid states, and handles change events.
|
|
86
|
+
*/
|
|
87
|
+
export function Switch({
|
|
91
88
|
ref,
|
|
92
89
|
label,
|
|
93
90
|
checked,
|
|
@@ -104,72 +101,63 @@ export const Switch = ({
|
|
|
104
101
|
defaultColor,
|
|
105
102
|
onChange,
|
|
106
103
|
...rest
|
|
107
|
-
}: SwitchProps)
|
|
108
|
-
const
|
|
109
|
-
const deferred = useDeferredValue(!!checked);
|
|
110
|
-
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
setActualValue(deferred);
|
|
113
|
-
}, [deferred]);
|
|
104
|
+
}: SwitchProps) {
|
|
105
|
+
const { currentValue, updateValue } = useControlledValue(!!checked, false);
|
|
114
106
|
|
|
115
107
|
const handleChange = useCallback(
|
|
116
|
-
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
117
|
-
|
|
108
|
+
(e?: React.ChangeEvent<HTMLInputElement>) => {
|
|
109
|
+
updateValue(e?.target.checked ?? false);
|
|
118
110
|
onChange?.(e?.target.checked ?? false);
|
|
119
111
|
},
|
|
120
|
-
[onChange],
|
|
112
|
+
[onChange, updateValue],
|
|
121
113
|
);
|
|
122
114
|
|
|
123
115
|
return (
|
|
124
116
|
<label
|
|
125
|
-
className={
|
|
117
|
+
className={cn(
|
|
126
118
|
invalid ? "ring-danger-500" : "ring-primary-500",
|
|
127
|
-
disabled
|
|
128
|
-
|
|
129
|
-
: "hover:opacity-100 cursor-pointer",
|
|
130
|
-
"inline-flex gap-1 py-1 items-center relative cursor-pointer opacity-85 rounded ring-offset-2 has-[:focus-visible]:ring-1",
|
|
119
|
+
disabled ? "opacity-50 cursor-not-allowed" : "opacity-85 hover:opacity-100 cursor-pointer",
|
|
120
|
+
"inline-flex gap-1 py-1 items-center relative rounded ring-offset-2 has-focus-visible:ring-1",
|
|
131
121
|
)}
|
|
132
122
|
style={{ width }}
|
|
133
123
|
>
|
|
134
124
|
<div
|
|
135
|
-
className={
|
|
136
|
-
|
|
137
|
-
!
|
|
138
|
-
|
|
139
|
-
"relative grid grid-cols-2 items-center h-6 min-w-10 cursor-pointer rounded-full p-1 transition-colors duration-200 ease-in-out",
|
|
125
|
+
className={cn(
|
|
126
|
+
currentValue && getBgClass(color ? `${color}-500` : "primary-500"),
|
|
127
|
+
!currentValue && (defaultColor ? getBgClass(`${defaultColor}-500`) : "bg-tint-200"),
|
|
128
|
+
"relative grid grid-cols-2 items-center h-[1.5em] min-w-[2.5em] rounded-full p-[0.25em] transition-colors duration-200 ease-in-out",
|
|
140
129
|
)}
|
|
141
130
|
style={{
|
|
142
|
-
backgroundColor:
|
|
143
|
-
? getColor(color)
|
|
144
|
-
: getColor(defaultColor),
|
|
131
|
+
backgroundColor: currentValue ? getColor(color) : getColor(defaultColor),
|
|
145
132
|
}}
|
|
146
133
|
>
|
|
147
134
|
<input
|
|
148
|
-
className={
|
|
149
|
-
"appearance-none absolute opacity-0 inset-0 bg-transparent border-none outline-none ring-0",
|
|
135
|
+
className={cn(
|
|
136
|
+
"appearance-none absolute opacity-0 inset-0 bg-transparent border-none cursor-[inherit] outline-none ring-0",
|
|
150
137
|
)}
|
|
151
138
|
aria-invalid={invalid}
|
|
152
139
|
aria-disabled={disabled}
|
|
153
140
|
disabled={disabled}
|
|
154
141
|
aria-errormessage={error}
|
|
155
142
|
type="checkbox"
|
|
143
|
+
name={name}
|
|
156
144
|
ref={ref}
|
|
157
145
|
size={1}
|
|
158
146
|
tabIndex={0}
|
|
159
147
|
autoComplete="off"
|
|
160
|
-
checked={
|
|
148
|
+
checked={!!currentValue}
|
|
161
149
|
onChange={handleChange}
|
|
162
150
|
{...rest}
|
|
163
151
|
/>
|
|
164
152
|
<span
|
|
165
153
|
aria-hidden="true"
|
|
166
|
-
className={
|
|
154
|
+
className={cn(
|
|
167
155
|
!disabled && "shadow-sm",
|
|
168
|
-
|
|
169
|
-
"pointer-events-none inline-block h-
|
|
156
|
+
currentValue ? "translate-x-full" : "translate-x-0",
|
|
157
|
+
"pointer-events-none inline-block h-[1em] inset-s-[0.25em] absolute rounded-full bg-white ring-0 transition duration-200 ease-in-out",
|
|
170
158
|
)}
|
|
171
159
|
style={{
|
|
172
|
-
width: "calc(50% - 0.
|
|
160
|
+
width: "calc(50% - 0.25em)",
|
|
173
161
|
}}
|
|
174
162
|
/>
|
|
175
163
|
{(!!onLabel || !!offLabel) && (
|
|
@@ -194,9 +182,7 @@ export const Switch = ({
|
|
|
194
182
|
)}
|
|
195
183
|
</div>
|
|
196
184
|
<ErrorIcon invalid={invalid} error={error} />
|
|
197
|
-
{label &&
|
|
198
|
-
<span className="flex-initial leading-5 truncate">{label}</span>
|
|
199
|
-
)}
|
|
185
|
+
{label && <span className="flex-initial leading-tight truncate">{label}</span>}
|
|
200
186
|
</label>
|
|
201
187
|
);
|
|
202
|
-
}
|
|
188
|
+
}
|