feat(input): data management improved

This commit is contained in:
Junior Garcia 2023-04-15 16:03:49 -03:00
parent da5aa53a6c
commit 8ce412c508
4 changed files with 59 additions and 54 deletions

View File

@ -5,7 +5,7 @@ import {AriaTextFieldProps} from "@react-types/textfield";
import {useFocusRing} from "@react-aria/focus"; import {useFocusRing} from "@react-aria/focus";
import {input} from "@nextui-org/theme"; import {input} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/dom-utils"; import {useDOMRef} from "@nextui-org/dom-utils";
import {usePress} from "@react-aria/interactions"; import {useHover, usePress} from "@react-aria/interactions";
import {clsx, dataAttr} from "@nextui-org/shared-utils"; import {clsx, dataAttr} from "@nextui-org/shared-utils";
import {useControlledState} from "@react-stately/utils"; import {useControlledState} from "@react-stately/utils";
import {useMemo, Ref, RefObject} from "react"; import {useMemo, Ref, RefObject} from "react";
@ -115,6 +115,8 @@ export function useInput(originalProps: UseInputProps) {
isTextInput: true, isTextInput: true,
}); });
const {isHovered, hoverProps} = useHover({isDisabled: !!originalProps?.isDisabled});
const {focusProps: clearFocusProps, isFocusVisible: isClearButtonFocusVisible} = useFocusRing(); const {focusProps: clearFocusProps, isFocusVisible: isClearButtonFocusVisible} = useFocusRing();
const {pressProps: clearPressProps} = usePress({ const {pressProps: clearPressProps} = usePress({
@ -138,19 +140,9 @@ export function useInput(originalProps: UseInputProps) {
...variantProps, ...variantProps,
isInvalid, isInvalid,
isClearable, isClearable,
isFocusVisible,
isLabelPlaceholder: isLabelPlaceholder && !hasStartContent, isLabelPlaceholder: isLabelPlaceholder && !hasStartContent,
isClearButtonFocusVisible,
}), }),
[ [...Object.values(variantProps), isInvalid, isClearable, isLabelPlaceholder, hasStartContent],
...Object.values(variantProps),
isInvalid,
isClearable,
isClearButtonFocusVisible,
isLabelPlaceholder,
hasStartContent,
isFocusVisible,
],
); );
const getBaseProps: PropGetter = (props = {}) => { const getBaseProps: PropGetter = (props = {}) => {
@ -159,6 +151,7 @@ export function useInput(originalProps: UseInputProps) {
"data-focus-visible": dataAttr(isFocusVisible), "data-focus-visible": dataAttr(isFocusVisible),
"data-focused": dataAttr(isFocused), "data-focused": dataAttr(isFocused),
"data-invalid": dataAttr(isInvalid), "data-invalid": dataAttr(isInvalid),
...props, ...props,
}; };
}; };
@ -175,9 +168,6 @@ export function useInput(originalProps: UseInputProps) {
return { return {
ref: domRef, ref: domRef,
className: slots.input({class: clsx(classNames?.input, !!inputValue ? "is-filled" : "")}), className: slots.input({class: clsx(classNames?.input, !!inputValue ? "is-filled" : "")}),
"data-focus-visible": dataAttr(isFocusVisible),
"data-focused": dataAttr(isFocused),
"data-invalid": dataAttr(isInvalid),
...mergeProps(focusProps, inputProps, filterDOMProps(otherProps, {labelable: true}), props), ...mergeProps(focusProps, inputProps, filterDOMProps(otherProps, {labelable: true}), props),
onChange: chain(inputProps.onChange, onChange), onChange: chain(inputProps.onChange, onChange),
}; };
@ -185,6 +175,7 @@ export function useInput(originalProps: UseInputProps) {
const getInputWrapperProps: PropGetter = (props = {}) => { const getInputWrapperProps: PropGetter = (props = {}) => {
return { return {
"data-hover": dataAttr(isHovered),
className: slots.inputWrapper({ className: slots.inputWrapper({
class: clsx(classNames?.inputWrapper, !!inputValue ? "is-filled" : ""), class: clsx(classNames?.inputWrapper, !!inputValue ? "is-filled" : ""),
}), }),
@ -193,7 +184,7 @@ export function useInput(originalProps: UseInputProps) {
domRef.current?.focus(); domRef.current?.focus();
} }
}, },
...props, ...mergeProps(props, hoverProps),
style: { style: {
cursor: "text", cursor: "text",
...props.style, ...props.style,
@ -231,6 +222,7 @@ export function useInput(originalProps: UseInputProps) {
role: "button", role: "button",
tabIndex: 0, tabIndex: 0,
className: slots.clearButton({class: classNames?.clearButton}), className: slots.clearButton({class: classNames?.clearButton}),
"data-focus-visible": dataAttr(isClearButtonFocusVisible),
...mergeProps(clearPressProps, clearFocusProps), ...mergeProps(clearPressProps, clearFocusProps),
}; };
}; };

View File

@ -16,7 +16,7 @@ import {modal} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {useAriaButton} from "@nextui-org/use-aria-button"; import {useAriaButton} from "@nextui-org/use-aria-button";
import {useFocusRing} from "@react-aria/focus"; import {useFocusRing} from "@react-aria/focus";
import {clsx, ReactRef} from "@nextui-org/shared-utils"; import {clsx, dataAttr, ReactRef} from "@nextui-org/shared-utils";
import {useOverlayTrigger} from "@react-aria/overlays"; import {useOverlayTrigger} from "@react-aria/overlays";
import {createDOMRef} from "@nextui-org/dom-utils"; import {createDOMRef} from "@nextui-org/dom-utils";
import {useOverlayTriggerState} from "@react-stately/overlays"; import {useOverlayTriggerState} from "@react-stately/overlays";
@ -148,9 +148,8 @@ export function useModal(originalProps: UseModalProps) {
() => () =>
modal({ modal({
...variantProps, ...variantProps,
isCloseButtonFocusVisible,
}), }),
[...Object.values(variantProps), isCloseButtonFocusVisible], [...Object.values(variantProps)],
); );
const getDialogProps: PropGetter = (props = {}, ref = null) => ({ const getDialogProps: PropGetter = (props = {}, ref = null) => ({
@ -158,6 +157,7 @@ export function useModal(originalProps: UseModalProps) {
...mergeProps(modalProps, otherProps, props), ...mergeProps(modalProps, otherProps, props),
className: slots.base({class: clsx(baseStyles, props.className)}), className: slots.base({class: clsx(baseStyles, props.className)}),
id: dialogId, id: dialogId,
"data-open": dataAttr(state.isOpen),
"aria-modal": true, "aria-modal": true,
"aria-labelledby": headerMounted ? headerId : undefined, "aria-labelledby": headerMounted ? headerId : undefined,
"aria-describedby": bodyMounted ? bodyId : undefined, "aria-describedby": bodyMounted ? bodyId : undefined,
@ -186,6 +186,7 @@ export function useModal(originalProps: UseModalProps) {
role: "button", role: "button",
tabIndex: 0, tabIndex: 0,
"aria-label": "Close", "aria-label": "Close",
"data-focus-visible": dataAttr(isCloseButtonFocusVisible),
className: slots.closeButton({class: classNames?.closeButton}), className: slots.closeButton({class: classNames?.closeButton}),
...mergeProps(closeButtonProps, closeButtonFocusProps), ...mergeProps(closeButtonProps, closeButtonFocusProps),
}; };

View File

@ -2,8 +2,6 @@ import type {VariantProps} from "tailwind-variants";
import {tv} from "tailwind-variants"; import {tv} from "tailwind-variants";
import {ringClasses} from "../utils";
/** /**
* Input wrapper **Tailwind Variants** component * Input wrapper **Tailwind Variants** component
* *
@ -24,7 +22,7 @@ import {ringClasses} from "../utils";
*/ */
const input = tv({ const input = tv({
slots: { slots: {
base: "flex flex-col gap-2", base: "group flex flex-col gap-2",
label: "block text-sm font-medium text-neutral-600", label: "block text-sm font-medium text-neutral-600",
inputWrapper: "relative w-full inline-flex flex-row items-center shadow-sm px-3 gap-3", inputWrapper: "relative w-full inline-flex flex-row items-center shadow-sm px-3 gap-3",
innerWrapper: "inline-flex h-full items-center w-full gap-1.5 box-border", innerWrapper: "inline-flex h-full items-center w-full gap-1.5 box-border",
@ -42,6 +40,13 @@ const input = tv({
"cursor-pointer", "cursor-pointer",
"active:!opacity-70", "active:!opacity-70",
"rounded-full", "rounded-full",
// focus ring
"data-[focus-visible]:outline-none",
"data-[focus-visible]:ring-2",
"data-[focus-visible]:!ring-primary",
"data-[focus-visible]:ring-offset-2",
"data-[focus-visible]:ring-offset-background",
"data-[focus-visible]:dark:ring-offset-background-dark",
], ],
description: "text-xs text-neutral-500", description: "text-xs text-neutral-500",
errorMessage: "text-xs text-danger", errorMessage: "text-xs text-danger",
@ -49,21 +54,25 @@ const input = tv({
variants: { variants: {
variant: { variant: {
flat: { flat: {
inputWrapper: ["bg-neutral-100", "hover:bg-neutral-200", "focus-within:!bg-neutral-100"], inputWrapper: [
"bg-neutral-100",
"data-[hover=true]:bg-neutral-200",
"focus-within:!bg-neutral-100",
],
}, },
faded: { faded: {
inputWrapper: [ inputWrapper: [
"bg-neutral-100", "bg-neutral-100",
"border", "border",
"border-neutral-200", "border-neutral-200",
"hover:border-neutral-400", "data-[hover=true]:border-neutral-400",
], ],
}, },
bordered: { bordered: {
inputWrapper: [ inputWrapper: [
"border-2", "border-2",
"border-neutral-200", "border-neutral-200",
"hover:border-neutral-400", "data-[hover=true]:border-neutral-400",
"focus-within:!border-foreground", "focus-within:!border-foreground",
], ],
}, },
@ -197,14 +206,6 @@ const input = tv({
base: "opacity-50 pointer-events-none", base: "opacity-50 pointer-events-none",
}, },
}, },
isFocusVisible: {
true: {},
},
isClearButtonFocusVisible: {
true: {
clearButton: [...ringClasses],
},
},
isInvalid: { isInvalid: {
true: { true: {
label: "!text-danger", label: "!text-danger",
@ -259,7 +260,7 @@ const input = tv({
class: { class: {
inputWrapper: [ inputWrapper: [
"bg-primary-50", "bg-primary-50",
"hover:bg-primary-100", "data-[hover=true]:bg-primary-100",
"text-primary", "text-primary",
"focus-within:!bg-primary-50", "focus-within:!bg-primary-50",
"placeholder:text-primary", "placeholder:text-primary",
@ -273,7 +274,7 @@ const input = tv({
class: { class: {
inputWrapper: [ inputWrapper: [
"bg-secondary-50", "bg-secondary-50",
"hover:bg-secondary-100", "data-[hover=true]:bg-secondary-100",
"text-secondary", "text-secondary",
"focus-within:!bg-secondary-50", "focus-within:!bg-secondary-50",
"placeholder:text-secondary", "placeholder:text-secondary",
@ -287,7 +288,7 @@ const input = tv({
class: { class: {
inputWrapper: [ inputWrapper: [
"bg-success-50", "bg-success-50",
"hover:bg-success-100", "data-[hover=true]:bg-success-100",
"text-success", "text-success",
"focus-within:!bg-success-50", "focus-within:!bg-success-50",
"placeholder:text-success", "placeholder:text-success",
@ -301,7 +302,7 @@ const input = tv({
class: { class: {
inputWrapper: [ inputWrapper: [
"bg-warning-50", "bg-warning-50",
"hover:bg-warning-100", "data-[hover=true]:bg-warning-100",
"text-warning", "text-warning",
"focus-within:!bg-warning-50", "focus-within:!bg-warning-50",
"placeholder:text-warning", "placeholder:text-warning",
@ -315,7 +316,7 @@ const input = tv({
class: { class: {
inputWrapper: [ inputWrapper: [
"bg-danger-50", "bg-danger-50",
"hover:bg-danger-100", "data-[hover=true]:bg-danger-100",
"text-danger", "text-danger",
"focus-within:!bg-danger-50", "focus-within:!bg-danger-50",
"placeholder:text-danger", "placeholder:text-danger",
@ -329,7 +330,7 @@ const input = tv({
color: "primary", color: "primary",
class: { class: {
label: "text-primary", label: "text-primary",
inputWrapper: "hover:border-primary focus-within:border-primary", inputWrapper: "data-[hover=true]:border-primary focus-within:border-primary",
}, },
}, },
{ {
@ -337,7 +338,7 @@ const input = tv({
color: "secondary", color: "secondary",
class: { class: {
label: "text-secondary", label: "text-secondary",
inputWrapper: "hover:border-secondary focus-within:border-secondary", inputWrapper: "data-[hover=true]:border-secondary focus-within:border-secondary",
}, },
}, },
{ {
@ -345,7 +346,7 @@ const input = tv({
color: "success", color: "success",
class: { class: {
label: "text-success", label: "text-success",
inputWrapper: "hover:border-success focus-within:border-success", inputWrapper: "data-[hover=true]:border-success focus-within:border-success",
}, },
}, },
{ {
@ -353,7 +354,7 @@ const input = tv({
color: "warning", color: "warning",
class: { class: {
label: "text-warning", label: "text-warning",
inputWrapper: "hover:border-warning focus-within:border-warning", inputWrapper: "data-[hover=true]:border-warning focus-within:border-warning",
}, },
}, },
{ {
@ -361,7 +362,7 @@ const input = tv({
color: "danger", color: "danger",
class: { class: {
label: "text-danger", label: "text-danger",
inputWrapper: "hover:border-danger focus-within:border-danger", inputWrapper: "data-[hover=true]:border-danger focus-within:border-danger",
}, },
}, },
// underlined & color // underlined & color
@ -480,12 +481,19 @@ const input = tv({
inputWrapper: "after:transition-width motion-reduce:after:transition-none", inputWrapper: "after:transition-width motion-reduce:after:transition-none",
}, },
}, },
// isFocusVisible & variant // flat & faded
{ {
isFocusVisible: true,
variant: ["flat", "faded"], variant: ["flat", "faded"],
class: { class: {
inputWrapper: [...ringClasses], inputWrapper: [
// focus ring
"group-data-[focus-visible]:outline-none",
"group-data-[focus-visible]:ring-2",
"group-data-[focus-visible]:!ring-primary",
"group-data-[focus-visible]:ring-offset-2",
"group-data-[focus-visible]:ring-offset-background",
"group-data-[focus-visible]:dark:ring-offset-background-dark",
],
}, },
}, },
// isInvalid & variant // isInvalid & variant
@ -493,7 +501,11 @@ const input = tv({
isInvalid: true, isInvalid: true,
variant: "flat", variant: "flat",
class: { class: {
inputWrapper: ["bg-danger-50", "hover:bg-danger-100", "focus-within:!bg-danger-50"], inputWrapper: [
"bg-danger-50",
"data-[hover=true]:bg-danger-100",
"focus-within:!bg-danger-50",
],
}, },
}, },
{ {

View File

@ -2,8 +2,6 @@ import type {VariantProps} from "tailwind-variants";
import {tv} from "tailwind-variants"; import {tv} from "tailwind-variants";
import {ringClasses} from "../utils";
/** /**
* Card **Tailwind Variants** component * Card **Tailwind Variants** component
* *
@ -66,6 +64,13 @@ const modal = tv({
"rounded-full", "rounded-full",
"hover:bg-neutral-100", "hover:bg-neutral-100",
"active:bg-neutral-200", "active:bg-neutral-200",
// focus ring
"data-[focus-visible]:outline-none",
"data-[focus-visible]:ring-2",
"data-[focus-visible]:!ring-primary",
"data-[focus-visible]:ring-offset-2",
"data-[focus-visible]:ring-offset-background",
"data-[focus-visible]:dark:ring-offset-background-dark",
], ],
}, },
variants: { variants: {
@ -130,11 +135,6 @@ const modal = tv({
base: "my-16", base: "my-16",
}, },
}, },
isCloseButtonFocusVisible: {
true: {
closeButton: [...ringClasses],
},
},
}, },
defaultVariants: { defaultVariants: {
size: "md", size: "md",