Skip to content

Commit 7b6d797

Browse files
authored
Merge branch 'nextui-org:canary' into canary
2 parents c9bb12e + e15ef62 commit 7b6d797

22 files changed

+156
-37
lines changed

.changeset/chilly-rules-marry.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/input": patch
3+
---
4+
5+
label placement with file input type (#4364)

.changeset/many-kiwis-pretend.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@nextui-org/alert": patch
3+
"@nextui-org/theme": patch
4+
---
5+
6+
Fix #4382 `hideIconWrapper` property wasn't removing the borded on `Alert` component

.changeset/old-peas-cheat.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/theme": patch
3+
---
4+
5+
menu base use overflow-clip to fix listbox section sticky (#4335)

.changeset/polite-dingos-call.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/alert": patch
3+
---
4+
5+
fix alert slots & variantProps import (#4336)

.changeset/silent-jars-grow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/input-otp": patch
3+
---
4+
5+
Change ensures that the input value does not accept any disallowed characters when the value prop contains them (#4329)

.changeset/two-ghosts-search.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/alert": patch
3+
---
4+
5+
replace decrepate onClick in Alert

packages/components/alert/src/alert.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const iconMap = {
2424

2525
export type AlertColor = keyof typeof iconMap;
2626

27-
export interface AlertProps extends Omit<UseAlertProps, "hasDescription"> {}
27+
export interface AlertProps extends Omit<UseAlertProps, "hasContent"> {}
2828

2929
const Alert = forwardRef<"div", AlertProps>((props, ref) => {
3030
const {
@@ -73,7 +73,7 @@ const Alert = forwardRef<"div", AlertProps>((props, ref) => {
7373
aria-label="Close"
7474
radius="full"
7575
variant="light"
76-
onClick={handleClose}
76+
onPress={handleClose}
7777
{...(getCloseButtonProps() as ButtonProps)}
7878
>
7979
<CloseIcon height={20} width={20} />

packages/components/alert/src/use-alert.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type {ButtonProps} from "@nextui-org/button";
2+
import type {AlertSlots, AlertVariantProps, SlotsToClasses} from "@nextui-org/theme";
23

34
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
4-
import {AlertSlots, SlotsToClasses} from "@nextui-org/theme";
55
import {filterDOMProps, ReactRef, useDOMRef} from "@nextui-org/react-utils";
6-
import {AlertVariantProps} from "@nextui-org/theme/src/components/alert";
76
import {ReactNode, useCallback, useMemo} from "react";
87
import {mergeProps} from "@react-aria/utils";
98
import {alert} from "@nextui-org/theme";
@@ -125,7 +124,7 @@ export function useAlert(originalProps: UseAlertProps) {
125124
}, [setIsVisible, onClose]);
126125

127126
const slots = useMemo(
128-
() => alert({hasDescription: !isEmpty(description), ...variantProps}),
127+
() => alert({hasContent: !isEmpty(description) || !isEmpty(children), ...variantProps}),
129128
[description, objectToDeps(variantProps)],
130129
);
131130

packages/components/alert/stories/alert.stories.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ const CustomStylesTemplate = (args) => {
189189
color={color}
190190
title="The documents you requested are ready to be viewed"
191191
>
192-
<div className="flex items-center gap-1 mt-3">
192+
<div className="flex items-center gap-1">
193193
<Button
194194
className="bg-background text-default-700 font-medium border-1 shadow-small"
195195
size="sm"
@@ -226,6 +226,14 @@ export const WithDescription = {
226226
},
227227
};
228228

229+
export const WithoutIconWrapper = {
230+
render: Template,
231+
args: {
232+
...defaultProps,
233+
hideIconWrapper: true,
234+
},
235+
};
236+
229237
export const Color = {
230238
render: ColorTemplate,
231239
args: {

packages/components/button/__tests__/button-group.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe("ButtonGroup", () => {
2626
const handler = jest.fn();
2727
const wrapper = render(
2828
<ButtonGroup isDisabled={true}>
29-
<Button disableRipple data-testid="button-test" onClick={handler}>
29+
<Button disableRipple data-testid="button-test" onPress={handler}>
3030
action
3131
</Button>
3232
</ButtonGroup>,

packages/components/button/stories/button.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const StateTemplate = (args: ButtonProps) => {
8282
{...args}
8383
aria-label={isOpen ? "Close" : "Open"}
8484
aria-pressed={isOpen}
85-
onClick={handlePress}
85+
onPress={handlePress}
8686
>
8787
{isOpen ? "Close" : "Open"}
8888
</Button>

packages/components/card/__tests__/card.test.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ describe("Card", () => {
4141
expect(onPress).toHaveBeenCalled();
4242
});
4343

44-
it("should trigger onClick function", async () => {
45-
const onClick = jest.fn();
46-
const {getByRole} = render(<Card disableRipple isPressable onClick={onClick} />);
44+
it("should trigger onPress function", async () => {
45+
const onPress = jest.fn();
46+
const {getByRole} = render(<Card disableRipple isPressable onPress={onPress} />);
4747

4848
const button = getByRole("button");
4949

5050
await user.click(button);
5151

52-
expect(onClick).toHaveBeenCalled();
52+
expect(onPress).toHaveBeenCalled();
5353
});
5454

5555
it("should render correctly when nested", () => {

packages/components/dropdown/stories/dropdown.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ const Template = ({
148148
<Button>{label}</Button>
149149
</DropdownTrigger>
150150
<DropdownMenu aria-label="Actions" color={color} variant={variant}>
151-
<DropdownItem key="new" onClick={() => alert("New file")}>
151+
<DropdownItem key="new" onPress={() => alert("New file")}>
152152
New file
153153
</DropdownItem>
154154
<DropdownItem key="copy">Copy link</DropdownItem>

packages/components/input-otp/__tests__/input-otp.test.tsx

+35-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import "@testing-library/jest-dom";
22

33
import * as React from "react";
44
import {render, renderHook, screen} from "@testing-library/react";
5-
import {useForm} from "react-hook-form";
5+
import {Controller, useForm} from "react-hook-form";
66
import userEvent, {UserEvent} from "@testing-library/user-event";
77

88
import {InputOtp} from "../src";
@@ -250,4 +250,38 @@ describe("InputOtp with react-hook-form", () => {
250250

251251
expect(onSubmit).toHaveBeenCalledTimes(1);
252252
});
253+
254+
it("should work correctly wiht react-hook-form controller", async () => {
255+
const {result} = renderHook(() =>
256+
useForm({
257+
defaultValues: {
258+
withController: "",
259+
},
260+
}),
261+
);
262+
263+
const {control} = result.current;
264+
265+
render(
266+
<form>
267+
<Controller
268+
control={control}
269+
name="withController"
270+
render={({field}) => <InputOtp length={4} {...field} data-testid="input-otp" />}
271+
/>
272+
</form>,
273+
);
274+
275+
const inputOtp = screen.getByTestId("input-otp");
276+
const input = inputOtp.querySelector("input");
277+
278+
if (!input) {
279+
throw new Error("Input not found");
280+
}
281+
282+
await user.click(input);
283+
await user.type(input, "1nj23aa4");
284+
285+
expect(input).toHaveAttribute("value", "1234");
286+
});
253287
});

packages/components/input-otp/src/use-input-otp.ts

+9
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export function useInputOtp(originalProps: UseInputOtpProps) {
119119
pasteTransformer,
120120
containerClassName,
121121
noScriptCSSFallback,
122+
onChange,
122123
...otherProps
123124
} = props;
124125

@@ -209,6 +210,14 @@ export function useInputOtp(originalProps: UseInputOtpProps) {
209210
}),
210211
filterDOMProps(props),
211212
),
213+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
214+
const val = e.target?.value;
215+
const regex = new RegExp(allowedKeys);
216+
217+
if (regex.test(val)) {
218+
onChange?.(e);
219+
}
220+
},
212221
};
213222
},
214223
[baseDomRef, slots, baseStyles, isDisabled, isInvalid, isRequired, isReadOnly, value, length],

packages/components/input-otp/stories/input-otp.stories.tsx

+52-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import {Meta} from "@storybook/react";
33
import {button, inputOtp} from "@nextui-org/theme";
4-
import {useForm} from "react-hook-form";
4+
import {Controller, useForm} from "react-hook-form";
55
import {ValidationResult} from "@react-types/shared";
66
import {Button} from "@nextui-org/button";
77
import {Form} from "@nextui-org/form";
@@ -177,6 +177,49 @@ const WithReactHookFormTemplate = (args) => {
177177
);
178178
};
179179

180+
const WithReactHookFormControllerTemplate = (args) => {
181+
const {
182+
handleSubmit,
183+
control,
184+
formState: {errors},
185+
} = useForm({
186+
defaultValues: {
187+
otp: "",
188+
},
189+
});
190+
191+
const onSubmit = (data) => {
192+
alert(JSON.stringify(data));
193+
};
194+
195+
return (
196+
<form className="flex flex-col gap-4 w-full max-w-[300px]" onSubmit={handleSubmit(onSubmit)}>
197+
<Controller
198+
control={control}
199+
name="otp"
200+
render={({field}) => (
201+
<InputOtp
202+
{...field}
203+
errorMessage={errors.otp && errors.otp.message}
204+
isInvalid={!!errors.otp}
205+
{...args}
206+
/>
207+
)}
208+
rules={{
209+
required: "OTP is required",
210+
minLength: {
211+
value: 4,
212+
message: "Please enter a valid OTP",
213+
},
214+
}}
215+
/>
216+
<Button className="max-w-fit" type="submit" variant="flat">
217+
Verify OTP
218+
</Button>
219+
</form>
220+
);
221+
};
222+
180223
const ServerValidationTemplate = (args) => {
181224
const [serverErrors, setServerErrors] = React.useState({});
182225

@@ -337,6 +380,14 @@ export const WithReactHookForm = {
337380
},
338381
};
339382

383+
export const WithReactHookFormController = {
384+
render: WithReactHookFormControllerTemplate,
385+
args: {
386+
...defaultProps,
387+
length: 4,
388+
},
389+
};
390+
340391
export const CustomWithClassNames = {
341392
render: Template,
342393
args: {

packages/components/input/src/use-input.ts

+1-14
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {useFocusRing} from "@react-aria/focus";
1313
import {input} from "@nextui-org/theme";
1414
import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
1515
import {useFocusWithin, useHover, usePress} from "@react-aria/interactions";
16-
import {clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel, warn} from "@nextui-org/shared-utils";
16+
import {clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel} from "@nextui-org/shared-utils";
1717
import {useControlledState} from "@react-stately/utils";
1818
import {useMemo, Ref, useCallback, useState} from "react";
1919
import {chain, mergeProps} from "@react-aria/utils";
@@ -228,19 +228,6 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
228228
const isInvalid = validationState === "invalid" || isAriaInvalid;
229229

230230
const labelPlacement = useMemo<InputVariantProps["labelPlacement"]>(() => {
231-
if (isFileTypeInput) {
232-
// if `labelPlacement` is not defined, choose `outside` instead
233-
// since the default value `inside` is not supported in file input
234-
if (!originalProps.labelPlacement) return "outside";
235-
236-
// throw a warning if `labelPlacement` is `inside`
237-
// and change it to `outside`
238-
if (originalProps.labelPlacement === "inside") {
239-
warn("Input with file type doesn't support inside label. Converting to outside ...");
240-
241-
return "outside";
242-
}
243-
}
244231
if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) {
245232
return "outside";
246233
}

packages/components/link/stories/link.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const PressableTemplate = (args: LinkProps) => {
5858
};
5959

6060
return (
61-
<Link {...args} onClick={handlePress}>
61+
<Link {...args} onPress={handlePress}>
6262
{isOpen ? "Open" : "Close"}
6363
</Link>
6464
);

packages/components/listbox/stories/listbox.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ const Template = ({color, variant, ...args}: ListboxProps) => (
174174
onAction={(key: Key) => alert(key)}
175175
{...args}
176176
>
177-
<ListboxItem key="new" onClick={() => alert("[onClick] New file")}>
177+
<ListboxItem key="new" onPress={() => alert("[onPress] New file")}>
178178
New file
179179
</ListboxItem>
180180
<ListboxItem key="copy">Copy link</ListboxItem>

packages/components/menu/stories/menu.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const defaultProps = {
4545

4646
const Template = ({color, variant, ...args}: MenuProps) => (
4747
<Menu aria-label="Actions" color={color} variant={variant} onAction={alert} {...args}>
48-
<MenuItem key="new" onClick={() => alert("[onClick] New file")}>
48+
<MenuItem key="new" onPress={() => alert("[onPress] New file")}>
4949
New file
5050
</MenuItem>
5151
<MenuItem key="copy">Copy link</MenuItem>

packages/core/theme/src/components/alert.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const alert = tv({
2929
title: "text-small w-full font-medium block text-inherit leading-5",
3030
description: "pl-[1px] text-small font-normal text-inherit",
3131
closeButton: "relative text-inherit translate-x-1 -translate-y-1",
32-
iconWrapper: "flex-none relative w-9 h-9 rounded-full",
32+
iconWrapper: "flex-none relative w-9 h-9 rounded-full grid place-items-center",
3333
alertIcon: "fill-current w-6 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2",
3434
},
3535
variants: {
@@ -76,13 +76,13 @@ const alert = tv({
7676
hideIconWrapper: {
7777
true: {
7878
base: "gap-x-0",
79-
iconWrapper: "!bg-transparent !shadow-none",
79+
iconWrapper: "!bg-transparent !shadow-none !border-none",
8080
},
8181
},
82-
hasDescription: {
82+
hasContent: {
8383
false: {
8484
base: "items-start",
85-
mainWrapper: "justify-center",
85+
mainWrapper: "justify-center items-center",
8686
},
8787
},
8888
},

packages/core/theme/src/components/menu.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {dataFocusVisibleClasses} from "../utils";
1111
*/
1212
const menu = tv({
1313
slots: {
14-
base: "w-full relative flex flex-col gap-1 p-1 overflow-hidden",
14+
base: "w-full relative flex flex-col gap-1 p-1 overflow-clip",
1515
list: "w-full flex flex-col gap-0.5 outline-none",
1616
emptyContent: [
1717
"h-10",

0 commit comments

Comments
 (0)