@nxgt/material 3.103.0 → 3.105.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.
Files changed (139) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +5 -3
  3. package/dist/{alert-dialog-NFyAiSqc.js → alert-dialog-CK_47jfm.js} +1 -1
  4. package/dist/{async-slice-D35bX79S.js → async-slice-1ZNMiwyJ.js} +1 -1
  5. package/dist/{button-Be7GZzF9.js → button-YfEMZbRO.js} +1 -1
  6. package/dist/{calculator-BGy1Q7rn.js → calculator-BmYZId4c.js} +11 -11
  7. package/dist/calculator-field.js +6 -6
  8. package/dist/{calculator-segment-uixk6lBg.js → calculator-segment-DJ08DJ-n.js} +1 -1
  9. package/dist/calculator.js +1 -1
  10. package/dist/charts.js +819 -764
  11. package/dist/{chip-3rWebZEM.js → chip-DPj6e-3v.js} +2 -2
  12. package/dist/{code-editor-BqSVMfy-.js → code-editor-CZg3nLZO.js} +4 -4
  13. package/dist/code-editor.js +4 -4
  14. package/dist/{code-language-items-Cf2LJVg2.js → code-language-items-Nq1iOGId.js} +2 -2
  15. package/dist/components/ui/display/chip/chip-soft.css +27 -2
  16. package/dist/components/ui/primitives/collapsible/collapsible.css +9 -0
  17. package/dist/{components-D2liJ9Yu.js → components-Cn14BksP.js} +16922 -16630
  18. package/dist/components.js +38 -38
  19. package/dist/{conversion-variant-clFZ6ZMJ.js → conversion-variant-C-LPx5ek.js} +4 -4
  20. package/dist/{currency-field-CBFEVNM1.js → currency-field-DnsRIA80.js} +4 -4
  21. package/dist/{dialog-CrIIINTk.js → dialog-BKBsDGFc.js} +3 -3
  22. package/dist/dnd.js +1 -1
  23. package/dist/{dropdown-menu-BnfLWu8n.js → dropdown-menu-QMDbRidH.js} +1 -1
  24. package/dist/editor.js +8 -8
  25. package/dist/{empty-state-CuUaCPY7.js → empty-state-BLIJ6znY.js} +1 -1
  26. package/dist/{financial-variant-BY_VCUuk.js → financial-variant-Ws0Jp01H.js} +5 -5
  27. package/dist/{hooks-hHoZbL-4.js → hooks-C3vkQmzh.js} +2 -2
  28. package/dist/hooks.js +2 -2
  29. package/dist/{hover-card-Do2-uzlF.js → hover-card-Df649U6I.js} +1 -1
  30. package/dist/i18n.js +3 -3
  31. package/dist/{icon-badge-CHaVNEmb.js → icon-badge-Cma1qOOJ.js} +1 -1
  32. package/dist/{icon-button-BIAubLeJ.js → icon-button-CpKxV264.js} +1 -1
  33. package/dist/keypad.js +3 -3
  34. package/dist/lib/components/ui/actions/index.d.ts +1 -0
  35. package/dist/lib/components/ui/actions/product-tile/index.d.ts +1 -0
  36. package/dist/lib/components/ui/actions/product-tile/product-tile-link.d.ts +16 -0
  37. package/dist/lib/components/ui/actions/product-tile/product-tile.d.ts +41 -0
  38. package/dist/lib/components/ui/collections/data-table/data-table-density.d.ts +1 -1
  39. package/dist/lib/components/ui/collections/data-table/partials/data-table-scroll-region.d.ts +4 -1
  40. package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-list-bar.d.ts +6 -3
  41. package/dist/lib/components/ui/collections/data-table/partials/layouts/list-bar-in-row.d.ts +2 -1
  42. package/dist/lib/components/ui/collections/data-table/types.d.ts +11 -8
  43. package/dist/lib/components/ui/collections/data-table/virtual-option.d.ts +9 -3
  44. package/dist/lib/components/ui/collections/filter/use-filter-field-config.d.ts +2 -0
  45. package/dist/lib/components/ui/collections/server-table/partials/server-table-passed-through.d.ts +1 -0
  46. package/dist/lib/components/ui/collections/server-table/types.d.ts +1 -1
  47. package/dist/lib/components/ui/display/chip/chip.variants.d.ts +5 -4
  48. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  49. package/dist/lib/components/ui/fields/index.d.ts +1 -0
  50. package/dist/lib/components/ui/fields/quantity-field/types.d.ts +1 -1
  51. package/dist/lib/components/ui/fields/quantity-stepper/index.d.ts +2 -0
  52. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper-model.d.ts +9 -0
  53. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper-value.d.ts +15 -0
  54. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper.d.ts +9 -0
  55. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper.types.d.ts +35 -0
  56. package/dist/lib/components/ui/fields/quantity-stepper/use-quantity-stepper.d.ts +28 -0
  57. package/dist/lib/components/ui/layout/app-shell/app-sidebar-entries.d.ts +3 -1
  58. package/dist/lib/components/ui/layout/app-shell/app-sidebar-group.d.ts +8 -3
  59. package/dist/lib/components/ui/layout/app-shell/app-sidebar.d.ts +3 -1
  60. package/dist/lib/components/ui/layout/app-shell/types.d.ts +15 -0
  61. package/dist/lib/components/ui/layout/pane-layout/pane-layout-phone-frames.d.ts +20 -0
  62. package/dist/lib/components/ui/layout/pane-layout/pane-layout.d.ts +8 -3
  63. package/dist/lib/components/ui/layout/pane-layout/partials/pane-layout-classes.d.ts +2 -2
  64. package/dist/lib/components/ui/layout/pane-layout/partials/pane-layout-context.d.ts +9 -0
  65. package/dist/lib/components/ui/layout/pane-layout/partials/use-pane-layout-state.d.ts +7 -2
  66. package/dist/lib/components/ui/layout/panel-card/panel-card.d.ts +3 -1
  67. package/dist/lib/components/ui/primitives/collapsible/collapsible.d.ts +9 -1
  68. package/dist/lib/components/ui/primitives/tabs/partials/tabs-list.d.ts +6 -1
  69. package/dist/lib/components/ui/primitives/tabs/tabs-classes.d.ts +1 -0
  70. package/dist/lib/components/ui/selection/chip-group-field/chip-group-field.d.ts +8 -0
  71. package/dist/lib/components/ui/selection/chip-group-field/chip-group-field.types.d.ts +6 -0
  72. package/dist/lib/components/ui/selection/chip-group-field/partials/chip-group-reasons.d.ts +10 -0
  73. package/dist/lib/components/ui/selection/chip-group-field/partials/use-chip-rail.d.ts +12 -0
  74. package/dist/lib/components/ui/selection/choice-group/choice-group-root.d.ts +5 -2
  75. package/dist/lib/components/ui/widgets/native-charts/core/label-placement.d.ts +25 -0
  76. package/dist/lib/components/ui/widgets/native-charts/core/reference-geometry.d.ts +3 -2
  77. package/dist/lib/i18n/resources/en/en.d.ts +3 -0
  78. package/dist/lib/i18n/resources/en/material.json.d.ts +4 -1
  79. package/dist/lib/i18n/resources/fr/fr.d.ts +3 -0
  80. package/dist/lib/i18n/resources/fr/material.json.d.ts +4 -1
  81. package/dist/lib/i18n/resources/resources.d.ts +6 -0
  82. package/dist/lib/i18n/translator.d.ts +1 -1
  83. package/dist/lib/print/output/csv.d.ts +37 -0
  84. package/dist/lib/print/output/index.d.ts +1 -0
  85. package/dist/lib.js +1 -1
  86. package/dist/main.js +54 -54
  87. package/dist/map.js +8 -8
  88. package/dist/material.css +1 -1
  89. package/dist/pdf-reader.js +1 -1
  90. package/dist/{percent-field-DU8eIMD3.js → percent-field-sAq7BaxN.js} +2 -2
  91. package/dist/{picker-surface-XmA--JVI.js → picker-surface--6E-nvpU.js} +4 -4
  92. package/dist/{popover-D8iHiAbl.js → popover-bEB8I_-w.js} +1 -1
  93. package/dist/{pos-types-BEAY27Rm.js → pos-types-Cpdc4E33.js} +1 -1
  94. package/dist/{pos-variant-ClGI92Lt.js → pos-variant-ClMGu59I.js} +5 -5
  95. package/dist/print.js +146 -127
  96. package/dist/{programmer-variant-Boq2O8hB.js → programmer-variant-ChzgyA7x.js} +2 -2
  97. package/dist/{public-DOrXKmcL.js → public-BY8N5NDT.js} +9 -9
  98. package/dist/{rich-code-block-Djj2XE_u.js → rich-code-block-D2GiWuqD.js} +5 -5
  99. package/dist/{scientific-variant-BzF_aMQP.js → scientific-variant-31_93gcZ.js} +2 -2
  100. package/dist/{sortable-provider-DCZjsIIH.js → sortable-provider-DGiVn72t.js} +2 -2
  101. package/dist/{spinner-Cg0y_E_K.js → spinner-CEVomQ5K.js} +1 -1
  102. package/dist/{tabs-DpessV5s.js → tabs-B8MXBbPW.js} +14 -14
  103. package/dist/{text-field-Dxk9lAKM.js → text-field-DN88qD0Q.js} +1 -1
  104. package/dist/theme-picker.js +2 -2
  105. package/dist/{theme-toggle-B6Jl5Kfn.js → theme-toggle-C7pnu1Xh.js} +1 -1
  106. package/dist/{toolbar-items-Cs1XrZsH.js → toolbar-items-BDfoh8QB.js} +4 -4
  107. package/dist/{translate-material-Du0j0t97.js → translate-material-s_lxIV43.js} +1 -1
  108. package/dist/{translator-BVs4n0Fz.js → translator-Cgql9srO.js} +4 -2
  109. package/dist/{use-calculator-keyboard-BZ1CA4Ut.js → use-calculator-keyboard-DysnFK8m.js} +1 -1
  110. package/dist/{use-chat-composer-B4m3OEm1.js → use-chat-composer-xCcp9fVc.js} +2050 -1996
  111. package/dist/{use-heading-spy-CO3_AtY9.js → use-heading-spy-FIZlf9qj.js} +4 -4
  112. package/dist/{use-material-translation-uNc1FyC8.js → use-material-translation-xNzbSVgS.js} +1 -1
  113. package/dist/{use-return-focus-AfLRrUm-.js → use-return-focus-CW9KkDkp.js} +1 -1
  114. package/docs/README.md +1 -1
  115. package/docs/components/README.md +1 -0
  116. package/docs/components/buttons-and-actions.md +47 -0
  117. package/docs/components/data-display.md +2 -2
  118. package/docs/components/data-table-filter-and-lists.md +19 -6
  119. package/docs/components/form-fields.md +60 -7
  120. package/docs/components/navigation-and-layout.md +21 -3
  121. package/docs/components/primitives.md +44 -2
  122. package/docs/components/selection-and-choice.md +56 -1
  123. package/docs/guides/app-shell.md +22 -2
  124. package/docs/guides/cards-and-tiles.md +10 -0
  125. package/docs/guides/csp.md +4 -3
  126. package/docs/guides/data-grid.md +5 -4
  127. package/docs/guides/field-look-refined.md +2 -2
  128. package/docs/guides/keypad.md +9 -1
  129. package/docs/guides/printing.md +51 -1
  130. package/docs/previews/buttons-actions-producttile.webp +0 -0
  131. package/docs/previews/form-fields-quantitystepper.webp +0 -0
  132. package/docs/previews/navigation-layout-panelcard.webp +0 -0
  133. package/docs/roadmap.md +10 -10
  134. package/docs/troubleshooting.md +5 -4
  135. package/lib/components/ui/display/chip/chip-soft.css +27 -2
  136. package/lib/components/ui/primitives/collapsible/collapsible.css +9 -0
  137. package/lib/components/ui/widgets/calculator/calculator-keys.css +3 -0
  138. package/lib/components/ui/widgets/calculator/calculator.css +38 -7
  139. package/package.json +1 -1
