|
1 | 1 | import { ChevronRightIcon } from "@heroicons/react/24/solid";
|
2 |
| -import { Link } from "@remix-run/react"; |
3 |
| -import { ReactNode, forwardRef, useState } from "react"; |
| 2 | +import { useNavigate } from "@remix-run/react"; |
| 3 | +import React, { ReactNode, forwardRef, useState } from "react"; |
4 | 4 | import { cn } from "~/utils/cn";
|
5 | 5 | import { Popover, PopoverContent, PopoverVerticalEllipseTrigger } from "./Popover";
|
6 | 6 | import { InfoIconTooltip } from "./Tooltip";
|
@@ -44,6 +44,7 @@ export const TableHeader = forwardRef<HTMLTableSectionElement, TableHeaderProps>
|
44 | 44 | "sticky top-0 z-10 bg-background-dimmed after:absolute after:bottom-0 after:left-0 after:right-0 after:h-px after:bg-grid-bright",
|
45 | 45 | className
|
46 | 46 | )}
|
| 47 | + tabIndex={-1} |
47 | 48 | >
|
48 | 49 | {children}
|
49 | 50 | </thead>
|
@@ -71,16 +72,49 @@ type TableRowProps = {
|
71 | 72 | children: ReactNode;
|
72 | 73 | disabled?: boolean;
|
73 | 74 | isSelected?: boolean;
|
| 75 | + to?: string; |
| 76 | + onClick?: (event: React.KeyboardEvent | React.MouseEvent) => void; |
74 | 77 | };
|
75 | 78 |
|
76 | 79 | export const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(
|
77 |
| - ({ className, disabled, isSelected, children }, ref) => { |
| 80 | + ({ className, disabled, isSelected, children, to, onClick }, ref) => { |
| 81 | + const navigate = useNavigate(); |
| 82 | + |
| 83 | + const handleInteraction = (event: React.KeyboardEvent | React.MouseEvent) => { |
| 84 | + if ((event.target as HTMLElement).closest('button, a, [role="button"]')) { |
| 85 | + return; |
| 86 | + } |
| 87 | + |
| 88 | + const firstCellWithTo = React.Children.toArray(children).find((child) => { |
| 89 | + if (React.isValidElement(child) && child.type === TableCell) { |
| 90 | + return child.props.to; |
| 91 | + } |
| 92 | + return false; |
| 93 | + }) as React.ReactElement | undefined; |
| 94 | + |
| 95 | + if (firstCellWithTo?.props.to) { |
| 96 | + navigate(firstCellWithTo.props.to); |
| 97 | + } else if (onClick) { |
| 98 | + onClick(event); |
| 99 | + } |
| 100 | + }; |
| 101 | + |
| 102 | + const handleKeyDown = (event: React.KeyboardEvent) => { |
| 103 | + if (event.key === "Enter") { |
| 104 | + event.preventDefault(); |
| 105 | + event.stopPropagation(); |
| 106 | + handleInteraction(event); |
| 107 | + } |
| 108 | + }; |
| 109 | + |
78 | 110 | return (
|
79 | 111 | <tr
|
80 | 112 | ref={ref}
|
81 |
| - tabIndex={0} |
| 113 | + tabIndex={disabled ? -1 : 0} |
| 114 | + onClick={handleInteraction} |
| 115 | + onKeyDown={handleKeyDown} |
82 | 116 | className={cn(
|
83 |
| - "group/table-row relative w-full outline-none after:absolute after:bottom-0 after:left-3 after:right-0 after:h-px after:bg-grid-dimmed focus:focus-custom", |
| 117 | + "group/table-row relative w-full cursor-pointer outline-none after:absolute after:bottom-0 after:left-3 after:right-0 after:h-px after:bg-grid-dimmed focus-visible:bg-background-bright", |
84 | 118 | disabled && "opacity-50",
|
85 | 119 | isSelected && isSelectedStyle,
|
86 | 120 | className
|
@@ -126,6 +160,7 @@ export const TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellP
|
126 | 160 | className
|
127 | 161 | )}
|
128 | 162 | colSpan={colSpan}
|
| 163 | + tabIndex={-1} |
129 | 164 | >
|
130 | 165 | {hiddenLabel ? (
|
131 | 166 | <span className="sr-only">{children}</span>
|
@@ -154,7 +189,7 @@ type TableCellProps = TableCellBasicProps & {
|
154 | 189 |
|
155 | 190 | const rowHoverStyles = {
|
156 | 191 | default:
|
157 |
| - "group-hover/table-row:bg-charcoal-800 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-750 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-750 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3", |
| 192 | + "group-hover/table-row:bg-charcoal-800 group-focus-visible/table-row:bg-background-bright group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-750 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-750 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3", |
158 | 193 | dimmed:
|
159 | 194 | "group-hover/table-row:bg-charcoal-850 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-800 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-800 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
|
160 | 195 | bright:
|
@@ -193,40 +228,21 @@ export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
|
193 | 228 | break;
|
194 | 229 | }
|
195 | 230 |
|
196 |
| - const flexClasses = cn( |
197 |
| - "flex w-full whitespace-nowrap px-3 py-3 text-xs text-text-dimmed", |
198 |
| - alignment === "left" |
199 |
| - ? "justify-start text-left" |
200 |
| - : alignment === "center" |
201 |
| - ? "justify-center text-center" |
202 |
| - : "justify-end text-right" |
203 |
| - ); |
204 |
| - |
205 | 231 | return (
|
206 | 232 | <td
|
207 | 233 | ref={ref}
|
208 | 234 | className={cn(
|
209 | 235 | "text-xs text-charcoal-400",
|
210 |
| - to || onClick || hasAction ? "cursor-pointer" : "px-3 py-3 align-middle", |
211 |
| - !to && !onClick && alignmentClassName, |
| 236 | + hasAction ? "cursor-pointer" : "px-3 py-3 align-middle", |
| 237 | + alignmentClassName, |
212 | 238 | isSticky && stickyStyles,
|
213 | 239 | isSelected && isSelectedStyle,
|
214 | 240 | !isSelected && rowHoverStyles[rowHoverStyle],
|
215 | 241 | className
|
216 | 242 | )}
|
217 | 243 | colSpan={colSpan}
|
218 | 244 | >
|
219 |
| - {to ? ( |
220 |
| - <Link to={to} tabIndex={-1} className={cn(flexClasses, actionClassName)}> |
221 |
| - {children} |
222 |
| - </Link> |
223 |
| - ) : onClick ? ( |
224 |
| - <button onClick={onClick} tabIndex={-1} className={cn(flexClasses, actionClassName)}> |
225 |
| - {children} |
226 |
| - </button> |
227 |
| - ) : ( |
228 |
| - <>{children}</> |
229 |
| - )} |
| 245 | + {children} |
230 | 246 | </td>
|
231 | 247 | );
|
232 | 248 | }
|
|
0 commit comments