mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
Fix/1492 (#1543)
* fix(select): select & input styles fixed * chore(input): extra data attr added to input wrapper
This commit is contained in:
parent
57909accde
commit
043b8420cf
11
.changeset/heavy-planes-begin.md
Normal file
11
.changeset/heavy-planes-begin.md
Normal 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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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. ",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -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:*",
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
@ -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
18
pnpm-lock.yaml
generated
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user