* fix(select): select & input styles fixed

* chore(input): extra data attr added to input wrapper
This commit is contained in:
Junior Garcia 2023-09-01 17:42:15 -03:00 committed by GitHub
parent 57909accde
commit 043b8420cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 110 additions and 36 deletions

View File

@ -0,0 +1,11 @@
---
"@nextui-org/select": patch
"@nextui-org/input": patch
"@nextui-org/theme": patch
---
Fix #1492 \n
- Select adn Input spaces fixed on helper wrapper
- New select wrapper added `mainWrapper` which contains the helperWrapper and the trigger slots
- Outside input with start content fixed

View File

@ -254,6 +254,7 @@ the popover and listbox components.
- **base**: The main wrapper of the select. This wraps the rest of the slots.
- **label**: The label of the select.
- **mainWrapper**: Wraps the `helperWrapper` and the `trigger` slots.
- **trigger**: The trigger of the select. This wraps the label the inner wrapper and the selector icon.
- **innerWrapper**: The wrapper of the select content. This wraps the start/end content and the select value.
- **selectorIcon**: The selector icon of the select. This is the icon that rotates when the select is open (`data-open`).
@ -369,7 +370,7 @@ the popover and listbox components.
| popoverProps | [PopoverProps](/docs/components/popover#api) | Props to be passed to the popover component. | - |
| listboxProps | [ListboxProps](/docs/components/listbox#api) | Props to be passed to the listbox component. | - |
| scrollShadowProps | [ScrollShadowProps](/docs/components/scroll-shadow#api) | Props to be passed to the scroll shadow component. | - |
| classNames | `Record<"base" "label" "trigger" "innerWrapper" "selectorIcon" "value" "listboxWrapper" "listbox" "popover" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
| classNames | `Record<"base" "label" "trigger" "mainWrapper" "innerWrapper" "selectorIcon" "value" "listboxWrapper" "listbox" "popover" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
### Select Events

View File

@ -17,8 +17,9 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
labelPlacement,
hasPlaceholder,
hasHelper,
isLabelOutside,
isLabelOutsideAsPlaceholder,
shouldLabelBeOutside,
shouldLabelBeInside,
errorMessage,
getBaseProps,
getLabelProps,
@ -82,7 +83,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
return (
<div {...getMainWrapperProps()}>
<div {...getInputWrapperProps()}>
{labelPlacement === "outside" && !hasPlaceholder ? labelContent : null}
{isLabelOutsideAsPlaceholder ? labelContent : null}
{innerWrapper}
</div>
{helperWrapper}
@ -103,7 +104,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
labelPlacement,
helperWrapper,
shouldLabelBeOutside,
shouldLabelBeInside,
isLabelOutsideAsPlaceholder,
hasPlaceholder,
labelContent,
innerWrapper,
@ -117,9 +118,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
{shouldLabelBeOutside && (labelPlacement === "outside-left" || hasPlaceholder)
? labelContent
: null}
{isLabelOutside ? labelContent : null}
{mainWrapper}
</Component>
);

View File

@ -173,6 +173,13 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
const shouldLabelBeInside = labelPlacement === "inside";
const hasStartContent = !!startContent;
const isLabelOutside = shouldLabelBeOutside
? labelPlacement === "outside-left" ||
hasPlaceholder ||
(labelPlacement === "outside" && hasStartContent)
: false;
const isLabelOutsideAsPlaceholder =
labelPlacement === "outside" && !hasPlaceholder && !hasStartContent;
const slots = useMemo(
() =>
@ -285,6 +292,8 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
(props = {}) => {
return {
"data-hover": dataAttr(isHovered),
"data-focus-visible": dataAttr(isFocusVisible),
"data-focus": dataAttr(isFocused),
className: slots.inputWrapper({
class: clsx(classNames?.inputWrapper, !!inputValue ? "is-filled" : ""),
}),
@ -300,7 +309,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
},
};
},
[slots, isHovered, inputValue, classNames?.inputWrapper],
[slots, isHovered, isFocusVisible, isFocused, inputValue, classNames?.inputWrapper],
);
const getInnerWrapperProps: PropGetter = useCallback(
@ -387,6 +396,9 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
isClearable,
isInvalid,
hasHelper,
hasStartContent,
isLabelOutside,
isLabelOutsideAsPlaceholder,
shouldLabelBeOutside,
shouldLabelBeInside,
hasPlaceholder,

View File

@ -74,7 +74,7 @@ const Template = (args) => (
);
const MirrorTemplate = (args) => (
<div className="w-full max-w-xl flex flex-row gap-4">
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input {...args} />
<Input {...args} placeholder="Enter your email" />
</div>
@ -170,7 +170,7 @@ const StartContentTemplate = (args) => (
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input
{...args}
placeholder="you@example.com"
// placeholder="you@example.com"
startContent={
<MailFilledIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
}
@ -489,7 +489,7 @@ export const WithDescription = {
args: {
...defaultProps,
description: "We'll never share your email with anyone else.",
description: "We'll never share your email with anyone else. ",
},
};

View File

@ -58,6 +58,7 @@
},
"devDependencies": {
"@nextui-org/avatar": "workspace:*",
"@nextui-org/input": "workspace:*",
"@nextui-org/chip": "workspace:*",
"framer-motion": "^10.15.1",
"@nextui-org/use-infinite-scroll": "workspace:*",

View File

@ -36,6 +36,7 @@ function Select<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLSelectE
getListboxProps,
getPopoverProps,
getSpinnerProps,
getMainWrapperProps,
shouldLabelBeOutside,
getInnerWrapperProps,
getHiddenSelectProps,
@ -115,20 +116,22 @@ function Select<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLSelectE
<div {...getBaseProps()}>
<HiddenSelect {...getHiddenSelectProps()} />
{shouldLabelBeOutside ? labelContent : null}
<Component {...getTriggerProps()}>
{!shouldLabelBeOutside ? labelContent : null}
<div {...getInnerWrapperProps()}>
{startContent}
<span {...getValueProps()}>
{renderSelectedItem}
{state.selectedItems && <VisuallyHidden>,</VisuallyHidden>}
</span>
{endContent}
</div>
{renderIndicator}
</Component>
<div {...getMainWrapperProps()}>
<Component {...getTriggerProps()}>
{!shouldLabelBeOutside ? labelContent : null}
<div {...getInnerWrapperProps()}>
{startContent}
<span {...getValueProps()}>
{renderSelectedItem}
{state.selectedItems && <VisuallyHidden>,</VisuallyHidden>}
</span>
{endContent}
</div>
{renderIndicator}
</Component>
{helperWrapper}
</div>
{disableAnimation ? popoverContent : <AnimatePresence>{popoverContent}</AnimatePresence>}
{helperWrapper}
</div>
);
}

View File

@ -308,12 +308,13 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
const getBaseProps: PropGetter = useCallback(
(props = {}) => ({
"data-filled": dataAttr(isFilled),
"data-has-helper": dataAttr(hasHelper),
className: slots.base({
class: clsx(baseStyles, props.className),
}),
...props,
}),
[slots, isFilled, baseStyles],
[slots, hasHelper, isFilled, baseStyles],
);
const getTriggerProps: PropGetter = useCallback(
@ -491,6 +492,18 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
[slots, classNames?.description],
);
const getMainWrapperProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
className: slots.mainWrapper({
class: clsx(classNames?.mainWrapper, props?.className),
}),
};
},
[slots, classNames?.mainWrapper],
);
const getErrorMessageProps: PropGetter = useCallback(
(props = {}) => {
return {
@ -546,6 +559,7 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
getListboxProps,
getPopoverProps,
getSpinnerProps,
getMainWrapperProps,
getListboxWrapperProps,
getHiddenSelectProps,
getInnerWrapperProps,

View File

@ -147,19 +147,14 @@ const input = tv({
},
labelPlacement: {
outside: {
base: "data-[has-helper=true]:pb-4",
label: "text-foreground pb-1.5",
mainWrapper: "flex flex-col",
description: "absolute left-1",
errorMessage: "absolute left-1",
},
"outside-left": {
base: "flex-row items-center flex-nowrap data-[has-helper=true]:pb-4",
base: "flex-row items-center flex-nowrap data-[has-helper=true]:items-start",
inputWrapper: "flex-1",
mainWrapper: "flex flex-col",
label: "text-foreground pr-2",
description: "absolute left-1",
errorMessage: "absolute left-1",
},
inside: {
label: "text-tiny cursor-text",
@ -648,6 +643,29 @@ const input = tv({
],
},
},
// outside-left & size & hasHelper
{
labelPlacement: "outside-left",
size: "sm",
class: {
label: "group-data-[has-helper=true]:pt-2",
},
},
{
labelPlacement: "outside-left",
size: "md",
class: {
label: "group-data-[has-helper=true]:pt-3",
},
},
{
labelPlacement: "outside-left",
size: "lg",
class: {
label: "group-data-[has-helper=true]:pt-4",
},
},
],
});

View File

@ -7,6 +7,7 @@ const select = tv({
slots: {
base: "group inline-flex flex-col relative w-full",
label: "block text-small font-medium text-foreground-500 pointer-events-none",
mainWrapper: "w-full flex flex-col",
trigger:
"relative px-3 gap-3 w-full inline-flex flex-row items-center shadow-sm outline-none tap-highlight-transparent",
innerWrapper:
@ -117,14 +118,10 @@ const select = tv({
outside: {
base: "data-[has-helper=true]:pb-4 flex flex-col",
label: "text-foreground pb-1.5",
description: "absolute left-1",
errorMessage: "absolute left-1",
},
"outside-left": {
base: "flex-row items-center flex-nowrap data-[has-helper=true]:pb-4",
base: "flex-row items-center flex-nowrap items-start",
label: "text-foreground pr-2",
description: "absolute left-1",
errorMessage: "absolute left-1",
},
inside: {
label: "text-tiny cursor-pointer",

18
pnpm-lock.yaml generated
View File

@ -1754,6 +1754,9 @@ importers:
'@nextui-org/chip':
specifier: workspace:*
version: link:../chip
'@nextui-org/input':
specifier: workspace:*
version: link:../input
'@nextui-org/use-infinite-scroll':
specifier: workspace:*
version: link:../../hooks/use-infinite-scroll
@ -3019,6 +3022,7 @@ packages:
/@babel/cli@7.22.10(@babel/core@7.22.11):
resolution: {integrity: sha512-rM9ZMmaII630zGvtMtQ3P4GyHs28CHLYE9apLG7L8TgaSqcfoIGrlLSLsh4Q8kDTdZQQEXZm1M0nQtOvU/2heg==}
engines: {node: '>=6.9.0'}
hasBin: true
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@ -12169,6 +12173,7 @@ packages:
/autoprefixer@10.4.15(postcss@8.4.28):
resolution: {integrity: sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
@ -14573,6 +14578,7 @@ packages:
/eslint-config-prettier@8.10.0(eslint@7.32.0):
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
@ -17418,6 +17424,7 @@ packages:
/jest-cli@28.1.3(@types/node@15.14.9)(ts-node@10.9.1):
resolution: {integrity: sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==}
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
@ -17859,6 +17866,7 @@ packages:
/jest@28.1.3(@types/node@15.14.9)(ts-node@10.9.1):
resolution: {integrity: sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==}
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
@ -17913,6 +17921,7 @@ packages:
/jscodeshift@0.14.0(@babel/preset-env@7.22.10):
resolution: {integrity: sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==}
hasBin: true
peerDependencies:
'@babel/preset-env': ^7.1.6
dependencies:
@ -19710,6 +19719,7 @@ packages:
/next-sitemap@4.2.2(next@13.4.12):
resolution: {integrity: sha512-cz5PyFibUNSJSXOY5mllq5TW0OH6SGG+8GJ9fR9pl1Thu4rvkDye+0N0790h+9kQihDStuVw2xfwC3qihDkflA==}
engines: {node: '>=14.18'}
hasBin: true
peerDependencies:
next: '*'
dependencies:
@ -19739,6 +19749,7 @@ packages:
/next@13.4.12(@babel/core@7.22.11)(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-eHfnru9x6NRmTMcjQp6Nz0J4XH9OubmzOa7CkWL+AUrUxpibub3vWwttjduu9No16dug1kq04hiUUpo7J3m3Xw==}
engines: {node: '>=16.8.0'}
hasBin: true
peerDependencies:
'@opentelemetry/api': ^1.1.0
fibers: '>= 3.1.0'
@ -23369,6 +23380,7 @@ packages:
/ts-node@10.9.1(@swc/core@1.3.80)(@types/node@15.14.9)(typescript@4.9.5):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
@ -23420,6 +23432,7 @@ packages:
/tsup@6.4.0(@swc/core@1.3.80)(ts-node@10.9.1)(typescript@4.9.5):
resolution: {integrity: sha512-4OlbqIK/SF+cJp0mMqPM2pKULvgj/1S2Gm3I1aFoFGIryUOyIqPZBoqKkqVQT6uFtWJ5AHftIv0riXKfHox1zQ==}
engines: {node: '>=14'}
hasBin: true
peerDependencies:
'@swc/core': ^1
postcss: ^8.4.12
@ -23905,6 +23918,7 @@ packages:
/update-browserslist-db@1.0.11(browserslist@4.21.10):
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
dependencies:
@ -24148,6 +24162,7 @@ packages:
/vite@4.4.9(@types/node@15.14.9):
resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
less: '*'
@ -24331,6 +24346,7 @@ packages:
/webpack-cli@3.3.12(webpack@5.88.2):
resolution: {integrity: sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==}
engines: {node: '>=6.11.5'}
hasBin: true
peerDependencies:
webpack: 4.x.x
dependencies:
@ -24368,6 +24384,7 @@ packages:
/webpack@5.88.2(@swc/core@1.3.80)(esbuild@0.15.18)(webpack-cli@3.3.12):
resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
webpack-cli: '*'
peerDependenciesMeta:
@ -24408,6 +24425,7 @@ packages:
/webpack@5.88.2(@swc/core@1.3.80)(esbuild@0.19.2)(webpack-cli@3.3.12):
resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
webpack-cli: '*'
peerDependenciesMeta: