@petrarca/sonnet-ui 0.6.0 → 0.8.0
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/README.md +64 -65
- package/dist/index.d.ts +25 -1
- package/dist/index.js +54 -18
- package/dist/index.js.map +1 -1
- package/dist/json-editor/index.d.ts +4 -2
- package/dist/json-editor/index.js +32 -17
- package/dist/json-editor/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
# @petrarca/sonnet-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The component layer of the Petrarca Sonnet component library. It ships three
|
|
4
|
+
kinds of thing: a stylesheet of design tokens, a Tailwind preset that maps
|
|
5
|
+
those tokens onto utility classes, and React components.
|
|
4
6
|
|
|
5
|
-
## What
|
|
7
|
+
## What it provides
|
|
6
8
|
|
|
7
|
-
**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
more.
|
|
9
|
+
**Primitives.** Buttons, badges, cards, dialogs, sheets, popovers, dropdowns,
|
|
10
|
+
tabs, selects, tooltips, steppers, scroll areas, resize handles and the rest of
|
|
11
|
+
the building blocks, most of them wrapping Radix.
|
|
11
12
|
|
|
12
|
-
**Data components
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- **SearchInput** — Faceted search input with chip-based filters (simple, searchFields, faceted modes)
|
|
18
|
-
- **JsonEditor** — CodeMirror JSON editor with validation (subpath: `@petrarca/sonnet-ui/json-editor`)
|
|
13
|
+
**Data components.** `EntityTable` renders a collection from a schema with
|
|
14
|
+
pagination, row actions and pluggable cell renderers. `SearchInput` produces a
|
|
15
|
+
`FilterExpr` in simple, multi-field or faceted mode. `EntitySelect` is an async
|
|
16
|
+
typeahead over an injected fetcher, `EntityTree` and `TreeView` cover
|
|
17
|
+
hierarchies, and `PropertyList` covers read-only display.
|
|
19
18
|
|
|
20
|
-
**
|
|
19
|
+
**Date and time inputs.** Locale-aware date, time and datetime controls with a
|
|
20
|
+
calendar, built on the parsing and formatting layer in `sonnet-core`.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**A JSON editor.** CodeMirror with validation and JSON-Pointer-constrained
|
|
23
|
+
editable regions, on its own subpath so the dependency is opt-in.
|
|
24
|
+
|
|
25
|
+
**Design tokens.** `styles.css` and `tailwind-preset.js`, the two files every
|
|
26
|
+
other `@petrarca/sonnet-*` package renders through.
|
|
23
27
|
|
|
24
28
|
## Install
|
|
25
29
|
|
|
@@ -27,44 +31,30 @@ more.
|
|
|
27
31
|
pnpm add @petrarca/sonnet-ui @petrarca/sonnet-core
|
|
28
32
|
```
|
|
29
33
|
|
|
30
|
-
Peer
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
| Peer | Range | Needed for |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `react`, `react-dom` | `>=19` | Everything |
|
|
37
|
+
| `tailwindcss` | `>=3` | The preset and every component class |
|
|
38
|
+
| `tailwindcss-animate` | `>=1` | Enter and exit animations on overlays |
|
|
39
|
+
| `@tailwindcss/typography` | `>=0.5` | Add the plugin to your Tailwind config |
|
|
40
|
+
| `@uiw/react-codemirror` | `>=4` | The `./json-editor` subpath only |
|
|
41
|
+
| `@codemirror/state`, `@codemirror/view`, `@codemirror/lang-json` | `>=6` | The `./json-editor` subpath only |
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
You do not declare any `@radix-ui/*` package yourself. Radix is a regular
|
|
44
|
+
dependency and arrives transitively
|
|
45
|
+
([ADR-0002](../../docs/adr/0002-radix-is-a-dependency-not-a-peer.md)).
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
/* index.css */
|
|
44
|
-
@import "@petrarca/sonnet-ui/styles.css";
|
|
45
|
-
|
|
46
|
-
/* Shell layout — add below the import (app-level, not provided by the library) */
|
|
47
|
-
html, body, #root { height: 100%; }
|
|
48
|
-
#root { display: flex; flex-direction: column; overflow: hidden; }
|
|
49
|
-
body { min-height: 100vh; overflow: hidden; }
|
|
50
|
-
```
|
|
47
|
+
## Usage
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
Import the stylesheet and the preset, then use the components.
|
|
53
50
|
|
|
54
51
|
```css
|
|
52
|
+
/* src/index.css */
|
|
55
53
|
@import "@petrarca/sonnet-ui/styles.css";
|
|
56
|
-
|
|
57
|
-
:root {
|
|
58
|
-
--primary: 210 80% 40%; /* custom brand color */
|
|
59
|
-
}
|
|
60
54
|
```
|
|
61
55
|
|
|
62
|
-
### Tailwind
|
|
63
|
-
|
|
64
|
-
Use the preset in `tailwind.config.js`. It maps all design tokens to Tailwind
|
|
65
|
-
utility classes (`bg-primary`, `text-muted-foreground`, `border-border`, etc.):
|
|
66
|
-
|
|
67
56
|
```js
|
|
57
|
+
// tailwind.config.js
|
|
68
58
|
module.exports = {
|
|
69
59
|
presets: [require("@petrarca/sonnet-ui/tailwind-preset")],
|
|
70
60
|
content: [
|
|
@@ -75,30 +65,39 @@ module.exports = {
|
|
|
75
65
|
};
|
|
76
66
|
```
|
|
77
67
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
```tsx
|
|
69
|
+
import { Badge, Button, Card, CardContent } from "@petrarca/sonnet-ui";
|
|
70
|
+
|
|
71
|
+
export function WidgetCard() {
|
|
72
|
+
return (
|
|
73
|
+
<Card>
|
|
74
|
+
<CardContent className="flex items-center gap-2">
|
|
75
|
+
<Badge badgeColor="green">active</Badge>
|
|
76
|
+
<Button size="sm">Create</Button>
|
|
77
|
+
</CardContent>
|
|
78
|
+
</Card>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
| `--card` / `--card-foreground` | Card surface / text |
|
|
88
|
-
| `--primary` / `--primary-foreground` | Brand action color |
|
|
89
|
-
| `--destructive` | Error / danger |
|
|
90
|
-
| `--muted` / `--muted-foreground` | Quiet surface / secondary text |
|
|
91
|
-
| `--tertiary-foreground` | Tertiary text (timestamps, helpers) |
|
|
92
|
-
| `--faint-foreground` | Ghost text (annotations, disabled) |
|
|
93
|
-
| `--border` / `--border-subtle` / `--border-strong` | 3-tier border system |
|
|
94
|
-
| `--state-hover` / `--state-selected` | Interaction state backgrounds |
|
|
95
|
-
| `--ring` | Focus ring |
|
|
96
|
-
| `--radius` | Base border radius |
|
|
83
|
+
The second content glob and the app-level layout CSS are the two steps most
|
|
84
|
+
often missed. [Getting started](docs/usage/getting-started.md) covers both, and
|
|
85
|
+
the token reference is in [theming](docs/usage/theming.md).
|
|
97
86
|
|
|
98
|
-
|
|
87
|
+
## Documentation
|
|
99
88
|
|
|
100
|
-
|
|
89
|
+
- [Usage guides](docs/usage/index.md) -- setup, theming,
|
|
90
|
+
[primitives](docs/usage/primitives.md),
|
|
91
|
+
[EntityTable](docs/usage/entity-table.md),
|
|
92
|
+
[SearchInput](docs/usage/search-input.md),
|
|
93
|
+
[trees and selects](docs/usage/trees-and-selects.md),
|
|
94
|
+
[date and time inputs](docs/usage/date-and-time-inputs.md) and the
|
|
95
|
+
[JSON editor](docs/usage/json-editor.md).
|
|
96
|
+
- [Design docs](docs/design/index.md) -- the token architecture and the
|
|
97
|
+
reasoning behind the data components.
|
|
98
|
+
- [Workspace documentation](../../docs/README.md) -- the design language, the
|
|
99
|
+
design system and the architecture decision records.
|
|
101
100
|
|
|
102
101
|
## License
|
|
103
102
|
|
|
104
|
-
See [LICENSE.md](../../LICENSE.md).
|
|
103
|
+
Apache 2.0. See [LICENSE.md](../../LICENSE.md).
|
package/dist/index.d.ts
CHANGED
|
@@ -707,8 +707,19 @@ type TableUiSchema = Record<string, UISchema & {
|
|
|
707
707
|
label?: string;
|
|
708
708
|
};
|
|
709
709
|
}> & {
|
|
710
|
+
/**
|
|
711
|
+
* Table-level options. Reserved for sorting and a sticky header; **neither is
|
|
712
|
+
* implemented yet**, so setting these has no effect today. Kept declared
|
|
713
|
+
* because both are intended features -- see the design doc.
|
|
714
|
+
*
|
|
715
|
+
* Note this key is unrelated to the `x-ui-globalOptions` of a form UISchema,
|
|
716
|
+
* which carries `UISchemaOptions` and does work. The two share a name and
|
|
717
|
+
* nothing else.
|
|
718
|
+
*/
|
|
710
719
|
"x-ui-globalOptions"?: {
|
|
720
|
+
/** Planned. Sorting is not wired up in EntityTable yet; this has no effect. */
|
|
711
721
|
sortable?: boolean;
|
|
722
|
+
/** Planned. No sticky positioning is applied yet; this has no effect. */
|
|
712
723
|
stickyHeader?: boolean;
|
|
713
724
|
};
|
|
714
725
|
};
|
|
@@ -877,6 +888,16 @@ interface EntityTableProps<TRow extends RowData> {
|
|
|
877
888
|
showChevron?: boolean;
|
|
878
889
|
selectionMode?: boolean;
|
|
879
890
|
onSelectionChange?: (selectedRows: TRow[]) => void;
|
|
891
|
+
/**
|
|
892
|
+
* Stable identity for a row, used to key the selection.
|
|
893
|
+
*
|
|
894
|
+
* Without it the selection is keyed by row position, so it means "the rows
|
|
895
|
+
* currently in these slots" and cannot survive paging or refiltering -- the
|
|
896
|
+
* table clears it whenever `data` changes to keep that safe. Supply this and
|
|
897
|
+
* the selection is keyed by identity instead: it survives a page change, and
|
|
898
|
+
* a bulk action can span pages.
|
|
899
|
+
*/
|
|
900
|
+
getRowId?: (row: TRow) => string;
|
|
880
901
|
pagination?: PaginationState;
|
|
881
902
|
onPaginationChange?: OnChangeFn<PaginationState>;
|
|
882
903
|
rowActions?: RowAction<TRow>[];
|
|
@@ -1225,6 +1246,9 @@ type SearchWidget = React.ComponentType<SearchWidgetProps>;
|
|
|
1225
1246
|
/** Registry mapping widget names to their implementations. */
|
|
1226
1247
|
type SearchWidgetRegistry = Record<string, SearchWidget>;
|
|
1227
1248
|
|
|
1249
|
+
/** Default search widget registry. Consumers extend this via the widgets prop. */
|
|
1250
|
+
declare const DEFAULT_SEARCH_WIDGETS: SearchWidgetRegistry;
|
|
1251
|
+
|
|
1228
1252
|
/**
|
|
1229
1253
|
* SearchInput -- controlled search and filter input with chip display.
|
|
1230
1254
|
*
|
|
@@ -1329,4 +1353,4 @@ type Props = {
|
|
|
1329
1353
|
*/
|
|
1330
1354
|
declare function ClipboardMenu({ onAddItem }: Props): react_jsx_runtime.JSX.Element;
|
|
1331
1355
|
|
|
1332
|
-
export { Alert, AlertDescription, AlertTitle, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, CELL_RENDERERS, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CellRenderer, type CellRendererProps, Checkbox, ClipboardButton, ClipboardItemComponent as ClipboardItem, ClipboardMenu, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, DateInput, type DateInputProps, DateTimeInput, type DateTimeInputProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EntitySelect, type EntitySelectProps, EntityTable, type EntityTableProps, EntityTree, type EntityTreeHandle, type EntityTreeProps, IconButton, type IconButtonProps, Input, InputError, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Popover, PopoverContent, PopoverTrigger, PropertyList, type PropertyListLayout, type PropertyListProps, PropertyValue, type PropertyValueProps, ResizeHandle, type ResizeHandleProps, type ResolvedColumn, type RowAction, ScrollArea, ScrollBar, SearchInput, type SearchMode, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetTitle, SheetTrigger, SimpleGroup, SimpleStack, SimpleTooltip, Skeleton, Spinner, Stepper, StepperContent, StepperDescription, StepperIndicator, StepperItem, StepperList, StepperNext, StepperPrev, type StepperProps, StepperSeparator, StepperTitle, StepperTrigger, type TableUiSchema, Tabs, TabsContent, TabsList, TabsSeparator, TabsTrigger, Textarea, TimeInput, type TimeInputProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type TreeNode, TreeView, type TreeViewHandle, type TreeViewProps, badgeVariants, buttonVariants, createRenderer, useStore as useStepper };
|
|
1356
|
+
export { Alert, AlertDescription, AlertTitle, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, CELL_RENDERERS, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CellRenderer, type CellRendererProps, Checkbox, ClipboardButton, ClipboardItemComponent as ClipboardItem, ClipboardMenu, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, DEFAULT_SEARCH_WIDGETS, DateInput, type DateInputProps, DateTimeInput, type DateTimeInputProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EntitySelect, type EntitySelectProps, EntityTable, type EntityTableProps, EntityTree, type EntityTreeHandle, type EntityTreeProps, IconButton, type IconButtonProps, Input, InputError, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Popover, PopoverContent, PopoverTrigger, PropertyList, type PropertyListLayout, type PropertyListProps, PropertyValue, type PropertyValueProps, ResizeHandle, type ResizeHandleProps, type ResolvedColumn, type RowAction, ScrollArea, ScrollBar, SearchInput, type SearchInputProps, type SearchMode, type SearchWidget, type SearchWidgetProps, type SearchWidgetRegistry, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetTitle, SheetTrigger, SimpleGroup, SimpleStack, SimpleTooltip, Skeleton, Spinner, Stepper, StepperContent, StepperDescription, StepperIndicator, StepperItem, StepperList, StepperNext, StepperPrev, type StepperProps, StepperSeparator, StepperTitle, StepperTrigger, type TableUiSchema, Tabs, TabsContent, TabsList, TabsSeparator, TabsTrigger, Textarea, TimeInput, type TimeInputProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type TreeNode, TreeView, type TreeViewHandle, type TreeViewProps, badgeVariants, buttonVariants, createRenderer, useStore as useStepper };
|
package/dist/index.js
CHANGED
|
@@ -693,7 +693,10 @@ var Input = React11.forwardRef(
|
|
|
693
693
|
{
|
|
694
694
|
type,
|
|
695
695
|
className: cn12(
|
|
696
|
-
|
|
696
|
+
// Focus: a quiet 1px halo plus a tinted border. Chrome matches
|
|
697
|
+
// :focus-visible on text fields even for mouse clicks, so a heavy
|
|
698
|
+
// ring would fire on every click into a field.
|
|
699
|
+
"flex h-10 w-full rounded-md border border-input bg-background transition-[color,box-shadow] px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
697
700
|
className
|
|
698
701
|
),
|
|
699
702
|
ref,
|
|
@@ -1263,7 +1266,7 @@ var SelectTrigger = React17.forwardRef(({ className, children, ...props }, ref)
|
|
|
1263
1266
|
{
|
|
1264
1267
|
ref,
|
|
1265
1268
|
className: cn18(
|
|
1266
|
-
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm
|
|
1269
|
+
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background transition-[color,box-shadow] px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1",
|
|
1267
1270
|
className
|
|
1268
1271
|
),
|
|
1269
1272
|
...props,
|
|
@@ -1376,7 +1379,8 @@ var Textarea = React18.forwardRef(({ className, ...props }, ref) => {
|
|
|
1376
1379
|
"textarea",
|
|
1377
1380
|
{
|
|
1378
1381
|
className: cn19(
|
|
1379
|
-
|
|
1382
|
+
// Focus treatment matches Input -- see the note there.
|
|
1383
|
+
"flex min-h-[80px] w-full rounded-md border border-input bg-background transition-[color,box-shadow] px-3 py-2 text-base placeholder:text-muted-foreground focus-visible:outline-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
1380
1384
|
className
|
|
1381
1385
|
),
|
|
1382
1386
|
ref,
|
|
@@ -3272,7 +3276,10 @@ function buildColumnDefs(resolved, localRenderers) {
|
|
|
3272
3276
|
)
|
|
3273
3277
|
};
|
|
3274
3278
|
if (col.width !== void 0) colDef.size = col.width;
|
|
3275
|
-
if (col.minWidth !== void 0)
|
|
3279
|
+
if (col.minWidth !== void 0) {
|
|
3280
|
+
colDef.minSize = col.minWidth;
|
|
3281
|
+
colDef.meta = { ...colDef.meta, minWidth: col.minWidth };
|
|
3282
|
+
}
|
|
3276
3283
|
return colDef;
|
|
3277
3284
|
});
|
|
3278
3285
|
}
|
|
@@ -3307,12 +3314,13 @@ function buildTableOptions(opts) {
|
|
|
3307
3314
|
state: opts.tableState
|
|
3308
3315
|
};
|
|
3309
3316
|
const selectionOpts = opts.selectionMode ? { enableRowSelection: true, onRowSelectionChange: opts.setRowSelection } : {};
|
|
3317
|
+
const rowIdOpts = opts.getRowId ? { getRowId: (row) => opts.getRowId(row) } : {};
|
|
3310
3318
|
const paginationOpts = opts.isPaginated ? {
|
|
3311
3319
|
manualPagination: true,
|
|
3312
3320
|
rowCount: opts.data?.meta.total ?? 0,
|
|
3313
3321
|
onPaginationChange: opts.onPaginationChange
|
|
3314
3322
|
} : {};
|
|
3315
|
-
return { ...base, ...selectionOpts, ...paginationOpts };
|
|
3323
|
+
return { ...base, ...selectionOpts, ...paginationOpts, ...rowIdOpts };
|
|
3316
3324
|
}
|
|
3317
3325
|
function useEntityTableState(props, selectionMode) {
|
|
3318
3326
|
const {
|
|
@@ -3322,7 +3330,8 @@ function useEntityTableState(props, selectionMode) {
|
|
|
3322
3330
|
data,
|
|
3323
3331
|
pagination,
|
|
3324
3332
|
onPaginationChange,
|
|
3325
|
-
onSelectionChange
|
|
3333
|
+
onSelectionChange,
|
|
3334
|
+
getRowId
|
|
3326
3335
|
} = props;
|
|
3327
3336
|
const isPaginated = !!(pagination && onPaginationChange);
|
|
3328
3337
|
const dataRows = useMemo5(() => data?.data ?? [], [data]);
|
|
@@ -3337,9 +3346,11 @@ function useEntityTableState(props, selectionMode) {
|
|
|
3337
3346
|
}
|
|
3338
3347
|
}, [total, isPaginated, pageIndex, pageSize, onPaginationChange]);
|
|
3339
3348
|
const [rowSelection, setRowSelection] = useState5({});
|
|
3349
|
+
const keyedById = !!getRowId;
|
|
3340
3350
|
useEffect6(() => {
|
|
3351
|
+
if (keyedById) return;
|
|
3341
3352
|
setRowSelection({});
|
|
3342
|
-
}, [data]);
|
|
3353
|
+
}, [data, keyedById]);
|
|
3343
3354
|
const [activeRowIndex, setActiveRowIndex] = useState5(-1);
|
|
3344
3355
|
const containerRef = useRef4(null);
|
|
3345
3356
|
const dataColumns = useMemo5(() => {
|
|
@@ -3358,9 +3369,10 @@ function useEntityTableState(props, selectionMode) {
|
|
|
3358
3369
|
onSelectionChangeRef.current = onSelectionChange;
|
|
3359
3370
|
useEffect6(() => {
|
|
3360
3371
|
if (!selectionMode || !onSelectionChangeRef.current) return;
|
|
3361
|
-
const
|
|
3372
|
+
const keys = Object.keys(rowSelection).filter((k) => rowSelection[k]);
|
|
3373
|
+
const selected = getRowId ? dataRows.filter((row) => keys.includes(getRowId(row))) : keys.map(Number).map((i) => dataRows[i]).filter((r) => r !== void 0);
|
|
3362
3374
|
onSelectionChangeRef.current(selected);
|
|
3363
|
-
}, [rowSelection, selectionMode, dataRows]);
|
|
3375
|
+
}, [rowSelection, selectionMode, dataRows, getRowId]);
|
|
3364
3376
|
const tableState = useMemo5(
|
|
3365
3377
|
() => ({
|
|
3366
3378
|
...isPaginated ? { pagination } : {},
|
|
@@ -3376,7 +3388,8 @@ function useEntityTableState(props, selectionMode) {
|
|
|
3376
3388
|
setRowSelection,
|
|
3377
3389
|
isPaginated,
|
|
3378
3390
|
data,
|
|
3379
|
-
onPaginationChange
|
|
3391
|
+
onPaginationChange,
|
|
3392
|
+
getRowId
|
|
3380
3393
|
});
|
|
3381
3394
|
const table = useReactTable(tableOptions);
|
|
3382
3395
|
useEffect6(() => {
|
|
@@ -3454,6 +3467,15 @@ function useTableKeyboard(table, activeRowIndex, setActiveRowIndex, selectionMod
|
|
|
3454
3467
|
[activeRowIndex, onRowClick, selectionMode, table, setActiveRowIndex]
|
|
3455
3468
|
);
|
|
3456
3469
|
}
|
|
3470
|
+
function headerWidthStyle(columnDef) {
|
|
3471
|
+
const size = columnDef.size;
|
|
3472
|
+
const minWidth = columnDef.meta?.minWidth;
|
|
3473
|
+
if (size === void 0 && minWidth === void 0) return void 0;
|
|
3474
|
+
return {
|
|
3475
|
+
...size !== void 0 && { width: size },
|
|
3476
|
+
...minWidth !== void 0 && { minWidth }
|
|
3477
|
+
};
|
|
3478
|
+
}
|
|
3457
3479
|
function handleEnterKey(e, tableRows, selectionMode, activeRowIndex, onRowClick) {
|
|
3458
3480
|
e.preventDefault();
|
|
3459
3481
|
if (selectionMode || activeRowIndex < 0 || !onRowClick) return;
|
|
@@ -3465,6 +3487,9 @@ function handleSpaceKey(e, tableRows, selectionMode, activeRowIndex) {
|
|
|
3465
3487
|
e.preventDefault();
|
|
3466
3488
|
tableRows[activeRowIndex]?.toggleSelected();
|
|
3467
3489
|
}
|
|
3490
|
+
function isKeyboardOperable(selectionMode, onRowClick) {
|
|
3491
|
+
return selectionMode || !!onRowClick;
|
|
3492
|
+
}
|
|
3468
3493
|
function resolveTrailingCols(rowActions, onRowClick, selectionMode, showChevron) {
|
|
3469
3494
|
const hasRowActions = !!(rowActions && rowActions.length > 0);
|
|
3470
3495
|
const hasChevron = !!(onRowClick && showChevron && !selectionMode && !hasRowActions);
|
|
@@ -3726,21 +3751,22 @@ function EntityTable(props) {
|
|
|
3726
3751
|
showChevron
|
|
3727
3752
|
);
|
|
3728
3753
|
const colCount = columns.length + (hasTrailingCol ? 1 : 0);
|
|
3754
|
+
const isInteractive = isKeyboardOperable(selectionMode, onRowClick);
|
|
3729
3755
|
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
3730
3756
|
/* @__PURE__ */ jsx34(
|
|
3731
3757
|
"div",
|
|
3732
3758
|
{
|
|
3733
|
-
ref:
|
|
3734
|
-
tabIndex:
|
|
3735
|
-
onKeyDown:
|
|
3736
|
-
className: cn32("rounded-lg border",
|
|
3759
|
+
ref: isInteractive ? containerRef : void 0,
|
|
3760
|
+
tabIndex: isInteractive ? 0 : void 0,
|
|
3761
|
+
onKeyDown: isInteractive ? handleKeyDown : void 0,
|
|
3762
|
+
className: cn32("rounded-lg border", isInteractive && "outline-none"),
|
|
3737
3763
|
children: /* @__PURE__ */ jsxs13("table", { className: "w-full text-sm", children: [
|
|
3738
3764
|
/* @__PURE__ */ jsx34("thead", { children: /* @__PURE__ */ jsxs13("tr", { className: "border-b bg-muted/40", children: [
|
|
3739
3765
|
table.getFlatHeaders().map((header) => /* @__PURE__ */ jsx34(
|
|
3740
3766
|
"th",
|
|
3741
3767
|
{
|
|
3742
|
-
className: "text-left text-xs font-medium text-
|
|
3743
|
-
style: header.column.columnDef
|
|
3768
|
+
className: "text-left text-xs font-medium text-foreground px-4 py-2.5",
|
|
3769
|
+
style: headerWidthStyle(header.column.columnDef),
|
|
3744
3770
|
children: header.isPlaceholder ? null : flexRender(
|
|
3745
3771
|
header.column.columnDef.header,
|
|
3746
3772
|
header.getContext()
|
|
@@ -3753,7 +3779,7 @@ function EntityTable(props) {
|
|
|
3753
3779
|
{
|
|
3754
3780
|
"aria-label": "Actions",
|
|
3755
3781
|
scope: "col",
|
|
3756
|
-
className: "w-24 text-right text-xs font-medium text-
|
|
3782
|
+
className: "w-24 text-right text-xs font-medium text-foreground px-4 py-2.5"
|
|
3757
3783
|
}
|
|
3758
3784
|
),
|
|
3759
3785
|
hasChevron && /* @__PURE__ */ jsx34("th", { "aria-label": "Open", scope: "col", className: "w-10" })
|
|
@@ -5170,6 +5196,8 @@ function useSearchInput({
|
|
|
5170
5196
|
} else if (!pendingFacetRef.current) {
|
|
5171
5197
|
if (allRequiredSatisfied(draftTermsRef.current)) {
|
|
5172
5198
|
submitDraft(draftTermsRef.current);
|
|
5199
|
+
} else {
|
|
5200
|
+
return true;
|
|
5173
5201
|
}
|
|
5174
5202
|
}
|
|
5175
5203
|
} else if (inputValueRef.current.trim().length >= minCharsRef.current) {
|
|
@@ -5177,6 +5205,7 @@ function useSearchInput({
|
|
|
5177
5205
|
buildSimpleExpr(inputValueRef.current, searchFieldsRef.current)
|
|
5178
5206
|
);
|
|
5179
5207
|
}
|
|
5208
|
+
return false;
|
|
5180
5209
|
}, [addChip, submitDraft, allRequiredSatisfied]);
|
|
5181
5210
|
const handleRemoveTerm = useCallback5((index) => {
|
|
5182
5211
|
const next = draftTermsRef.current.filter((_, i) => i !== index);
|
|
@@ -5787,7 +5816,13 @@ function SearchInput(props) {
|
|
|
5787
5816
|
showSearchButton,
|
|
5788
5817
|
mode,
|
|
5789
5818
|
onClear: handleClear,
|
|
5790
|
-
onCommit:
|
|
5819
|
+
onCommit: () => {
|
|
5820
|
+
if (handleCommit()) {
|
|
5821
|
+
setPickerNavigated(false);
|
|
5822
|
+
setPickerOpen(true);
|
|
5823
|
+
inputRef.current?.focus();
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5791
5826
|
}
|
|
5792
5827
|
)
|
|
5793
5828
|
]
|
|
@@ -6068,6 +6103,7 @@ export {
|
|
|
6068
6103
|
CommandList,
|
|
6069
6104
|
CommandSeparator,
|
|
6070
6105
|
CommandShortcut,
|
|
6106
|
+
DEFAULT_SEARCH_WIDGETS,
|
|
6071
6107
|
DateInput,
|
|
6072
6108
|
DateTimeInput,
|
|
6073
6109
|
Dialog,
|