Skip to content

Commit

Permalink
Add ChipInput component (#808)
Browse files Browse the repository at this point in the history
  • Loading branch information
princerajpoot20 authored Oct 10, 2023
1 parent cc5fce8 commit dbeb742
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
76 changes: 76 additions & 0 deletions apps/design-system/src/components/ChipInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useState } from "react";
import { ChipInput } from "@asyncapi/studio-ui";

const meta = {
component: ChipInput,
parameters: {
layout: 'fullscreen',
backgrounds: {
default: 'light'
}
},
};

export default meta;

export const Default = () => {
const [currentChips, setCurrentChips] = useState<string[]>([]);

return (
<div className="p-4 bg-gray-100 flex items-center">
<ChipInput
name="chip-input-default"
id="chip-input-id-default"
chips={currentChips}
onChange={setCurrentChips}
/>
</div>
);
};

export const WithTags = () => {
const [currentChips, setCurrentChips] = useState<string[]>(['production', 'platform']);

return (
<div className="p-4 bg-gray-100 flex items-center">
<ChipInput
name="chip-input-chip-text"
id="chip-input-id-chip-text"
chips={currentChips}
onChange={setCurrentChips}
/>
</div>
);
};

export const WithSomeDefaultText = () => {
const [currentChips, setCurrentChips] = useState<string[]>(['production', 'platform']);

return (
<div className="p-4 bg-gray-100 flex items-center">
<ChipInput
name="chip-input-default-text-in-input"
id="chip-input-id-default-text-in-input"
chips={currentChips}
onChange={setCurrentChips}
defaultValue="registr"
/>
</div>
);
};

export const WithCustomPlaceholder = () => {
const [currentChips, setCurrentChips] = useState<string[]>([]);

return (
<div className="p-4 bg-gray-100 flex items-center">
<ChipInput
name="chip-input-custom-placeholder"
id="chip-input-id-placeholder"
chips={currentChips}
onChange={setCurrentChips}
placeholder="Enter a custom chip"
/>
</div>
);
};
80 changes: 80 additions & 0 deletions packages/ui/components/ChipInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { FunctionComponent, KeyboardEvent, useRef } from 'react';

interface ChipInputProps {
name: string;
id: string;
className?: string;
chips: string[];
onChange: (chips: string[]) => void;
isDisabled?: boolean;
placeholder?: string;
defaultValue?: string;
}

export const ChipInput: FunctionComponent<ChipInputProps> = ({
name,
id,
className,
chips,
onChange,
isDisabled = false,
placeholder = 'Add Tags',
defaultValue = ''
}) => {
const inputRef = useRef<HTMLInputElement>(null);
const firstChipRef = useRef<HTMLDivElement>(null);

const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter' && event.currentTarget.value.trim()) {
onChange([...chips, event.currentTarget.value.trim()]);
event.currentTarget.value = '';
} else if (event.key === 'Backspace' && !event.currentTarget.value) {
onChange(chips.slice(0, -1));
} else if (event.key === 'Tab' && !event.shiftKey) {
event.preventDefault();
firstChipRef.current?.focus();
}
};

const handleChipKeyDown = (index: number) => (event: KeyboardEvent<HTMLDivElement>) => {
if (event.key === 'Backspace') {
const updatedChips = [...chips];
updatedChips.splice(index, 1);
onChange(updatedChips);
}
};

const handleDelete = (chipToDelete: string) => () => {
const updatedChips = chips.filter(chip => chip !== chipToDelete);
onChange(updatedChips);
};

return (
<div className={`${className} flex flex-wrapitems-center p-1 bg-gray-900 rounded border border-gray-800`} style={{ width: '862px', height: '46px' }}>
{chips.map((chip, index) => (
<div
key={chip}
className="m-1 bg-gray-100 text-gray-900 rounded px-2 py-1 flex items-center border border-gray-400 focus:border-blue-500 focus:border-2 focus:outline-none"
style={{ height: '28px', borderStyle: 'solid' }}
tabIndex={0}
onKeyDown={handleChipKeyDown(index)}
ref={index === 0 ? firstChipRef : undefined}
>
<span>{chip}</span>
<button onClick={handleDelete(chip)} tabIndex={-1} className="ml-1 text-gray-400 focus:outline-none">×</button>
</div>
))}
<input
ref={inputRef}
name={name}
id={id}
type="text"
onKeyDown={handleKeyDown}
className="p-1 bg-gray-900 text-white rounded outline-none"
placeholder={placeholder}
disabled={isDisabled}
defaultValue={defaultValue}
/>
</div>
);
};
1 change: 1 addition & 0 deletions packages/ui/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import './styles.css'

// components
export * from './ChipInput'
export * from './EditorSwitch'
export * from './DropdownMenu'
export * from './Logo'
Expand Down

0 comments on commit dbeb742

Please sign in to comment.