@viliha/vui-ui 1.15.0 → 1.16.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/AGENT.md +2 -0
- package/CHANGELOG.md +21 -0
- package/package.json +1 -1
- package/src/record-view.tsx +21 -6
package/AGENT.md
CHANGED
|
@@ -348,6 +348,8 @@ Never hand-build an HTML table; always use `RecordView`. Configure columns throu
|
|
|
348
348
|
|
|
349
349
|
Long cell text never wraps: cells truncate to one line at `maxCellChars` (view prop; defaults to `NEXT_PUBLIC_MAX_CELL_CHARS` or 25) with an ellipsis + hover tooltip. Override a column with the field's `maxChars` (`0` = never truncate). Don't add your own `truncate`/`title` on cells — it's built in.
|
|
350
350
|
|
|
351
|
+
A choice field (`options`) shows the option's **label** in the cell (e.g. `SYSTEM` → "System") while staying editable — don't use `render` just to map an enum to a friendly label. To customize the full-page form's breadcrumb, pass a `crumbs` array to `RecordForm` (each `{ label, onClick? }`, last = current page) — e.g. to add an "Access" parent or rename "Create new role" → "New Role".
|
|
352
|
+
|
|
351
353
|
Sorting follows column visibility by default; use `sortable` to decouple them — `sortable: true` sorts a field with no column (e.g. a `hideInTable` name shown via `getPrimary`), `sortable: false` locks a visible column. Set the flag; don't rewire the Sort dropdown or headers.
|
|
352
354
|
|
|
353
355
|
Form controls come from the field: `options` → `Select`, `input: "combobox"` → a searchable `Combobox` (`@viliha/vui-ui/combobox`, use for long lists), `input: "number" | "date"` → native inputs. For anything the built-ins don't cover (checkbox, radio group, slider, custom widget), set `renderInput({ value, onChange, field, invalid })` on the field — it drops any component into the Add/Edit form while the field keeps its label, required mark, and Save validation. Don't hand-build a `<form>`.
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ backward-compatible features, **major** for breaking changes.
|
|
|
7
7
|
|
|
8
8
|
To upgrade, see [Upgrading](./AGENT.md#upgrading) in the agent guide.
|
|
9
9
|
|
|
10
|
+
## 1.16.0 — 2026-07-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Configurable page-form breadcrumb.** `RecordForm` (page layout) takes a
|
|
15
|
+
`crumbs` prop that fully replaces the default `Home › {title} › Create/Update
|
|
16
|
+
{singular}` trail — add parents (e.g. an "Access" section), rename the last
|
|
17
|
+
crumb ("New Role"), or reshape it per route. Each crumb is `{ label, onClick? }`;
|
|
18
|
+
the last is the current page. The `Crumb` type is re-exported from
|
|
19
|
+
`@viliha/vui-ui/record-view` (also in `@viliha/vui-ui/breadcrumbs`).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **Choice-field cells show the option label, not the raw value.** A field with
|
|
24
|
+
`options` now renders its matching label in the table (e.g. `SYSTEM` →
|
|
25
|
+
"System") while staying editable — no need for a read-only `render` just to map
|
|
26
|
+
an enum to a friendly label. Falls back to the raw value when unmatched.
|
|
27
|
+
|
|
28
|
+
**For agents:** use `options` labels for enum columns (not `render`), and pass
|
|
29
|
+
`crumbs` to `RecordForm` to shape a route's breadcrumb. Docs: `/docs/data-table`.
|
|
30
|
+
|
|
10
31
|
## 1.15.0 — 2026-07-27
|
|
11
32
|
|
|
12
33
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viliha/vui-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "Vui UI — a clean, token-driven React admin/CRM component library built on Tailwind CSS v4, shadcn-style patterns, and Radix Icons. Ships as TypeScript source (Just-in-Time), compiled by the consuming app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Suman Bonakurthi",
|
package/src/record-view.tsx
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
|
|
35
35
|
import { cn } from "./utils";
|
|
36
36
|
import { Breadcrumbs, type Crumb } from "./breadcrumbs";
|
|
37
|
+
export type { Crumb } from "./breadcrumbs";
|
|
37
38
|
import { Button } from "./button";
|
|
38
39
|
import { Checkbox } from "./checkbox";
|
|
39
40
|
import { Input } from "./input";
|
|
@@ -1170,7 +1171,12 @@ export function RecordView<T extends { id: RowId }>({
|
|
|
1170
1171
|
);
|
|
1171
1172
|
}
|
|
1172
1173
|
const value = String(row[field.key] ?? "");
|
|
1173
|
-
|
|
1174
|
+
// For a choice field, show the option's friendly label (e.g. SYSTEM →
|
|
1175
|
+
// "System") while the cell stays editable — no `render`, no read-only.
|
|
1176
|
+
const display = Array.isArray(field.options)
|
|
1177
|
+
? (field.options.find((o) => o.value === value)?.label ?? value)
|
|
1178
|
+
: value;
|
|
1179
|
+
const clip = clipCell(display, field.maxChars ?? maxCellChars);
|
|
1174
1180
|
const cellKey = `${row.id}:${field.key}`;
|
|
1175
1181
|
const hoverActions =
|
|
1176
1182
|
(field.editable || (field.copyable && value)) ? (
|
|
@@ -2074,6 +2080,11 @@ interface DetailPanelProps<T extends { id: RowId }> {
|
|
|
2074
2080
|
/** Persist the in-progress draft under this key (e.g. the route), so a
|
|
2075
2081
|
* half-filled form survives leaving and returning via the open-tabs strip. */
|
|
2076
2082
|
persistKey?: string;
|
|
2083
|
+
/** Page-form breadcrumb override (fully configurable). When set, these crumbs
|
|
2084
|
+
* replace the default `Home › {title} › Create/Update {singular}` — so you can
|
|
2085
|
+
* add parents ("Access") or rename the last crumb ("New Role"). Build each
|
|
2086
|
+
* crumb as `{ label, onClick? }`; the last one is the current page. */
|
|
2087
|
+
crumbs?: Crumb[];
|
|
2077
2088
|
}
|
|
2078
2089
|
|
|
2079
2090
|
function RecordDetailPanel<T extends { id: RowId }>({
|
|
@@ -2093,6 +2104,7 @@ function RecordDetailPanel<T extends { id: RowId }>({
|
|
|
2093
2104
|
onHome,
|
|
2094
2105
|
formDescription,
|
|
2095
2106
|
persistKey,
|
|
2107
|
+
crumbs,
|
|
2096
2108
|
}: DetailPanelProps<T>) {
|
|
2097
2109
|
const draftKey = persistKey ? `${persistKey}::draft` : undefined;
|
|
2098
2110
|
const [draft, setDraft] = usePersistentState<T>(draftKey, row);
|
|
@@ -2364,11 +2376,14 @@ function RecordDetailPanel<T extends { id: RowId }>({
|
|
|
2364
2376
|
<div className="flex h-12 shrink-0 items-center border-b border-border px-4">
|
|
2365
2377
|
<Breadcrumbs
|
|
2366
2378
|
onBack={onCancel}
|
|
2367
|
-
crumbs={
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2379
|
+
crumbs={
|
|
2380
|
+
crumbs ??
|
|
2381
|
+
([
|
|
2382
|
+
...(onHome ? [{ label: "Home", onClick: onHome }] : []),
|
|
2383
|
+
{ label: title ?? singular, onClick: onCancel },
|
|
2384
|
+
{ label: crumb },
|
|
2385
|
+
] as Crumb[])
|
|
2386
|
+
}
|
|
2372
2387
|
/>
|
|
2373
2388
|
</div>
|
|
2374
2389
|
{/* Content — form card (left) + optional documentation panel (right). */}
|