{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"filter-table","title":"Filter Table","description":"Status chips that reorganize live data.","dependencies":[],"registryDependencies":["https://ward.so/r/foundation.json"],"files":[{"path":"registry/ward/FilterTable.tsx","content":"\"use client\";\n/*\n * MIT License\n *\n * Copyright (c) 2026 Shane Levine\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport \"./styles/foundation.css\";\n\nimport { useState } from \"react\";\n\n/* ─────────────────────────────────────────────────────────\n * FILTER TABLE\n * Status chips directly filter the task table.\n * ───────────────────────────────────────────────────────── */\n\ntype Status = \"todo\" | \"progress\" | \"done\";\n\nexport type TableRow = { task: string; date: string; status: Status; owner: string };\n\nexport type FilterTableLabels = {\n  columns: { task: string; date: string; status: string; owner: string };\n};\n\nconst FILTERS: { key: \"all\" | Status; label: string; dot?: string; count: number }[] = [\n  { key: \"all\", label: \"All\", count: 5 },\n  { key: \"todo\", label: \"To do\", dot: \"#f09a2f\", count: 2 },\n  { key: \"progress\", label: \"In Progress\", dot: \"#16a6c7\", count: 2 },\n  { key: \"done\", label: \"Completed\", dot: \"#25a878\", count: 1 },\n];\n\nconst ROWS: TableRow[] = [\n  { task: \"Restock mango sorbet\", date: \"Dec 03\", status: \"todo\", owner: \"Mango Moon Brand\" },\n  { task: \"Plan black sesame\", date: \"Sep 22\", status: \"progress\", owner: \"Kumo Studio\" },\n  { task: \"Print summer menu\", date: \"Jan 02\", status: \"todo\", owner: \"Coral Coast Sorbet\" },\n  { task: \"Taste-test batch 42\", date: \"Nov 08\", status: \"progress\", owner: \"Maple Orbit\" },\n  { task: \"Order design assets\", date: \"Apr 14\", status: \"done\", owner: \"Aurora Works\" },\n];\n\nconst LABELS: FilterTableLabels = {\n  columns: { task: \"Task name\", date: \"Date\", status: \"Status\", owner: \"Advisor\" },\n};\n\nconst PILLS: Record<Status, { label: string; cls: string }> = {\n  todo: { label: \"To do\", cls: \"filter-status-todo\" },\n  progress: { label: \"In Progress\", cls: \"filter-status-progress\" },\n  done: { label: \"Completed\", cls: \"filter-status-done\" },\n};\n\nexport default function FilterTable({\n  rows = ROWS,\n  labels = LABELS,\n}: {\n  rows?: TableRow[];\n  labels?: FilterTableLabels;\n  variant?: string;\n} = {}) {\n  const [filter, setFilter] = useState<\"all\" | Status>(\"all\");\n\n  return (\n    <div className=\"w-full max-w-105\">\n      {/* filter chips */}\n      <div\n        className=\"-mx-1 mb-1 flex items-center gap-1 overflow-x-auto px-1 py-1\"\n        style={{ scrollbarWidth: \"none\" }}\n      >\n        {FILTERS.map((f) => {\n          const active = filter === f.key;\n          return (\n            <button\n              key={f.key}\n              type=\"button\"\n              aria-pressed={active}\n              onClick={() => setFilter(f.key)}\n              className={`flex h-6.5 shrink-0 items-center gap-1.5 rounded-full px-2.5 text-[12px]\n                font-medium transition-[background-color,box-shadow,color] duration-200\n                ${active ? \"bg-card text-ink shadow-btn\" : \"text-ink-2 hover:bg-hover\"}`}\n            >\n              {f.dot && <span className=\"size-1.5 rounded-full\" style={{ background: f.dot }} />}\n              {f.label}\n              <span\n                className={`rounded-[4px] px-1 text-[10.5px] tabular-nums\n                  ${active ? \"bg-field text-ink-2\" : \"text-ink-3\"}`}\n              >\n                {f.count}\n              </span>\n            </button>\n          );\n        })}\n      </div>\n\n      {/* table */}\n      <div\n        aria-label=\"Scrollable task table\"\n        className=\"overflow-x-auto rounded-card bg-card shadow-card\"\n        role=\"region\"\n        tabIndex={0}\n        style={{ scrollbarWidth: \"none\" }}\n      >\n        <div className=\"min-w-[420px]\">\n          <div className=\"grid grid-cols-[minmax(0,1.3fr)_minmax(0,0.6fr)_minmax(0,0.95fr)_minmax(0,0.9fr)] border-b border-[var(--grid-line)] text-[12.5px] font-medium text-ink-2\">\n            <span className=\"border-r border-[var(--grid-line)] px-3 py-2\">{labels.columns.task}</span>\n            <span className=\"border-r border-[var(--grid-line)] px-3 py-2\">{labels.columns.date}</span>\n            <span className=\"border-r border-[var(--grid-line)] px-3 py-2\">{labels.columns.status}</span>\n            <span className=\"px-3 py-2\">{labels.columns.owner}</span>\n          </div>\n          {rows.map((row) => {\n            const shown = filter === \"all\" || row.status === filter;\n            const pill = PILLS[row.status];\n            return (\n              <div\n                key={row.task}\n                className=\"grid transition-[grid-template-rows,opacity] duration-300\"\n                style={{\n                  gridTemplateRows: shown ? \"1fr\" : \"0fr\",\n                  opacity: shown ? 1 : 0,\n                  transitionTimingFunction: \"cubic-bezier(0.23, 1, 0.32, 1)\",\n                }}\n              >\n                <div className=\"overflow-hidden\">\n                  <div\n                    className=\"grid grid-cols-[minmax(0,1.3fr)_minmax(0,0.6fr)_minmax(0,0.95fr)_minmax(0,0.9fr)] border-b\n                      border-[var(--grid-line)] text-[13px] transition-colors duration-100 hover:bg-hover\"\n                  >\n                    <span className=\"flex min-w-0 items-center border-r border-[var(--grid-line)] px-3 py-2\">\n                      <span className=\"truncate font-medium text-ink\">{row.task}</span>\n                    </span>\n                    <span className=\"flex items-center whitespace-nowrap border-r border-[var(--grid-line)] px-3 py-2 text-ink-2 tabular-nums\">\n                      {row.date}\n                    </span>\n                    <span className=\"flex items-center border-r border-[var(--grid-line)] px-3 py-2\">\n                      <span\n                        className={`inline-flex h-[23px] shrink-0 items-center whitespace-nowrap rounded-[8px] border px-[7px]\n                          text-[13px] font-medium ${pill.cls}`}\n                      >\n                        {pill.label}\n                      </span>\n                    </span>\n                    <span className=\"flex min-w-0 items-center px-3 py-2 text-ink-2\">\n                      <span className=\"truncate\">{row.owner}</span>\n                    </span>\n                  </div>\n                </div>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n    </div>\n  );\n}\n","type":"registry:component","target":"components/ward/FilterTable.tsx"}],"meta":{"variants":["Default"],"version":"1.1.0","source":"https://github.com/slev12397/beautiful-ui/blob/44a274e598395ab61e7c96c26fda2758780253b7/components/primitives/FilterTable.tsx","access":"free"},"categories":["data"],"type":"registry:component"}