@hyddenlabs/hydn-ui 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data-display/data-grid/data-grid.d.ts +40 -1
- package/dist/components/data-display/data-grid/data-grid.d.ts.map +1 -1
- package/dist/components/data-display/data-grid/data-grid.js +57 -16
- package/dist/components/data-display/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-display/data-grid/index.d.ts +1 -1
- package/dist/components/data-display/data-grid/index.d.ts.map +1 -1
- package/dist/components/forms/button/button.d.ts +22 -7
- package/dist/components/forms/button/button.d.ts.map +1 -1
- package/dist/components/forms/button/button.js +45 -10
- package/dist/components/forms/button/button.js.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
|
@@ -144,6 +144,33 @@ export type DataGridProps<T> = {
|
|
|
144
144
|
title?: string;
|
|
145
145
|
/** Header actions displayed above the grid (right side of header). */
|
|
146
146
|
headerActions?: HeaderAction[];
|
|
147
|
+
/**
|
|
148
|
+
* Container width (px) below which the grid collapses into list mode.
|
|
149
|
+
* Defaults to 480. Column hiding (via `hidePriority` / `minWidth`) still
|
|
150
|
+
* runs for widths above this breakpoint.
|
|
151
|
+
*/
|
|
152
|
+
listBreakpoint?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Custom render function for list mode. When provided, each row is rendered
|
|
155
|
+
* using this function instead of the default vertical-stack fallback.
|
|
156
|
+
* Use this to create type-specific list layouts with the right fields,
|
|
157
|
+
* actions, and visual hierarchy for the entity being displayed.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```tsx
|
|
161
|
+
* renderListItem={(row, index, { actions, isSelected, onToggleSelect }) => (
|
|
162
|
+
* <div className="flex items-center gap-3">
|
|
163
|
+
* <Avatar name={row.name} />
|
|
164
|
+
* <div className="flex-1 min-w-0">
|
|
165
|
+
* <Text weight="medium" className="truncate">{row.name}</Text>
|
|
166
|
+
* <Text size="sm" variant="muted" className="truncate">{row.email}</Text>
|
|
167
|
+
* </div>
|
|
168
|
+
* {actions}
|
|
169
|
+
* </div>
|
|
170
|
+
* )}
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
renderListItem?: (row: T, index: number, context: DataGridListItemContext) => ReactNode;
|
|
147
174
|
};
|
|
148
175
|
export type HeaderAction = {
|
|
149
176
|
/** Button text; if omitted and `icon` provided, button will be icon-only */
|
|
@@ -163,6 +190,18 @@ export type HeaderAction = {
|
|
|
163
190
|
/** Additional className forwarded to the Button */
|
|
164
191
|
className?: string;
|
|
165
192
|
};
|
|
193
|
+
/**
|
|
194
|
+
* Context passed to `renderListItem` so list-mode renders can embed grid actions
|
|
195
|
+
* and selection state without needing to manage them independently.
|
|
196
|
+
*/
|
|
197
|
+
export type DataGridListItemContext = {
|
|
198
|
+
/** Pre-rendered action buttons derived from the `actions` prop */
|
|
199
|
+
actions: ReactNode;
|
|
200
|
+
/** Whether this row is currently selected */
|
|
201
|
+
isSelected: boolean;
|
|
202
|
+
/** Toggle selection for this row. Defined only when `selectable` is true. */
|
|
203
|
+
onToggleSelect?: () => void;
|
|
204
|
+
};
|
|
166
205
|
/**
|
|
167
206
|
* DataGrid - Responsive data display component with Vercel-style layout
|
|
168
207
|
*
|
|
@@ -196,7 +235,7 @@ export type HeaderAction = {
|
|
|
196
235
|
* />
|
|
197
236
|
* ```
|
|
198
237
|
*/
|
|
199
|
-
declare function DataGrid<T>({ data, columns, className, striped, hoverable, compact, sortable, paginated, pageSize, selectable, searchable, searchKeys, searchPlaceholder, onSearchChange, actions, actionsLabel, rowHref, onRowClick, onSelectionChange, emptyState, headerActions, title, initialSort }: DataGridProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
238
|
+
declare function DataGrid<T>({ data, columns, className, striped, hoverable, compact, sortable, paginated, pageSize, selectable, searchable, searchKeys, searchPlaceholder, onSearchChange, actions, actionsLabel, rowHref, onRowClick, onSelectionChange, emptyState, headerActions, title, initialSort, listBreakpoint, renderListItem }: DataGridProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
200
239
|
declare namespace DataGrid {
|
|
201
240
|
var displayName: string;
|
|
202
241
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid.d.ts","sourceRoot":"","sources":["../../../../src/components/data-display/data-grid/data-grid.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-grid.d.ts","sourceRoot":"","sources":["../../../../src/components/data-display/data-grid/data-grid.tsx"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ function isInteractiveElement(element, container) {
|
|
|
24
24
|
}
|
|
25
25
|
return false;
|
|
26
26
|
}
|
|
27
|
-
const
|
|
27
|
+
const DEFAULT_LIST_BREAKPOINT = 480;
|
|
28
28
|
function DataGrid({
|
|
29
29
|
data,
|
|
30
30
|
columns,
|
|
@@ -53,10 +53,12 @@ function DataGrid({
|
|
|
53
53
|
},
|
|
54
54
|
headerActions,
|
|
55
55
|
title,
|
|
56
|
-
initialSort
|
|
56
|
+
initialSort,
|
|
57
|
+
listBreakpoint = DEFAULT_LIST_BREAKPOINT,
|
|
58
|
+
renderListItem
|
|
57
59
|
}) {
|
|
58
60
|
const [searchQuery, setSearchQuery] = useState("");
|
|
59
|
-
const [
|
|
61
|
+
const [isListMode, setIsListMode] = useState(false);
|
|
60
62
|
const handleSearchChange = (value) => {
|
|
61
63
|
setSearchQuery(value);
|
|
62
64
|
if (onSearchChange) {
|
|
@@ -95,9 +97,9 @@ function DataGrid({
|
|
|
95
97
|
const hasHideableColumns = columns.some((col) => col.hidePriority !== void 0 || col.minWidth !== void 0);
|
|
96
98
|
const updateLayout = () => {
|
|
97
99
|
const containerWidth = container.offsetWidth;
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
if (
|
|
100
|
+
const nowListMode = containerWidth < listBreakpoint;
|
|
101
|
+
setIsListMode(nowListMode);
|
|
102
|
+
if (nowListMode || !hasHideableColumns) {
|
|
101
103
|
setVisibleColumns(columns);
|
|
102
104
|
return;
|
|
103
105
|
}
|
|
@@ -163,7 +165,7 @@ function DataGrid({
|
|
|
163
165
|
return () => {
|
|
164
166
|
observer.disconnect();
|
|
165
167
|
};
|
|
166
|
-
}, [columns, selectable, actions, actionsMinWidth, compact, data]);
|
|
168
|
+
}, [columns, selectable, actions, actionsMinWidth, compact, data, listBreakpoint]);
|
|
167
169
|
const effectiveSearchKeys = searchKeys || visibleColumns.map((col) => col.key);
|
|
168
170
|
const tableOptions = {
|
|
169
171
|
data,
|
|
@@ -352,7 +354,7 @@ function DataGrid({
|
|
|
352
354
|
}
|
|
353
355
|
return parts.join(" ");
|
|
354
356
|
};
|
|
355
|
-
const gridTemplateColumns = !
|
|
357
|
+
const gridTemplateColumns = !isListMode ? buildGridTemplateColumns() : void 0;
|
|
356
358
|
const renderRow = (row, rowIndex) => {
|
|
357
359
|
const actualIndex = paginated ? (currentPage - 1) * pageSize + rowIndex : rowIndex;
|
|
358
360
|
const isSelected = isRowSelected(actualIndex);
|
|
@@ -367,8 +369,47 @@ function DataGrid({
|
|
|
367
369
|
hoverable && isClickable ? "hover:bg-muted/50 transition-colors" : "",
|
|
368
370
|
isSelected ? "bg-primary/5" : ""
|
|
369
371
|
].filter(Boolean).join(" ");
|
|
370
|
-
const layoutClasses =
|
|
371
|
-
const rowStyle = !
|
|
372
|
+
const layoutClasses = isListMode ? "flex flex-col gap-3" : "grid items-center gap-4";
|
|
373
|
+
const rowStyle = !isListMode && gridTemplateColumns ? { gridTemplateColumns } : void 0;
|
|
374
|
+
if (isListMode && renderListItem) {
|
|
375
|
+
const actionsContent = renderActions(row, actualIndex);
|
|
376
|
+
const listItemContent = renderListItem(row, actualIndex, {
|
|
377
|
+
actions: actionsContent,
|
|
378
|
+
isSelected,
|
|
379
|
+
onToggleSelect: selectable ? () => handleToggleRow(actualIndex) : void 0
|
|
380
|
+
});
|
|
381
|
+
const pointerClass = hasHref ? "pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_label]:pointer-events-auto [&_[data-interactive]]:pointer-events-auto" : "";
|
|
382
|
+
const listRowClickProps = !hasHref && hasOnRowClick ? {
|
|
383
|
+
onClick: (e) => {
|
|
384
|
+
if (isInteractiveElement(e.target, e.currentTarget)) return;
|
|
385
|
+
onRowClick?.(row, actualIndex);
|
|
386
|
+
},
|
|
387
|
+
onKeyDown: (e) => {
|
|
388
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
389
|
+
e.preventDefault();
|
|
390
|
+
onRowClick?.(row, actualIndex);
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
role: "button",
|
|
394
|
+
tabIndex: 0,
|
|
395
|
+
className: "cursor-pointer"
|
|
396
|
+
} : {};
|
|
397
|
+
return /* @__PURE__ */ jsxs(
|
|
398
|
+
"div",
|
|
399
|
+
{
|
|
400
|
+
className: `relative ${rowPadding} ${rowClasses} ${listRowClickProps.className || ""}`,
|
|
401
|
+
onClick: listRowClickProps.onClick,
|
|
402
|
+
onKeyDown: listRowClickProps.onKeyDown,
|
|
403
|
+
role: listRowClickProps.role,
|
|
404
|
+
tabIndex: listRowClickProps.tabIndex,
|
|
405
|
+
children: [
|
|
406
|
+
hasHref && href && /* @__PURE__ */ jsx(Link, { to: href, className: "absolute inset-0 z-1", "aria-label": "View details", tabIndex: 0 }),
|
|
407
|
+
/* @__PURE__ */ jsx("div", { className: pointerClass, children: listItemContent })
|
|
408
|
+
]
|
|
409
|
+
},
|
|
410
|
+
actualIndex
|
|
411
|
+
);
|
|
412
|
+
}
|
|
372
413
|
const rowClickProps = !hasHref && hasOnRowClick ? {
|
|
373
414
|
onClick: (e) => {
|
|
374
415
|
if (isInteractiveElement(e.target, e.currentTarget)) {
|
|
@@ -397,7 +438,7 @@ function DataGrid({
|
|
|
397
438
|
tabIndex: rowClickProps.tabIndex,
|
|
398
439
|
children: [
|
|
399
440
|
hasHref && href && /* @__PURE__ */ jsx(Link, { to: href, className: "absolute inset-0 z-1", "aria-label": `View details`, tabIndex: 0 }),
|
|
400
|
-
selectable && /* @__PURE__ */ jsx("div", { className: `relative z-10 ${
|
|
441
|
+
selectable && /* @__PURE__ */ jsx("div", { className: `relative z-10 ${isListMode ? "" : "shrink-0"}`, children: /* @__PURE__ */ jsx(
|
|
401
442
|
Checkbox,
|
|
402
443
|
{
|
|
403
444
|
checked: isSelected,
|
|
@@ -408,13 +449,13 @@ function DataGrid({
|
|
|
408
449
|
visibleColumns.map((column) => {
|
|
409
450
|
const value = row[column.key];
|
|
410
451
|
const content = renderCellContent(value, column, row, actualIndex);
|
|
411
|
-
const showLabel =
|
|
452
|
+
const showLabel = isListMode && column.showLabelOnMobile !== false;
|
|
412
453
|
const alignClass = column.align === "center" ? "text-center" : column.align === "right" ? "text-right" : "text-left";
|
|
413
454
|
const pointerClass = hasHref ? "pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_label]:pointer-events-auto [&_[data-interactive]]:pointer-events-auto" : "";
|
|
414
455
|
return /* @__PURE__ */ jsxs(
|
|
415
456
|
"div",
|
|
416
457
|
{
|
|
417
|
-
className: `${alignClass} ${
|
|
458
|
+
className: `${alignClass} ${isListMode ? "flex flex-col gap-0.5" : "min-w-0 overflow-hidden"} ${pointerClass}`,
|
|
418
459
|
children: [
|
|
419
460
|
showLabel && /* @__PURE__ */ jsx(Text, { size: "xs", variant: "muted", className: "uppercase tracking-wide", children: column.label }),
|
|
420
461
|
/* @__PURE__ */ jsx("div", { className: column.wrapText ? "" : "truncate", children: content })
|
|
@@ -423,7 +464,7 @@ function DataGrid({
|
|
|
423
464
|
String(column.key)
|
|
424
465
|
);
|
|
425
466
|
}),
|
|
426
|
-
actions && /* @__PURE__ */ jsx("div", { className: `relative z-10 shrink-0 ${
|
|
467
|
+
actions && /* @__PURE__ */ jsx("div", { className: `relative z-10 shrink-0 ${isListMode ? "flex justify-end pt-1" : "justify-self-end"}`, children: renderActions(row, actualIndex) })
|
|
427
468
|
]
|
|
428
469
|
},
|
|
429
470
|
actualIndex
|
|
@@ -493,7 +534,7 @@ function DataGrid({
|
|
|
493
534
|
description: `No items match "${searchQuery}". Try adjusting your search.`
|
|
494
535
|
}
|
|
495
536
|
) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
496
|
-
!
|
|
537
|
+
!isListMode && /* @__PURE__ */ jsxs(
|
|
497
538
|
"div",
|
|
498
539
|
{
|
|
499
540
|
className: `grid items-center gap-4 ${rowPadding} border-b border-border bg-muted/30`,
|
|
@@ -519,7 +560,7 @@ function DataGrid({
|
|
|
519
560
|
]
|
|
520
561
|
}
|
|
521
562
|
),
|
|
522
|
-
|
|
563
|
+
isListMode && !renderListItem && selectable && /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-2 ${rowPadding} border-b border-border`, children: [
|
|
523
564
|
/* @__PURE__ */ jsx(Checkbox, { checked: isAllSelected, onChange: handleToggleAll, ariaLabel: "Select all rows" }),
|
|
524
565
|
/* @__PURE__ */ jsx(Text, { size: "sm", variant: "muted", children: "Select all" })
|
|
525
566
|
] }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid.js","sources":["../../../../src/components/data-display/data-grid/data-grid.tsx"],"sourcesContent":["import { ReactNode, useState, useEffect, useRef } from 'react';\nimport { Icon } from '../../system/icon/icon';\nimport IconButton from '../../forms/button/icon-button';\nimport Input from '../../forms/input/input';\nimport InputGroup from '../../forms/input-group/input-group';\n\nimport Checkbox from '../../forms/checkbox/checkbox';\nimport Button from '../../forms/button/button';\nimport Tooltip from '../../feedback/tooltip/tooltip';\nimport type { ButtonProps } from '../../forms/button/button';\nimport Stack from '../../layout/stack/stack';\nimport Badge from '../badge/badge';\nimport Text from '../../typography/text/text';\nimport { useTable, UseTableOptions } from '../data-table/use-table';\nimport { Size } from '@/theme/size-tokens';\nimport { ColorVariant } from '@/theme/tokens';\nimport EmptyState from '../empty-state/empty-state';\nimport StatusIndicator from '../status-indicator/status-indicator';\nimport { Link } from 'react-router-dom';\n\n/** Interactive element tags that should not trigger onRowClick callback */\nconst INTERACTIVE_TAGS = new Set(['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL']);\n\n/** Check if an element or any of its ancestors (up to container) is interactive - used for onRowClick only */\nfunction isInteractiveElement(element: HTMLElement | null, container: HTMLElement | null): boolean {\n let current = element;\n while (current && current !== container) {\n if (INTERACTIVE_TAGS.has(current.tagName)) return true;\n if (current.getAttribute('role') === 'button') return true;\n current = current.parentElement;\n }\n return false;\n}\n\nexport type DataGridAction<T> = {\n /** Icon name for the action button */\n icon: string;\n /** Size of the icon */\n iconSize?: Size;\n /** Color variant for the icon */\n iconColor?: ColorVariant;\n /** Icon to display on hover (optional) */\n hoverIcon?: string;\n /** Accessible label for the action (shown in tooltip or screen readers) */\n label: string;\n /** Tooltip text to display on hover. If not provided, label will be used for aria-label only. */\n tooltip?: string;\n /** Callback when the action is clicked */\n onClick: (row: T, index: number) => void;\n /** Visual variant for the action button */\n variant?: 'primary' | 'accent' | 'neutral' | 'success' | 'warning' | 'error' | 'info';\n};\n\nexport type DataGridActionItem<T> = DataGridAction<T> | ReactNode;\n\nexport type DataGridColumnDef<T> = {\n /** Key of the data property to display in this column */\n key: keyof T;\n /** Column header label */\n label: string;\n /** Whether this column can be sorted */\n sortable?: boolean;\n /** CSS width class or value for the column (e.g., 'w-48', '200px', 'flex-1') */\n width?: string;\n /**\n * Minimum width in pixels for the column. When set:\n * - Column truncates but never shrinks below this width\n * - Column auto-hides if container can't fit it at this width\n * - No need to also set hidePriority (though you can for explicit hide ordering)\n *\n * @example minWidth: 120 // Hide if email would be squished below 120px\n */\n minWidth?: number;\n /**\n * Maximum width in pixels for the column. Prevents column from growing too wide.\n * Use for columns like status/role that don't need much space.\n *\n * @example maxWidth: 100 // Cap role column at 100px\n */\n maxWidth?: number;\n /** Text alignment for cells in this column */\n align?: 'left' | 'center' | 'right';\n /** Whether text should wrap instead of truncating (useful for long strings) */\n wrapText?: boolean;\n /** Optional priority for responsive hiding. Lower values hide first when container width shrinks. Columns without hidePriority or minWidth are never hidden. */\n hidePriority?: number;\n /** Whether to show this column's label in mobile/vertical layout (default: true) */\n showLabelOnMobile?: boolean;\n /** Custom render function for cell content (use as escape hatch when config options don't cover your use case) */\n render?: (value: T[keyof T], row: T, index: number) => ReactNode;\n\n // Config-driven rendering options (preferred over custom render)\n /** Pre-built formatter for common data types */\n format?: 'date' | 'currency' | 'number' | 'percent';\n /** Options for Intl formatters (NumberFormat or DateTimeFormat) */\n formatOptions?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;\n /** Map values to badge variants. Unmatched values render with 'neutral' variant. Use '*' key to override the default fallback. */\n badgeMap?: {\n [key: string]: { variant?: ColorVariant; label?: string };\n };\n /** Map values to status dot colors. Renders text with a colored dot to the left. Lighter alternative to badges for status indicators. */\n statusDotMap?: {\n [key: string]: { color?: ColorVariant; label?: string };\n };\n /**\n * Render cell values as badges. When the value is an array, each item is rendered\n * as an individual badge; for scalar values, the value is wrapped in a single badge.\n */\n renderAsBadges?: boolean;\n /** Variant for badge rendering */\n badgeVariant?: ColorVariant;\n /** Size for badge rendering */\n componentSize?: 'sm' | 'md' | 'lg';\n /** Fallback value to display when cell value is null, undefined, or empty string */\n fallback?: string;\n};\n\nexport type DataGridProps<T> = {\n /** Array of data objects to display in the grid */\n data: T[];\n /** Column definitions specifying how to render each column */\n columns: DataGridColumnDef<T>[];\n /** Additional CSS classes to apply */\n className?: string;\n\n // Styling options\n /** Whether to apply striped row styling (alternating background) */\n striped?: boolean;\n /** Whether rows have hover effects */\n hoverable?: boolean;\n /** Whether to use compact spacing for dense data */\n compact?: boolean;\n\n // Features\n /** Whether columns can be sorted (can be overridden per column) */\n sortable?: boolean;\n /** Whether to enable client-side pagination */\n paginated?: boolean;\n /** Number of rows per page when pagination is enabled */\n pageSize?: number;\n /** Whether to show checkboxes for row selection */\n selectable?: boolean;\n /** Whether to enable search/filter functionality */\n searchable?: boolean;\n /** Specific keys to search within. If not provided, searches all fields. */\n searchKeys?: (keyof T)[];\n /** Placeholder text for the search input */\n searchPlaceholder?: string;\n /** Callback when search query changes */\n onSearchChange?: (query: string) => void;\n\n // Actions - either array of action configs/components OR function returning actions/render\n /** Action buttons, function returning actions based on row data, or custom render function for the actions column */\n actions?: DataGridActionItem<T>[] | ((row: T, index: number) => DataGridActionItem<T>[] | ReactNode);\n /** Label for the actions column header */\n actionsLabel?: string;\n\n // Row link - makes entire row clickable for navigation\n /** Function returning href for row navigation. When provided, entire row becomes a link. */\n rowHref?: (row: T, index: number) => string | undefined;\n\n // Callbacks\n /** Callback when a row is clicked (if rowHref not provided) */\n onRowClick?: (row: T, index: number) => void;\n /** Callback when row selection changes (provides array of selected row indices) */\n onSelectionChange?: (selectedIndices: number[]) => void;\n\n // Empty state\n emptyState?: {\n /** Message to display when there is no data */\n title?: string;\n /** Description to display when there is no data */\n description?: string;\n /** Text for the button in the empty state */\n buttonText?: string;\n /** Click handler for the button in the empty state */\n onButtonClick?: () => void;\n };\n\n // Initial state\n /** Initial sort configuration */\n initialSort?: { key: keyof T; direction: 'asc' | 'desc' };\n /** Title displayed above the grid (left side of header) */\n title?: string;\n /** Header actions displayed above the grid (right side of header). */\n headerActions?: HeaderAction[];\n};\n\nexport type HeaderAction = {\n /** Button text; if omitted and `icon` provided, button will be icon-only */\n label?: string;\n /** Icon name to render inside the button (maps to library `Icon`) */\n icon?: string;\n /** Accessible label for screen readers. Required for icon-only buttons (when label is omitted). */\n ariaLabel?: string;\n /** Click handler invoked when the button is clicked */\n onClick?: () => void;\n /** Button variant (maps to Button `variant` prop) */\n variant?: ButtonProps['variant'];\n /** Button style (maps to Button `style` prop) */\n style?: ButtonProps['style'];\n /** Button size (maps to Button `size` prop) */\n size?: ButtonProps['size'];\n /** Additional className forwarded to the Button */\n className?: string;\n};\n\n/** Breakpoint width (in px) below which we switch to vertical/mobile layout */\nconst MOBILE_BREAKPOINT = 640;\n\n/**\n * DataGrid - Responsive data display component with Vercel-style layout\n *\n * Features:\n * - Generic typed data and columns (same API as DataTable)\n * - Responsive layout: horizontal rows on desktop, vertical card-like on mobile\n * - Clickable rows via rowHref with interactive elements taking priority\n * - Client-side sorting, pagination, selection, and search\n * - Custom cell rendering with DataGridCell for multi-element stacking\n *\n * @example\n * ```tsx\n * <DataGrid\n * data={deployments}\n * columns={[\n * {\n * key: 'name',\n * label: 'Deployment',\n * render: (value, row) => (\n * <DataGridCell>\n * <Text weight=\"medium\">{row.name}</Text>\n * <Text size=\"sm\" variant=\"muted\">{row.url}</Text>\n * </DataGridCell>\n * )\n * },\n * { key: 'status', label: 'Status', badgeMap: { ready: { variant: 'success' } } },\n * { key: 'createdAt', label: 'Created', format: 'date' }\n * ]}\n * rowHref={(row) => `/deployments/${row.id}`}\n * hoverable\n * />\n * ```\n */\nfunction DataGrid<T>({\n data,\n columns,\n className = '',\n striped = false,\n hoverable = true,\n compact = false,\n sortable = true,\n paginated = false,\n pageSize = 10,\n selectable = false,\n searchable = false,\n searchKeys,\n searchPlaceholder = 'Search...',\n onSearchChange,\n actions,\n actionsLabel = 'Actions',\n rowHref,\n onRowClick,\n onSelectionChange,\n emptyState = {\n title: 'No data available',\n description: undefined,\n buttonText: undefined,\n onButtonClick: undefined\n },\n headerActions,\n title,\n initialSort\n}: DataGridProps<T>) {\n // Search state\n const [searchQuery, setSearchQuery] = useState('');\n\n // Layout state (desktop vs mobile)\n const [isMobile, setIsMobile] = useState(false);\n\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n if (onSearchChange) {\n onSearchChange(value);\n }\n };\n\n // Container ref for responsive behavior\n const containerRef = useRef<HTMLDivElement>(null);\n const [visibleColumns, setVisibleColumns] = useState<DataGridColumnDef<T>[]>(() => columns);\n\n // Calculate minimum width needed for actions column based on max actions in any row\n const calculateActionsMinWidth = (): number => {\n if (!actions) return 0;\n\n let maxActionCount = 0;\n\n if (Array.isArray(actions)) {\n // Static actions - all rows have the same actions\n maxActionCount = actions.length;\n } else {\n // Dynamic actions - need to check all rows\n data.forEach((row, index) => {\n const result = actions(row, index);\n if (Array.isArray(result)) {\n maxActionCount = Math.max(maxActionCount, result.length);\n } else {\n // Custom render - assume it needs reasonable space (equivalent to 2 actions)\n maxActionCount = Math.max(maxActionCount, 2);\n }\n });\n }\n\n if (maxActionCount === 0) {\n // No actions, but we still need some minimum space in case actions appear\n return 60;\n }\n\n // Each action button takes ~36px (icon + button padding)\n // Stack spacing between actions is 8px (spacing=\"sm\")\n // Formula: (actionWidth * count) + (gap * (count - 1)) + extraPadding\n const actionWidth = 24;\n const gapWidth = 8;\n const extraPadding = 16; // breathing room\n\n return actionWidth * maxActionCount + gapWidth * Math.max(0, maxActionCount - 1) + extraPadding;\n };\n\n const actionsMinWidth = calculateActionsMinWidth();\n\n // ResizeObserver to handle responsive column hiding and mobile layout\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n // Check if any columns have hidePriority or minWidth set (both make columns hideable)\n const hasHideableColumns = columns.some((col) => col.hidePriority !== undefined || col.minWidth !== undefined);\n\n const updateLayout = () => {\n const containerWidth = container.offsetWidth;\n\n // Check if we should switch to mobile layout\n const nowMobile = containerWidth < MOBILE_BREAKPOINT;\n setIsMobile(nowMobile);\n\n // In mobile/vertical layout, show all columns (they stack vertically)\n // Only apply responsive hiding in desktop/horizontal mode\n if (nowMobile || !hasHideableColumns) {\n setVisibleColumns(columns);\n return;\n }\n\n // Columns are hideable if they have hidePriority OR minWidth\n const isHideable = (col: DataGridColumnDef<T>) => col.hidePriority !== undefined || col.minWidth !== undefined;\n\n // Separate columns into hideable and non-hideable\n const hideableColumns = columns\n .map((col, index) => ({ col, originalIndex: index }))\n .filter(({ col }) => isHideable(col))\n .sort((a, b) => {\n // Sort by hidePriority if both have it (lower hides first)\n const aPriority = a.col.hidePriority;\n const bPriority = b.col.hidePriority;\n\n if (aPriority !== undefined && bPriority !== undefined) {\n if (aPriority !== bPriority) return aPriority - bPriority;\n }\n // Columns with explicit hidePriority hide before minWidth-only columns\n if (aPriority !== undefined && bPriority === undefined) return -1;\n if (aPriority === undefined && bPriority !== undefined) return 1;\n\n // For minWidth-only columns, larger minWidth hides first (needs more space)\n const aMin = a.col.minWidth ?? 0;\n const bMin = b.col.minWidth ?? 0;\n if (aMin !== bMin) return bMin - aMin;\n\n // Finally, later columns hide first (preserve leading columns)\n return b.originalIndex - a.originalIndex;\n });\n\n const nonHideableColumns = columns.filter((col) => !isHideable(col));\n\n // Estimate column width - use minWidth if set, otherwise parse width or default\n const estimateColumnWidth = (col: DataGridColumnDef<T>): number => {\n // Use minWidth if explicitly set (this is the minimum space the column needs)\n if (col.minWidth) return col.minWidth;\n\n if (col.width) {\n const match = col.width.match(/(\\d+)/);\n if (match) {\n const num = parseInt(match[1], 10);\n if (col.width.includes('px')) return num;\n return num * 4;\n }\n }\n return 150;\n };\n\n // Calculate horizontal padding (px-3 = 24px total, px-4 = 32px total)\n const horizontalPadding = compact ? 24 : 32;\n // Grid gap is 16px (gap-4) between each column\n const gridGap = 16;\n\n // Start with non-hideable columns\n let currentWidth = nonHideableColumns.reduce((sum, col) => sum + estimateColumnWidth(col), 0);\n let totalColumns = nonHideableColumns.length;\n\n // Account for selection and actions columns\n if (selectable) {\n currentWidth += 48;\n totalColumns += 1;\n }\n if (actions) {\n currentWidth += actionsMinWidth;\n totalColumns += 1;\n }\n\n // Add hideable columns until we run out of space\n const columnsToShow: DataGridColumnDef<T>[] = [...nonHideableColumns];\n\n for (const { col } of hideableColumns) {\n const colWidth = estimateColumnWidth(col);\n const newTotalColumns = totalColumns + 1;\n // Calculate total gaps needed with the new column (N columns = N-1 gaps)\n const totalGaps = Math.max(0, newTotalColumns - 1) * gridGap;\n const totalWidthNeeded = currentWidth + colWidth + totalGaps + horizontalPadding;\n\n if (totalWidthNeeded <= containerWidth) {\n columnsToShow.push(col);\n currentWidth += colWidth;\n totalColumns = newTotalColumns;\n }\n }\n\n // Restore original column order\n const orderedVisibleColumns = columns.filter((col) => columnsToShow.includes(col));\n setVisibleColumns(orderedVisibleColumns);\n };\n\n // Call once on mount\n updateLayout();\n\n // Set up observer\n const observer = new ResizeObserver(() => {\n updateLayout();\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [columns, selectable, actions, actionsMinWidth, compact, data]);\n\n // Use table hook for state management\n const effectiveSearchKeys = searchKeys || visibleColumns.map((col) => col.key);\n\n const tableOptions: UseTableOptions<T> = {\n data,\n initialSort,\n pageSize,\n searchQuery,\n searchKeys: effectiveSearchKeys\n };\n\n const {\n currentData,\n sortedData,\n filteredData,\n sortConfig,\n handleSort,\n currentPage,\n totalPages,\n nextPage,\n prevPage,\n canNextPage,\n canPrevPage,\n selectedRows,\n toggleRow,\n toggleAll,\n isRowSelected,\n isAllSelected\n } = useTable(tableOptions);\n\n // Display data (paginated uses currentData, non-paginated uses sortedData)\n const displayData = paginated ? currentData : sortedData;\n\n // Header title and actions\n const hasHeader = Boolean(\n (title && String(title).length > 0) ||\n (Array.isArray(headerActions) ? headerActions.length > 0 : headerActions) ||\n searchable\n );\n\n // Selection handlers\n const handleToggleRow = (index: number) => {\n toggleRow(index);\n if (onSelectionChange) {\n const newSelection = new Set(selectedRows);\n if (newSelection.has(index)) {\n newSelection.delete(index);\n } else {\n newSelection.add(index);\n }\n onSelectionChange(Array.from(newSelection));\n }\n };\n\n const handleToggleAll = () => {\n toggleAll();\n if (onSelectionChange) {\n if (isAllSelected) {\n onSelectionChange([]);\n } else {\n const startIndex = (currentPage - 1) * pageSize;\n const allIndices = displayData.map((_, idx) => startIndex + idx);\n onSelectionChange(allIndices);\n }\n }\n };\n\n // Format value based on column configuration\n const formatValue = (value: unknown, column: DataGridColumnDef<T>): string => {\n if (value == null) return '';\n\n switch (column.format) {\n case 'date': {\n const dateValue = value instanceof Date ? value : new Date(value as string | number);\n return new Intl.DateTimeFormat('en-US', column.formatOptions as Intl.DateTimeFormatOptions).format(dateValue);\n }\n\n case 'currency':\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n ...column.formatOptions\n } as Intl.NumberFormatOptions).format(Number(value));\n\n case 'number':\n return new Intl.NumberFormat('en-US', column.formatOptions as Intl.NumberFormatOptions).format(Number(value));\n\n case 'percent':\n return new Intl.NumberFormat('en-US', {\n style: 'percent',\n ...column.formatOptions\n } as Intl.NumberFormatOptions).format(Number(value));\n\n default:\n return String(value);\n }\n };\n\n const renderCellContent = (value: unknown, column: DataGridColumnDef<T>, row: T, rowIndex: number): ReactNode => {\n const isEmpty = value == null || value === '';\n\n if (isEmpty && column.fallback !== undefined) {\n return column.fallback;\n }\n\n if (column.render) {\n return column.render(value as T[keyof T], row, rowIndex);\n }\n\n if (column.badgeMap) {\n const stringValue = String(value);\n const badgeConfig = column.badgeMap[stringValue] || column.badgeMap['*'] || { variant: 'neutral' };\n\n return (\n <Badge variant={badgeConfig.variant || 'neutral'} size={column.componentSize || 'md'}>\n {badgeConfig.label || stringValue}\n </Badge>\n );\n }\n\n if (column.statusDotMap) {\n const stringValue = String(value);\n const dotConfig = column.statusDotMap[stringValue] || column.statusDotMap['*'] || { color: 'neutral' };\n\n return <StatusIndicator variant={dotConfig.color || 'neutral'}>{dotConfig.label || stringValue}</StatusIndicator>;\n }\n\n if (column.renderAsBadges) {\n if (Array.isArray(value)) {\n if (value.length === 0 && column.fallback !== undefined) {\n return column.fallback;\n }\n\n return (\n <Stack direction=\"horizontal\" spacing=\"xs\" wrap>\n {value.map((item, idx) => (\n <Badge key={idx} variant={column.badgeVariant || 'neutral'} size={column.componentSize || 'md'}>\n {String(item)}\n </Badge>\n ))}\n </Stack>\n );\n } else {\n return (\n <Badge variant={column.badgeVariant || 'neutral'} size={column.componentSize || 'md'}>\n {String(value)}\n </Badge>\n );\n }\n }\n\n if (column.format) {\n return formatValue(value, column);\n }\n\n return String(value ?? '');\n };\n\n // Render sort indicator\n const renderSortIcon = (columnKey: keyof T) => {\n if (!sortable) return null;\n\n const isSorted = sortConfig?.key === columnKey;\n\n if (!isSorted) {\n return <Icon name=\"selector\" size=\"xs\" color=\"neutral\" />;\n }\n\n if (sortConfig?.direction === 'asc') {\n return <Icon name=\"chevron-up\" size=\"xs\" color=\"primary\" />;\n }\n\n return <Icon name=\"chevron-down\" size=\"xs\" color=\"primary\" />;\n };\n\n // Render actions for a row\n const renderActions = (row: T, actualIndex: number) => {\n if (!actions) return null;\n\n let rowActions: DataGridActionItem<T>[] | ReactNode;\n\n if (Array.isArray(actions)) {\n rowActions = actions;\n } else {\n const result = actions(row, actualIndex);\n if (Array.isArray(result)) {\n rowActions = result;\n } else {\n return <div data-interactive>{result}</div>;\n }\n }\n\n return (\n <Stack direction=\"horizontal\" spacing=\"sm\" data-interactive>\n {(rowActions as DataGridActionItem<T>[]).map((action, actionIndex) => {\n if (action && typeof action === 'object' && 'onClick' in action) {\n const actionConfig = action as DataGridAction<T>;\n const button = (\n <IconButton\n key={actionIndex}\n icon={actionConfig.icon}\n iconSize={actionConfig.iconSize || 'md'}\n buttonStyle=\"ghost\"\n variant={actionConfig.variant || 'neutral'}\n iconColor={actionConfig.iconColor}\n hoverIcon={actionConfig.hoverIcon}\n ariaLabel={actionConfig.label}\n onClick={() => actionConfig.onClick(row, actualIndex)}\n noPadding\n />\n );\n\n return actionConfig.tooltip ? (\n <Tooltip key={actionIndex} content={actionConfig.tooltip}>\n {button}\n </Tooltip>\n ) : (\n button\n );\n } else {\n return (\n <div key={actionIndex} data-interactive>\n {action as ReactNode}\n </div>\n );\n }\n })}\n </Stack>\n );\n };\n\n // Row padding classes\n const rowPadding = compact ? 'py-2 px-3' : 'py-3 px-4';\n\n // Build grid template columns for desktop layout\n const buildGridTemplateColumns = () => {\n const parts: string[] = [];\n\n // Selection checkbox column - fixed width for consistency across rows\n if (selectable) {\n parts.push('24px');\n }\n\n // Data columns\n visibleColumns.forEach((col) => {\n if (col.width) {\n // Explicit width (Tailwind class won't work in grid-template-columns)\n // Try to extract pixel value or use minmax\n const widthMatch = col.width.match(/(\\d+)px/);\n if (widthMatch) {\n parts.push(`${widthMatch[1]}px`);\n } else {\n parts.push('1fr');\n }\n } else if (col.minWidth && col.maxWidth) {\n // Both min and max - constrained range\n parts.push(`minmax(${col.minWidth}px, ${col.maxWidth}px)`);\n } else if (col.minWidth) {\n // Min only - can grow but not shrink below\n parts.push(`minmax(${col.minWidth}px, 1fr)`);\n } else if (col.maxWidth) {\n // Max only - can shrink but not grow beyond\n parts.push(`minmax(auto, ${col.maxWidth}px)`);\n } else {\n parts.push('1fr');\n }\n });\n\n // Actions column - dynamically sized based on max actions across all rows\n // Allows growing to max-content to accommodate multiple action buttons\n if (actions) {\n parts.push(`minmax(${actionsMinWidth}px, max-content)`);\n }\n\n return parts.join(' ');\n };\n\n const gridTemplateColumns = !isMobile ? buildGridTemplateColumns() : undefined;\n\n // Render a single row\n const renderRow = (row: T, rowIndex: number) => {\n const actualIndex = paginated ? (currentPage - 1) * pageSize + rowIndex : rowIndex;\n const isSelected = isRowSelected(actualIndex);\n const href = rowHref?.(row, actualIndex);\n const hasHref = Boolean(href);\n const hasOnRowClick = Boolean(onRowClick);\n const isClickable = hasHref || hasOnRowClick;\n\n // Row styling - add relative for Link overlay positioning\n const rowClasses = [\n 'relative',\n 'border-b border-border/50',\n striped && rowIndex % 2 === 1 ? 'bg-muted/30' : '',\n hoverable && isClickable ? 'hover:bg-muted/50 transition-colors' : '',\n isSelected ? 'bg-primary/5' : ''\n ]\n .filter(Boolean)\n .join(' ');\n\n // Desktop layout: CSS Grid for consistent column widths\n // Mobile layout: vertical flex\n const layoutClasses = isMobile ? 'flex flex-col gap-3' : 'grid items-center gap-4';\n\n // Grid style for desktop layout\n const rowStyle = !isMobile && gridTemplateColumns ? { gridTemplateColumns } : undefined;\n\n // Props for onRowClick (when no href) - handlers are on the row div\n // Uses isInteractiveElement check to avoid triggering on links/buttons\n const rowClickProps =\n !hasHref && hasOnRowClick\n ? {\n onClick: (e: React.MouseEvent<HTMLDivElement>) => {\n // Don't trigger if clicked on an interactive element (links, buttons, etc.)\n if (isInteractiveElement(e.target as HTMLElement, e.currentTarget)) {\n return;\n }\n onRowClick?.(row, actualIndex);\n },\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onRowClick?.(row, actualIndex);\n }\n },\n role: 'button' as const,\n tabIndex: 0,\n className: 'cursor-pointer'\n }\n : {};\n\n return (\n <div\n key={actualIndex}\n className={`${layoutClasses} ${rowPadding} ${rowClasses} ${rowClickProps.className || ''}`}\n style={rowStyle}\n onClick={rowClickProps.onClick}\n onKeyDown={rowClickProps.onKeyDown}\n role={rowClickProps.role}\n tabIndex={rowClickProps.tabIndex}\n >\n {/* Row link overlay - positioned behind content */}\n {hasHref && href && (\n <Link to={href} className=\"absolute inset-0 z-1\" aria-label={`View details`} tabIndex={0} />\n )}\n\n {/* Selection checkbox - above link layer */}\n {selectable && (\n <div className={`relative z-10 ${isMobile ? '' : 'shrink-0'}`}>\n <Checkbox\n checked={isSelected}\n onChange={() => handleToggleRow(actualIndex)}\n ariaLabel={`Select row ${actualIndex + 1}`}\n />\n </div>\n )}\n\n {/* Data cells - pointer-events-none lets clicks pass through to link layer */}\n {/* Interactive elements inside (links, buttons) keep their default pointer-events */}\n {visibleColumns.map((column) => {\n const value = row[column.key];\n const content = renderCellContent(value, column, row, actualIndex);\n const showLabel = isMobile && column.showLabelOnMobile !== false;\n\n // Alignment\n const alignClass =\n column.align === 'center' ? 'text-center' : column.align === 'right' ? 'text-right' : 'text-left';\n\n // Only disable pointer events when we have a link overlay\n const pointerClass = hasHref\n ? 'pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_label]:pointer-events-auto [&_[data-interactive]]:pointer-events-auto'\n : '';\n\n return (\n <div\n key={String(column.key)}\n className={`${alignClass} ${isMobile ? 'flex flex-col gap-0.5' : 'min-w-0 overflow-hidden'} ${pointerClass}`}\n >\n {showLabel && (\n <Text size=\"xs\" variant=\"muted\" className=\"uppercase tracking-wide\">\n {column.label}\n </Text>\n )}\n <div className={column.wrapText ? '' : 'truncate'}>{content}</div>\n </div>\n );\n })}\n\n {/* Actions - above link layer */}\n {actions && (\n <div className={`relative z-10 shrink-0 ${isMobile ? 'flex justify-end pt-1' : 'justify-self-end'}`}>\n {renderActions(row, actualIndex)}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div ref={containerRef} className={`overflow-hidden ${className}`}>\n {/* Header with title, search, actions */}\n {hasHeader && (\n <div className=\"mb-3\">\n {searchable ? (\n <div className=\"flex flex-col gap-3\">\n {title && <h2 className=\"text-lg font-semibold text-foreground\">{title}</h2>}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-3 sm:justify-between\">\n <div className=\"flex-1 sm:max-w-md\">\n <InputGroup prefix={<Icon name=\"search\" size=\"sm\" />} className=\"w-full\">\n <Input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => handleSearchChange(e.target.value)}\n placeholder={searchPlaceholder}\n />\n </InputGroup>\n </div>\n\n {Array.isArray(headerActions) && headerActions.length > 0 && (\n <div className=\"flex items-center gap-2 flex-wrap sm:flex-nowrap ml-auto\">\n {headerActions.map((act, idx) => (\n <Button\n key={idx}\n onClick={act.onClick}\n variant={act.variant}\n style={act.style}\n size={act.size}\n className={act.className}\n ariaLabel={act.ariaLabel || (!act.label && act.icon ? 'Action' : undefined)}\n >\n {act.icon ? <Icon name={act.icon} size=\"sm\" /> : null}\n {act.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div className=\"flex-1\">\n {title && <h2 className=\"text-lg font-semibold text-foreground\">{title}</h2>}\n </div>\n\n {Array.isArray(headerActions) && headerActions.length > 0 && (\n <div className=\"flex items-center gap-2 flex-wrap sm:flex-nowrap\">\n {headerActions.map((act, idx) => (\n <Button\n key={idx}\n onClick={act.onClick}\n variant={act.variant}\n style={act.style}\n size={act.size}\n className={act.className}\n ariaLabel={act.ariaLabel || (!act.label && act.icon ? 'Action' : undefined)}\n >\n {act.icon ? <Icon name={act.icon} size=\"sm\" /> : null}\n {act.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Empty states */}\n {data.length === 0 ? (\n <div className=\"border border-border rounded-lg\">\n <EmptyState\n title={emptyState.title}\n description={emptyState.description}\n buttonText={emptyState.buttonText}\n onButtonClick={emptyState.onButtonClick}\n />\n </div>\n ) : filteredData.length === 0 && searchQuery.trim() ? (\n <div className=\"border border-border rounded-lg\">\n <EmptyState\n title=\"No results found\"\n description={`No items match \"${searchQuery}\". Try adjusting your search.`}\n />\n </div>\n ) : (\n <>\n {/* Column headers (desktop only) */}\n {!isMobile && (\n <div\n className={`grid items-center gap-4 ${rowPadding} border-b border-border bg-muted/30`}\n style={gridTemplateColumns ? { gridTemplateColumns } : undefined}\n >\n {selectable && (\n <div>\n <Checkbox checked={isAllSelected} onChange={handleToggleAll} ariaLabel=\"Select all rows\" />\n </div>\n )}\n\n {visibleColumns.map((column) => {\n const alignClass =\n column.align === 'center' ? 'text-center' : column.align === 'right' ? 'text-right' : 'text-left';\n\n return (\n <div key={String(column.key)} className={`min-w-0 ${alignClass}`}>\n {column.sortable !== false && sortable ? (\n <button\n onClick={() => handleSort(column.key)}\n className=\"flex items-center gap-1 hover:text-foreground transition-colors font-medium text-sm text-muted-foreground\"\n type=\"button\"\n >\n {column.label}\n {renderSortIcon(column.key)}\n </button>\n ) : (\n <Text size=\"sm\" variant=\"muted\" weight=\"medium\">\n {column.label}\n </Text>\n )}\n </div>\n );\n })}\n\n {actions && (\n <div className=\"justify-self-end\">\n <Text size=\"sm\" variant=\"muted\" weight=\"medium\">\n {actionsLabel}\n </Text>\n </div>\n )}\n </div>\n )}\n\n {/* Select all checkbox (mobile) */}\n {isMobile && selectable && (\n <div className={`flex items-center gap-2 ${rowPadding} border-b border-border`}>\n <Checkbox checked={isAllSelected} onChange={handleToggleAll} ariaLabel=\"Select all rows\" />\n <Text size=\"sm\" variant=\"muted\">\n Select all\n </Text>\n </div>\n )}\n\n {/* Rows */}\n <div className=\"divide-y divide-border/50\">{displayData.map((row, idx) => renderRow(row, idx))}</div>\n\n {/* Pagination controls */}\n {paginated && totalPages > 1 && (\n <div className=\"flex items-center justify-between px-4 py-3 border-t border-border\">\n <div className=\"text-sm text-muted-foreground\">\n Page {currentPage} of {totalPages} ({filteredData.length} {searchQuery.trim() ? 'filtered' : 'total'}{' '}\n rows\n {searchQuery.trim() && data.length !== filteredData.length ? ` of ${data.length}` : ''})\n </div>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" style=\"outline\" onClick={prevPage} disabled={!canPrevPage}>\n Previous\n </Button>\n <Button size=\"sm\" style=\"outline\" onClick={nextPage} disabled={!canNextPage}>\n Next\n </Button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nDataGrid.displayName = 'DataGrid';\n\nexport default DataGrid;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid.js","sources":["../../../../src/components/data-display/data-grid/data-grid.tsx"],"sourcesContent":["import { ReactNode, useState, useEffect, useRef } from 'react';\nimport { Icon } from '../../system/icon/icon';\nimport IconButton from '../../forms/button/icon-button';\nimport Input from '../../forms/input/input';\nimport InputGroup from '../../forms/input-group/input-group';\n\nimport Checkbox from '../../forms/checkbox/checkbox';\nimport Button from '../../forms/button/button';\nimport Tooltip from '../../feedback/tooltip/tooltip';\nimport type { ButtonProps } from '../../forms/button/button';\nimport Stack from '../../layout/stack/stack';\nimport Badge from '../badge/badge';\nimport Text from '../../typography/text/text';\nimport { useTable, UseTableOptions } from '../data-table/use-table';\nimport { Size } from '@/theme/size-tokens';\nimport { ColorVariant } from '@/theme/tokens';\nimport EmptyState from '../empty-state/empty-state';\nimport StatusIndicator from '../status-indicator/status-indicator';\nimport { Link } from 'react-router-dom';\n\n/** Interactive element tags that should not trigger onRowClick callback */\nconst INTERACTIVE_TAGS = new Set(['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL']);\n\n/** Check if an element or any of its ancestors (up to container) is interactive - used for onRowClick only */\nfunction isInteractiveElement(element: HTMLElement | null, container: HTMLElement | null): boolean {\n let current = element;\n while (current && current !== container) {\n if (INTERACTIVE_TAGS.has(current.tagName)) return true;\n if (current.getAttribute('role') === 'button') return true;\n current = current.parentElement;\n }\n return false;\n}\n\nexport type DataGridAction<T> = {\n /** Icon name for the action button */\n icon: string;\n /** Size of the icon */\n iconSize?: Size;\n /** Color variant for the icon */\n iconColor?: ColorVariant;\n /** Icon to display on hover (optional) */\n hoverIcon?: string;\n /** Accessible label for the action (shown in tooltip or screen readers) */\n label: string;\n /** Tooltip text to display on hover. If not provided, label will be used for aria-label only. */\n tooltip?: string;\n /** Callback when the action is clicked */\n onClick: (row: T, index: number) => void;\n /** Visual variant for the action button */\n variant?: 'primary' | 'accent' | 'neutral' | 'success' | 'warning' | 'error' | 'info';\n};\n\nexport type DataGridActionItem<T> = DataGridAction<T> | ReactNode;\n\nexport type DataGridColumnDef<T> = {\n /** Key of the data property to display in this column */\n key: keyof T;\n /** Column header label */\n label: string;\n /** Whether this column can be sorted */\n sortable?: boolean;\n /** CSS width class or value for the column (e.g., 'w-48', '200px', 'flex-1') */\n width?: string;\n /**\n * Minimum width in pixels for the column. When set:\n * - Column truncates but never shrinks below this width\n * - Column auto-hides if container can't fit it at this width\n * - No need to also set hidePriority (though you can for explicit hide ordering)\n *\n * @example minWidth: 120 // Hide if email would be squished below 120px\n */\n minWidth?: number;\n /**\n * Maximum width in pixels for the column. Prevents column from growing too wide.\n * Use for columns like status/role that don't need much space.\n *\n * @example maxWidth: 100 // Cap role column at 100px\n */\n maxWidth?: number;\n /** Text alignment for cells in this column */\n align?: 'left' | 'center' | 'right';\n /** Whether text should wrap instead of truncating (useful for long strings) */\n wrapText?: boolean;\n /** Optional priority for responsive hiding. Lower values hide first when container width shrinks. Columns without hidePriority or minWidth are never hidden. */\n hidePriority?: number;\n /** Whether to show this column's label in mobile/vertical layout (default: true) */\n showLabelOnMobile?: boolean;\n /** Custom render function for cell content (use as escape hatch when config options don't cover your use case) */\n render?: (value: T[keyof T], row: T, index: number) => ReactNode;\n\n // Config-driven rendering options (preferred over custom render)\n /** Pre-built formatter for common data types */\n format?: 'date' | 'currency' | 'number' | 'percent';\n /** Options for Intl formatters (NumberFormat or DateTimeFormat) */\n formatOptions?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;\n /** Map values to badge variants. Unmatched values render with 'neutral' variant. Use '*' key to override the default fallback. */\n badgeMap?: {\n [key: string]: { variant?: ColorVariant; label?: string };\n };\n /** Map values to status dot colors. Renders text with a colored dot to the left. Lighter alternative to badges for status indicators. */\n statusDotMap?: {\n [key: string]: { color?: ColorVariant; label?: string };\n };\n /**\n * Render cell values as badges. When the value is an array, each item is rendered\n * as an individual badge; for scalar values, the value is wrapped in a single badge.\n */\n renderAsBadges?: boolean;\n /** Variant for badge rendering */\n badgeVariant?: ColorVariant;\n /** Size for badge rendering */\n componentSize?: 'sm' | 'md' | 'lg';\n /** Fallback value to display when cell value is null, undefined, or empty string */\n fallback?: string;\n};\n\nexport type DataGridProps<T> = {\n /** Array of data objects to display in the grid */\n data: T[];\n /** Column definitions specifying how to render each column */\n columns: DataGridColumnDef<T>[];\n /** Additional CSS classes to apply */\n className?: string;\n\n // Styling options\n /** Whether to apply striped row styling (alternating background) */\n striped?: boolean;\n /** Whether rows have hover effects */\n hoverable?: boolean;\n /** Whether to use compact spacing for dense data */\n compact?: boolean;\n\n // Features\n /** Whether columns can be sorted (can be overridden per column) */\n sortable?: boolean;\n /** Whether to enable client-side pagination */\n paginated?: boolean;\n /** Number of rows per page when pagination is enabled */\n pageSize?: number;\n /** Whether to show checkboxes for row selection */\n selectable?: boolean;\n /** Whether to enable search/filter functionality */\n searchable?: boolean;\n /** Specific keys to search within. If not provided, searches all fields. */\n searchKeys?: (keyof T)[];\n /** Placeholder text for the search input */\n searchPlaceholder?: string;\n /** Callback when search query changes */\n onSearchChange?: (query: string) => void;\n\n // Actions - either array of action configs/components OR function returning actions/render\n /** Action buttons, function returning actions based on row data, or custom render function for the actions column */\n actions?: DataGridActionItem<T>[] | ((row: T, index: number) => DataGridActionItem<T>[] | ReactNode);\n /** Label for the actions column header */\n actionsLabel?: string;\n\n // Row link - makes entire row clickable for navigation\n /** Function returning href for row navigation. When provided, entire row becomes a link. */\n rowHref?: (row: T, index: number) => string | undefined;\n\n // Callbacks\n /** Callback when a row is clicked (if rowHref not provided) */\n onRowClick?: (row: T, index: number) => void;\n /** Callback when row selection changes (provides array of selected row indices) */\n onSelectionChange?: (selectedIndices: number[]) => void;\n\n // Empty state\n emptyState?: {\n /** Message to display when there is no data */\n title?: string;\n /** Description to display when there is no data */\n description?: string;\n /** Text for the button in the empty state */\n buttonText?: string;\n /** Click handler for the button in the empty state */\n onButtonClick?: () => void;\n };\n\n // Initial state\n /** Initial sort configuration */\n initialSort?: { key: keyof T; direction: 'asc' | 'desc' };\n /** Title displayed above the grid (left side of header) */\n title?: string;\n /** Header actions displayed above the grid (right side of header). */\n headerActions?: HeaderAction[];\n\n // Responsive / list mode\n /**\n * Container width (px) below which the grid collapses into list mode.\n * Defaults to 480. Column hiding (via `hidePriority` / `minWidth`) still\n * runs for widths above this breakpoint.\n */\n listBreakpoint?: number;\n /**\n * Custom render function for list mode. When provided, each row is rendered\n * using this function instead of the default vertical-stack fallback.\n * Use this to create type-specific list layouts with the right fields,\n * actions, and visual hierarchy for the entity being displayed.\n *\n * @example\n * ```tsx\n * renderListItem={(row, index, { actions, isSelected, onToggleSelect }) => (\n * <div className=\"flex items-center gap-3\">\n * <Avatar name={row.name} />\n * <div className=\"flex-1 min-w-0\">\n * <Text weight=\"medium\" className=\"truncate\">{row.name}</Text>\n * <Text size=\"sm\" variant=\"muted\" className=\"truncate\">{row.email}</Text>\n * </div>\n * {actions}\n * </div>\n * )}\n * ```\n */\n renderListItem?: (row: T, index: number, context: DataGridListItemContext) => ReactNode;\n};\n\nexport type HeaderAction = {\n /** Button text; if omitted and `icon` provided, button will be icon-only */\n label?: string;\n /** Icon name to render inside the button (maps to library `Icon`) */\n icon?: string;\n /** Accessible label for screen readers. Required for icon-only buttons (when label is omitted). */\n ariaLabel?: string;\n /** Click handler invoked when the button is clicked */\n onClick?: () => void;\n /** Button variant (maps to Button `variant` prop) */\n variant?: ButtonProps['variant'];\n /** Button style (maps to Button `style` prop) */\n style?: ButtonProps['style'];\n /** Button size (maps to Button `size` prop) */\n size?: ButtonProps['size'];\n /** Additional className forwarded to the Button */\n className?: string;\n};\n\n/** Breakpoint width (in px) below which we switch to list mode */\nconst DEFAULT_LIST_BREAKPOINT = 480;\n\n/**\n * Context passed to `renderListItem` so list-mode renders can embed grid actions\n * and selection state without needing to manage them independently.\n */\nexport type DataGridListItemContext = {\n /** Pre-rendered action buttons derived from the `actions` prop */\n actions: ReactNode;\n /** Whether this row is currently selected */\n isSelected: boolean;\n /** Toggle selection for this row. Defined only when `selectable` is true. */\n onToggleSelect?: () => void;\n};\n\n/**\n * DataGrid - Responsive data display component with Vercel-style layout\n *\n * Features:\n * - Generic typed data and columns (same API as DataTable)\n * - Responsive layout: horizontal rows on desktop, vertical card-like on mobile\n * - Clickable rows via rowHref with interactive elements taking priority\n * - Client-side sorting, pagination, selection, and search\n * - Custom cell rendering with DataGridCell for multi-element stacking\n *\n * @example\n * ```tsx\n * <DataGrid\n * data={deployments}\n * columns={[\n * {\n * key: 'name',\n * label: 'Deployment',\n * render: (value, row) => (\n * <DataGridCell>\n * <Text weight=\"medium\">{row.name}</Text>\n * <Text size=\"sm\" variant=\"muted\">{row.url}</Text>\n * </DataGridCell>\n * )\n * },\n * { key: 'status', label: 'Status', badgeMap: { ready: { variant: 'success' } } },\n * { key: 'createdAt', label: 'Created', format: 'date' }\n * ]}\n * rowHref={(row) => `/deployments/${row.id}`}\n * hoverable\n * />\n * ```\n */\nfunction DataGrid<T>({\n data,\n columns,\n className = '',\n striped = false,\n hoverable = true,\n compact = false,\n sortable = true,\n paginated = false,\n pageSize = 10,\n selectable = false,\n searchable = false,\n searchKeys,\n searchPlaceholder = 'Search...',\n onSearchChange,\n actions,\n actionsLabel = 'Actions',\n rowHref,\n onRowClick,\n onSelectionChange,\n emptyState = {\n title: 'No data available',\n description: undefined,\n buttonText: undefined,\n onButtonClick: undefined\n },\n headerActions,\n title,\n initialSort,\n listBreakpoint = DEFAULT_LIST_BREAKPOINT,\n renderListItem\n}: DataGridProps<T>) {\n // Search state\n const [searchQuery, setSearchQuery] = useState('');\n\n // Layout state – true when container width is below listBreakpoint\n const [isListMode, setIsListMode] = useState(false);\n\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n if (onSearchChange) {\n onSearchChange(value);\n }\n };\n\n // Container ref for responsive behavior\n const containerRef = useRef<HTMLDivElement>(null);\n const [visibleColumns, setVisibleColumns] = useState<DataGridColumnDef<T>[]>(() => columns);\n\n // Calculate minimum width needed for actions column based on max actions in any row\n const calculateActionsMinWidth = (): number => {\n if (!actions) return 0;\n\n let maxActionCount = 0;\n\n if (Array.isArray(actions)) {\n // Static actions - all rows have the same actions\n maxActionCount = actions.length;\n } else {\n // Dynamic actions - need to check all rows\n data.forEach((row, index) => {\n const result = actions(row, index);\n if (Array.isArray(result)) {\n maxActionCount = Math.max(maxActionCount, result.length);\n } else {\n // Custom render - assume it needs reasonable space (equivalent to 2 actions)\n maxActionCount = Math.max(maxActionCount, 2);\n }\n });\n }\n\n if (maxActionCount === 0) {\n // No actions, but we still need some minimum space in case actions appear\n return 60;\n }\n\n // Each action button takes ~36px (icon + button padding)\n // Stack spacing between actions is 8px (spacing=\"sm\")\n // Formula: (actionWidth * count) + (gap * (count - 1)) + extraPadding\n const actionWidth = 24;\n const gapWidth = 8;\n const extraPadding = 16; // breathing room\n\n return actionWidth * maxActionCount + gapWidth * Math.max(0, maxActionCount - 1) + extraPadding;\n };\n\n const actionsMinWidth = calculateActionsMinWidth();\n\n // ResizeObserver to handle responsive column hiding and mobile layout\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n // Check if any columns have hidePriority or minWidth set (both make columns hideable)\n const hasHideableColumns = columns.some((col) => col.hidePriority !== undefined || col.minWidth !== undefined);\n\n const updateLayout = () => {\n const containerWidth = container.offsetWidth;\n\n // Check if we should switch to list mode\n const nowListMode = containerWidth < listBreakpoint;\n setIsListMode(nowListMode);\n\n // In list mode, show all columns (either renderListItem handles layout\n // or the fallback vertical stack renders them all with labels).\n // Only apply responsive column hiding in grid mode.\n if (nowListMode || !hasHideableColumns) {\n setVisibleColumns(columns);\n return;\n }\n\n // Columns are hideable if they have hidePriority OR minWidth\n const isHideable = (col: DataGridColumnDef<T>) => col.hidePriority !== undefined || col.minWidth !== undefined;\n\n // Separate columns into hideable and non-hideable\n const hideableColumns = columns\n .map((col, index) => ({ col, originalIndex: index }))\n .filter(({ col }) => isHideable(col))\n .sort((a, b) => {\n // Sort by hidePriority if both have it (lower hides first)\n const aPriority = a.col.hidePriority;\n const bPriority = b.col.hidePriority;\n\n if (aPriority !== undefined && bPriority !== undefined) {\n if (aPriority !== bPriority) return aPriority - bPriority;\n }\n // Columns with explicit hidePriority hide before minWidth-only columns\n if (aPriority !== undefined && bPriority === undefined) return -1;\n if (aPriority === undefined && bPriority !== undefined) return 1;\n\n // For minWidth-only columns, larger minWidth hides first (needs more space)\n const aMin = a.col.minWidth ?? 0;\n const bMin = b.col.minWidth ?? 0;\n if (aMin !== bMin) return bMin - aMin;\n\n // Finally, later columns hide first (preserve leading columns)\n return b.originalIndex - a.originalIndex;\n });\n\n const nonHideableColumns = columns.filter((col) => !isHideable(col));\n\n // Estimate column width - use minWidth if set, otherwise parse width or default\n const estimateColumnWidth = (col: DataGridColumnDef<T>): number => {\n // Use minWidth if explicitly set (this is the minimum space the column needs)\n if (col.minWidth) return col.minWidth;\n\n if (col.width) {\n const match = col.width.match(/(\\d+)/);\n if (match) {\n const num = parseInt(match[1], 10);\n if (col.width.includes('px')) return num;\n return num * 4;\n }\n }\n return 150;\n };\n\n // Calculate horizontal padding (px-3 = 24px total, px-4 = 32px total)\n const horizontalPadding = compact ? 24 : 32;\n // Grid gap is 16px (gap-4) between each column\n const gridGap = 16;\n\n // Start with non-hideable columns\n let currentWidth = nonHideableColumns.reduce((sum, col) => sum + estimateColumnWidth(col), 0);\n let totalColumns = nonHideableColumns.length;\n\n // Account for selection and actions columns\n if (selectable) {\n currentWidth += 48;\n totalColumns += 1;\n }\n if (actions) {\n currentWidth += actionsMinWidth;\n totalColumns += 1;\n }\n\n // Add hideable columns until we run out of space\n const columnsToShow: DataGridColumnDef<T>[] = [...nonHideableColumns];\n\n for (const { col } of hideableColumns) {\n const colWidth = estimateColumnWidth(col);\n const newTotalColumns = totalColumns + 1;\n // Calculate total gaps needed with the new column (N columns = N-1 gaps)\n const totalGaps = Math.max(0, newTotalColumns - 1) * gridGap;\n const totalWidthNeeded = currentWidth + colWidth + totalGaps + horizontalPadding;\n\n if (totalWidthNeeded <= containerWidth) {\n columnsToShow.push(col);\n currentWidth += colWidth;\n totalColumns = newTotalColumns;\n }\n }\n\n // Restore original column order\n const orderedVisibleColumns = columns.filter((col) => columnsToShow.includes(col));\n setVisibleColumns(orderedVisibleColumns);\n };\n\n // Call once on mount\n updateLayout();\n\n // Set up observer\n const observer = new ResizeObserver(() => {\n updateLayout();\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [columns, selectable, actions, actionsMinWidth, compact, data, listBreakpoint]);\n\n // Use table hook for state management\n const effectiveSearchKeys = searchKeys || visibleColumns.map((col) => col.key);\n\n const tableOptions: UseTableOptions<T> = {\n data,\n initialSort,\n pageSize,\n searchQuery,\n searchKeys: effectiveSearchKeys\n };\n\n const {\n currentData,\n sortedData,\n filteredData,\n sortConfig,\n handleSort,\n currentPage,\n totalPages,\n nextPage,\n prevPage,\n canNextPage,\n canPrevPage,\n selectedRows,\n toggleRow,\n toggleAll,\n isRowSelected,\n isAllSelected\n } = useTable(tableOptions);\n\n // Display data (paginated uses currentData, non-paginated uses sortedData)\n const displayData = paginated ? currentData : sortedData;\n\n // Header title and actions\n const hasHeader = Boolean(\n (title && String(title).length > 0) ||\n (Array.isArray(headerActions) ? headerActions.length > 0 : headerActions) ||\n searchable\n );\n\n // Selection handlers\n const handleToggleRow = (index: number) => {\n toggleRow(index);\n if (onSelectionChange) {\n const newSelection = new Set(selectedRows);\n if (newSelection.has(index)) {\n newSelection.delete(index);\n } else {\n newSelection.add(index);\n }\n onSelectionChange(Array.from(newSelection));\n }\n };\n\n const handleToggleAll = () => {\n toggleAll();\n if (onSelectionChange) {\n if (isAllSelected) {\n onSelectionChange([]);\n } else {\n const startIndex = (currentPage - 1) * pageSize;\n const allIndices = displayData.map((_, idx) => startIndex + idx);\n onSelectionChange(allIndices);\n }\n }\n };\n\n // Format value based on column configuration\n const formatValue = (value: unknown, column: DataGridColumnDef<T>): string => {\n if (value == null) return '';\n\n switch (column.format) {\n case 'date': {\n const dateValue = value instanceof Date ? value : new Date(value as string | number);\n return new Intl.DateTimeFormat('en-US', column.formatOptions as Intl.DateTimeFormatOptions).format(dateValue);\n }\n\n case 'currency':\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n ...column.formatOptions\n } as Intl.NumberFormatOptions).format(Number(value));\n\n case 'number':\n return new Intl.NumberFormat('en-US', column.formatOptions as Intl.NumberFormatOptions).format(Number(value));\n\n case 'percent':\n return new Intl.NumberFormat('en-US', {\n style: 'percent',\n ...column.formatOptions\n } as Intl.NumberFormatOptions).format(Number(value));\n\n default:\n return String(value);\n }\n };\n\n const renderCellContent = (value: unknown, column: DataGridColumnDef<T>, row: T, rowIndex: number): ReactNode => {\n const isEmpty = value == null || value === '';\n\n if (isEmpty && column.fallback !== undefined) {\n return column.fallback;\n }\n\n if (column.render) {\n return column.render(value as T[keyof T], row, rowIndex);\n }\n\n if (column.badgeMap) {\n const stringValue = String(value);\n const badgeConfig = column.badgeMap[stringValue] || column.badgeMap['*'] || { variant: 'neutral' };\n\n return (\n <Badge variant={badgeConfig.variant || 'neutral'} size={column.componentSize || 'md'}>\n {badgeConfig.label || stringValue}\n </Badge>\n );\n }\n\n if (column.statusDotMap) {\n const stringValue = String(value);\n const dotConfig = column.statusDotMap[stringValue] || column.statusDotMap['*'] || { color: 'neutral' };\n\n return <StatusIndicator variant={dotConfig.color || 'neutral'}>{dotConfig.label || stringValue}</StatusIndicator>;\n }\n\n if (column.renderAsBadges) {\n if (Array.isArray(value)) {\n if (value.length === 0 && column.fallback !== undefined) {\n return column.fallback;\n }\n\n return (\n <Stack direction=\"horizontal\" spacing=\"xs\" wrap>\n {value.map((item, idx) => (\n <Badge key={idx} variant={column.badgeVariant || 'neutral'} size={column.componentSize || 'md'}>\n {String(item)}\n </Badge>\n ))}\n </Stack>\n );\n } else {\n return (\n <Badge variant={column.badgeVariant || 'neutral'} size={column.componentSize || 'md'}>\n {String(value)}\n </Badge>\n );\n }\n }\n\n if (column.format) {\n return formatValue(value, column);\n }\n\n return String(value ?? '');\n };\n\n // Render sort indicator\n const renderSortIcon = (columnKey: keyof T) => {\n if (!sortable) return null;\n\n const isSorted = sortConfig?.key === columnKey;\n\n if (!isSorted) {\n return <Icon name=\"selector\" size=\"xs\" color=\"neutral\" />;\n }\n\n if (sortConfig?.direction === 'asc') {\n return <Icon name=\"chevron-up\" size=\"xs\" color=\"primary\" />;\n }\n\n return <Icon name=\"chevron-down\" size=\"xs\" color=\"primary\" />;\n };\n\n // Render actions for a row\n const renderActions = (row: T, actualIndex: number) => {\n if (!actions) return null;\n\n let rowActions: DataGridActionItem<T>[] | ReactNode;\n\n if (Array.isArray(actions)) {\n rowActions = actions;\n } else {\n const result = actions(row, actualIndex);\n if (Array.isArray(result)) {\n rowActions = result;\n } else {\n return <div data-interactive>{result}</div>;\n }\n }\n\n return (\n <Stack direction=\"horizontal\" spacing=\"sm\" data-interactive>\n {(rowActions as DataGridActionItem<T>[]).map((action, actionIndex) => {\n if (action && typeof action === 'object' && 'onClick' in action) {\n const actionConfig = action as DataGridAction<T>;\n const button = (\n <IconButton\n key={actionIndex}\n icon={actionConfig.icon}\n iconSize={actionConfig.iconSize || 'md'}\n buttonStyle=\"ghost\"\n variant={actionConfig.variant || 'neutral'}\n iconColor={actionConfig.iconColor}\n hoverIcon={actionConfig.hoverIcon}\n ariaLabel={actionConfig.label}\n onClick={() => actionConfig.onClick(row, actualIndex)}\n noPadding\n />\n );\n\n return actionConfig.tooltip ? (\n <Tooltip key={actionIndex} content={actionConfig.tooltip}>\n {button}\n </Tooltip>\n ) : (\n button\n );\n } else {\n return (\n <div key={actionIndex} data-interactive>\n {action as ReactNode}\n </div>\n );\n }\n })}\n </Stack>\n );\n };\n\n // Row padding classes\n const rowPadding = compact ? 'py-2 px-3' : 'py-3 px-4';\n\n // Build grid template columns for desktop layout\n const buildGridTemplateColumns = () => {\n const parts: string[] = [];\n\n // Selection checkbox column - fixed width for consistency across rows\n if (selectable) {\n parts.push('24px');\n }\n\n // Data columns\n visibleColumns.forEach((col) => {\n if (col.width) {\n // Explicit width (Tailwind class won't work in grid-template-columns)\n // Try to extract pixel value or use minmax\n const widthMatch = col.width.match(/(\\d+)px/);\n if (widthMatch) {\n parts.push(`${widthMatch[1]}px`);\n } else {\n parts.push('1fr');\n }\n } else if (col.minWidth && col.maxWidth) {\n // Both min and max - constrained range\n parts.push(`minmax(${col.minWidth}px, ${col.maxWidth}px)`);\n } else if (col.minWidth) {\n // Min only - can grow but not shrink below\n parts.push(`minmax(${col.minWidth}px, 1fr)`);\n } else if (col.maxWidth) {\n // Max only - can shrink but not grow beyond\n parts.push(`minmax(auto, ${col.maxWidth}px)`);\n } else {\n parts.push('1fr');\n }\n });\n\n // Actions column - dynamically sized based on max actions across all rows\n // Allows growing to max-content to accommodate multiple action buttons\n if (actions) {\n parts.push(`minmax(${actionsMinWidth}px, max-content)`);\n }\n\n return parts.join(' ');\n };\n\n const gridTemplateColumns = !isListMode ? buildGridTemplateColumns() : undefined;\n\n // Render a single row\n const renderRow = (row: T, rowIndex: number) => {\n const actualIndex = paginated ? (currentPage - 1) * pageSize + rowIndex : rowIndex;\n const isSelected = isRowSelected(actualIndex);\n const href = rowHref?.(row, actualIndex);\n const hasHref = Boolean(href);\n const hasOnRowClick = Boolean(onRowClick);\n const isClickable = hasHref || hasOnRowClick;\n\n // Row styling - add relative for Link overlay positioning\n const rowClasses = [\n 'relative',\n 'border-b border-border/50',\n striped && rowIndex % 2 === 1 ? 'bg-muted/30' : '',\n hoverable && isClickable ? 'hover:bg-muted/50 transition-colors' : '',\n isSelected ? 'bg-primary/5' : ''\n ]\n .filter(Boolean)\n .join(' ');\n\n // Grid mode: CSS Grid for consistent column widths\n // List mode: vertical flex (fallback) or custom renderListItem\n const layoutClasses = isListMode ? 'flex flex-col gap-3' : 'grid items-center gap-4';\n\n // Grid style for grid mode only\n const rowStyle = !isListMode && gridTemplateColumns ? { gridTemplateColumns } : undefined;\n\n // ----------------------------------------------------------------\n // List mode with custom render – delegate layout to renderListItem\n // ----------------------------------------------------------------\n if (isListMode && renderListItem) {\n const actionsContent = renderActions(row, actualIndex);\n const listItemContent = renderListItem(row, actualIndex, {\n actions: actionsContent,\n isSelected,\n onToggleSelect: selectable ? () => handleToggleRow(actualIndex) : undefined\n });\n\n // Pointer-events wrapper mirrors the grid row behaviour\n const pointerClass = hasHref\n ? 'pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_label]:pointer-events-auto [&_[data-interactive]]:pointer-events-auto'\n : '';\n\n const listRowClickProps =\n !hasHref && hasOnRowClick\n ? {\n onClick: (e: React.MouseEvent<HTMLDivElement>) => {\n if (isInteractiveElement(e.target as HTMLElement, e.currentTarget)) return;\n onRowClick?.(row, actualIndex);\n },\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onRowClick?.(row, actualIndex);\n }\n },\n role: 'button' as const,\n tabIndex: 0,\n className: 'cursor-pointer'\n }\n : {};\n\n return (\n <div\n key={actualIndex}\n className={`relative ${rowPadding} ${rowClasses} ${listRowClickProps.className || ''}`}\n onClick={listRowClickProps.onClick}\n onKeyDown={listRowClickProps.onKeyDown}\n role={listRowClickProps.role}\n tabIndex={listRowClickProps.tabIndex}\n >\n {hasHref && href && (\n <Link to={href} className=\"absolute inset-0 z-1\" aria-label=\"View details\" tabIndex={0} />\n )}\n <div className={pointerClass}>{listItemContent}</div>\n </div>\n );\n }\n\n // ----------------------------------------------------------------\n // Props for onRowClick (when no href) - handlers are on the row div\n // Uses isInteractiveElement check to avoid triggering on links/buttons\n const rowClickProps =\n !hasHref && hasOnRowClick\n ? {\n onClick: (e: React.MouseEvent<HTMLDivElement>) => {\n // Don't trigger if clicked on an interactive element (links, buttons, etc.)\n if (isInteractiveElement(e.target as HTMLElement, e.currentTarget)) {\n return;\n }\n onRowClick?.(row, actualIndex);\n },\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onRowClick?.(row, actualIndex);\n }\n },\n role: 'button' as const,\n tabIndex: 0,\n className: 'cursor-pointer'\n }\n : {};\n\n return (\n <div\n key={actualIndex}\n className={`${layoutClasses} ${rowPadding} ${rowClasses} ${rowClickProps.className || ''}`}\n style={rowStyle}\n onClick={rowClickProps.onClick}\n onKeyDown={rowClickProps.onKeyDown}\n role={rowClickProps.role}\n tabIndex={rowClickProps.tabIndex}\n >\n {/* Row link overlay - positioned behind content */}\n {hasHref && href && (\n <Link to={href} className=\"absolute inset-0 z-1\" aria-label={`View details`} tabIndex={0} />\n )}\n\n {/* Selection checkbox - above link layer */}\n {selectable && (\n <div className={`relative z-10 ${isListMode ? '' : 'shrink-0'}`}>\n <Checkbox\n checked={isSelected}\n onChange={() => handleToggleRow(actualIndex)}\n ariaLabel={`Select row ${actualIndex + 1}`}\n />\n </div>\n )}\n\n {/* Data cells - pointer-events-none lets clicks pass through to link layer */}\n {/* Interactive elements inside (links, buttons) keep their default pointer-events */}\n {visibleColumns.map((column) => {\n const value = row[column.key];\n const content = renderCellContent(value, column, row, actualIndex);\n const showLabel = isListMode && column.showLabelOnMobile !== false;\n\n // Alignment\n const alignClass =\n column.align === 'center' ? 'text-center' : column.align === 'right' ? 'text-right' : 'text-left';\n\n // Only disable pointer events when we have a link overlay\n const pointerClass = hasHref\n ? 'pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_label]:pointer-events-auto [&_[data-interactive]]:pointer-events-auto'\n : '';\n\n return (\n <div\n key={String(column.key)}\n className={`${alignClass} ${isListMode ? 'flex flex-col gap-0.5' : 'min-w-0 overflow-hidden'} ${pointerClass}`}\n >\n {showLabel && (\n <Text size=\"xs\" variant=\"muted\" className=\"uppercase tracking-wide\">\n {column.label}\n </Text>\n )}\n <div className={column.wrapText ? '' : 'truncate'}>{content}</div>\n </div>\n );\n })}\n\n {/* Actions - above link layer */}\n {actions && (\n <div className={`relative z-10 shrink-0 ${isListMode ? 'flex justify-end pt-1' : 'justify-self-end'}`}>\n {renderActions(row, actualIndex)}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div ref={containerRef} className={`overflow-hidden ${className}`}>\n {/* Header with title, search, actions */}\n {hasHeader && (\n <div className=\"mb-3\">\n {searchable ? (\n <div className=\"flex flex-col gap-3\">\n {title && <h2 className=\"text-lg font-semibold text-foreground\">{title}</h2>}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-3 sm:justify-between\">\n <div className=\"flex-1 sm:max-w-md\">\n <InputGroup prefix={<Icon name=\"search\" size=\"sm\" />} className=\"w-full\">\n <Input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => handleSearchChange(e.target.value)}\n placeholder={searchPlaceholder}\n />\n </InputGroup>\n </div>\n\n {Array.isArray(headerActions) && headerActions.length > 0 && (\n <div className=\"flex items-center gap-2 flex-wrap sm:flex-nowrap ml-auto\">\n {headerActions.map((act, idx) => (\n <Button\n key={idx}\n onClick={act.onClick}\n variant={act.variant}\n style={act.style}\n size={act.size}\n className={act.className}\n ariaLabel={act.ariaLabel || (!act.label && act.icon ? 'Action' : undefined)}\n >\n {act.icon ? <Icon name={act.icon} size=\"sm\" /> : null}\n {act.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div className=\"flex-1\">\n {title && <h2 className=\"text-lg font-semibold text-foreground\">{title}</h2>}\n </div>\n\n {Array.isArray(headerActions) && headerActions.length > 0 && (\n <div className=\"flex items-center gap-2 flex-wrap sm:flex-nowrap\">\n {headerActions.map((act, idx) => (\n <Button\n key={idx}\n onClick={act.onClick}\n variant={act.variant}\n style={act.style}\n size={act.size}\n className={act.className}\n ariaLabel={act.ariaLabel || (!act.label && act.icon ? 'Action' : undefined)}\n >\n {act.icon ? <Icon name={act.icon} size=\"sm\" /> : null}\n {act.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Empty states */}\n {data.length === 0 ? (\n <div className=\"border border-border rounded-lg\">\n <EmptyState\n title={emptyState.title}\n description={emptyState.description}\n buttonText={emptyState.buttonText}\n onButtonClick={emptyState.onButtonClick}\n />\n </div>\n ) : filteredData.length === 0 && searchQuery.trim() ? (\n <div className=\"border border-border rounded-lg\">\n <EmptyState\n title=\"No results found\"\n description={`No items match \"${searchQuery}\". Try adjusting your search.`}\n />\n </div>\n ) : (\n <>\n {/* Column headers – grid mode only (hidden in list mode) */}\n {!isListMode && (\n <div\n className={`grid items-center gap-4 ${rowPadding} border-b border-border bg-muted/30`}\n style={gridTemplateColumns ? { gridTemplateColumns } : undefined}\n >\n {selectable && (\n <div>\n <Checkbox checked={isAllSelected} onChange={handleToggleAll} ariaLabel=\"Select all rows\" />\n </div>\n )}\n\n {visibleColumns.map((column) => {\n const alignClass =\n column.align === 'center' ? 'text-center' : column.align === 'right' ? 'text-right' : 'text-left';\n\n return (\n <div key={String(column.key)} className={`min-w-0 ${alignClass}`}>\n {column.sortable !== false && sortable ? (\n <button\n onClick={() => handleSort(column.key)}\n className=\"flex items-center gap-1 hover:text-foreground transition-colors font-medium text-sm text-muted-foreground\"\n type=\"button\"\n >\n {column.label}\n {renderSortIcon(column.key)}\n </button>\n ) : (\n <Text size=\"sm\" variant=\"muted\" weight=\"medium\">\n {column.label}\n </Text>\n )}\n </div>\n );\n })}\n\n {actions && (\n <div className=\"justify-self-end\">\n <Text size=\"sm\" variant=\"muted\" weight=\"medium\">\n {actionsLabel}\n </Text>\n </div>\n )}\n </div>\n )}\n\n {/* Select all checkbox (list mode fallback only – renderListItem handles its own selection UI) */}\n {isListMode && !renderListItem && selectable && (\n <div className={`flex items-center gap-2 ${rowPadding} border-b border-border`}>\n <Checkbox checked={isAllSelected} onChange={handleToggleAll} ariaLabel=\"Select all rows\" />\n <Text size=\"sm\" variant=\"muted\">\n Select all\n </Text>\n </div>\n )}\n\n {/* Rows */}\n <div className=\"divide-y divide-border/50\">{displayData.map((row, idx) => renderRow(row, idx))}</div>\n\n {/* Pagination controls */}\n {paginated && totalPages > 1 && (\n <div className=\"flex items-center justify-between px-4 py-3 border-t border-border\">\n <div className=\"text-sm text-muted-foreground\">\n Page {currentPage} of {totalPages} ({filteredData.length} {searchQuery.trim() ? 'filtered' : 'total'}{' '}\n rows\n {searchQuery.trim() && data.length !== filteredData.length ? ` of ${data.length}` : ''})\n </div>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" style=\"outline\" onClick={prevPage} disabled={!canPrevPage}>\n Previous\n </Button>\n <Button size=\"sm\" style=\"outline\" onClick={nextPage} disabled={!canNextPage}>\n Next\n </Button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nDataGrid.displayName = 'DataGrid';\n\nexport default DataGrid;\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as DataGrid } from './data-grid';
|
|
2
2
|
export { default as DataGridCell } from './data-grid-cell';
|
|
3
|
-
export type { DataGridProps, DataGridColumnDef, DataGridAction, DataGridActionItem, HeaderAction } from './data-grid';
|
|
3
|
+
export type { DataGridProps, DataGridColumnDef, DataGridAction, DataGridActionItem, DataGridListItemContext, HeaderAction } from './data-grid';
|
|
4
4
|
export type { DataGridCellProps } from './data-grid-cell';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/data-display/data-grid/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/data-display/data-grid/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -5,20 +5,20 @@ export type ButtonProps = {
|
|
|
5
5
|
/** Button label content - text, icons, or other elements */
|
|
6
6
|
children?: React.ReactNode;
|
|
7
7
|
/** Click event handler */
|
|
8
|
-
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
8
|
+
onClick?: (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
|
|
9
9
|
/** Mouse enter event handler */
|
|
10
|
-
onMouseEnter?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
10
|
+
onMouseEnter?: (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
|
|
11
11
|
/** Mouse leave event handler */
|
|
12
|
-
onMouseLeave?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
12
|
+
onMouseLeave?: (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
|
|
13
13
|
/** Mouse down event handler */
|
|
14
|
-
onMouseDown?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
14
|
+
onMouseDown?: (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
|
|
15
15
|
/** Blur event handler */
|
|
16
|
-
onBlur?: (e: React.FocusEvent<HTMLButtonElement>) => void;
|
|
16
|
+
onBlur?: (e: React.FocusEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
|
|
17
17
|
/** Accessible label for icon-only buttons (required when no children) */
|
|
18
18
|
ariaLabel?: string;
|
|
19
19
|
/** Disables button interaction and applies disabled styling */
|
|
20
20
|
disabled?: boolean;
|
|
21
|
-
/** HTML button type attribute */
|
|
21
|
+
/** HTML button type attribute (ignored when `to` or `href` is set) */
|
|
22
22
|
type?: 'button' | 'submit' | 'reset';
|
|
23
23
|
/** Additional CSS classes applied to the button */
|
|
24
24
|
className?: string;
|
|
@@ -52,6 +52,20 @@ export type ButtonProps = {
|
|
|
52
52
|
'aria-haspopup'?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';
|
|
53
53
|
/** ARIA controls - ID of element controlled by this button */
|
|
54
54
|
'aria-controls'?: string;
|
|
55
|
+
/**
|
|
56
|
+
* React Router path. When provided the component renders as a `<Link>` (anchor tag)
|
|
57
|
+
* instead of a `<button>`, giving you router-aware navigation with full button styling.
|
|
58
|
+
*/
|
|
59
|
+
to?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Plain URL. When provided (and `to` is not set) the component renders as an `<a>` tag.
|
|
62
|
+
* Use `to` instead when navigating within the app so React Router manages the history.
|
|
63
|
+
*/
|
|
64
|
+
href?: string;
|
|
65
|
+
/** Link target attribute (`_blank`, `_self`, etc.) – only used when `to` or `href` is set */
|
|
66
|
+
target?: React.HTMLAttributeAnchorTarget;
|
|
67
|
+
/** Rel attribute for the anchor – defaults to `"noreferrer noopener"` when `target="_blank"` */
|
|
68
|
+
rel?: string;
|
|
55
69
|
};
|
|
56
70
|
/**
|
|
57
71
|
* Accessible Button component
|
|
@@ -60,7 +74,8 @@ export type ButtonProps = {
|
|
|
60
74
|
* - Sizes: xs, sm, md (default), lg, xl
|
|
61
75
|
* - Supports icons with flexible positioning (left/right)
|
|
62
76
|
* - Icon-only buttons require `ariaLabel` for accessibility
|
|
77
|
+
* - Pass `to` to render as a React Router `<Link>`, or `href` for a plain `<a>`, keeping full button styling
|
|
63
78
|
*/
|
|
64
|
-
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
79
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
|
|
65
80
|
export default Button;
|
|
66
81
|
//# sourceMappingURL=button.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/button/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/button/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAoB,eAAe,EAAE,UAAU,EAAmB,MAAM,4BAA4B,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAoC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAElG,MAAM,MAAM,WAAW,GAAG;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,0BAA0B;IAC1B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC/E,gCAAgC;IAChC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpF,gCAAgC;IAChC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpF,+BAA+B;IAC/B,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACnF,yBAAyB;IACzB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC9E,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,gDAAgD;IAChD,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,qIAAqI;IACrI,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACxD,mEAAmE;IACnE,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,4HAA4H;IAC5H,OAAO,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACnD,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,eAAe,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC/F,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,MAAM,CAAC,EAAE,KAAK,CAAC,yBAAyB,CAAC;IACzC,gGAAgG;IAChG,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,QAAA,MAAM,MAAM,2GA8LX,CAAC;AAIF,eAAe,MAAM,CAAC"}
|