feat(hooks): needed hooks to create input added

This commit is contained in:
Junior Garcia 2023-04-01 16:09:41 -03:00
parent 77e3e7194c
commit 3a7579dbf5
18 changed files with 563 additions and 3 deletions

View File

@ -0,0 +1,24 @@
# @nextui-org/input
A Quick description of the component
> This is an internal utility, not intended for public usage.
## Installation
```sh
yarn add @nextui-org/input
# or
npm i @nextui-org/input
```
## Contribution
Yes please! See the
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
for details.
## Licence
This project is licensed under the terms of the
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).

View File

@ -0,0 +1,19 @@
import * as React from "react";
import {render} from "@testing-library/react";
import {Input} from "../src";
describe("Input", () => {
it("should render correctly", () => {
const wrapper = render(<Input />);
expect(() => wrapper.unmount()).not.toThrow();
});
it("ref should be forwarded", () => {
const ref = React.createRef<HTMLDivElement>();
render(<Input ref={ref} />);
expect(ref.current).not.toBeNull();
});
});

View File

@ -0,0 +1,60 @@
{
"name": "@nextui-org/input",
"version": "2.0.0-beta.1",
"description": "The input component is designed for capturing user input within a text field.",
"keywords": [
"input"
],
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
"license": "MIT",
"main": "src/index.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nextui-org/nextui.git",
"directory": "packages/components/input"
},
"bugs": {
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"build": "tsup src --dts",
"build:fast": "tsup src",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"peerDependencies": {
"react": ">=18"
},
"dependencies": {
"@nextui-org/dom-utils": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/system": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@react-aria/textfield": "^3.9.0"
},
"devDependencies": {
"@react-types/textfield": "^3.7.0",
"clean-package": "2.2.0",
"react": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json",
"tsup": {
"clean": true,
"target": "es2019",
"format": [
"cjs",
"esm"
]
}
}

View File

@ -0,0 +1,10 @@
import Input from "./input";
// export types
export type {InputProps} from "./input";
// export hooks
export {useInput} from "./use-input";
// export component
export {Input};

View File

@ -0,0 +1,19 @@
import {forwardRef} from "@nextui-org/system";
import {UseInputProps, useInput} from "./use-input";
export interface InputProps extends Omit<UseInputProps, "ref"> {}
const Input = forwardRef<InputProps, "div">((props, ref) => {
const {Component, domRef, children, styles, ...otherProps} = useInput({ref, ...props});
return (
<Component ref={domRef} className={styles} {...otherProps}>
{children}
</Component>
);
});
Input.displayName = "NextUI.Input";
export default Input;

View File

@ -0,0 +1,37 @@
import type {InputVariantProps} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {input} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/dom-utils";
import {ReactRef} from "@nextui-org/shared-utils";
import {useMemo} from "react";
export interface UseInputProps extends HTMLNextUIProps<"div", InputVariantProps> {
/**
* Ref to the DOM node.
*/
ref?: ReactRef<HTMLElement | null>;
}
export function useInput(originalProps: UseInputProps) {
const [props, variantProps] = mapPropsVariants(originalProps, input.variantKeys);
const {ref, as, className, ...otherProps} = props;
const Component = as || "div";
const domRef = useDOMRef(ref);
const styles = useMemo(
() =>
input({
...variantProps,
className,
}),
[...Object.values(variantProps), className],
);
return {Component, styles, domRef, ...otherProps};
}
export type UseInputReturn = ReturnType<typeof useInput>;

View File

@ -0,0 +1,46 @@
import React from "react";
import {ComponentStory, ComponentMeta} from "@storybook/react";
import {input} from "@nextui-org/theme";
import {Input, InputProps} from "../src";
export default {
title: "Components/Input",
component: Input,
argTypes: {
color: {
control: {
type: "select",
options: ["neutral", "primary", "secondary", "success", "warning", "danger"],
},
},
radius: {
control: {
type: "select",
options: ["none", "base", "sm", "md", "lg", "xl", "full"],
},
},
size: {
control: {
type: "select",
options: ["xs", "sm", "md", "lg", "xl"],
},
},
isDisabled: {
control: {
type: "boolean",
},
},
},
} as ComponentMeta<typeof Input>;
const defaultProps = {
...input.defaultVariants,
};
const Template: ComponentStory<typeof Input> = (args: InputProps) => <Input {...args} />;
export const Default = Template.bind({});
Default.args = {
...defaultProps,
};

View File

@ -0,0 +1,10 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"tailwind-variants": ["../../../node_modules/tailwind-variants"]
}
},
"include": ["src", "index.ts"]
}

View File

@ -0,0 +1,24 @@
# @nextui-org/use-aria-field
A Quick description of the component
> This is an internal utility, not intended for public usage.
## Installation
```sh
yarn add @nextui-org/use-aria-field
# or
npm i @nextui-org/use-aria-field
```
## Contribution
Yes please! See the
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
for details.
## Licence
This project is licensed under the terms of the
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).