@@ -41,7 +41,7 @@ import { TextField } from '@nxgt/material/components';
41
41
  | --- | --- |
42
42
  | `TextField` and the `*Field` text wrappers | `leading` / `trailing` icons and actions are muted with no well fill; a text unit (`"/ 20"`, a currency code) sits inline at the end in muted text. `CurrencyField` follows |
43
43
  | `NumberField`, `PercentField`, `CalculatorField` | one `role="group"` box; the value is end-aligned in tabular figures, the suffix hugs it, the Decrease and Increase buttons are a tinted round pair at the end (the `DurationField` look), no dividers |
44
- | `QuantityField`, `AgeField` | the value, the unit and the pair share one box; the unit is a chip that opens a menu |
44
+ | `QuantityField`, `AgeField` | the value, the unit and the pair share one box; the unit is a chip that opens a menu (no chip without `units` or `allowCustomUnit`) |
45
45
  | `NumberField variant="score"` | a big value with its maximum, no box at rest; see [the form fields page](../components/form-fields.md#numberfield) |
46
46
  | Date, time and duration fields | the shared focus ring, a dashed hairline when read-only, the recessed surface when disabled |
47
47
 
@@ -49,7 +49,7 @@ import { TextField } from '@nxgt/material/components';
49
49
 
50
50
  - The `NumberField` order is the input, Decrease, Increase (it was Decrease,
51
51
  input, Increase). With a `CalculatorField`: input, Open calculator,
52
- Decrease, Increase. A `QuantityField` is value, unit, Decrease, Increase.
52
+ Decrease, Increase. A `QuantityField` is value, unit (when it has one), Decrease, Increase.
53
53
  - The number box is a `group`. A test that queries an unnamed
54
54
  `getByRole('group')` now also matches it: name the one you mean.
55
55
  - A `QuantityField` unit is a button named "Unit: mg", not a `combobox`:
@@ -170,6 +170,14 @@ written at `=`.
170
170
  is not called). `settlement` is `{ status: 'paid', change }` (change may be
171
171
  `'0'`) or `{ status: 'short', due }`, as exact decimal text. A short payment is a
