feat(controllers): add new input and button components

* Introduced ButtonCtrl, IconButtonCtrl, NativeSelectCtrl, PasswordInputCtrl, SwitchCtrl, TextAreaCtrl, TextInputCtrl
* Updated FormerControllers.types.ts to include SpecialIDProps
* Enhanced lib.ts to export new components
This commit is contained in:
2026-01-14 22:42:17 +02:00
parent e777e1fa3a
commit 9df2f3b504
13 changed files with 287 additions and 3 deletions

0
src/Boxer/index.ts Normal file
View File

8
src/Boxer/todo.md Normal file
View File

@@ -0,0 +1,8 @@
- [ ] Auto Complete
- [ ] Multi Select
- [ ] Virtualize
- [ ] Search
- [ ] Clear, Menu buttons
- [ ] Headerspec API
- [ ] Relspec API
- [ ] SocketSpec API

View File

@@ -0,0 +1,35 @@
import { Button, type ButtonProps, Tooltip } from '@mantine/core';
import { useState } from 'react';
import type { SpecialIDProps } from '../FormerControllers.types';
const ButtonCtrl = (
props: {
onClick?: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => Promise<void>;
} & Omit<ButtonProps, 'onClick'> &
SpecialIDProps
) => {
const [loading, setLoading] = useState(false);
return (
<Tooltip label={props.tooltip ?? ''} withArrow>
<Button
loaderProps={{
type: 'bars',
}}
{...props}
loading={loading || props.loading}
onClick={(e) => {
if (props.onClick) {
setLoading(true);
props.onClick(e).finally(() => setLoading(false));
}
}}
>
{props.children}
</Button>
</Tooltip>
);
};
export { ButtonCtrl };
export default ButtonCtrl;

View File

@@ -0,0 +1,36 @@
import { ActionIcon, type ActionIconProps, Tooltip, VisuallyHidden } from '@mantine/core';
import { useState } from 'react';
import type { SpecialIDProps } from '../FormerControllers.types';
const IconButtonCtrl = (
props: {
onClick?: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => Promise<void>;
} & Omit<ActionIconProps, 'onClick'> &
SpecialIDProps
) => {
const [loading, setLoading] = useState(false);
return (
<Tooltip label={props.tooltip ?? ''} withArrow>
<ActionIcon
loaderProps={{
type: 'bars',
}}
{...props}
loading={loading || props.loading}
onClick={(e) => {
if (props.onClick) {
setLoading(true);
props.onClick(e).finally(() => setLoading(false));
}
}}
>
{props.children}
<VisuallyHidden>Action Button: {props.tooltip ?? props.sid ?? ''}</VisuallyHidden>
</ActionIcon>
</Tooltip>
);
};
export { IconButtonCtrl };
export default IconButtonCtrl;

View File

@@ -0,0 +1,8 @@
import type { ControllerProps } from 'react-hook-form';
export type FormerControllersProps = Omit<ControllerProps, 'render'>;
export interface SpecialIDProps {
sid?: string;
tooltip?: string;
}

View File

@@ -0,0 +1,30 @@
import { NativeSelect, type NativeSelectProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const NativeSelectCtrl = (props: FormerControllersProps & NativeSelectProps & SpecialIDProps) => {
const { control, name, sid, tooltip, ...innerProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<NativeSelect
{...innerProps}
{...field}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
>
{props.children}
</NativeSelect>
</Tooltip>
)}
/>
);
};
export { NativeSelectCtrl };
export default NativeSelectCtrl;

View File

@@ -0,0 +1,36 @@
import { NumberInput, type NumberInputProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const NumberInputCtrl = (props: FormerControllersProps & NumberInputProps & SpecialIDProps) => {
const { control, name, sid, tooltip, ...textProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<NumberInput
{...textProps}
{...field}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
onChange={(num) =>
field.onChange(num !== undefined && num !== null ? Number(num) : undefined)
}
value={
field.value !== undefined && field.value !== null ? Number(field.value) : undefined
}
>
{props.children}
</NumberInput>
</Tooltip>
)}
/>
);
};
export { NumberInputCtrl };
export default NumberInputCtrl;

View File

@@ -0,0 +1,30 @@
import { PasswordInput, type PasswordInputProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const PasswordInputCtrl = (props: FormerControllersProps & PasswordInputProps & SpecialIDProps) => {
const { control, name, sid, tooltip, ...textProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<PasswordInput
{...textProps}
{...field}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
>
{props.children}
</PasswordInput>
</Tooltip>
)}
/>
);
};
export { PasswordInputCtrl };
export default PasswordInputCtrl;

View File

@@ -0,0 +1,32 @@
import { Switch, type SwitchProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const SwitchCtrl = (props: FormerControllersProps & SpecialIDProps & SwitchProps) => {
const { control, name, sid, tooltip, ...innerProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<Switch
{...innerProps}
{...field}
checked={!!field.value}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
onChange={(e) => {
field.onChange((e.currentTarget ?? e.target)?.checked);
}}
/>
</Tooltip>
)}
/>
);
};
export { SwitchCtrl };
export default SwitchCtrl;

View File

@@ -0,0 +1,31 @@
import { Textarea, type TextareaProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const TextAreaCtrl = (props: FormerControllersProps & SpecialIDProps & TextareaProps) => {
const { control, name, sid, tooltip, ...innerProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<Textarea
minRows={4}
{...innerProps}
{...field}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
>
{props.children}
</Textarea>
</Tooltip>
)}
/>
);
};
export { TextAreaCtrl };
export default TextAreaCtrl;

View File

@@ -0,0 +1,30 @@
import { TextInput, type TextInputProps, Tooltip } from '@mantine/core';
import { Controller } from 'react-hook-form';
import type { FormerControllersProps, SpecialIDProps } from '../FormerControllers.types';
const TextInputCtrl = (props: FormerControllersProps & SpecialIDProps & TextInputProps) => {
const { control, name, sid, tooltip, ...textProps } = props;
return (
<Controller
control={control}
name={name}
render={({ field, formState }) => (
<Tooltip label={tooltip ?? ''} withArrow>
<TextInput
{...textProps}
{...field}
disabled={formState.disabled}
id={`field_${name}_${sid ?? ''}`}
key={`field_${name}_${sid ?? ''}`}
>
{props.children}
</TextInput>
</Tooltip>
)}
/>
);
};
export { TextInputCtrl };
export default TextInputCtrl;

View File

@@ -0,0 +1,7 @@
export { ButtonCtrl } from './Buttons/ButtonCtrl';
export { IconButtonCtrl } from './Buttons/IconButtonCtrl';
export { NativeSelectCtrl } from './Inputs/NativeSelectCtrl';
export { PasswordInputCtrl } from './Inputs/PasswordInputCtrl';
export { SwitchCtrl } from './Inputs/SwitchCtrl';
export { TextAreaCtrl } from './Inputs/TextAreaCtrl';
export { TextInputCtrl } from './Inputs/TextInputCtrl';

View File

@@ -1,5 +1,6 @@
export * from './Gridler' export * from './Former';
export * from './FormerControllers';
export * from './Gridler';
export { export {
type MantineBetterMenuInstance, type MantineBetterMenuInstance,
@@ -7,4 +8,4 @@ export {
MantineBetterMenusProvider, MantineBetterMenusProvider,
type MantineBetterMenuStoreState, type MantineBetterMenuStoreState,
useMantineBetterMenus, useMantineBetterMenus,
} from "./MantineBetterMenu"; } from './MantineBetterMenu';