@dashforge/tw 0.5.0-beta → 0.7.0-beta
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/CHANGELOG.md +526 -0
- package/THEME-AUDIT.md +175 -0
- package/dist/index.esm.js +2504 -51
- package/dist/src/components/Accordion/accordion.variants.d.ts.map +1 -1
- package/dist/src/components/Box/box.variants.d.ts.map +1 -1
- package/dist/src/components/DataGrid/DataGrid.d.ts +29 -0
- package/dist/src/components/DataGrid/DataGrid.d.ts.map +1 -0
- package/dist/src/components/DataGrid/dataGrid.types.d.ts +171 -0
- package/dist/src/components/DataGrid/dataGrid.types.d.ts.map +1 -0
- package/dist/src/components/DataGrid/dataGrid.variants.d.ts +216 -0
- package/dist/src/components/DataGrid/dataGrid.variants.d.ts.map +1 -0
- package/dist/src/components/Dialog/dialog.variants.d.ts.map +1 -1
- package/dist/src/components/Divider/divider.variants.d.ts.map +1 -1
- package/dist/src/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/src/components/Pagination/pagination.variants.d.ts.map +1 -1
- package/dist/src/components/Popover/popover.variants.d.ts.map +1 -1
- package/dist/src/components/Skeleton/skeleton.variants.d.ts.map +1 -1
- package/dist/src/components/Table/Table.d.ts +24 -0
- package/dist/src/components/Table/Table.d.ts.map +1 -0
- package/dist/src/components/Table/cells/RenderButton.d.ts +13 -0
- package/dist/src/components/Table/cells/RenderButton.d.ts.map +1 -0
- package/dist/src/components/Table/cells/RenderChip.d.ts +80 -0
- package/dist/src/components/Table/cells/RenderChip.d.ts.map +1 -0
- package/dist/src/components/Table/cells/RenderText.d.ts +21 -0
- package/dist/src/components/Table/cells/RenderText.d.ts.map +1 -0
- package/dist/src/components/Table/cells/RenderTwoLine.d.ts +20 -0
- package/dist/src/components/Table/cells/RenderTwoLine.d.ts.map +1 -0
- package/dist/src/components/Table/cells/RowActionsMenu.d.ts +36 -0
- package/dist/src/components/Table/cells/RowActionsMenu.d.ts.map +1 -0
- package/dist/src/components/Table/cells/index.d.ts +11 -0
- package/dist/src/components/Table/cells/index.d.ts.map +1 -0
- package/dist/src/components/Table/table.types.d.ts +312 -0
- package/dist/src/components/Table/table.types.d.ts.map +1 -0
- package/dist/src/components/Table/table.variants.d.ts +285 -0
- package/dist/src/components/Table/table.variants.d.ts.map +1 -0
- package/dist/src/components/Tabs/tabs.variants.d.ts.map +1 -1
- package/dist/src/components/Tooltip/tooltip.variants.d.ts.map +1 -1
- package/dist/src/components/Typography/typography.variants.d.ts.map +1 -1
- package/dist/src/components/_shared/data/getNestedValue.d.ts +20 -0
- package/dist/src/components/_shared/data/getNestedValue.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useColumnAutoDetect.d.ts +45 -0
- package/dist/src/components/_shared/data/useColumnAutoDetect.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useControllableState.d.ts +23 -0
- package/dist/src/components/_shared/data/useControllableState.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useDebouncedValue.d.ts +10 -0
- package/dist/src/components/_shared/data/useDebouncedValue.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useTableFilter.d.ts +13 -0
- package/dist/src/components/_shared/data/useTableFilter.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useTableSearch.d.ts +23 -0
- package/dist/src/components/_shared/data/useTableSearch.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useTableSelection.d.ts +25 -0
- package/dist/src/components/_shared/data/useTableSelection.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useTableSort.d.ts +20 -0
- package/dist/src/components/_shared/data/useTableSort.d.ts.map +1 -0
- package/dist/src/components/_shared/data/useVirtualizer.d.ts +107 -0
- package/dist/src/components/_shared/data/useVirtualizer.d.ts.map +1 -0
- package/dist/src/index.d.ts +10 -1
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/Accordion/accordion.variants.ts +5 -3
- package/src/components/Box/Box.test.tsx +32 -11
- package/src/components/Box/box.variants.ts +23 -4
- package/src/components/DataGrid/DataGrid.test.tsx +496 -0
- package/src/components/DataGrid/DataGrid.tsx +831 -0
- package/src/components/DataGrid/dataGrid.types.ts +189 -0
- package/src/components/DataGrid/dataGrid.variants.ts +144 -0
- package/src/components/Dialog/dialog.variants.ts +10 -6
- package/src/components/Divider/Divider.test.tsx +3 -1
- package/src/components/Divider/Divider.tsx +1 -1
- package/src/components/Divider/divider.variants.ts +2 -1
- package/src/components/Pagination/Pagination.tsx +3 -1
- package/src/components/Pagination/pagination.variants.ts +19 -13
- package/src/components/Popover/popover.variants.ts +10 -4
- package/src/components/Skeleton/skeleton.variants.ts +2 -1
- package/src/components/Table/Table.test.tsx +603 -0
- package/src/components/Table/Table.tsx +816 -0
- package/src/components/Table/cells/RenderButton.tsx +23 -0
- package/src/components/Table/cells/RenderChip.tsx +103 -0
- package/src/components/Table/cells/RenderText.tsx +37 -0
- package/src/components/Table/cells/RenderTwoLine.tsx +34 -0
- package/src/components/Table/cells/RowActionsMenu.tsx +147 -0
- package/src/components/Table/cells/index.ts +14 -0
- package/src/components/Table/table.types.ts +346 -0
- package/src/components/Table/table.variants.ts +207 -0
- package/src/components/Tabs/tabs.variants.ts +19 -8
- package/src/components/Tooltip/tooltip.variants.ts +12 -2
- package/src/components/Typography/Typography.test.tsx +3 -1
- package/src/components/Typography/typography.variants.ts +6 -2
- package/src/components/_shared/data/getNestedValue.test.ts +50 -0
- package/src/components/_shared/data/getNestedValue.ts +32 -0
- package/src/components/_shared/data/useColumnAutoDetect.test.ts +123 -0
- package/src/components/_shared/data/useColumnAutoDetect.ts +100 -0
- package/src/components/_shared/data/useControllableState.ts +48 -0
- package/src/components/_shared/data/useDebouncedValue.ts +24 -0
- package/src/components/_shared/data/useTableFilter.ts +37 -0
- package/src/components/_shared/data/useTableSearch.test.ts +115 -0
- package/src/components/_shared/data/useTableSearch.ts +66 -0
- package/src/components/_shared/data/useTableSelection.test.ts +100 -0
- package/src/components/_shared/data/useTableSelection.ts +100 -0
- package/src/components/_shared/data/useTableSort.test.ts +150 -0
- package/src/components/_shared/data/useTableSort.ts +141 -0
- package/src/components/_shared/data/useVirtualizer.test.ts +158 -0
- package/src/components/_shared/data/useVirtualizer.ts +199 -0
- package/src/components/_shared/themeIdentity.test.ts +113 -0
- package/src/index.ts +59 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MouseEvent, ReactNode } from 'react';
|
|
2
|
+
import { Button } from '../../Button/Button.js';
|
|
3
|
+
import type { ButtonProps } from '../../Button/button.types.js';
|
|
4
|
+
|
|
5
|
+
export interface RenderButtonProps
|
|
6
|
+
extends Pick<ButtonProps, 'variant' | 'color' | 'size' | 'disabled' | 'access'> {
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Inline button cell renderer. Thin wrapper over `<Button>` with
|
|
13
|
+
* the size narrowed to `sm` by default (table density expects compact
|
|
14
|
+
* controls).
|
|
15
|
+
*/
|
|
16
|
+
export function RenderButton(props: RenderButtonProps) {
|
|
17
|
+
const { label, onClick, variant = 'ghost', size = 'sm', ...rest } = props;
|
|
18
|
+
return (
|
|
19
|
+
<Button variant={variant} size={size} onClick={onClick} {...rest}>
|
|
20
|
+
{label}
|
|
21
|
+
</Button>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Internal mini-chip used by the cell renderer library. Not exported
|
|
7
|
+
* from `@dashforge/tw` as a standalone component (per Sprint 4.1
|
|
8
|
+
* scope decision — a standalone `<Chip>` may ship in Sprint 5 if
|
|
9
|
+
* demand emerges).
|
|
10
|
+
*
|
|
11
|
+
* Variants:
|
|
12
|
+
* - `color`: 7 intents (neutral / primary / success / warning /
|
|
13
|
+
* danger / info / secondary)
|
|
14
|
+
* - `variant`: `soft` (default) / `solid` / `outline`
|
|
15
|
+
* - `size`: `sm` / `md`
|
|
16
|
+
*/
|
|
17
|
+
const chipVariants = tv({
|
|
18
|
+
base: [
|
|
19
|
+
'inline-flex items-center gap-1 rounded-full font-medium',
|
|
20
|
+
'whitespace-nowrap',
|
|
21
|
+
],
|
|
22
|
+
variants: {
|
|
23
|
+
color: {
|
|
24
|
+
neutral: '',
|
|
25
|
+
primary: '',
|
|
26
|
+
success: '',
|
|
27
|
+
warning: '',
|
|
28
|
+
danger: '',
|
|
29
|
+
info: '',
|
|
30
|
+
secondary: '',
|
|
31
|
+
},
|
|
32
|
+
variant: {
|
|
33
|
+
soft: '',
|
|
34
|
+
solid: '',
|
|
35
|
+
outline: '',
|
|
36
|
+
},
|
|
37
|
+
size: {
|
|
38
|
+
sm: 'h-5 px-2 text-xs',
|
|
39
|
+
md: 'h-6 px-2.5 text-xs',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
compoundVariants: [
|
|
43
|
+
// soft = subtle bg + dark text.
|
|
44
|
+
// Neutral row uses NO `dark:` variants — the dashforgePreset()
|
|
45
|
+
// CSS-var swap auto-inverts the neutral palette already.
|
|
46
|
+
// Color rows below KEEP `dark:` variants because color palettes
|
|
47
|
+
// don't auto-invert: the `dark:` shift is an intentional design
|
|
48
|
+
// choice (darker bg + lighter text in dark mode for visual cohesion).
|
|
49
|
+
{ variant: 'soft', color: 'neutral', class: 'bg-neutral-100 text-neutral-700' },
|
|
50
|
+
{ variant: 'soft', color: 'primary', class: 'bg-primary-100 dark:bg-primary-950 text-primary-700 dark:text-primary-300' },
|
|
51
|
+
{ variant: 'soft', color: 'success', class: 'bg-success-100 dark:bg-success-950 text-success-700 dark:text-success-300' },
|
|
52
|
+
{ variant: 'soft', color: 'warning', class: 'bg-warning-100 dark:bg-warning-950 text-warning-700 dark:text-warning-300' },
|
|
53
|
+
{ variant: 'soft', color: 'danger', class: 'bg-danger-100 dark:bg-danger-950 text-danger-700 dark:text-danger-300' },
|
|
54
|
+
{ variant: 'soft', color: 'info', class: 'bg-info-100 dark:bg-info-950 text-info-700 dark:text-info-300' },
|
|
55
|
+
{ variant: 'soft', color: 'secondary', class: 'bg-secondary-100 dark:bg-secondary-950 text-secondary-700 dark:text-secondary-300' },
|
|
56
|
+
// solid = full bg + light text
|
|
57
|
+
// solid neutral: bg + text both anchored to neutral palette
|
|
58
|
+
// (auto-inverts). `text-white` would not invert and would break
|
|
59
|
+
// contrast in light mode against a `bg-neutral-700` dark bg, so
|
|
60
|
+
// we stick to `text-neutral-50` (light text in light mode, dark
|
|
61
|
+
// in dark — wait, that's wrong too). Actually `text-neutral-50`
|
|
62
|
+
// auto-inverts: light text in light mode (against dark bg) is
|
|
63
|
+
// what we want; in dark mode `bg-neutral-700` becomes light AND
|
|
64
|
+
// `text-neutral-50` becomes dark — contrast preserved.
|
|
65
|
+
{ variant: 'solid', color: 'neutral', class: 'bg-neutral-700 text-neutral-50' },
|
|
66
|
+
{ variant: 'solid', color: 'primary', class: 'bg-primary-500 text-white' },
|
|
67
|
+
{ variant: 'solid', color: 'success', class: 'bg-success-500 text-white' },
|
|
68
|
+
{ variant: 'solid', color: 'warning', class: 'bg-warning-500 text-white' },
|
|
69
|
+
{ variant: 'solid', color: 'danger', class: 'bg-danger-500 text-white' },
|
|
70
|
+
{ variant: 'solid', color: 'info', class: 'bg-info-500 text-white' },
|
|
71
|
+
{ variant: 'solid', color: 'secondary', class: 'bg-secondary-500 text-white' },
|
|
72
|
+
// outline = border + colored text
|
|
73
|
+
// outline neutral: both border + text auto-invert via CSS-var swap.
|
|
74
|
+
{ variant: 'outline', color: 'neutral', class: 'border border-neutral-300 text-neutral-700' },
|
|
75
|
+
{ variant: 'outline', color: 'primary', class: 'border border-primary-500 text-primary-700 dark:text-primary-300' },
|
|
76
|
+
{ variant: 'outline', color: 'success', class: 'border border-success-500 text-success-700 dark:text-success-300' },
|
|
77
|
+
{ variant: 'outline', color: 'warning', class: 'border border-warning-500 text-warning-700 dark:text-warning-300' },
|
|
78
|
+
{ variant: 'outline', color: 'danger', class: 'border border-danger-500 text-danger-700 dark:text-danger-300' },
|
|
79
|
+
{ variant: 'outline', color: 'info', class: 'border border-info-500 text-info-700 dark:text-info-300' },
|
|
80
|
+
{ variant: 'outline', color: 'secondary', class: 'border border-secondary-500 text-secondary-700 dark:text-secondary-300' },
|
|
81
|
+
],
|
|
82
|
+
defaultVariants: {
|
|
83
|
+
color: 'neutral',
|
|
84
|
+
variant: 'soft',
|
|
85
|
+
size: 'sm',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
type ChipVariants = VariantProps<typeof chipVariants>;
|
|
90
|
+
|
|
91
|
+
export interface RenderChipProps extends ChipVariants {
|
|
92
|
+
children: ReactNode;
|
|
93
|
+
className?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function RenderChip(props: RenderChipProps) {
|
|
97
|
+
const { children, color, variant, size, className } = props;
|
|
98
|
+
return (
|
|
99
|
+
<span className={cn(chipVariants({ color, variant, size }), className)}>
|
|
100
|
+
{children}
|
|
101
|
+
</span>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { cn } from '../../../utils/cn.js';
|
|
3
|
+
|
|
4
|
+
export interface RenderTextProps {
|
|
5
|
+
value: ReactNode;
|
|
6
|
+
/** Truncate to one line with ellipsis on overflow. @default false */
|
|
7
|
+
truncate?: boolean;
|
|
8
|
+
/** Secondary text color (less prominent). @default false */
|
|
9
|
+
muted?: boolean;
|
|
10
|
+
/** Extra class merged via `tailwind-merge`. */
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Plain text cell renderer. Wraps the value in a `<span>` and
|
|
16
|
+
* optionally truncates on overflow. Use this for the most common
|
|
17
|
+
* case: render a single string value.
|
|
18
|
+
*
|
|
19
|
+
* The Table component does NOT use this by default for plain
|
|
20
|
+
* string columns — it just renders `{value}` directly. Use
|
|
21
|
+
* `RenderText` when you need the truncate / muted styling.
|
|
22
|
+
*/
|
|
23
|
+
export function RenderText(props: RenderTextProps) {
|
|
24
|
+
const { value, truncate, muted, className } = props;
|
|
25
|
+
return (
|
|
26
|
+
<span
|
|
27
|
+
className={cn(
|
|
28
|
+
truncate && 'block max-w-full truncate',
|
|
29
|
+
// Neutral palette auto-inverts via dashforgePreset() CSS-var swap.
|
|
30
|
+
muted && 'text-neutral-500',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
{value}
|
|
35
|
+
</span>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { cn } from '../../../utils/cn.js';
|
|
3
|
+
|
|
4
|
+
export interface RenderTwoLineProps {
|
|
5
|
+
primary: ReactNode;
|
|
6
|
+
secondary: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Two-line cell renderer: a bold primary line stacked above a muted
|
|
12
|
+
* secondary line. Useful for `Name + email`, `Title + ID`, etc.
|
|
13
|
+
*
|
|
14
|
+
* Replaces the MUI-side `RenderTwoLineCell` without the magic-number
|
|
15
|
+
* vertical-align fudges (`mt: 0.8 / 0.2`) — flexbox handles the
|
|
16
|
+
* vertical layout cleanly.
|
|
17
|
+
*
|
|
18
|
+
* Dashforge identity rule: text colors auto-invert via the
|
|
19
|
+
* `dashforgePreset()` CSS-variable swap. No `dark:` variants needed
|
|
20
|
+
* on neutral palette.
|
|
21
|
+
*/
|
|
22
|
+
export function RenderTwoLine(props: RenderTwoLineProps) {
|
|
23
|
+
const { primary, secondary, className } = props;
|
|
24
|
+
return (
|
|
25
|
+
<div className={cn('flex flex-col leading-tight', className)}>
|
|
26
|
+
<span className="font-medium text-neutral-900">
|
|
27
|
+
{primary}
|
|
28
|
+
</span>
|
|
29
|
+
<span className="text-xs text-neutral-500 mt-0.5">
|
|
30
|
+
{secondary}
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { useState, type ReactNode } from 'react';
|
|
2
|
+
import type { AccessRequirement } from '@dashforge/rbac';
|
|
3
|
+
import { Popover } from '../../Popover/Popover.js';
|
|
4
|
+
import { useAccessState } from '../../../hooks/useAccessState.js';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Single action definition for `<RowActionsMenu>`.
|
|
9
|
+
*
|
|
10
|
+
* `access` (optional) gates the action via RBAC:
|
|
11
|
+
* - `onUnauthorized: 'hide'` → action not rendered
|
|
12
|
+
* - `onUnauthorized: 'disable'` → action visible, disabled
|
|
13
|
+
* - `onUnauthorized: 'readonly'` → action visible, disabled
|
|
14
|
+
*/
|
|
15
|
+
export interface TableRowAction<T> {
|
|
16
|
+
label: ReactNode;
|
|
17
|
+
onClick: (row: T) => void;
|
|
18
|
+
icon?: ReactNode;
|
|
19
|
+
color?: 'default' | 'danger' | 'warning';
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
access?: AccessRequirement;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RowActionsMenuProps<T> {
|
|
25
|
+
row: T;
|
|
26
|
+
actions: TableRowAction<T>[];
|
|
27
|
+
/** Custom trigger element. Defaults to a ⋮ icon button. */
|
|
28
|
+
trigger?: ReactNode;
|
|
29
|
+
/** Aria-label for the default trigger. */
|
|
30
|
+
ariaLabel?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 3-dot row actions menu. Renders a trigger button that opens a
|
|
35
|
+
* Popover (Sprint 3 component) with a list of action menu items.
|
|
36
|
+
*
|
|
37
|
+
* Replaces the MUI-side `RowActions.tsx` (IconButton + Menu) with
|
|
38
|
+
* the TW equivalents. Per-action RBAC honored: hidden actions are
|
|
39
|
+
* filtered out, disabled actions render disabled.
|
|
40
|
+
*/
|
|
41
|
+
export function RowActionsMenu<T>(props: RowActionsMenuProps<T>) {
|
|
42
|
+
const { row, actions, trigger, ariaLabel = 'Row actions' } = props;
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
|
|
45
|
+
// Filter actions by RBAC (hidden actions removed entirely)
|
|
46
|
+
const visibleActions = actions.filter((action) => {
|
|
47
|
+
if (!action.access) return true;
|
|
48
|
+
return action.access.onUnauthorized !== 'hide';
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (visibleActions.length === 0) return null;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Popover
|
|
55
|
+
open={open}
|
|
56
|
+
onOpenChange={setOpen}
|
|
57
|
+
side="bottom"
|
|
58
|
+
align="end"
|
|
59
|
+
content={
|
|
60
|
+
<ul className="flex flex-col gap-0.5 min-w-[140px]" role="menu">
|
|
61
|
+
{visibleActions.map((action, idx) => (
|
|
62
|
+
<RowActionMenuItem
|
|
63
|
+
key={idx}
|
|
64
|
+
action={action}
|
|
65
|
+
row={row}
|
|
66
|
+
onClose={() => setOpen(false)}
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
69
|
+
</ul>
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
{trigger ?? (
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
aria-label={ariaLabel}
|
|
76
|
+
aria-haspopup="menu"
|
|
77
|
+
aria-expanded={open}
|
|
78
|
+
className={cn(
|
|
79
|
+
'inline-flex items-center justify-center h-8 w-8 rounded-md',
|
|
80
|
+
// Neutral palette auto-inverts via the dashforgePreset()
|
|
81
|
+
// CSS-var swap — no `dark:` variant needed.
|
|
82
|
+
'text-neutral-500 hover:text-neutral-900',
|
|
83
|
+
'hover:bg-neutral-100',
|
|
84
|
+
'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500',
|
|
85
|
+
'transition-colors motion-reduce:transition-none',
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
<svg
|
|
89
|
+
width="1em"
|
|
90
|
+
height="1em"
|
|
91
|
+
viewBox="0 0 16 16"
|
|
92
|
+
fill="currentColor"
|
|
93
|
+
aria-hidden="true"
|
|
94
|
+
>
|
|
95
|
+
<circle cx="8" cy="3" r="1.4" />
|
|
96
|
+
<circle cx="8" cy="8" r="1.4" />
|
|
97
|
+
<circle cx="8" cy="13" r="1.4" />
|
|
98
|
+
</svg>
|
|
99
|
+
</button>
|
|
100
|
+
)}
|
|
101
|
+
</Popover>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function RowActionMenuItem<T>(props: {
|
|
106
|
+
action: TableRowAction<T>;
|
|
107
|
+
row: T;
|
|
108
|
+
onClose: () => void;
|
|
109
|
+
}) {
|
|
110
|
+
const { action, row, onClose } = props;
|
|
111
|
+
const accessState = useAccessState(action.access);
|
|
112
|
+
const isDisabled = action.disabled || accessState.disabled || accessState.readonly;
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<li role="none">
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
role="menuitem"
|
|
119
|
+
disabled={isDisabled}
|
|
120
|
+
onClick={() => {
|
|
121
|
+
onClose();
|
|
122
|
+
action.onClick(row);
|
|
123
|
+
}}
|
|
124
|
+
className={cn(
|
|
125
|
+
'flex items-center gap-2 w-full text-left',
|
|
126
|
+
'px-3 py-1.5 rounded-md text-sm',
|
|
127
|
+
// Neutral palette auto-inverts; danger/warning are color
|
|
128
|
+
// palettes (no auto-invert) so they keep their `dark:` shift
|
|
129
|
+
// intentionally — design choice, not a bug.
|
|
130
|
+
'hover:bg-neutral-100',
|
|
131
|
+
'focus:outline-none focus-visible:bg-neutral-100',
|
|
132
|
+
'transition-colors motion-reduce:transition-none',
|
|
133
|
+
'disabled:opacity-50 disabled:pointer-events-none',
|
|
134
|
+
action.color === 'danger' && 'text-danger-700 dark:text-danger-300',
|
|
135
|
+
action.color === 'warning' && 'text-warning-700 dark:text-warning-300',
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
138
|
+
{action.icon && (
|
|
139
|
+
<span className="inline-flex shrink-0" aria-hidden="true">
|
|
140
|
+
{action.icon}
|
|
141
|
+
</span>
|
|
142
|
+
)}
|
|
143
|
+
<span>{action.label}</span>
|
|
144
|
+
</button>
|
|
145
|
+
</li>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { RenderText } from './RenderText.js';
|
|
2
|
+
export type { RenderTextProps } from './RenderText.js';
|
|
3
|
+
|
|
4
|
+
export { RenderTwoLine } from './RenderTwoLine.js';
|
|
5
|
+
export type { RenderTwoLineProps } from './RenderTwoLine.js';
|
|
6
|
+
|
|
7
|
+
export { RenderChip } from './RenderChip.js';
|
|
8
|
+
export type { RenderChipProps } from './RenderChip.js';
|
|
9
|
+
|
|
10
|
+
export { RenderButton } from './RenderButton.js';
|
|
11
|
+
export type { RenderButtonProps } from './RenderButton.js';
|
|
12
|
+
|
|
13
|
+
export { RowActionsMenu } from './RowActionsMenu.js';
|
|
14
|
+
export type { RowActionsMenuProps, TableRowAction } from './RowActionsMenu.js';
|