View File

@ -0,0 +1,58 @@
{
"name": "@nextui-org/use-aria-field",
"version": "2.0.0-beta.1",
"description": "Based on react-aria useField hook, provides the accessibility implementation for input fields",
"keywords": [
"use-aria-field"
],
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
"license": "MIT",
"main": "src/index.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nextui-org/nextui.git",
"directory": "packages/hooks/use-aria-field"
},
"bugs": {
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"build": "tsup src --dts",
"build:fast": "tsup src",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"dependencies": {
"@nextui-org/use-aria-label": "workspace:*",
"@nextui-org/use-aria-slot-id": "workspace:*",
"@react-aria/utils": "^3.15.0"
},
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"@react-types/shared": "^3.15.0",
"clean-package": "2.2.0",
"react": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json",
"tsup": {
"clean": true,
"target": "es2019",
"format": [
"cjs",
"esm"
]
}
}

View File

@ -0,0 +1,56 @@
// based on @react-aria/use-field hook, but with useId from react 18
// thanks to @adobe/react-spectrum for the great work ❤️
import {DOMAttributes, HelpTextProps, Validation} from "@react-types/shared";
import {mergeProps} from "@react-aria/utils";
import {LabelAria, LabelAriaProps, useAriaLabel} from "@nextui-org/use-aria-label";
import {useAriaSlotId} from "@nextui-org/use-aria-slot-id";
export interface FieldAria extends LabelAria {
/** Props for the description element, if any. */
descriptionProps: DOMAttributes;
/** Props for the error message element, if any. */
errorMessageProps: DOMAttributes;
}
export interface UseAriaFieldProps
extends LabelAriaProps,
HelpTextProps,
Omit<Validation, "isRequired"> {}
export function useAriaField(props: UseAriaFieldProps = {}): FieldAria {
let {description, errorMessage, validationState} = props;
let {labelProps, fieldProps} = useAriaLabel(props);
let descriptionId = useAriaSlotId([Boolean(description), Boolean(errorMessage), validationState]);
let errorMessageId = useAriaSlotId([
Boolean(description),
Boolean(errorMessage),
validationState,
]);
fieldProps = mergeProps(fieldProps, {
"aria-describedby":
[
descriptionId,
// Use aria-describedby for error message because aria-errormessage is unsupported using VoiceOver or NVDA. See https://github.com/adobe/react-spectrum/issues/1346#issuecomment-740136268
errorMessageId,
props["aria-describedby"],
]
.filter(Boolean)
.join(" ") || undefined,
});
return {
labelProps,
fieldProps,
descriptionProps: {
id: descriptionId,
},
errorMessageProps: {
id: errorMessageId,
},
};
}
export type UseAriaFieldReturn = ReturnType<typeof useAriaField>;

View File

@ -0,0 +1,4 @@
{
"extends": "../../../tsconfig.json",
"include": ["src", "index.ts"]
}

View File

@ -1,3 +1,6 @@
// based on @react-aria/use-label hook, but with useId from react 18
// thanks to @adobe/react-spectrum for the great work ❤️
import {useId} from "react";
import {AriaLabelingProps, DOMAttributes, DOMProps, LabelableProps} from "@react-types/shared";
import {ElementType, LabelHTMLAttributes} from "react";

View File

@ -0,0 +1,24 @@
# @nextui-org/use-aria-slot-id
A Quick description of the component
> This is an internal utility, not intended for public usage.
## Installation
```sh
yarn add @nextui-org/use-aria-slot-id
# or
npm i @nextui-org/use-aria-slot-id
```
## Contribution
Yes please! See the
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
for details.
## Licence
This project is licensed under the terms of the
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).

View File

@ -0,0 +1,55 @@
{
"name": "@nextui-org/use-aria-slot-id",
"version": "2.0.0-beta.1",
"description": "Based on react-aria useSlotId, used to generate an id, and after render check if that id is rendered",
"keywords": [
"use-aria-slot-id"
],
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
"license": "MIT",
"main": "src/index.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nextui-org/nextui.git",
"directory": "packages/hooks/use-aria-slot-id"
},
"bugs": {
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"build": "tsup src --dts",
"build:fast": "tsup src",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"dependencies": {
"@react-aria/utils": "^3.15.0"
},
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"clean-package": "2.2.0",
"react": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json",
"tsup": {
"clean": true,
"target": "es2019",
"format": [
"cjs",
"esm"
]
}
}

View File

@ -0,0 +1,25 @@
// based on @react-aria/use-slot-id hook, but with useId from react 18
// thanks to @adobe/react-spectrum for the great work ❤️
import {useId, useCallback} from "react";
import {useValueEffect, useLayoutEffect} from "@react-aria/utils";
export interface UseAriaSlotIdProps {}
export function useAriaSlotId(depArray: ReadonlyArray<any> = []): string {
let id = useId();
let [resolvedId, setResolvedId] = useValueEffect(id);
let updateId = useCallback(() => {
setResolvedId(function* () {
yield id;
yield document.getElementById(id) ? id : undefined;
});
}, [id, setResolvedId]);
useLayoutEffect(updateId, [id, updateId, ...depArray]);
return resolvedId;
}
export type UseAriaSlotIdReturn = ReturnType<typeof useAriaSlotId>;

