@nxgt/material 3.28.0 → 3.29.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.
@@ -1570,6 +1570,48 @@ one. The page clears it when the condition changes, by passing no error. The
1570
1570
  words are `material.filter.error.*`; `fieldErrors(errors, model, locked)` in
1571
1571
  the core lists what the bar shows.
1572
1572
 
1573
+ #### A refused search, and a refusal of no field
1574
+
1575
+ `errors` is keyed by field id, so it cannot name the search box nor carry a
1576
+ refusal that belongs to no field. Two more props, on the same three surfaces
1577
+ (`Filter`, `FilterBar` and `ServerTable`'s `filter`), take them:
1578
+
1579
+ ```tsx
1580
+ <FilterBar
1581
+ model={model}
1582
+ params={params}
1583
+ onParamsChange={setParams}
1584
+ searchError="Not a valid item."
1585
+ formError="The list could not be filtered right now."
1586
+ />
1587
+ ```
1588
+
1589
+ - **`searchError`** (a node) is the refusal of the typed search. The search
1590
+ box takes the error tone and shows an icon, "Invalid." and the message under
1591
+ it; the input is `aria-invalid` and `aria-describedby` points at the message.
1592
+ Nothing for a model with `search: false`.
1593
+ - **`formError`** (a node) is a refusal that belongs to no field: one error
1594
+ `Alert` under the bar, in place (under the bar's row in `FilterBar`, between
1595
+ the band and the chips in `ServerTable`, under the search in the facets
1596
+ panel). It is no live region of its own.
1597
+
1598
+ Both are told by the bar's one polite live region, the same refusal path as a
1599
+ field's, once and after the count: "Search: Not a valid item." and the
1600
+ `formError`'s text (a node is read as its text). The page drops them when the
1601
+ search or the query changes, by passing nothing, as it does for `errors`.
1602
+
1603
+ When the loader answers one flat record, `splitFilterErrors(refusal, model)`
1604
+ from `@nxgt/material-core/filter` splits it: the key equal to the model's
1605
+ search param becomes `searchError`, the key `FILTER_FORM_ERROR_KEY`
1606
+ (`'$form'`, never a field id) becomes `formError`, and the rest stays in
1607
+ `errors`. Messages are trimmed and an empty one is dropped:
1608
+
1609
+ ```tsx
1610
+ // the loader answered { item: 'Not a valid item.', $form: 'Try again later.', period: 'Too long.' }
1611
+ <FilterBar model={model} params={params} onParamsChange={setParams}
1612
+ {...splitFilterErrors(data.fieldErrors, model)} />
1613
+ ```
1614
+
1573
1615
  #### A list without a search box
1574
1616
 
1575
1617
  `defineFilterModel({ search: false, fields })` declares a list with no text
@@ -2538,6 +2538,25 @@ the field out of `locked`. `fieldErrors(errors, model, locked)` from
2538
2538
  <ServerTable filter={{ model, locked, errors: { period: 'The period cannot exceed 366 days.' } }} {...table} />
2539
2539
  ```
2540
2540
 
2541
+ ### A refused search or a refusal of no field shows nothing
2542
+
2543
+ **When:** the server refuses the typed search, or refuses with a message that
2544
+ names no field, and the page passes it as `errors={{ item: 'Not a valid item' }}`
2545
+ (the search param as a key) or `errors={{ form: '…' }}`: the search box looks
2546
+ normal and no Alert shows. Nothing is printed.
2547
+ **Why:** `errors` only reads field ids. The search box and a refusal of no field
2548
+ have their own props, `searchError` and `formError`.
2549
+ **Fix:** pass them as props, or split one flat record with `splitFilterErrors`
2550
+ from `@nxgt/material-core/filter` (the key equal to `model.search.param` is the
2551
+ search, `'$form'` is the form). A model with `search: false` shows no
2552
+ `searchError`, and an empty message shows nothing. The page must drop them when
2553
+ the search changes:
2554
+
2555
+ ```tsx
2556
+ <FilterBar model={model} params={params} onParamsChange={setParams}
2557
+ {...splitFilterErrors({ item: 'Not a valid item.', $form: 'Try again later.' }, model)} />
2558
+ ```
2559
+
2541
2560
  ### `@nxgt/material-core/filter: unknown time zone "…", using the runtime's`
2542
2561
 
2543
2562
  **When:** in the console, once, when a date preset (`this-month`) is matched or
@@ -2566,7 +2585,8 @@ const conditions = resolveDateConditions(effectiveConditions(query, model, locke
2566
2585
  neither, it has nothing to offer. The functions live in `fieldProps`, never in
2567
2586
  the model, so the loader can share it.
2568
2587
  **Fix:** give the field `options`, or a `search` (and `resolveLabels`, for the
2569
- ids a link brings) by field id:
2588
+ ids a link brings) by field id. A field only a link sets (`addable: false`)
2589
+ is never offered for picking and needs neither, so it raises no warning:
2570
2590
 
2571
2591
  ```tsx
2572
2592
  const fieldProps: FilterFieldProps = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.28.0",
3
+ "version": "3.29.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"
@@ -362,7 +362,7 @@
362
362
  "docs:previews": "rm -rf node_modules/.cache/nxgt-preview-free/missing && NXGT_PREVIEW_FREE=1 vitest run --project previews && bun .storybook/preview-free-report.ts"
363
363
  },
364
364
  "dependencies": {
365
- "@nxgt/material-core": "^0.36.0",
365
+ "@nxgt/material-core": "^0.37.0",
366
366
  "@base-ui/react": "^1.6.0",
367
367
  "@dnd-kit/core": "^6.3.1",
368
368
  "@dnd-kit/sortable": "^10.0.0",