172
172
  settlement, not an error. **The app owns the charge**: the keypad only reports.
173
+ - The settlement row carries a tone: **success** while the payment covers the
174
+ total (change may be `0`), **warning** while an amount is still due, with the
175
+ figure emphasised (AA text on a tinted band, light and dark).
176
+ - The keys follow one scheme: digits neutral, the editing keys (C, backspace)
177
+ one tone, the commit key filled primary, the quick amounts tonal chips in a
178
+ two-column grid (an odd last chip takes the full row; amounts never
179
+ truncate). Without a decimal key the 0 key spans nine of the twelve columns,
180
+ the commit key the other three.
173
181
  - `total` must be a valid, non-negative amount (a number or exact decimal text);
174
182
  without one the commit key does nothing.
175
183
 
@@ -211,7 +219,7 @@ taller keys. Colours and shapes follow the theme and dark mode through
211
219
 
212
220
  - The keys are native buttons in one `role="group"` (one tab stop, arrow keys
213
221
  over the grid), at least 44px on a coarse pointer at 360px and 320px.
214
- - Each key's glyph is decoration; its name is spoken (Plus, Minus, Double zero,
222
+ - Each key's glyph is decoration; its name is spoken (Plus, Minus, "00, double zero",
215
223
  Clear all, Enter, "Amount €20.00" in English, "Amount 20,00 €" in French). `commitLabel` replaces the commit key's name.