View File

@ -0,0 +1,4 @@
{
"extends": "../../../tsconfig.json",
"include": ["src", "index.ts"]
}

88
pnpm-lock.yaml generated
View File

@ -817,6 +817,34 @@ importers:
specifier: ^18.2.0
version: 18.2.0
packages/components/input:
dependencies:
'@nextui-org/dom-utils':
specifier: workspace:*
version: link:../../utilities/dom-utils
'@nextui-org/shared-utils':
specifier: workspace:*
version: link:../../utilities/shared-utils
'@nextui-org/system':
specifier: workspace:*
version: link:../../core/system
'@nextui-org/theme':
specifier: workspace:*
version: link:../../core/theme
'@react-aria/textfield':
specifier: ^3.9.0
version: 3.9.0(react@18.2.0)
devDependencies:
'@react-types/textfield':
specifier: ^3.7.0
version: 3.7.0(react@18.2.0)
clean-package:
specifier: 2.2.0
version: 2.2.0
react:
specifier: ^18.2.0
version: 18.2.0
packages/components/link:
dependencies:
'@nextui-org/dom-utils':
@ -1322,6 +1350,28 @@ importers:
specifier: ^18.2.0
version: 18.2.0
packages/hooks/use-aria-field:
dependencies:
'@nextui-org/use-aria-label':
specifier: workspace:*
version: link:../use-aria-label
'@nextui-org/use-aria-slot-id':
specifier: workspace:*
version: link:../use-aria-slot-id
'@react-aria/utils':
specifier: ^3.15.0
version: 3.15.0(react@18.2.0)
devDependencies:
'@react-types/shared':
specifier: ^3.15.0
version: 3.17.0(react@18.2.0)
clean-package:
specifier: 2.2.0
version: 2.2.0
react:
specifier: ^18.2.0
version: 18.2.0
packages/hooks/use-aria-label:
dependencies:
'@react-aria/utils':
@ -1338,6 +1388,19 @@ importers:
specifier: ^18.2.0
version: 18.2.0
packages/hooks/use-aria-slot-id:
dependencies:
'@react-aria/utils':
specifier: ^3.15.0
version: 3.15.0(react@18.2.0)
devDependencies:
clean-package:
specifier: 2.2.0
version: 2.2.0
react:
specifier: ^18.2.0
version: 18.2.0
packages/hooks/use-clipboard:
devDependencies:
clean-package:
@ -1440,9 +1503,6 @@ importers:
'@nextui-org/theme':
specifier: workspace:*
version: link:../core/theme
'@vercel/analytics':
specifier: ^0.1.6
version: 0.1.6(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
@ -5850,6 +5910,20 @@ packages:
react: 18.2.0
dev: false
/@react-aria/textfield@3.9.0(react@18.2.0):
resolution: {integrity: sha512-plX+/RDidTpz4kfQni2mnH10g9iARC5P7oi4XBXqwrVCIqpTUNoyGLUH952wObYOI9k7lG2QG0+b+3GyrV159g==}
peerDependencies:
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
dependencies:
'@react-aria/focus': 3.11.0(react@18.2.0)
'@react-aria/label': 3.5.0(react@18.2.0)
'@react-aria/utils': 3.15.0(react@18.2.0)
'@react-types/shared': 3.17.0(react@18.2.0)
'@react-types/textfield': 3.7.0(react@18.2.0)
'@swc/helpers': 0.4.14
react: 18.2.0
dev: false
/@react-aria/toggle@3.5.0(react@18.2.0):
resolution: {integrity: sha512-K49OmHBmYW8pk0rXJU1TNRzR+PxLVvfL/ni6ifV5gcxoxV6DmFsNFj+5B/U3AMnCEQeyKQeiY6z9X7EBVX6j9Q==}
peerDependencies:
@ -6139,6 +6213,14 @@ packages:
react: 18.2.0
dev: false
/@react-types/textfield@3.7.0(react@18.2.0):
resolution: {integrity: sha512-4Rqld8VZG324hecw6bqGY2gta1gm5sDhO48nyChfdmjVlFHXLDKazAcrgP76uSmUI6tffUPj3eYxQyTp5uLhyQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
dependencies:
'@react-types/shared': 3.17.0(react@18.2.0)
react: 18.2.0
/@react-types/tooltip@3.3.0(react@18.2.0):
resolution: {integrity: sha512-TMaKkjYbysZbMnY8zjI2Djh8QMHvB8LoN9EjOZX++3ZsO74CeCeOoGARh6+4c0Bu5rg4BXhNyi+y1JL3jtUEBg==}
peerDependencies: