@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 CHANGED
@@ -1,25 +1,29 @@
1
1
  # @petrarca/sonnet-ui
2
2
 
3
- UI primitives and data components for the Petrarca Sonnet component library.
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's included
7
+ ## What it provides
6
8
 
7
- **UI primitives** — Tailwind + Radix UI components: Button, Badge, Card,
8
- Dialog, Tabs, Input, Textarea, Checkbox, Label, Tooltip, Spinner, Avatar,
9
- Separator, Stepper, ResizeHandle (draggable divider for resizable panes), and
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** — Higher-level data-driven UI:
13
- - **EntityTable** — Schema-driven table with pagination, row actions, custom cell renderers
14
- - **EntitySelect** — Async searchable select with typeahead, backed by a fetcher API
15
- - **EntityTree** — Hierarchical tree browser with search and edit support
16
- - **TreeView** — Generic accessible tree with keyboard navigation and row selection
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
- **Design tokens** — Shipped as `styles.css` and `tailwind-preset.js`.
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 dependencies: `react >=19`, `react-dom >=19`, `tailwindcss >=3`,
31
- `tailwindcss-animate`, `@tailwindcss/typography`.
32
-
33
- ---
34
-
35
- ## Setup
36
-
37
- ### CSS
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
- Import `styles.css` in your app's global CSS. It provides design tokens
40
- (light + dark), base resets, heading utilities, and typography classes.
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
- ```css
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
- Override any token after the import for white-labeling:
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
- ## Design tokens
81
-
82
- All tokens are CSS custom properties (HSL triplets). Key semantic tokens:
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
- | Token | Role |
85
- |---|---|
86
- | `--background` / `--foreground` | Page surface / primary text |
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
- See `DESIGN.md` at the repo root for the full token reference.
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
- "flex h-10 w-full rounded-md border border-input bg-background 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 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
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 ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1",
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
- "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
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) colDef.minSize = col.minWidth;
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 selected = Object.keys(rowSelection).filter((k) => rowSelection[k]).map(Number).map((i) => dataRows[i]).filter((r) => r !== void 0);
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: selectionMode ? containerRef : void 0,
3734
- tabIndex: selectionMode ? 0 : void 0,
3735
- onKeyDown: selectionMode ? handleKeyDown : void 0,
3736
- className: cn32("rounded-lg border", selectionMode && "outline-none"),
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-muted-foreground px-4 py-2.5",
3743
- style: header.column.columnDef.size !== void 0 ? { width: header.column.columnDef.size } : void 0,
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-muted-foreground px-4 py-2.5"
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: handleCommit
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,