feat: toggleGroup for selecting action

This commit is contained in:
Anish Lakhwara 2025-02-24 23:11:39 -08:00
parent b268065d13
commit f4e9ecb90b
4 changed files with 338 additions and 43 deletions

View file

@ -11,6 +11,8 @@
"@radix-ui/react-checkbox": "^1.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2",
"@tanstack/react-table": "^8.20.5",
"@vlcn.io/react": "^3.1.0",
"@vlcn.io/rx-tbl": "^0.15.0",
@ -729,6 +731,67 @@
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
"integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
@ -757,6 +820,20 @@
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
"integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-icons": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
@ -765,6 +842,23 @@
"react": "^16.x || ^17.x || ^18.x"
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz",
@ -827,6 +921,77 @@
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
"integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-collection": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
@ -858,6 +1023,112 @@
}
}
},
"node_modules/@radix-ui/react-toggle": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.2.tgz",
"integrity": "sha512-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ==",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-toggle-group": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.2.tgz",
"integrity": "sha512-JBm6s6aVG/nwuY5eadhU2zDi/IwYS0sDM5ZWb4nymv/hn3hZdkw+gENn0LP4iY1yCd7+bgJaCwueMYJIU3vk4A==",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-roving-focus": "1.1.2",
"@radix-ui/react-toggle": "1.1.2",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
},
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
},
"node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",

View file

@ -13,6 +13,8 @@
"@radix-ui/react-checkbox": "^1.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2",
"@tanstack/react-table": "^8.20.5",
"@vlcn.io/react": "^3.1.0",
"@vlcn.io/rx-tbl": "^0.15.0",

View file

@ -137,7 +137,6 @@ function App({ ctx }) {
]);
break;
}
console.log("Why won't you clear?!")
setNewText("");
setRowSelection({});
} catch (error) {
@ -199,7 +198,6 @@ function App({ ctx }) {
<section className="pt-8 container">
<Input type="text"
className="bg-background"
placeholder="..."
value={newText}
onKeyUp={parseTodos}
onActionChange={handleActionChange}

View file

@ -2,6 +2,8 @@ import * as React from "react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { Search, Plus, Pencil, Check } from "lucide-react"
// Add onActionChange to InputProps interface
export interface InputProps
@ -13,6 +15,7 @@ export interface InputProps
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, onActionChange, onSubmit, value, ...props }, ref) => {
const [selectedIndex, setSelectedIndex] = React.useState(0)
const [selectedToggle, setSelectedToggle] = React.useState("add")
const options = ["add", "filter", "done", "delete"]
const handleWheel = (event: React.WheelEvent) => {
@ -28,54 +31,75 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
}
}
const handleToggleChange = (value: string) => {
if (value) {
setSelectedToggle(value)
onActionChange?.(value)
}
}
const handleSubmit = () => {
if (onSubmit && value) {
console.log("trigger button")
onSubmit(options[selectedIndex] + " " + value);
onSubmit(selectedToggle + " " + value);
}
}
return (
<div className="relative items-center" onWheel={handleWheel}>
<select
className={cn(
"absolute top-0 left-0 h-9 rounded-l-md border-r border-input bg-transparent px-2 text-sm cursor-default",
"shadow-sm transition-all duration-200 text-center appearance-none",
)}
value={options[selectedIndex]}
onChange={(e) => {
const newIndex = options.indexOf(e.target.value)
setSelectedIndex(newIndex)
onActionChange?.(e.target.value)
}}
>
<option value="" disabled selected>
Actions
</option>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<input
type={type}
className={cn(
"flex-1 h-9 w-full rounded-md border border-input bg-background px-[90px] text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
value={value}
{...props}
/>
<Button
type="button"
onClick={handleSubmit}
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 z-10"
variant="secondary"
>
Submit
</Button>
<div className="flex flex-col group" onWheel={handleWheel}>
<div className="flex w-full">
<div className="relative w-auto">
<ToggleGroup type="single"
value={selectedToggle}
onValueChange={handleToggleChange}
defaultValue="add"
className={cn(
"h-11 border rounded-t-md border-b-0 bg-transparent text-sm cursor-default pt-1/2 pl-1 pr-1 pb-1/2",
"shadow-sm transition-colors duration-0 text-center appearance-none group-focus-within:border-ring",
"rounded-t-md rounded-b-none",
"focus:border-ring"
)}>
<ToggleGroupItem value="filter" aria-label="filter tasks">
<Search className="h-4 w-4 rounded-none" />
</ToggleGroupItem>
<ToggleGroupItem value="modify" aria-label="Modify selected task(s)">
<Pencil className="h-4 w-4" />
</ToggleGroupItem>
<ToggleGroupItem value="add" aria-label="Add a task">
<Plus className="h-4 w-4" />
</ToggleGroupItem>
<ToggleGroupItem value="done" aria-label="Toggle selected task(s) done">
<Check className="h-4 w-4" />
</ToggleGroupItem>
</ToggleGroup>
<div className="absolute bottom-0 left-0 right-0 h-[2px] border border-b-0 border-t-0 group-focus-within:border-ring bg-background z-20 translate-y-[1px]"></div>
</div>
<div className="flex-1"></div>
</div>
<div className="relative w-full">
<input
type={type}
placeholder={selectedToggle}
className={cn(
"flex-1 h-9 w-full border rounded-r-md rounded-tl-none rounded-bl-md bg-background px-3 pr-12 text-base",
"shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1",
"disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"group-focus-within:border-ring",
className
)}
ref={ref}
value={value}
{...props}
/>
<Button
type="button"
onClick={handleSubmit}
className="absolute right-1 bottom-1 h-7 z-10"
>
</Button>
</div>
</div>
)
}