216
224
  - Results and, in cash, the change or amount still due are announced in a
217
225
  polite live region; the display itself is not live, so typing is not read digit by digit.
@@ -2,7 +2,9 @@
2
2
 
3
3
  This page covers building PDF documents with `@nxgt/material/print`, turning
4
4
  them into a download, a new tab or a server response in one call, and
5
- shipping them from a browser or from a server bundle that must not crash.
5
+ shipping them from a browser or from a server bundle that must not crash. It
6
+ also covers [`toCsv` and `csvResponse`](#a-csv-export-tocsv-and-csvresponse),
7
+ the CSV export beside `pdfResponse`.
6
8
 
7
9
  ```bash
8
10
  bun add @react-pdf/renderer@^4.9 react-pdf-tailwind
@@ -619,6 +621,8 @@ export function DownloadInvoice({ invoice }: { invoice: Invoice }) {
619
621
  | `openPdf(doc \| blob, options?)` | `Promise<void>`: the file opens in a new tab | browser |
620
622
  | `usePdfFile(doc \| null, options?)` | `{ blob, url, loading, error, refresh }` | browser (a React hook) |
621
623
  | `pdfResponse(doc, options?)` | `Promise<Response>` with the PDF and its headers | Node 18+, Bun |
624
+ | `toCsv(rows, columns, options?)` | `string`: the CSV text | everywhere |
625
+ | `csvResponse(text, fileName?, options?)` | `Response` with the CSV and its headers | Node 18+, Bun |
622
626
  | `renderPdfBuffer(doc, options?)` | `Promise<Uint8Array>` | browser, Node 18+, Bun |
623
627
  | `renderPdfBlob(doc, options?)` | `Promise<Blob>` of type `application/pdf` | browser, Node 18+, Bun |
624
628
  | `renderPdfStream(doc, options?)` | `Promise<ReadableStream<Uint8Array>>` (a Web stream) | Node 18+, Bun |
@@ -825,6 +829,50 @@ of your own. A `PdfReader` in the browser opens the route by its URL, with
825
829
  <PdfReader file={{ url: `/invoices/${id}/pdf`, httpHeaders: { Authorization: `Bearer ${token}` } }} fileName={`${number}.pdf`} />
826
830
  ```
827
831
 
832
+ ### A CSV export: `toCsv` and `csvResponse`
833
+
834
+ A list exported to a spreadsheet is the same job as a PDF: text, then a
835
+ download response. `toCsv` writes the text (RFC 4180) and `csvResponse` wraps
836
+ it, with the same `Content-Disposition` helper as `pdfResponse`. Both are pure
837
+ and server-safe, and add nothing to a client bundle.
838
+
839
+ ```ts
840
+ import { csvResponse, toCsv } from '@nxgt/material/print';
841
+
842
+ export async function loader() {
843
+ const items = await getItems();
844
+ const text = toCsv(
845
+ items,
846
+ [
847
+ { header: 'Name', value: (item) => item.name },
848
+ { header: 'Amount', value: (item) => item.amount },
849
+ ],
850
+ { separator: ';', bom: true },
851
+ );
852
+ return csvResponse(text, 'items.csv');
853
+ }
854
+ ```
855
+
856
+ | `toCsv` option | Type | Default | Effect |
857
+ | --- | --- | --- | --- |
858
+ | `separator` | `','` \| `';'` \| `'\t'` | `','` | `';'` is what spreadsheets in comma-decimal locales (French, German) expect |
859
+ | `bom` | `boolean` | `false` | Prefixes a UTF-8 byte order mark, which Excel needs to read accents |
860
+
861
+ - The first line is the headers (`columns[].header`); each row then gives one
862
+ line from `columns[].value(row)`. Lines end with CRLF, with none after the last.
863
+ - A field holding the separator, a quote, CR or LF is quoted and its quotes
864
+ doubled. `null` and `undefined` are empty fields; numbers and booleans are
865
+ written with `String()` and a `Date` as ISO 8601. Format amounts and dates in
866
+ `value` (see `formatAmount`) when the sheet should show them by locale.
867
+ - A cell starting with `=`, `+`, `-` or `@` is written as it is: a
868
+ spreadsheet may read it as a formula, so prefix user-typed text yourself when
869
+ the file is opened by someone other than its author.
870
+
871
+ `csvResponse(text, fileName?, options?)` answers with `Content-Type: text/csv;
872
+ charset=utf-8`, an attachment `Content-Disposition` (an ASCII `filename` and a
873
+ UTF-8 `filename*`, `.csv` added when missing) and `Cache-Control: private,
874
+ no-store`, which `options.headers` can override.
875
+
828
876
  ### Bytes and streams: `renderPdfBuffer`, `renderPdfStream`
829
877
 
830
878
  For anything that is not a response (an email attachment, an upload to object
@@ -896,6 +944,8 @@ function renderPdfStream(input: PdfInput, options?: PdfRenderInputOptions): Prom
896
944
  function downloadPdf(input: PdfInput | Blob, options?: PdfOutputOptions): Promise<void>;
897
945
  function openPdf(input: PdfInput | Blob, options?: PdfOutputOptions): Promise<void>;
898
946
  function pdfResponse(input: PdfInput, options?: PdfResponseOptions & PdfRenderInputOptions): Promise<Response>;
947
+ function toCsv<Row>(rows: readonly Row[], columns: readonly CsvColumn<Row>[], options?: CsvOptions): string;
948
+ function csvResponse(text: string, fileName?: string, options?: { headers?: HeadersInit }): Response;
899
949
  function contentDisposition(disposition: 'inline' | 'attachment', fileName: string): string;
900
950
  function usePdfFile(input: PdfInput | null, options?: PdfRenderInputOptions): PdfFileState;
901
951
 
package/docs/roadmap.md CHANGED
@@ -6,15 +6,6 @@ version they shipped in, and planned entries may name the major they target.
6
6
 
7
7
  ## Now
8
8
 
9
- - **Keypad** — `@nxgt/material/keypad` is a touch and keyboard numeric keypad
10
- you can use outside the Calculator widget, for quantity, price, percentage
11
- and cash-tendered entry with change. Entry is a decimal or minor units, the
12
- display is optional, and the keyboard is on `'focus'` by default (opt in to
13
- `'global'`). `useKeypadNumber` and `useKeypadQuantity` bind it to
14
- `NumberField`, `PercentField` and `CurrencyField`. A `cash` variant reports
15
- `onTender(tendered, settlement)` and leaves the charge to your app. It is
16
- styled by `calculator.css`, with no separate stylesheet
17
- ([guide](guides/keypad.md)).
18
9
  - **Calculator** — `@nxgt/material/calculator` is an exact-decimal calculator
19
10
  (Standard, Scientific, point of sale, Financial, Conversion, Programmer;
20
11
  every variant but Standard loads on demand)
@@ -391,7 +382,16 @@ version they shipped in, and planned entries may name the major they target.
391
382
 
392
383
  ## Shipped
393
384
 
394
- - **A status chip that opens its choices** — `StatusMenu` shows a record's
385
+ - **Keypad (3.103.0)** — `@nxgt/material/keypad` is a touch and keyboard numeric keypad
386
+ you can use outside the Calculator widget, for quantity, price, percentage
387
+ and cash-tendered entry with change. Entry is a decimal or minor units, the
388
+ display is optional, and the keyboard is on `'focus'` by default (opt in to
389
+ `'global'`). `useKeypadNumber` and `useKeypadQuantity` bind it to
390
+ `NumberField`, `PercentField` and `CurrencyField`. A `cash` variant reports
391
+ `onTender(tendered, settlement)` and leaves the charge to your app. It is
392
+ styled by `calculator.css`, with no separate stylesheet
393
+ ([guide](guides/keypad.md)).
394
+ - **A status chip that opens its choices (3.103.0)** — `StatusMenu` shows a record's
395
395
  status as a tone-and-icon chip and changes it in one tap: a menu on a wide
396
396
  screen, a bottom sheet on a phone. Statuses not reachable from the current
397
397
  one are greyed with the reason, a locked or read-only record explains why,
@@ -392,7 +392,7 @@ words in your error.
392
392
  - [An empty gap under the `ServerTable` band while nothing is selected](#an-empty-gap-under-the-servertable-band-while-nothing-is-selected)
393
393
  - [The focus falls to the page after a `DataTable` bulk action](#the-focus-falls-to-the-page-after-a-datatable-bulk-action)
394
394
  - [A test's `getByText('No data available')` finds two elements after a change](#a-tests-getbytextno-data-available-finds-two-elements-after-a-change)
395
- - [`` [@nxgt/material] DataTable: `virtual` needs `maxHeight`; the rows are not virtualized. ``](#nxgtmaterial-datatable-virtual-needs-maxheight-the-rows-are-not-virtualized)
395
+ - [`` [@nxgt/material] DataTable: `virtual` needs `maxHeight` or `maxHeightClassName`; the rows are not virtualized. ``](#nxgtmaterial-datatable-virtual-needs-maxheight-or-maxheightclassname-the-rows-are-not-virtualized)
396
396
  - [`` [@nxgt/material] DataTable: `renderExpandedRow` is ignored while `virtual` is on. ``](#nxgtmaterial-datatable-renderexpandedrow-is-ignored-while-virtual-is-on)
397
397
  - [`` [@nxgt/material] DataTable: `virtual` does not apply to the `cards` layout and is ignored. ``](#nxgtmaterial-datatable-virtual-does-not-apply-to-the-cards-layout-and-is-ignored)
398
398
  - [`` [@nxgt/material] DataTable: `layout="cards"` needs `renderCard`; each card shows its first column. ``](#nxgtmaterial-datatable-layoutcards-needs-rendercard-each-card-shows-its-first-column)
@@ -7226,14 +7226,15 @@ expect(within(empty).getByText('No data available')).toBeVisible();
7226
7226
  const status = canvasElement.querySelector<HTMLElement>('[data-slot="data-table-status"]')!;
7227
7227
  expect(status).toHaveTextContent('No data available');
7228
7228
  ```
7229
- ### `` [@nxgt/material] DataTable: `virtual` needs `maxHeight`; the rows are not virtualized. ``
7229
+ ### `` [@nxgt/material] DataTable: `virtual` needs `maxHeight` or `maxHeightClassName`; the rows are not virtualized. ``
7230
7230
 
7231
- **When:** in development, a `DataTable` with `virtual` and no `maxHeight` logs this once, and renders its rows paged, as without `virtual`.
7231
+ **When:** in development, a `DataTable` with `virtual` and neither `maxHeight` nor `maxHeightClassName` logs this once, and renders its rows paged, as without `virtual`.
7232
7232
  **Why:** virtual rows scroll inside the table's own box; with no height cap there is no box to scroll, and the page would hold every row.
7233
- **Fix:** give the table a height, in pixels or any CSS length:
7233
+ **Fix:** give the table a height, in pixels or any CSS length, or a Tailwind class (no inline `style`, for a strict CSP):
7234
7234
 
7235
7235
  ```tsx
7236
7236
  <DataTable data={people} columns={columns} virtual maxHeight="70vh" />
7237
+ <DataTable data={people} columns={columns} virtual maxHeightClassName="max-h-[28rem]" />
7237
7238
  ```
7238
7239
 
7239
7240
  ### `` [@nxgt/material] DataTable: `renderExpandedRow` is ignored while `virtual` is on. ``
@@ -1,5 +1,5 @@
1
1
  /* Chip `tonal` and `filled`, "soft": no outline at all. A low tonal fill that reads as a
2
- * chip on any surface; selected = the library's primary tint, a hairline
2
+ * chip on any surface; selected = the library's primary tint (a toggle chip of a tone: the filled tone, last block), a hairline
3
3
  * ring in primary-text and a check (the ≥3:1 cue), the label unchanged. In
4
4
  * dark the tint is mixed from --primary-text, the light end of the primary,
5
5
  * 56 % at rest and 58 % on hover, and the label is white: in all 14 themes
@@ -91,7 +91,8 @@
91
91
  * (--nxgt-tone-text, 4.5:1 or more on it). It reads --nxgt-tint-status, not
92
92
  * --nxgt-tint-container: the container of a calm zone (calm.css) fades to
93
93
  * the surface through its flags, and a status chip keeps its tint there. Selected
94
- * keeps the primary tint and the foreground label above. */
94
+ * keeps the primary tint and the foreground label above, except a toggle chip of a
95
+ * tone (the last block). */
95
96
  @layer components {
96
97
  .nxgt-chip[data-look="soft"]:not([data-tone="neutral"]) {
97
98
  --chip-status-base: var(--nxgt-tone);
@@ -121,3 +122,27 @@
121
122
  color: var(--nxgt-tone-text);
122
123
  }
123
124
  }
125
+
126
+ /* A coloured toggle chip, selected: the filled tone (--nxgt-tone) under the
127
+ * tone's on-colour (--nxgt-tone-on, 4.5:1 or more, light and dark), the ring
128
+ * in the on-colour so the edge holds on the page. The check stays the
129
+ * non-colour cue. A status chip (`active`, not a toggle) keeps the tint. */
130
+ @layer components {
131
+ .nxgt-chip[data-look="soft"]:not([data-tone="neutral"])[data-selected]:is(
132
+ [aria-checked="true"],
133
+ [aria-pressed="true"]
134
+ ) {
135
+ --chip-on: var(--nxgt-tone);
136
+ --chip-on-hover: color-mix(
137
+ in oklab,
138
+ var(--nxgt-tone-on) 10%,
139
+ var(--nxgt-tone)
140
+ );
141
+ --chip-on-ring: color-mix(
142
+ in oklab,
143
+ var(--nxgt-tone-on) 55%,
144
+ var(--nxgt-tone)
145
+ );
146
+ --chip-on-text: var(--nxgt-tone-on);
147
+ }
148
+ }
@@ -73,6 +73,15 @@
73
73
  .nxgt-collapsible-trigger[data-variant="tonal"][data-state="open"] {
74
74
  border-radius: 0.75rem;
75
75
  }
76
+ /* `flush` (text only): label at the left edge, the parent's font, so the
77
+ * trigger can sit in a heading. */
78
+ .nxgt-collapsible-trigger[data-variant="text"][data-flush] {
79
+ min-height: 1.5rem;
80
+ padding: 0.25rem 0.25rem 0.25rem 0;
81
+ border-radius: 0.5rem;
82
+ font: inherit;
83
+ letter-spacing: inherit;
84
+ }
76
85
  .nxgt-collapsible-trigger:hover:not(:disabled) {
77
86
  background-color: color-mix(in oklab, var(--ct-fg) 8%, var(--ct-bg));
78
87
  }
@@ -32,6 +32,9 @@
32
32
  .nxgt-calc-key[data-span="3"] {
33
33
  grid-column: span 3;
34
34
  }
35
+ .nxgt-calc-key[data-span="9"] {
36
+ grid-column: span 9;
37
+ }
35
38
  .nxgt-calc-key[data-span="6"] {
36
39
  grid-column: span 6;
37
40
  }
@@ -137,9 +137,8 @@
137
137
  .nxgt-keypad-cash {
138
138
  display: flex;
139
139
  flex-direction: column;
140
- gap: 0.25rem;
140
+ gap: 0.5rem;
141
141
  margin: 0;
142
- padding-inline: 0.5rem;
143
142
  font-variant-numeric: tabular-nums;
144
143
  }
145
144
  .nxgt-keypad-cash > div {
@@ -147,6 +146,7 @@
147
146
  align-items: baseline;
148
147
  justify-content: space-between;
149
148
  gap: 0.5rem;
149
+ padding-inline: 1.25rem;
150
150
  }
151
151
  .nxgt-keypad-cash dt {
152
152
  color: var(--muted-foreground);
@@ -156,21 +156,49 @@
156
156
  font-size: 1.25rem;
157
157
  font-weight: 600;
158
158
  }
159
+ /* The settlement row is the figure the cashier acts on: success while there
160
+ * is change to give back, warning while an amount is still due. The figure
161
+ * takes the tone's AA text colour on its own tinted band. */
162
+ .nxgt-keypad-cash [data-status] {
163
+ align-items: baseline;
164
+ padding-block: 0.375rem;
165
+ border-radius: 1rem;
166
+ }
167
+ .nxgt-keypad-cash [data-status] dd {
168
+ font-size: 1.625rem;
169
+ font-weight: 700;
170
+ }
171
+ .nxgt-keypad-cash [data-status="paid"] {
172
+ background: color-mix(in oklab, var(--success) 20%, var(--background));
173
+ }
174
+ .nxgt-keypad-cash [data-status="paid"] dt,
175
+ .nxgt-keypad-cash [data-status="paid"] dd {
176
+ color: var(--success-text);
177
+ }
178
+ .nxgt-keypad-cash [data-status="short"] {
179
+ background: color-mix(in oklab, var(--warning) 22%, var(--background));
180
+ }
181
+ .nxgt-keypad-cash [data-status="short"] dt,
159
182
  .nxgt-keypad-cash [data-status="short"] dd {
160
- color: var(--destructive);
183
+ color: var(--warning-text);
161
184
  }
162
185
  .nxgt-keypad-shortcuts {
163
- display: flex;
164
- flex-wrap: wrap;
186
+ display: grid;
187
+ grid-template-columns: repeat(2, minmax(0, 1fr));
165
188
  gap: var(--calc-gap);
166
189
  }
167
190
  .nxgt-keypad-shortcuts button {
168
- flex: 1 1 4.5rem;
169
191
  min-width: 0;
192
+ padding-inline: 0.875rem;
193
+ white-space: nowrap;
170
194
  min-height: max(calc(var(--calc-key) * 0.8), 2.75rem);
171
195
  border: 0;
172
196
  border-radius: 9999px;
173
- background: var(--secondary-container);
197
+ background: color-mix(
198
+ in oklab,
199
+ var(--primary) 16%,
200
+ color-mix(in oklab, var(--foreground) 3%, var(--background))
201
+ );
174
202
  color: var(--foreground);
175
203
  font: inherit;
176
204
  font-weight: 500;
@@ -178,6 +206,9 @@
178
206
  cursor: pointer;
179
207
  touch-action: manipulation;
180
208
  }
209
+ .nxgt-keypad-shortcuts button:last-child:nth-child(odd) {
210
+ grid-column: 1 / -1;
211
+ }
181
212
  .nxgt-keypad-shortcuts button:focus-visible {
182
213
  outline: 2px solid var(--ring);
183
214
  outline-offset: 2px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.103.0",
3
+ "version": "3.105.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"