Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce NumberField #4475

Draft
wants to merge 82 commits into
base: canary
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
0764168
feat(number-field): init structure
wingkwong Dec 15, 2024
2101db4
Merge branch 'canary' into feat/eng-363
wingkwong Dec 20, 2024
0bfd74d
feat(deps): add `@nextui-org/button` & `@react-types/button`
wingkwong Dec 21, 2024
914783f
feat(theme): export number-field
wingkwong Dec 21, 2024
18d7139
feat(number-field): storybook init structure
wingkwong Dec 21, 2024
4dff6f1
feat(number-field): add NumberFieldHorizontalStepper
wingkwong Dec 21, 2024
d3ba207
feat(number-field): add NumberFieldHorizontalStepper
wingkwong Dec 21, 2024
e9b3049
feat(theme): init number field theme
wingkwong Dec 21, 2024
a8a7a77
feat(number-field): number-field draft
wingkwong Dec 21, 2024
9a9cb46
refactor(number-field): revise stepper icons
wingkwong Dec 21, 2024
5b55991
feat(shared-icons): add ChevronLeftIcon
wingkwong Dec 21, 2024
52d3673
feat(theme): stepperButton styles
wingkwong Dec 21, 2024
b67320d
feat(theme): number-field styles
wingkwong Dec 22, 2024
37b06be
fix(number-field): label layout
wingkwong Dec 22, 2024
31b971c
Merge branch 'canary' into feat/eng-363
wingkwong Dec 24, 2024
3adda56
feat(number-field): vertical stepper wrapper
wingkwong Dec 24, 2024
734af76
feat(number-field): use-number-field (wip)
wingkwong Dec 24, 2024
7f49f00
feat(number-field): add data-direction
wingkwong Dec 24, 2024
f3f8057
feat(theme): center the text if it is horizontal stepper
wingkwong Dec 24, 2024
0ddddd6
feat(number-field): add HorizontalStepper
wingkwong Dec 24, 2024
2cc8470
feat(number-field): add HideStepper
wingkwong Dec 24, 2024
79d2cbc
chore(number-field): revise minValue & defaultValue
wingkwong Dec 24, 2024
c82faa6
feat(docs): init number field structure
wingkwong Dec 24, 2024
823bc99
fix(theme): outside-left styles
wingkwong Dec 24, 2024
14e284b
Merge branch 'canary' into feat/eng-363
wingkwong Dec 27, 2024
8d54dab
refactor(theme): remove labelPlacement styles
wingkwong Dec 27, 2024
5998dea
refactor(number-field): remove labelContent logic
wingkwong Dec 27, 2024
7d17aef
refactor(number-field): remove labelPlacement args
wingkwong Dec 27, 2024
3f5d8f0
Merge branch 'canary' into feat/eng-363
wingkwong Dec 28, 2024
0ad45c8
feat(number-field): helper text
wingkwong Dec 28, 2024
6f42342
feat(number-field): revise number field stories
wingkwong Dec 28, 2024
68fd5be
feat(number-field): description
wingkwong Dec 28, 2024
8fca2bc
refactor(number-field): revise number field stories
wingkwong Dec 28, 2024
9897a56
feat(theme): numberFieldLabelClasses
wingkwong Dec 28, 2024
d085088
fix(number-field): incorrect button props
wingkwong Dec 28, 2024
61c991e
fix(number-field): typing issue on stepper buttons
wingkwong Dec 28, 2024
ad56507
Merge branch 'canary' into feat/eng-363
wingkwong Dec 31, 2024
2f78e9c
chore(number-field): add aria-label
wingkwong Dec 31, 2024
04e6bc9
refactor(number-field): merge props
wingkwong Dec 31, 2024
29c32bf
fix(number-field): pass originalProps instead
wingkwong Dec 31, 2024
2da4d9c
chore(number-field): revise Required story args
wingkwong Dec 31, 2024
1c3d416
feat(number-field): add WithStepValue & WithWheelDisabled & revise st…
wingkwong Jan 1, 2025
9af3f4b
chore(number-field): add label to Required
wingkwong Jan 1, 2025
1c3858a
feat(docs): number-field doc page
wingkwong Jan 1, 2025
5448878
fix(number-field): typing issue
wingkwong Jan 1, 2025
b7028a6
fix(number-field): test cases
wingkwong Jan 1, 2025
ed783f3
fix(number-field): user.keyboard & defaultValue
wingkwong Jan 1, 2025
02ff389
fix(number-field): should work with defaultValues
wingkwong Jan 1, 2025
c628b0c
chore(number-field): add type: number
wingkwong Jan 1, 2025
fb82263
chore(number-field): remove hidden related code
wingkwong Jan 1, 2025
59433b0
fix(number-field): numeric value
wingkwong Jan 1, 2025
498e02d
chore(changeset): add changeset
wingkwong Jan 1, 2025
439eee5
feat(deps): add "@nextui-org/number-field" to docs
wingkwong Jan 1, 2025
5b26972
feat(react): export `@nextui-org/number-field`
wingkwong Jan 1, 2025
cf7e2e3
feat(changeset): add @nextui-org/react
wingkwong Jan 1, 2025
7cf4fd4
feat(docs): number-field examples
wingkwong Jan 1, 2025
10f80f4
chore(number-field): use text instead
wingkwong Jan 1, 2025
eb9ba4c
refactor(number-field): remove unnecessary filled-within
wingkwong Jan 1, 2025
6ba9b27
fix(number-field): test case
wingkwong Jan 2, 2025
4c71835
Merge branch 'canary' into feat/eng-363
wingkwong Jan 4, 2025
500a161
chore(number-field): remove aria-label for stepper buttons
wingkwong Jan 4, 2025
5be13df
feat(docs): add incrementAriaLabel & decrementAriaLabel to NumberField
wingkwong Jan 4, 2025
9d7ba10
chore(number-field): reorder WithFormatOptions
wingkwong Jan 4, 2025
c165bef
fix(deps): update number-field's peerDependencies & dependencies
wingkwong Jan 4, 2025
231bc83
feat(number-field): hidden input for holding numeric vaule
wingkwong Jan 4, 2025
5d2cd06
fix(docs): number field title
wingkwong Jan 4, 2025
939eda8
feat(docs): add format options to number field
wingkwong Jan 4, 2025
db3a825
chore(docs): revise number field content
wingkwong Jan 4, 2025
85ce591
chore(number-field): add type to useDOMRef
wingkwong Jan 4, 2025
b39f664
fix(number-field): clear button
wingkwong Jan 4, 2025
a00a316
fix(theme): clear button styles
wingkwong Jan 4, 2025
f7cb758
refactor(theme): stepper button styles
wingkwong Jan 4, 2025
843849b
chore(number-field): accept stepperButton class
wingkwong Jan 4, 2025
ac0c559
fix(theme): helper wrapper padding
wingkwong Jan 5, 2025
25ad5cb
feat(deps): add `@react-aria/i18n`
wingkwong Jan 5, 2025
b8de20c
fix(number-field): use locale from `@react-aria/i18n`
wingkwong Jan 5, 2025
c097167
Merge branch 'canary' into feat/eng-363
wingkwong Jan 5, 2025
01bcd26
fix(deps): dependency order
wingkwong Jan 5, 2025
9510a41
Merge branch 'canary' into feat/eng-363
wingkwong Jan 6, 2025
51a88d1
fix(docs): incorrect command
wingkwong Jan 6, 2025
cd00b74
chore(docs): remove type=number
wingkwong Jan 7, 2025
8bf0ee1
chore(theme): add padding to stepper wrapper
wingkwong Jan 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/witty-flies-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@nextui-org/number-field": patch
"@nextui-org/shared-icons": patch
"@nextui-org/theme": patch
"@nextui-org/react": minor
---

