Skip to content

Commit

Permalink
Merge branch 'master' into chore/docs-next14.2.12
Browse files Browse the repository at this point in the history
  • Loading branch information
Kenzo-Wada authored Sep 25, 2024
2 parents b33c360 + 5193ba7 commit 9a163f7
Show file tree
Hide file tree
Showing 157 changed files with 5,134 additions and 322 deletions.
324 changes: 162 additions & 162 deletions .yarn/releases/yarn-4.4.1.cjs → .yarn/releases/yarn-4.5.0.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.4.1.cjs
yarnPath: .yarn/releases/yarn-4.5.0.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
margin-top: var(--mantine-spacing-lg);
}

.inner {
.innerContainer {
--table-of-contents-width: 300px;

display: flex;
Expand All @@ -38,6 +38,12 @@
}
}

.inner {
width: 100%;
max-width: calc(100% - var(--table-of-contents-width));
overflow: hidden;
}

.content {
flex: 0 0 calc(100% - var(--table-of-contents-width));
max-width: 100%;
Expand Down
8 changes: 5 additions & 3 deletions apps/help.mantine.dev/src/components/MdxLayout/MdxLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ export function MdxLayout({ meta, children }: MdxLayoutProps) {
</Text>
</Container>
</header>
<Container size="md" className={classes.inner}>
<div className={classes.content} id="mdx">
{children}
<Container size="md" className={classes.innerContainer}>
<div className={classes.inner}>
<div className={classes.content} id="mdx">
{children}
</div>
</div>
<TableOfContents />
</Container>
Expand Down
116 changes: 116 additions & 0 deletions apps/help.mantine.dev/src/demos/CustomInputUseForm.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* eslint-disable no-console */
import { Button, Text } from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useUncontrolled } from '@mantine/hooks';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { Button, Text } from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useUncontrolled } from '@mantine/hooks';
interface CustomInputProps extends Omit<React.ComponentPropsWithoutRef<'input'>, 'onChange'> {
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
error?: React.ReactNode;
}
function CustomInput({ value, defaultValue, onChange, error, ...others }: CustomInputProps) {
const [_value, setValue] = useUncontrolled({
value,
defaultValue,
finalValue: '',
onChange,
});
return (
<div>
<input value={_value} onChange={(event) => setValue(event.currentTarget.value)} {...others} />
<Text c="red">{error}</Text>
</div>
);
}
function Demo() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
customInput: '',
},
validate: {
customInput: isNotEmpty('This field is required'),
},
});
return (
<form onSubmit={form.onSubmit(console.log)}>
<CustomInput
{...form.getInputProps('customInput')}
key={form.key('customInput')}
placeholder="Custom input"
/>
<Button type="submit" mt="md">
Submit
</Button>
</form>
);
}
`;

interface CustomInputProps extends Omit<React.ComponentPropsWithoutRef<'input'>, 'onChange'> {
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
error?: React.ReactNode;
}

function CustomInput({ value, defaultValue, onChange, error, ...others }: CustomInputProps) {
const [_value, setValue] = useUncontrolled({
value,
defaultValue,
finalValue: '',
onChange,
});

return (
<div>
<input value={_value} onChange={(event) => setValue(event.currentTarget.value)} {...others} />
<Text c="red">{error}</Text>
</div>
);
}

function Demo() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
customInput: '',
},
validate: {
customInput: isNotEmpty('This field is required'),
},
});

return (
<form onSubmit={form.onSubmit(console.log)}>
<CustomInput
{...form.getInputProps('customInput')}
key={form.key('customInput')}
placeholder="Custom input"
/>

<Button type="submit" mt="md">
Submit
</Button>
</form>
);
}

export const CustomInputUseFormDemo: MantineDemo = {
type: 'code',
component: Demo,
code,
centered: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.inputField {
&:not(:only-child)::placeholder {
color: transparent;
}
}
31 changes: 31 additions & 0 deletions apps/help.mantine.dev/src/demos/MultiSelectPlaceholder.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { MultiSelect } from '@mantine/core';
import { MantineDemo } from '@mantinex/demo';
import classes from './MultiSelectPlaceholder.demo.module.css';

const code = `
`;

const cssCode = `.inputField {
&:not(:only-child)::placeholder {
color: transparent;
}
}`;

function Demo() {
return (
<MultiSelect
data={['React', 'Angular']}
placeholder="Pick one or more"
classNames={{ inputField: classes.inputField }}
/>
);
}

export const MultiSelectPlaceholderDemo: MantineDemo = {
type: 'code',
component: Demo,
code: [
{ fileName: 'Demo.module.css', code: cssCode, language: 'scss' },
{ fileName: 'Demo.tsx', code, language: 'tsx' },
],
};
12 changes: 12 additions & 0 deletions apps/help.mantine.dev/src/mdx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { meta as canIUseMantineWithAstro } from './pages/q/can-i-use-mantine-wit
import { meta as canIUseMantineWithCra } from './pages/q/can-i-use-mantine-with-cra.mdx';
import { meta as colorSchemeColor } from './pages/q/color-scheme-color.mdx';
import { meta as comboboxTesting } from './pages/q/combobox-testing.mdx';
import { meta as customInputUseForm } from './pages/q/custom-input-use-form.mdx';
import { meta as dataGridINeed } from './pages/q/data-grid-i-need.mdx';
import { meta as datesMissingStyles } from './pages/q/dates-missing-styles.mdx';
import { meta as disableAllInputsInForm } from './pages/q/disable-all-inputs-in-form.mdx';
Expand All @@ -27,18 +28,23 @@ import { meta as inputMask } from './pages/q/input-mask.mdx';
import { meta as inputsPlaceholderColor } from './pages/q/inputs-placeholder-color.mdx';
import { meta as lightDarkElements } from './pages/q/light-dark-elements.mdx';
import { meta as lightDarkIsNotEnough } from './pages/q/light-dark-is-not-enough.mdx';
import { meta as listOfStringsInUseForm } from './pages/q/list-of-strings-in-use-form.mdx';
import { meta as mantineProviderMissing } from './pages/q/mantine-provider-missing.mdx';
import { meta as multiselectValuePlaceholder } from './pages/q/multiselect-value-placeholder.mdx';
import { meta as nextLoadFonts } from './pages/q/next-load-fonts.mdx';
import { meta as notificationsEmptyScreen } from './pages/q/notifications-empty-screen.mdx';
import { meta as notificationsMissingStyles } from './pages/q/notifications-missing-styles.mdx';
import { meta as otherLibs } from './pages/q/other-libs.mdx';
import { meta as pinchToZoomModal } from './pages/q/pinch-to-zoom-modal.mdx';
import { meta as polymorphicInPolymorphic } from './pages/q/polymorphic-in-polymorphic.mdx';
import { meta as privateCssVariables } from './pages/q/private-css-variables.mdx';
import { meta as remixLoadFonts } from './pages/q/remix-load-fonts.mdx';
import { meta as roadmap } from './pages/q/roadmap.mdx';
import { meta as scrollToTheTopOfTheForm } from './pages/q/scroll-to-the-top-of-the-form.mdx';
import { meta as segmentedControlNoValue } from './pages/q/segmented-control-no-value.mdx';
import { meta as selectAutocompleteDifference } from './pages/q/select-autocomplete-difference.mdx';
import { meta as serverComponents } from './pages/q/server-components.mdx';
import { meta as stylesOrder } from './pages/q/styles-order.mdx';
import { meta as tabsBorderColor } from './pages/q/tabs-border-color.mdx';
import { meta as thirdPartyStyles } from './pages/q/third-party-styles.mdx';
import { meta as viteLoadFonts } from './pages/q/vite-load-fonts.mdx';
Expand All @@ -54,6 +60,7 @@ export const MDX_DATA = [
canIUseMantineWithCra,
colorSchemeColor,
comboboxTesting,
customInputUseForm,
dataGridINeed,
datesMissingStyles,
disableAllInputsInForm,
Expand All @@ -75,18 +82,23 @@ export const MDX_DATA = [
inputsPlaceholderColor,
lightDarkElements,
lightDarkIsNotEnough,
listOfStringsInUseForm,
mantineProviderMissing,
multiselectValuePlaceholder,
nextLoadFonts,
notificationsEmptyScreen,
notificationsMissingStyles,
otherLibs,
pinchToZoomModal,
polymorphicInPolymorphic,
privateCssVariables,
remixLoadFonts,
roadmap,
scrollToTheTopOfTheForm,
segmentedControlNoValue,
selectAutocompleteDifference,
serverComponents,
stylesOrder,
tabsBorderColor,
thirdPartyStyles,
viteLoadFonts,
Expand Down
75 changes: 75 additions & 0 deletions apps/help.mantine.dev/src/pages/q/custom-input-use-form.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { CustomInputUseFormDemo } from '@/demos/CustomInputUseForm.demo';
import { Layout } from '@/layout';

export const meta = {
title: 'How to integrate custom input with use-form hook?',
description: 'Learn how to add use-form support for custom inputs',
slug: 'custom-input-use-form',
category: 'forms',
tags: ['use-form', 'useForm'],
created_at: 'July 22, 2024',
last_updated_at: 'July 22, 2024',
};

export default Layout(meta);

## How @mantine/form works

[use-form](https://mantine.dev/form/use-form) is used to store form values,
errors, touched, dirty and validation state. In order to support all `@mantine/form`
features (including `form.getInputProps()`) custom inputs must accept the following props:

- `value` – input value in controlled mode
- `defaultValue` – input value in uncontrolled mode
- `onChange` – input change handler used both for controlled and uncontrolled modes
- `error` – validation error message
- `onBlur` – used to set field as touched

## use-uncontrolled hook

In most cases, the easiest way to add support for both controlled and uncontrolled modes is to use
[use-uncontrolled](https://mantine.dev/hooks/use-uncontrolled) hook. It allows to use `value` and
`defaultValue` props together and automatically handles controlled/uncontrolled mode switching.

Example of a custom input that supports both controlled and uncontrolled modes:

```tsx
import { useUncontrolled } from '@mantine/hooks';

interface CustomInputProps {
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
}

function CustomInput({
value,
defaultValue,
onChange,
}: CustomInputProps) {
const [_value, handleChange] = useUncontrolled({
value,
defaultValue,
finalValue: 'Final',
onChange,
});

return (
<input
type="text"
value={_value}
onChange={(event) => handleChange(event.currentTarget.value)}
/>
);
}
```

## Full example

In the following example `CustomInput` component supports all `@mantine/form` features:

- `value`, `defaultValue` and `onChange` are used to control input value
- `error` is used to display validation error message
- `onBlur` (part of `...others` props) is used to set field as touched

<Demo data={CustomInputUseFormDemo} />
Loading

0 comments on commit 9a163f7

Please sign in to comment.