add TagsInput component

This commit is contained in:
jeffvli
2026-07-16 20:04:20 -07:00
parent 45c660dcc5
commit 38ad3e5d5a
3 changed files with 130 additions and 1 deletions
@@ -0,0 +1,66 @@
.root {
& [data-disabled='true'] {
opacity: 0.6;
}
}
.label {
margin-bottom: var(--theme-spacing-sm);
}
.dropdown {
padding: var(--theme-spacing-xs);
color: var(--theme-colors-surface-foreground);
background: var(--theme-colors-surface);
border: 1px solid var(--theme-colors-border);
}
.input {
width: 100%;
border: 1px solid transparent;
&[data-variant='default'] {
color: var(--theme-colors-surface-foreground);
background: var(--theme-colors-surface);
}
&[data-variant='filled'] {
color: var(--theme-colors-foreground);
background: var(--theme-colors-background);
& .pill {
background: var(--theme-colors-surface);
}
}
}
.input:focus-within {
border-color: lighten(var(--theme-colors-border), 10%);
}
.input-field {
color: inherit;
}
.option {
position: relative;
padding: var(--theme-spacing-sm) var(--theme-spacing-md);
}
.option:hover {
background: lighten(var(--theme-colors-surface), 5%);
}
.pill {
font-size: var(--theme-font-size-sm);
background: var(--theme-colors-background);
border-radius: var(--theme-radius-sm);
}
.pills-list {
padding-right: var(--theme-spacing-lg);
}
.clear-button {
background: transparent !important;
}
@@ -0,0 +1,58 @@
import {
TagsInput as MantineTagsInput,
TagsInputProps as MantineTagsInputProps,
} from '@mantine/core';
import { CSSProperties, useMemo } from 'react';
import styles from './tags-input.module.css';
export interface TagsInputProps extends MantineTagsInputProps {
maxWidth?: CSSProperties['maxWidth'];
width?: CSSProperties['width'];
}
const defaultClassNames = {
dropdown: styles.dropdown,
input: styles.input,
inputField: styles.inputField,
label: styles.label,
option: styles.option,
pill: styles.pill,
pillsList: styles.pillsList,
root: styles.root,
};
const defaultClearButtonProps = {
classNames: {
root: styles.clearButton,
},
variant: 'transparent' as const,
};
export const TagsInput = ({
classNames,
maxWidth,
variant = 'default',
width,
...props
}: TagsInputProps) => {
const mergedClassNames = useMemo(
() => (classNames ? { ...defaultClassNames, ...classNames } : defaultClassNames),
[classNames],
);
const style = useMemo(
() => (maxWidth || width ? { maxWidth, width } : undefined),
[maxWidth, width],
);
return (
<MantineTagsInput
classNames={mergedClassNames}
clearButtonProps={defaultClearButtonProps}
style={style}
variant={variant}
{...props}
/>
);
};
+6 -1
View File
@@ -1,7 +1,8 @@
import { ActionIconSize, PillVariant } from '@mantine/core';
import { ActionIconSize, PillVariant, TagsInputVariant } from '@mantine/core';
type ExtendedActionIconSize = 'compact-md' | 'compact-sm' | 'compact-xs' | ActionIconSize;
type ExtendedPillVariant = 'outline' | PillVariant;
type ExtendedTagsInputVariant = 'default' | 'filled' | TagsInputVariant;
declare module '@mantine/core' {
export interface ActionIconProps {
@@ -11,4 +12,8 @@ declare module '@mantine/core' {
export interface PillProps {
variant?: ExtendedPillVariant;
}
export interface TagsInputProps {
variant?: ExtendedTagsInputVariant;
}
}