introduce NumberField
7 changes: 7 additions & 0 deletions apps/docs/config/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,13 @@
"keywords": "navbar, navigation, top menu, website header",
"path": "/docs/components/navbar.mdx"
},
{
"key": "number-field",
"title": "Number Field",
"keywords": "input, numeric input, number field",
"path": "/docs/components/number-field.mdx",
"newPost": true
},
{
"key": "pagination",
"title": "Pagination",
Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export * from "./table";
export * from "./autocomplete";
export * from "./alert";
export * from "./drawer";
export * from "./number-field";
16 changes: 16 additions & 0 deletions apps/docs/content/components/number-field/clear-button.raw.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {NumberField} from "@nextui-org/react";

export default function App() {
return (
<NumberField
isClearable
className="max-w-xs"
defaultValue={1024}
label="Width"
placeholder="Enter the width"
variant="bordered"
// eslint-disable-next-line no-console
onClear={() => console.log("number field cleared")}
/>
);
}
9 changes: 9 additions & 0 deletions apps/docs/content/components/number-field/clear-button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import App from "./clear-button.raw.jsx?raw";

const react = {
"/App.jsx": App,
};

export default {
...react,
};
20 changes: 20 additions & 0 deletions apps/docs/content/components/number-field/colors.raw.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {NumberField} from "@nextui-org/react";

export default function App() {
const colors = ["default", "primary", "secondary", "success", "warning", "danger"];

return (
<div className="w-full flex flex-row flex-wrap gap-4">
{colors.map((color) => (
<NumberField
key={color}
className="max-w-[220px]"
color={color}
defaultValue={1024}
label="Width"
placeholder="Enter the width"
/>
))}
</div>
);
}
9 changes: 9 additions & 0 deletions apps/docs/content/components/number-field/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import App from "./colors.raw.jsx?raw";

const react = {
"/App.jsx": App,
};

export default {
...react,
};
17 changes: 17 additions & 0 deletions apps/docs/content/components/number-field/controlled.raw.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {NumberField} from "@nextui-org/react";

export default function App() {
const [value, setValue] = React.useState();

return (
<div className="w-full flex flex-col gap-2 max-w-[240px]">
<NumberField
label="Width"
placeholder="Enter the width"
value={value}
onValueChange={setValue}
/>
<p className="text-default-500 text-small">NumberField value: {value}</p>
</div>
);
}
9 changes: 9 additions & 0 deletions apps/docs/content/components/number-field/controlled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import App from "./controlled.raw.jsx?raw";

const react = {
"/App.jsx": App,
};

export default {
...react,
};
162 changes: 162 additions & 0 deletions apps/docs/content/components/number-field/custom-impl.raw.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import React, {forwardRef} from "react";
import {useInput} from "@nextui-org/react";

export const SearchIcon = (props) => {
return (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M11.5 21C16.7467 21 21 16.7467 21 11.5C21 6.25329 16.7467 2 11.5 2C6.25329 2 2 6.25329 2 11.5C2 16.7467 6.25329 21 11.5 21Z"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
<path
d="M22 22L20 20"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
</svg>
);
};

export const CloseFilledIcon = (props) => {
return (
<svg
aria-hidden="true"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M12 2a10 10 0 1010 10A10.016 10.016 0 0012 2zm3.36 12.3a.754.754 0 010 1.06.748.748 0 01-1.06 0l-2.3-2.3-2.3 2.3a.748.748 0 01-1.06 0 .754.754 0 010-1.06l2.3-2.3-2.3-2.3A.75.75 0 019.7 8.64l2.3 2.3 2.3-2.3a.75.75 0 011.06 1.06l-2.3 2.3z"
fill="currentColor"
/>
</svg>
);
};

const styles = {
label: "text-black/50 dark:text-white/90",
input: [
"bg-transparent",
"text-black/90 dark:text-white/90",
"placeholder:text-default-700/50 dark:placeholder:text-white/60",
],
innerWrapper: "bg-transparent",
inputWrapper: [
"shadow-xl",
"bg-default-200/50",
"dark:bg-default/60",
"backdrop-blur-xl",
"backdrop-saturate-200",
"hover:bg-default-200/70",
"focus-within:!bg-default-200/50",
"dark:hover:bg-default/70",
"dark:focus-within:!bg-default/60",
"!cursor-text",
],
};

const MyInput = forwardRef((props, ref) => {
const {
Component,
label,
domRef,
description,
isClearable,
startContent,
endContent,
shouldLabelBeOutside,
shouldLabelBeInside,
errorMessage,
getBaseProps,
getLabelProps,
getInputProps,
getInnerWrapperProps,
getInputWrapperProps,
getDescriptionProps,
getErrorMessageProps,
getClearButtonProps,
} = useInput({
...props,
ref,
// this is just for the example, the props bellow should be passed by the parent component
label: "Search",
type: "search",
placeholder: "Type to search...",
startContent: (
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
),
// custom styles
classNames: {
...styles,
},
});

const labelContent = <label {...getLabelProps()}>{label}</label>;

const end = React.useMemo(() => {
if (isClearable) {
return <span {...getClearButtonProps()}>{endContent || <CloseFilledIcon />}</span>;
}

return endContent;
}, [isClearable, getClearButtonProps]);

const innerWrapper = React.useMemo(() => {
if (startContent || end) {
return (
<div {...getInnerWrapperProps()}>
{startContent}
<input {...getInputProps()} />
{end}
</div>
);
}

return <input {...getInputProps()} />;
}, [startContent, end, getInputProps, getInnerWrapperProps]);

return (
<div className="w-[340px] h-[300px] px-8 rounded-2xl flex justify-center items-center bg-gradient-to-tr from-pink-500 to-yellow-500 text-white shadow-lg">
<Component {...getBaseProps()}>
{shouldLabelBeOutside ? labelContent : null}
<div
tabIndex={0}
{...getInputWrapperProps()}
role="button"
onClick={() => {
domRef.current?.focus();
}}
onKeyDown={() => {
domRef.current?.focus();
}}
>
{shouldLabelBeInside ? labelContent : null}
{innerWrapper}
</div>
{description && <div {...getDescriptionProps()}>{description}</div>}
{errorMessage && <div {...getErrorMessageProps()}>{errorMessage}</div>}
</Component>
</div>
);
});

MyInput.displayName = "MyInput";

export default MyInput;
9 changes: 9 additions & 0 deletions apps/docs/content/components/number-field/custom-impl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import App from "./custom-impl.raw.jsx?raw";

const react = {
"/App.jsx": App,
};

export default {
...react,
};
68 changes: 68 additions & 0 deletions apps/docs/content/components/number-field/custom-styles.raw.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {NumberField} from "@nextui-org/react";

export const SearchIcon = (props) => {
return (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M11.5 21C16.7467 21 21 16.7467 21 11.5C21 6.25329 16.7467 2 11.5 2C6.25329 2 2 6.25329 2 11.5C2 16.7467 6.25329 21 11.5 21Z"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
<path
d="M22 22L20 20"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
</svg>
);
};

export default function App() {
return (
<div className="w-[340px] h-[240px] px-8 rounded-2xl flex justify-center items-center bg-gradient-to-tr from-pink-500 to-yellow-500 text-white shadow-lg">
<NumberField
isClearable
classNames={{
label: "text-black/50 dark:text-white/90",
input: [
"bg-transparent",
"text-black/90 dark:text-white/90",
"placeholder:text-default-700/50 dark:placeholder:text-white/60",
],
innerWrapper: "bg-transparent",
inputWrapper: [
"shadow-xl",
"bg-default-200/50",
"dark:bg-default/60",
"backdrop-blur-xl",
"backdrop-saturate-200",
"hover:bg-default-200/70",
"dark:hover:bg-default/70",
"group-data-[focus=true]:bg-default-200/50",
"dark:group-data-[focus=true]:bg-default/60",
"!cursor-text",
],
}}
label="Search"
placeholder="Type to search..."
radius="lg"
startContent={
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
}
/>
</div>
);
}
9 changes: 9 additions & 0 deletions apps/docs/content/components/number-field/custom-styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import App from "./custom-styles.raw.jsx?raw";

const react = {
"/App.jsx": App,
};

export default {
...react,
};
Loading
Loading