{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "masai-dropdown-checkbox-filter", "title": "Masai Dropdown Checkbox Filter", "description": "Radix dropdown with multi-select checkbox rows; controlled selected values surfaced to parent via onValueChange.", "dependencies": [ "@radix-ui/react-dropdown-menu", "lucide-react" ], "files": [ { "path": "registry/components/masai-dropdown-checkbox-filter.tsx", "content": "\"use client\";\n\nimport * as DropdownMenu from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/** Matches `MasaiCheckbox` / `masai-checkbox.tsx` regular size (18px root, h-3 check). */\nconst CHECKBOX_VISUAL_CLASSES = {\n root: \"h-[18px] w-[18px] rounded-[2px]\",\n icon: \"h-3 w-3\",\n} as const;\n\n/** One selectable row inside the dropdown. */\nexport type MasaiDropdownCheckboxFilterOption = {\n value: string;\n label: string;\n disabled?: boolean;\n};\n\nexport type MasaiDropdownCheckboxFilterProps = {\n options: MasaiDropdownCheckboxFilterOption[];\n /** Controlled selection — pass from parent state. */\n value: string[];\n /** Called when the user toggles any option (full next array). */\n onValueChange: (values: string[]) => void;\n /** Label on the default trigger (ignored when `children` is set). */\n triggerLabel?: string;\n /** Custom trigger; must be a single element (`asChild`). */\n children?: React.ReactElement;\n disabled?: boolean;\n /** Root wrapper classes (layout, width). */\n className?: string;\n triggerClassName?: string;\n contentClassName?: string;\n contentAlign?: \"start\" | \"center\" | \"end\";\n sideOffset?: number;\n};\n\nconst contentClassName =\n \"z-[220] max-h-[min(320px,var(--radix-dropdown-menu-content-available-height))] min-w-[var(--radix-dropdown-menu-trigger-width)] overflow-y-auto rounded-lg border border-gray-200 bg-white p-1 text-gray-900 shadow-md\";\n\nconst checkboxItemClassName = cn(\n \"relative flex cursor-pointer select-none items-center rounded-[2px] py-2 pl-9 pr-3 type-b2-regular text-gray-900 outline-none transition-colors\",\n \"data-highlighted:bg-gray-50\",\n \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n);\n\nfunction toggleSelected(values: string[], optionValue: string, checked: boolean) {\n if (checked) {\n return Array.from(new Set([...values, optionValue]));\n }\n return values.filter((v) => v !== optionValue);\n}\n\n/**\n * MasaiDropdownCheckboxFilter — Radix DropdownMenu with multi-select checkbox rows.\n * Selection is controlled — parent owns `value` and updates from `onValueChange`.\n */\nexport function MasaiDropdownCheckboxFilter({\n options,\n value,\n onValueChange,\n triggerLabel = \"Filter\",\n children,\n disabled = false,\n className,\n triggerClassName,\n contentClassName: contentClassNameProp,\n contentAlign = \"start\",\n sideOffset = 6,\n}: MasaiDropdownCheckboxFilterProps) {\n return (\n
\n \n \n {children ? (\n children\n ) : (\n \n {triggerLabel}\n \n {value.length > 0 ? (\n \n {value.length}\n \n ) : null}\n \n \n \n )}\n \n\n \n \n \n {options.map((option) => {\n const isChecked = value.includes(option.value);\n return (\n \n onValueChange(toggleSelected(value, option.value, checked === true))\n }\n onSelect={(event) => {\n event.preventDefault();\n }}\n >\n \n {isChecked ? (\n \n ) : null}\n \n {option.label}\n \n );\n })}\n \n \n \n \n
\n );\n}\n", "type": "registry:ui" } ], "type": "registry:ui" }