@povio/ui 2.3.0 → 2.3.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/dist/components/inputs/DateTime/shared/DatePickerInput.js +2 -1
- package/dist/components/inputs/Input/NumberInput/NumberInput.js +14 -9
- package/dist/components/inputs/Input/TextInput/TextInput.js +4 -3
- package/dist/components/inputs/Selection/shared/SelectInput.js +1 -1
- package/dist/components/inputs/shared/InputClear.js +4 -1
- package/dist/components/overlays/BottomSheet/BottomSheet.js +26 -2
- package/dist/config/uiConfig.context.d.ts +3 -1
- package/dist/config/uiConfig.context.js +2 -1
- package/dist/utils/dom.utils.js +1 -1
- package/package.json +1 -1
|
@@ -108,7 +108,8 @@ var DatePickerInput = ({ ref, as, groupProps, fieldProps, endFieldProps, buttonP
|
|
|
108
108
|
icon: TodayIcon,
|
|
109
109
|
size: "none",
|
|
110
110
|
onPress: onToday,
|
|
111
|
-
className: "relative z-1"
|
|
111
|
+
className: "relative z-1",
|
|
112
|
+
isDisabled
|
|
112
113
|
}),
|
|
113
114
|
disableManualEntry && placeholder && !fieldProps.value ? /* @__PURE__ */ jsx(Typography, {
|
|
114
115
|
size: "label-1",
|
|
@@ -33,7 +33,8 @@ var NumberInputBase = (props) => {
|
|
|
33
33
|
locale,
|
|
34
34
|
formatOptions
|
|
35
35
|
};
|
|
36
|
-
const
|
|
36
|
+
const state = useNumberFieldState(numberProps);
|
|
37
|
+
const { labelProps, inputProps } = useNumberField(numberProps, state, numberFieldRef);
|
|
37
38
|
const formFieldProps = {
|
|
38
39
|
error,
|
|
39
40
|
label,
|
|
@@ -47,6 +48,10 @@ var NumberInputBase = (props) => {
|
|
|
47
48
|
headerClassName,
|
|
48
49
|
errorClassName
|
|
49
50
|
};
|
|
51
|
+
const handleInputBlur = useCallback((e) => {
|
|
52
|
+
const target = numberFieldRef.current ?? e?.target;
|
|
53
|
+
onBlur?.({ target });
|
|
54
|
+
}, [onBlur]);
|
|
50
55
|
const inputContentProps = {
|
|
51
56
|
unit,
|
|
52
57
|
isLoading,
|
|
@@ -55,12 +60,12 @@ var NumberInputBase = (props) => {
|
|
|
55
60
|
leadingIcon,
|
|
56
61
|
trailingIcon,
|
|
57
62
|
isClearable,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
onChange: (val) => {
|
|
64
|
+
if (val === "") state.setInputValue("");
|
|
65
|
+
onChange?.(val === "" ? null : Number(val));
|
|
66
|
+
},
|
|
67
|
+
value: state.inputValue,
|
|
68
|
+
onBlur: handleInputBlur
|
|
64
69
|
};
|
|
65
70
|
const headerProps = {
|
|
66
71
|
label,
|
|
@@ -97,10 +102,10 @@ var NumberInputBase = (props) => {
|
|
|
97
102
|
size,
|
|
98
103
|
children: /* @__PURE__ */ jsx(Input, {
|
|
99
104
|
...inputProps,
|
|
100
|
-
ref: mergeRefs(ref, inputRef),
|
|
105
|
+
ref: mergeRefs(ref, inputRef, numberFieldRef),
|
|
101
106
|
"data-is-dirty": isDirty || void 0,
|
|
102
107
|
"data-is-required": isRequired || void 0,
|
|
103
|
-
"data-is-empty":
|
|
108
|
+
"data-is-empty": state.inputValue === "" || state.inputValue === void 0 || state.inputValue === null || void 0,
|
|
104
109
|
placeholder: as === "floating" ? "\xA0" : inputProps.placeholder,
|
|
105
110
|
className: "w-full outline-none",
|
|
106
111
|
onFocus: (e) => {
|
|
@@ -19,13 +19,14 @@ var TextInputBase = (props) => {
|
|
|
19
19
|
const { ref, inputClassName, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, className, unit, isLoading, action, leadingIcon, trailingIcon, value, onChange, onBlur, as = ui.input.as, hideLabel = ui.input.hideLabel, variant = ui.input.variant, size = ui.input.size, isClearable = ui.input.isClearable, ...rest } = props;
|
|
20
20
|
const textFieldRef = useRef(null);
|
|
21
21
|
const { isFocusVisible } = useFocusVisible();
|
|
22
|
+
const inputValue = value ?? "";
|
|
22
23
|
const { labelProps, inputProps } = useTextField({
|
|
23
24
|
...rest,
|
|
24
25
|
label,
|
|
25
26
|
isDisabled,
|
|
26
27
|
isInvalid: !!error,
|
|
27
28
|
isRequired,
|
|
28
|
-
value,
|
|
29
|
+
value: inputValue,
|
|
29
30
|
onChange,
|
|
30
31
|
onBlur
|
|
31
32
|
}, textFieldRef);
|
|
@@ -50,7 +51,7 @@ var TextInputBase = (props) => {
|
|
|
50
51
|
leadingIcon,
|
|
51
52
|
trailingIcon,
|
|
52
53
|
isClearable,
|
|
53
|
-
value,
|
|
54
|
+
value: inputValue,
|
|
54
55
|
onChange,
|
|
55
56
|
onBlur
|
|
56
57
|
};
|
|
@@ -90,7 +91,7 @@ var TextInputBase = (props) => {
|
|
|
90
91
|
children: /* @__PURE__ */ jsx(Input, {
|
|
91
92
|
...inputProps,
|
|
92
93
|
ref: mergeRefs(ref, inputRef),
|
|
93
|
-
"data-is-empty":
|
|
94
|
+
"data-is-empty": inputValue === "" || void 0,
|
|
94
95
|
"data-is-dirty": isDirty || void 0,
|
|
95
96
|
"data-is-required": isRequired || void 0,
|
|
96
97
|
"data-is-disabled": isDisabled || void 0,
|
|
@@ -27,7 +27,7 @@ var SelectInput = ({ ref, placeholder, variant, as, size, isDisabled, isInvalid,
|
|
|
27
27
|
const { fieldState, isOpen, setIsOpen, listItems, selectedItems, onChange, onClear, onRemove, isMultiple, isLoading } = SelectContext.useSelect();
|
|
28
28
|
const isEmpty = selectedItems.length === 0;
|
|
29
29
|
const showTags = isMultiple && !isEmpty;
|
|
30
|
-
const showClearButton = isClearable &&
|
|
30
|
+
const showClearButton = isClearable && (selectedItems.length > 0 || isSearchable && fieldState.inputValue !== "");
|
|
31
31
|
const labelProps = useMemo(() => {
|
|
32
32
|
const { labelProps: headerLabelProps } = headerProps ?? {};
|
|
33
33
|
if (!(as && ["filter", "floating"].includes(as)) || isSearchable) return headerLabelProps;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CloseIcon } from "../../../assets/icons/Close.js";
|
|
2
|
+
import { UIConfig } from "../../../config/uiConfig.context.js";
|
|
2
3
|
import { InlineIconButton } from "../../buttons/InlineIconButton/InlineIconButton.js";
|
|
3
4
|
import "../../../config/i18n.js";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -7,12 +8,14 @@ import { useTranslation } from "react-i18next";
|
|
|
7
8
|
//#region src/components/inputs/shared/InputClear.tsx
|
|
8
9
|
var InputClear = ({ onClear, className, style, show }) => {
|
|
9
10
|
const { t } = useTranslation("ui");
|
|
11
|
+
const alwaysShowClear = UIConfig.useConfig().input.alwaysShowClear;
|
|
10
12
|
return /* @__PURE__ */ jsx(InlineIconButton, {
|
|
11
13
|
color: "secondary",
|
|
12
|
-
className: clsx("
|
|
14
|
+
className: clsx("relative z-1 flex items-center", !alwaysShowClear && "md:invisible group-focus-within:visible group-hover/date-picker-content:visible group-hover/select-content:visible group-hover/text-area:visible group-hover:visible", "border-0!", !show && "invisible!", className),
|
|
13
15
|
label: t(($) => $.ui.clearAlt),
|
|
14
16
|
icon: CloseIcon,
|
|
15
17
|
onPress: onClear,
|
|
18
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
16
19
|
excludeFromTabOrder: true,
|
|
17
20
|
style
|
|
18
21
|
});
|
|
@@ -26,6 +26,7 @@ var staticTransition = {
|
|
|
26
26
|
1
|
|
27
27
|
]
|
|
28
28
|
};
|
|
29
|
+
var KEYBOARD_INSET_THRESHOLD = 48;
|
|
29
30
|
var BottomSheetBase = ({ isOpen, onOpenChange, onStateChange, isDismissable = true, isScrollable = true, height = "full", label, portalContainerRef, children, footer, hideHeader, hideThumb: hideThumbProp, sheetMarginTop = 96, sheetMarginBottom = 128, closeDragThreshold: closeDragThresholdProp, closeVelocityThreshold: closeVelocityThresholdProp, shouldCloseOnInteractOutside, containerClassName, overlayClassName, headerTypography: headerTypographyProp }) => {
|
|
30
31
|
const uiConfig = UIConfig.useConfig();
|
|
31
32
|
const closeDragThreshold = closeDragThresholdProp ?? uiConfig.bottomSheet.closeDragThreshold;
|
|
@@ -48,6 +49,27 @@ var BottomSheetBase = ({ isOpen, onOpenChange, onStateChange, isDismissable = tr
|
|
|
48
49
|
const focusTrapRef = useRef(null);
|
|
49
50
|
const [footerElement, footerRef, setFooterElement] = useStateAndRef(null);
|
|
50
51
|
const [footerHeight, setFooterHeight] = useState(0);
|
|
52
|
+
const [keyboardInset, setKeyboardInset] = useState(0);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!isOpen) {
|
|
55
|
+
setKeyboardInset(0);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const vv = window.visualViewport;
|
|
59
|
+
if (!vv) return;
|
|
60
|
+
const update = () => {
|
|
61
|
+
const naturalHeight = vv.height * Math.max(vv.scale, 1);
|
|
62
|
+
const next = Math.max(0, window.innerHeight - naturalHeight);
|
|
63
|
+
setKeyboardInset(next > KEYBOARD_INSET_THRESHOLD ? Math.round(next) : 0);
|
|
64
|
+
};
|
|
65
|
+
update();
|
|
66
|
+
vv.addEventListener("resize", update);
|
|
67
|
+
vv.addEventListener("scroll", update);
|
|
68
|
+
return () => {
|
|
69
|
+
vv.removeEventListener("resize", update);
|
|
70
|
+
vv.removeEventListener("scroll", update);
|
|
71
|
+
};
|
|
72
|
+
}, [isOpen]);
|
|
51
73
|
useEffect(() => {
|
|
52
74
|
if (!footerElement) return;
|
|
53
75
|
const onResize = () => {
|
|
@@ -77,6 +99,7 @@ var BottomSheetBase = ({ isOpen, onOpenChange, onStateChange, isDismissable = tr
|
|
|
77
99
|
isOpen: true,
|
|
78
100
|
UNSTABLE_portalContainer: portalContainerRef?.current,
|
|
79
101
|
className: clsx("fixed top-0 left-0 z-10 w-screen h-dvh", containerClassName),
|
|
102
|
+
style: { "--bottom-sheet-keyboard-inset": `${keyboardInset}px` },
|
|
80
103
|
onOpenChange,
|
|
81
104
|
isDismissable,
|
|
82
105
|
ref: overlayRef,
|
|
@@ -110,7 +133,8 @@ var BottomSheetBase = ({ isOpen, onOpenChange, onStateChange, isDismissable = tr
|
|
|
110
133
|
transition: staticTransition,
|
|
111
134
|
style: {
|
|
112
135
|
y,
|
|
113
|
-
|
|
136
|
+
height: "calc(100dvh - var(--bottom-sheet-keyboard-inset, 0px))",
|
|
137
|
+
minHeight: "calc(100dvh - var(--bottom-sheet-keyboard-inset, 0px))"
|
|
114
138
|
},
|
|
115
139
|
drag: "y",
|
|
116
140
|
dragListener: false,
|
|
@@ -188,7 +212,7 @@ var BottomSheetBase = ({ isOpen, onOpenChange, onStateChange, isDismissable = tr
|
|
|
188
212
|
initial: { opacity: 0 },
|
|
189
213
|
exit: { opacity: 0 },
|
|
190
214
|
ref: setFooterElement,
|
|
191
|
-
className: clsx("pointer-events-auto absolute z-50 w-full bg-elevation-fill-default-2", "top-[100dvh] left-0 translate-y-[calc(-100%-var(--scroll-position,
|
|
215
|
+
className: clsx("pointer-events-auto absolute z-50 w-full bg-elevation-fill-default-2", "top-[calc(100dvh-var(--bottom-sheet-keyboard-inset,0))] left-0 translate-y-[calc(-100%-var(--scroll-position,0))]"),
|
|
192
216
|
children: footer
|
|
193
217
|
})
|
|
194
218
|
] })
|
|
@@ -19,7 +19,9 @@ export declare namespace UIConfig {
|
|
|
19
19
|
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : Exclude<T[P], null | undefined>;
|
|
20
20
|
};
|
|
21
21
|
export interface Options {
|
|
22
|
-
input: Pick<TextInputProps, "variant" | "isClearable" | "hideLabel" | "as" | "size"
|
|
22
|
+
input: Pick<TextInputProps, "variant" | "isClearable" | "hideLabel" | "as" | "size"> & {
|
|
23
|
+
alwaysShowClear: boolean;
|
|
24
|
+
};
|
|
23
25
|
button: Pick<ButtonProps, "variant" | "size">;
|
|
24
26
|
numberInput: Pick<NumberInputProps, "formatOptions">;
|
|
25
27
|
radioGroup: Pick<RadioGroupProps, "variant" | "hideLabel">;
|
package/dist/utils/dom.utils.js
CHANGED
|
@@ -9,7 +9,7 @@ var DomUtils;
|
|
|
9
9
|
"image"
|
|
10
10
|
]);
|
|
11
11
|
_DomUtils.isKeyboardInput = (elem) => {
|
|
12
|
-
return elem.tagName === "INPUT" && !KEYBOARD_INPUTS.has(elem.type) || elem.hasAttribute("contenteditable");
|
|
12
|
+
return elem.tagName === "INPUT" && !KEYBOARD_INPUTS.has(elem.type) || elem.tagName === "TEXTAREA" || elem.hasAttribute("contenteditable");
|
|
13
13
|
};
|
|
14
14
|
_DomUtils.isKeyboardEvent = (event) => {
|
|
15
15
|
return event.nativeEvent instanceof KeyboardEvent;
|