@nxgt/material 3.91.0 → 3.93.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 (149) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +3 -3
  3. package/dist/{alert-dialog-BFk4ye-3.js → alert-dialog-D37eph4I.js} +1 -1
  4. package/dist/{async-slice-gGyfyUw2.js → async-slice-BSqwhAj-.js} +1 -1
  5. package/dist/{button-C5OEq9bi.js → button-CG9SBAT-.js} +1 -1
  6. package/dist/{calculator-Dg_L6d3R.js → calculator-YD3I3y-I.js} +10 -10
  7. package/dist/calculator-field.js +6 -6
  8. package/dist/{calculator-segment-CvAaDqKf.js → calculator-segment-Cjec9zi7.js} +1 -1
  9. package/dist/calculator.js +1 -1
  10. package/dist/charts.js +3 -3
  11. package/dist/{chip-DOxFA4BI.js → chip-BbUSBl3i.js} +2 -2
  12. package/dist/{code-editor-tiAjhXW-.js → code-editor-ZEM7AAcs.js} +4 -4
  13. package/dist/code-editor.js +4 -4
  14. package/dist/{code-language-items-CcdzQvLT.js → code-language-items-CAuHPrHd.js} +2 -2
  15. package/dist/components/components.css +1 -0
  16. package/dist/components/ui/widgets/event-calendar/event-calendar-backdrop.css +43 -0
  17. package/dist/{components-G0nEVa52.js → components-CuFTrmGy.js} +19023 -18257
  18. package/dist/components.js +38 -38
  19. package/dist/{conversion-variant-4gCdFWV-.js → conversion-variant-DmEtTCSP.js} +3 -3
  20. package/dist/{currency-field-CIqe7Wg4.js → currency-field-CabGnVO9.js} +5 -5
  21. package/dist/{dialog-d6Kdf5wc.js → dialog-Jhpx6ulb.js} +3 -3
  22. package/dist/dnd.js +1 -1
  23. package/dist/{dropdown-menu-DO5kUvof.js → dropdown-menu-nl0Q3tQ2.js} +1 -1
  24. package/dist/editor.js +7 -7
  25. package/dist/{empty-state-DQnICuun.js → empty-state-mrJuqph3.js} +1 -1
  26. package/dist/{financial-variant-D80C1hVD.js → financial-variant-P8gFA9aI.js} +5 -5
  27. package/dist/{hooks-C-yLDF39.js → hooks-CjSpziWf.js} +2 -2
  28. package/dist/hooks.js +2 -2
  29. package/dist/{hover-card-DU3TAME4.js → hover-card-BNb1M8ij.js} +1 -1
  30. package/dist/i18n.js +3 -3
  31. package/dist/{icon-badge-BGczZ4Hc.js → icon-badge-CVMHwdFm.js} +1 -1
  32. package/dist/{icon-button-D0xjBCst.js → icon-button-Ch0PThsa.js} +1 -1
  33. package/dist/{input-group-CSlXMFxu.js → input-group-CPMSQcBx.js} +1 -1
  34. package/dist/lib/components/ui/collections/day-grouped-list/day-grouped-list.d.ts +30 -2
  35. package/dist/lib/components/ui/collections/day-grouped-list/index.d.ts +7 -2
  36. package/dist/lib/components/ui/collections/day-grouped-list/partials/day-group-section.d.ts +17 -0
  37. package/dist/lib/components/ui/collections/day-grouped-list/use-day-groups.d.ts +24 -0
  38. package/dist/lib/components/ui/display/entity-header/entity-metadata.d.ts +2 -0
  39. package/dist/lib/components/ui/display/event-chip/event-chip-badges.d.ts +21 -0
  40. package/dist/lib/components/ui/display/event-chip/event-chip-content.d.ts +5 -7
  41. package/dist/lib/components/ui/display/event-chip/event-chip-title.d.ts +9 -0
  42. package/dist/lib/components/ui/display/event-chip/event-chip.classes.d.ts +9 -0
  43. package/dist/lib/components/ui/display/event-chip/event-chip.d.ts +15 -2
  44. package/dist/lib/components/ui/fields/attributes/attribute-values-form-field-set/attribute-values-form-field-set.d.ts +1 -1
  45. package/dist/lib/components/ui/fields/choice-list/choice-list-control.d.ts +1 -1
  46. package/dist/lib/components/ui/fields/choice-list/choice-list-field.d.ts +1 -1
  47. package/dist/lib/components/ui/fields/choice-list/choice-list-focus.d.ts +6 -3
  48. package/dist/lib/components/ui/fields/choice-list/choice-list-form-field.d.ts +2 -2
  49. package/dist/lib/components/ui/fields/choice-list/choice-list-names.d.ts +2 -0
  50. package/dist/lib/components/ui/fields/choice-list/choice-list.utils.d.ts +2 -0
  51. package/dist/lib/components/ui/fields/choice-list/index.d.ts +1 -1
  52. package/dist/lib/components/ui/fields/choice-list/partials/choice-row.d.ts +9 -3
  53. package/dist/lib/components/ui/fields/choice-list/types.d.ts +20 -0
  54. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  55. package/dist/lib/components/ui/layout/record-page/record-details.d.ts +6 -6
  56. package/dist/lib/components/ui/media/file-list/file-list-describe.d.ts +8 -0
  57. package/dist/lib/components/ui/media/file-list/file-list-field-row.d.ts +4 -1
  58. package/dist/lib/components/ui/media/file-list/file-list-field.d.ts +13 -0
  59. package/dist/lib/components/ui/media/file-list/index.d.ts +1 -1
  60. package/dist/lib/components/ui/media/file-list/partials/file-list-items.d.ts +5 -1
  61. package/dist/lib/components/ui/media/file-list/partials/file-list-move-buttons.d.ts +9 -0
  62. package/dist/lib/components/ui/media/file-list/partials/file-list-row-actions.d.ts +3 -1
  63. package/dist/lib/components/ui/media/file-list/types.d.ts +9 -0
  64. package/dist/lib/components/ui/media/file-list/use-file-list-field.d.ts +7 -1
  65. package/dist/lib/components/ui/media/file-list/use-file-list-move.d.ts +24 -0
  66. package/dist/lib/components/ui/media/upload/network-upload-field/network-upload-item.d.ts +7 -0
  67. package/dist/lib/components/ui/widgets/editor/extensions/marks/compact-mark-buttons.d.ts +5 -1
  68. package/dist/lib/components/ui/widgets/editor/kit/editor-features.d.ts +2 -1
  69. package/dist/lib/components/ui/widgets/editor/kit/features/marks.d.ts +6 -1
  70. package/dist/lib/components/ui/widgets/event-calendar/backdrop.types.d.ts +75 -0
  71. package/dist/lib/components/ui/widgets/event-calendar/chrome.types.d.ts +12 -0
  72. package/dist/lib/components/ui/widgets/event-calendar/event-calendar-context.d.ts +8 -1
  73. package/dist/lib/components/ui/widgets/event-calendar/event-calendar-events.utils.d.ts +3 -1
  74. package/dist/lib/components/ui/widgets/event-calendar/event-calendar-shell.d.ts +1 -1
  75. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.backdrop.d.ts +38 -0
  76. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.badges.d.ts +14 -0
  77. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.labels.d.ts +14 -1
  78. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.lanes.d.ts +9 -0
  79. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.read-only.d.ts +57 -0
  80. package/dist/lib/components/ui/widgets/event-calendar/event-calendar.resources.d.ts +6 -1
  81. package/dist/lib/components/ui/widgets/event-calendar/index.d.ts +2 -1
  82. package/dist/lib/components/ui/widgets/event-calendar/partials/all-day-bars.d.ts +14 -0
  83. package/dist/lib/components/ui/widgets/event-calendar/partials/backdrop-bands.d.ts +11 -0
  84. package/dist/lib/components/ui/widgets/event-calendar/partials/backdrop-bar.d.ts +11 -0
  85. package/dist/lib/components/ui/widgets/event-calendar/partials/backdrop-cell.d.ts +13 -0
  86. package/dist/lib/components/ui/widgets/event-calendar/partials/backdrop-row.d.ts +8 -0
  87. package/dist/lib/components/ui/widgets/event-calendar/partials/calendar-badge.d.ts +16 -0
  88. package/dist/lib/components/ui/widgets/event-calendar/partials/month-day-cell.d.ts +4 -1
  89. package/dist/lib/components/ui/widgets/event-calendar/partials/month-day-parts.d.ts +12 -1
  90. package/dist/lib/components/ui/widgets/event-calendar/partials/resource-header.d.ts +2 -1
  91. package/dist/lib/components/ui/widgets/event-calendar/partials/span-event.d.ts +3 -1
  92. package/dist/lib/components/ui/widgets/event-calendar/partials/time-grid-header-day.d.ts +3 -6
  93. package/dist/lib/components/ui/widgets/event-calendar/partials/zone-corner.d.ts +10 -2
  94. package/dist/lib/components/ui/widgets/event-calendar/template.types.d.ts +7 -2
  95. package/dist/lib/components/ui/widgets/event-calendar/types.d.ts +25 -13
  96. package/dist/lib/components/ui/widgets/event-calendar/use-backdrops.d.ts +8 -0
  97. package/dist/lib/components/ui/widgets/event-calendar/use-badges.d.ts +5 -0
  98. package/dist/lib/components/ui/widgets/event-calendar/use-event-calendar.d.ts +3 -2
  99. package/dist/lib/components/ui/widgets/event-calendar/use-month-day.d.ts +6 -1
  100. package/dist/lib/components/ui/widgets/event-calendar/use-time-column.d.ts +1 -0
  101. package/dist/lib/i18n/resources/en/en.d.ts +10 -0
  102. package/dist/lib/i18n/resources/en/material.json.d.ts +11 -1
  103. package/dist/lib/i18n/resources/fr/fr.d.ts +10 -0
  104. package/dist/lib/i18n/resources/fr/material.json.d.ts +11 -1
  105. package/dist/lib/i18n/resources/resources.d.ts +20 -0
  106. package/dist/lib/i18n/translator.d.ts +1 -1
  107. package/dist/lib.js +1 -1
  108. package/dist/main.js +54 -54
  109. package/dist/map.js +7 -7
  110. package/dist/material.css +1 -1
  111. package/dist/pdf-reader.js +1 -1
  112. package/dist/{percent-field-DyJ2yOH4.js → percent-field-TWyupyr_.js} +1 -1
  113. package/dist/{picker-surface-CnlOKQ3D.js → picker-surface-CoNsDWxX.js} +4 -4
  114. package/dist/{popover-BevReSHi.js → popover-BA1U82Wk.js} +1 -1
  115. package/dist/{pos-types-BrZBX0Zg.js → pos-types-BQqv-kb6.js} +1 -1
  116. package/dist/{pos-variant-G12HCSfQ.js → pos-variant-D043n5y8.js} +4 -4
  117. package/dist/print.js +1 -1
  118. package/dist/{programmer-variant-WWLwTGRF.js → programmer-variant-jneMqtLs.js} +2 -2
  119. package/dist/{public-C1a6wQ6o.js → public-DgrbdeZj.js} +9 -9
  120. package/dist/{rich-code-block-Dh9J-VZ8.js → rich-code-block-CGNjHawR.js} +5 -5
  121. package/dist/{scientific-variant-BvutlF8a.js → scientific-variant-1L7brNNT.js} +2 -2
  122. package/dist/{sortable-provider-BrA5tfJX.js → sortable-provider-DZLV_svg.js} +2 -2
  123. package/dist/{spinner-JnLLiLIO.js → spinner-CQqRWxAW.js} +1 -1
  124. package/dist/{tabs-dXCZGShv.js → tabs-DQTx3C8e.js} +1 -1
  125. package/dist/theme-picker.js +2 -2
  126. package/dist/{theme-toggle-BmcK6mXV.js → theme-toggle-3NQ3VmJH.js} +1 -1
  127. package/dist/{toolbar-items-B-kMYsDT.js → toolbar-items-BYCdJGUf.js} +4 -4
  128. package/dist/{translate-material-BmpcP1p1.js → translate-material-jxfcGlD5.js} +1 -1
  129. package/dist/{translator-CfoXTrZd.js → translator-6XuDmqUJ.js} +18 -2
  130. package/dist/{use-chat-composer-DFD_eF-r.js → use-chat-composer-1eb4I1kM.js} +32 -31
  131. package/dist/{use-heading-spy-BcNK1qvq.js → use-heading-spy-CzPujlKr.js} +4 -4
  132. package/dist/{use-material-translation-DoymV6IP.js → use-material-translation-BUPqNmAg.js} +1 -1
  133. package/dist/{use-return-focus-CLEnhfka.js → use-return-focus-B_enQxp5.js} +1 -1
  134. package/docs/README.md +1 -0
  135. package/docs/components/data-display.md +6 -1
  136. package/docs/components/data-table-filter-and-lists.md +35 -0
  137. package/docs/components/form-fields.md +38 -5
  138. package/docs/components/media-and-files.md +16 -0
  139. package/docs/components/navigation-and-layout.md +1 -0
  140. package/docs/components/rich-widgets.md +73 -5
  141. package/docs/guides/event-calendar.md +163 -0
  142. package/docs/guides/forms.md +2 -1
  143. package/docs/guides/i18n.md +2 -0
  144. package/docs/previews/data-display-eventchip.webp +0 -0
  145. package/docs/previews/rich-widgets-eventcalendar.webp +0 -0
  146. package/docs/roadmap.md +12 -0
  147. package/lib/components/components.css +1 -0
  148. package/lib/components/ui/widgets/event-calendar/event-calendar-backdrop.css +43 -0
  149. package/package.json +3 -3
@@ -333,8 +333,8 @@ masculine one.
333
333
  ![ChoiceListField](../previews/form-fields-choicelistfield.webp)
334
334
 
335
335
  An editable list of answer choices, for a quiz question: each row has a text
336
- and a "correct" mark. `ChoiceListFormField` wires it to react-hook-form; the
337
- value is an array of `{ id, text, correct }`.
336
+ and a "correct" mark (and, with `rowDetail`, a short explanation). `ChoiceListFormField` wires it to react-hook-form; the
337
+ value is an array of `{ id, text, correct }` (plus `explanation?` with `rowDetail`).
338
338
 
339
339
  ```tsx
340
340
  import { useForm } from 'react-hook-form';
@@ -403,6 +403,8 @@ form.setError('choices.1.text', { message }, { shouldFocus: true });
403
403
  | `label` | `ReactNode` | none | names the group (a `group`, or a `radiogroup` in `single`) |
404
404
  | `rowLabel`, `addLabel` | `string` | "answer", "Add answer" | lower-case noun for the buttons (translated by default) |
405
405
  | `error`, `rowErrors` | `ReactNode`, `{ [id]: ReactNode }` | none | the list's error and each row's, by id (`ChoiceListField`; the form field fills them from the form) |
406
+ | `rowDetail` | `boolean \| { label?, placeholder?, maxLength? }` | off | adds a textarea under each row, stored as `ChoiceRow.explanation` (why a choice is right or wrong). `true` uses the defaults (`ChoiceRowDetail` types the object): label "Explanation" (translated, numbered "Explanation 2"), no placeholder, no limit. `maxLength` limits the text and shows a counter. Off: rows are `{ id, text, correct }` and nothing changes |
407
+ | `rowDetailErrors` | `{ [id]: ReactNode }` | none | each row's detail error, by id (`ChoiceListField`; the form field fills them from the form) |
406
408
  | `onBlur` | `() => void` | none | `ChoiceListField` alone: called when the focus leaves the whole list. In a form the list's root is registered with the form's `FieldBlur`, so touched works without it |
407
409
  | `onAssignIds` | `(rows) => void` | `onChange` | `ChoiceListField`: called once on mount with ids given to rows that had none or repeated one; the form field sets them without marking the form dirty |
408
410
  | other props | `div` props | | passed to the group's root (`className`, `id`, `data-*`, `ref`) |
@@ -414,6 +416,28 @@ form.setError('choices.1.text', { message }, { shouldFocus: true });
414
416
  one on mount (the form field does it with `setValue` when the `FormProvider` above is its own form, and then leaves the form clean; otherwise it calls `onChange`). Give the rows ids in `defaultValues`, the clean path: with assigned ids `defaultValues` still lack them, so `dirtyFields.choices` marks rows after the first real edit.
415
417
  In `single`, the new row is marked when no row is. A list that arrives with
416
418
  several rows marked is not changed: it fails the `too-many` rule.
419
+ - **Row detail:** with `rowDetail`, each row gets a textarea named "Explanation 2"
420
+ (or your `label`) that edits `ChoiceRow.explanation`. It follows its row through
421
+ reorder, add and remove, like `text`. A resolver's issue on
422
+ `choices.2.explanation` shows under that textarea, and `setFocus('choices.2.explanation')`
423
+ focuses it. The built-in rules never refuse a blank explanation; require one in
424
+ your schema. `explanation` stays absent on a row until its textarea is edited.
425
+
426
+ ```tsx
427
+ import type { ChoiceRowDetail } from '@nxgt/material/components';
428
+
429
+ const detail: ChoiceRowDetail = { label: 'Why', maxLength: 200 };
430
+ // <ChoiceListFormField … rowDetail={detail} />
431
+ ```
432
+
433
+ ```tsx
434
+ <ChoiceListFormField
435
+ control={control}
436
+ name="choices"
437
+ label="Answers"
438
+ rowDetail={{ label: 'Why', placeholder: 'Why is it right or wrong?', maxLength: 200 }}
439
+ />
440
+ ```
417
441
  - **Semantics:** each row's text is a labelled input ("Answer 2"); its mark
418
442
  is a radio or a checkbox named "Correct: answer 2" (the visible word
419
443
  "Correct" starts the name), so `getByRole('checkbox', { name: 'Correct: answer 2' })`
@@ -433,7 +457,7 @@ form.setError('choices.1.text', { message }, { shouldFocus: true });
433
457
  list, and blank rows are marked invalid (only for that rule, never for a resolver's or another rule's message). With a resolver (zod), an issue on
434
458
  `choices.2.text` shows under row 3 and an issue on `choices` under the list.
435
459
  When both fail in one pass, react-hook-form keeps only the list's.
436
- - **Translations:** `material.choice-list.*` (English and French). The
460
+ - **Translations:** `material.choice-list.*` (English and French; `detail` is the default label of `rowDetail`). The
437
461
  messages name the row with `rowLabel` ("Fill in every answer"); `too-few`
438
462
  is a plural that adds `s` to it, and the French templates carry the
439
463
  feminine article, so a French app overrides the keys for a masculine noun.
@@ -1753,7 +1777,14 @@ import { AttributesFormField } from '@nxgt/material/components';
1753
1777
  ```tsx
1754
1778
  import { AttributeValuesFormFieldSet, FormSection } from '@nxgt/material/components';
1755
1779
 
1756
- const form = useForm({ defaultValues: { attributes: { color: '#2563eb', size: 'M' } } });
1780
+ interface ItemValues {
1781
+ label: string;
1782
+ attributes: Record<string, string>;
1783
+ }
1784
+
1785
+ const form = useForm<ItemValues>({
1786
+ defaultValues: { label: 'Shirt', attributes: { color: '#2563eb', size: 'M' } },
1787
+ });
1757
1788
 
1758
1789
  <FormSection title="Attributes">
1759
1790
  <AttributeValuesFormFieldSet
@@ -1769,10 +1800,12 @@ const form = useForm({ defaultValues: { attributes: { color: '#2563eb', size: 'M
1769
1800
  </FormSection>
1770
1801
  ```
1771
1802
 
1803
+ `T` is inferred from `control`, so `name` is checked against the form's paths and no `as never` cast is needed.
1804
+
1772
1805
  | Prop | |
1773
1806
  | --- | --- |
1774
1807
  | `attributes` | the attributes to fill, one input each |
1775
- | `control`, `name` | the form and the path of the object it writes |
1808
+ | `control`, `name` | the form and the path of the object it writes; generic over the form values (`Control<T>`, `Path<T>`), so a typed form needs no cast |
1776
1809
  | `label` | the fieldset's accessible name (required) |
1777
1810
  | `hideLabel` | default `false`. `true` keeps `label` as the name but draws nothing, for a `FormSection` that already has the title |
1778
1811
  | `defaultValues` | optional fallback, used only while the form value at `name` is empty: `undefined`, `null` or an object with no keys (`{}`). Any other value in the form wins |
@@ -258,6 +258,22 @@ saved images).
258
258
  | `value` / `onValueChange` | `string[]` | `[]` | field variants: the stored URLs |
259
259
  | `onUpload` / `getPresignedUrl` | see [S3UploadField](#s3uploadfield-networkuploadfield) | — | field variants: how a file is sent |
260
260
  | `required` | `boolean` | — | field variants: the asterisk, and a "required" description on the field group (below) |
261
+ | `describe` | `(value: string) => FileDescription \| null \| undefined` | — | field variants: names, sizes and types a kept value (an id, a key) instead of showing the value. `FileDescription` is `{ name?, size?, type?, href? }`; `href` is its download link (dropped when not safe: `javascript:` and the like get no Download button). `null` or `undefined` falls back to the plain display. Runs on every render: keep it pure and cheap |
262
+ | `reorderable` | `boolean` | `false` | field variants: move up / move down buttons on the kept files, disabled at the ends and when the field is `disabled`; `onValueChange` receives the new order. The focus stays on the pressed button (the row's other one at an end) and a polite status says "Moved {name} to position {to}". Uploads in flight sit last until they finish |
263
+
264
+ Kept files by name, size and type, reorderable (the value stays a `string[]`):
265
+
266
+ ```tsx
267
+ <FileListS3Field
268
+ value={ids}
269
+ onValueChange={setIds}
270
+ getPresignedUrl={getPresignedUrl}
271
+ describe={(id) => files[id]} // { name, size, type, href? } | undefined
272
+ reorderable
273
+ />
274
+ ```
275
+
276
+ A row's data is `NetworkUploadDisplayItem`, which gains an optional `type` and `href` (`null`: described with a link that is not safe). New `material.*` keys: `file-list.move-up` (`Move {name} up`), `file-list.move-down` (`Move {name} down`) and `file-list.moved` (`Moved {name} to position {to}`).
261
277
 
262
278
  The dropzone is a button, and a button may not carry `aria-required`, so the
263
279
  field's list and dropzone sit in a `group` named by the label. With `required`,
@@ -1249,6 +1249,7 @@ import { Badge, Button, Card, CardContent, Description, RecordDetails, RecordPag
1249
1249
  | `created`, `updated` | `{ label: string; at: Date \| string \| number }` | — | The two segments of the muted meta line; each « label date » stays on one line |
1250
1250
  | `timeZone` | IANA zone | `'UTC'` | The zone the dates are written in, the same on a server and in a browser. Dates have no seconds and no zone suffix |
1251
1251
  | `maxColumns` | `1`-`6` | `4` | The most columns of the facts: the panel's own width gives one, a stacked and wide panel up to this |
1252
+ | other `div` props | `ComponentProps<'div'>` minus `title` | — | `data-*`, `id`, `aria-*` and `className` go to the root card; `className` is merged with its own classes |
1252
1253
 
1253
1254
  The facts are a [`DescriptionList`](data-display.md#descriptionlist), so the columns follow the card's width, not the window's.
1254
1255
 
@@ -309,15 +309,18 @@ To edit and delete in your own dialog instead of the built-in inline fields:
309
309
  | `onEventClick` | `(event: CalendarEvent) => void` | — | an event was clicked; it runs even with `onSlotClick` set (an event click never reports a slot) |
310
310
  | `eventPreview` | `boolean` | `true` | `false` skips the preview popover, so `onEventClick` alone handles the click |
311
311
  | `previewFields` | `EventCalendarPreviewField[]` | all three | the fields the preview edits in place (`'title' \| 'color' \| 'description'`); `[]` keeps the time range and the actions |
312
- | `onEventEdit` | `(event: CalendarEvent) => void` | — | adds an Edit button to the preview; the app opens its own editor; hidden when the calendar or the event is `disabled` |
313
- | `onEventDelete` | `(event: CalendarEvent) => void` | — | the preview's delete button calls this instead of the built-in confirmation and removal; the app confirms and deletes; hidden when the calendar or the event is `disabled`, so it never runs for those |
312
+ | `readOnlyEvents` | `boolean` | `false` | no event can be dragged, resized, moved with the keys, edited or deleted; events stay focusable, clickable and at full strength, `onSlotClick` still fires, see [Read-only events](#eventcalendar-read-only-events) |
313
+ | `spans` | `EventCalendarSpan[]` | — | stretches of time shaded behind the events (a closure, a term, a half day off); they never block a slot, see the [guide](../guides/event-calendar.md#spans) |
314
+ | `dayBadges` / `weekBadges` | `EventCalendarBadges` | — | a `{ label, tone? }` badge on a day, or on a week (keyed by its first day per `weekStartsOn`), see the [guide](../guides/event-calendar.md#day-and-week-badges) |
315
+ | `onEventEdit` | `(event: CalendarEvent) => void` | — | adds an Edit button to the preview; the app opens its own editor; hidden when the calendar or the event is `disabled`, and with `readOnlyEvents` |
316
+ | `onEventDelete` | `(event: CalendarEvent) => void` | — | the preview's delete button calls this instead of the built-in confirmation and removal; the app confirms and deletes; hidden when the calendar or the event is `disabled`, so it never runs for those, nor with `readOnlyEvents` |
314
317
  | `view` / `defaultView` | `'month' \| 'week' \| 'workweek' \| 'day' \| 'agenda'` | `'month'` | the visible view |
315
318
  | `date` / `defaultDate` | `string` | today | the date the view is centred on |
316
319
  | `startHour` / `endHour` | `number` | `0` / `24` | hours shown in the time grids |
317
320
  | `slotDurationMinutes` | `number` | `60` | grid step for creation and snapping |
318
321
  | `toolbar` | `ReactNode` | built-in | replace (or `null` to hide) the toolbar |
319
322
  | `views` | `EventCalendarView[]` | all five | the views the switcher offers, in order |
320
- | `weekStartsOn` | `0`–`6` | the locale's | the first day of the week |
323
+ | `weekStartsOn` | `0`–`6` | the locale's | the first day of the week; the week view starts on it and `weekBadges` are keyed by it ([guide](../guides/event-calendar.md#weekstartson)) |
321
324
  | `density` | `'comfortable' \| 'compact'` | `'comfortable'` | compact: 40px hours, shorter month cells |
322
325
  | `eventVariant` | `'soft' \| 'solid' \| 'outline'` | `'soft'` | how events are drawn ([EventChip](data-display.md#eventchip)) |
323
326
  | `sidebar` | `boolean` | `false` | the side panel from 1024px: mini month and the day's events |
@@ -339,12 +342,40 @@ trade-off: each event stays reachable by keyboard (Tab and the arrow keys move
339
342
  through the events), and the agenda view lists every event in full, which is the
340
343
  accessible route.
341
344
 
345
+ ### EventCalendar read-only events
346
+
347
+ A schedule to read and click, not to rearrange: set `readOnlyEvents`. No event
348
+ can be dragged, resized or moved with Ctrl or Cmd and the arrow keys, and the
349
+ preview offers no edit or delete. Each event keeps its look, its tab stop and
350
+ `onEventClick`, empty slots still call `onSlotClick`, and no drag instruction
351
+ is announced: the calendar is named "Event calendar" in both cases, and only a
352
+ draggable one describes itself with "Drag event". Because `readOnlyEvents` leaves
353
+ no edit path, it also hides the Edit button of `onEventEdit`.
354
+
355
+ ```tsx
356
+ <EventCalendar
357
+ defaultView="day"
358
+ defaultDate="2026-03-12"
359
+ readOnlyEvents
360
+ onEventClick={(event) => open(event.id)}
361
+ onSlotClick={(slot) => book(slot.start)}
362
+ events={events}
363
+ />
364
+ ```
365
+
366
+ It is not `disabled`, which locks the whole calendar (no slot click, no
367
+ navigation), nor `CalendarEvent.disabled`, which dims one event and makes its
368
+ button inert. Both keep their meaning; `readOnlyEvents` is React only for now
369
+ (the Vue twin is tracked in #2526).
370
+
342
371
  ### EventCalendar event badge
343
372
 
344
373
  An event takes an optional `badge` (`CalendarEventBadge`: `{ label, tone? }`): a
345
374
  small tinted label that marks it, such as a category or a follow-up. `tone` is a
346
375
  tone of the library or one your app declared (neutral when omitted). The same
347
- prop is on [`EventChip`](data-display.md).
376
+ prop is on [`EventChip`](data-display.md). An event also takes `tone` (its colour)
377
+ and `status: 'cancelled'` (struck through, announced as cancelled); see
378
+ [the EventCalendar guide](../guides/event-calendar.md#event-tone-badges-and-cancelled-events).
348
379
 
349
380
  ```tsx
350
381
  import { EventCalendar, type CalendarEvent } from '@nxgt/material/components';
@@ -372,6 +403,28 @@ const events: CalendarEvent[] = [
372
403
  in the event's accessible name. The agenda view wraps a long description
373
404
  instead of cutting it.
374
405
 
406
+ For a status and a priority together, add `badges` (`CalendarEventBadge[]`):
407
+ further badges drawn after `badge`, in the same places and order, all part of
408
+ the event's accessible name (`Visit, Follow-up, Urgent, 2/3`). Each becomes its
409
+ own tone dot where the box is narrow or short. `badges` works with or without
410
+ `badge`.
411
+
412
+ ```tsx
413
+ const events: CalendarEvent[] = [
414
+ {
415
+ id: '2',
416
+ title: 'Operation',
417
+ start: '2026-03-12T11:00:00Z',
418
+ end: '2026-03-12T13:00:00Z',
419
+ badge: { label: 'Scheduled', tone: 'info' },
420
+ badges: [
421
+ { label: 'Urgent', tone: 'warning' },
422
+ { label: '2/3', tone: 'success' },
423
+ ],
424
+ },
425
+ ];
426
+ ```
427
+
375
428
  ### EventCalendar resources
376
429
 
377
430
  `resources` splits the **day view** into one column per room, person or team
@@ -547,7 +600,7 @@ zone's wall clock. Without it, nothing changes: the machine's clock.
547
600
  <EventCalendar view="day" date="2026-03-12" timeZone="Asia/Tokyo" events={events} />
548
601
  ```
549
602
 
550
- **Storybook:** `Rich widgets/EventCalendar`, `Rich widgets/EventCalendar/Layouts`, `Rich widgets/EventCalendar/Resources`, `Rich widgets/EventCalendar/Resources on a phone`, `Rich widgets/EventCalendar/Resources a11y`, `Rich widgets/EventCalendar/Time zone`, `Rich widgets/EventCalendar/Back to back`, `Rich widgets/EventCalendar/Resource tone`, `Rich widgets/EventCalendar/Hydration`, `Rich widgets/EventCalendar/Template week` · **Vue:** `EventCalendar` (the new props and layouts, `resources`, `timeZone` and `mode="template"`: React only for now, #892, #1780 and #2458)
603
+ **Storybook:** `Rich widgets/EventCalendar`, `Rich widgets/EventCalendar/Layouts`, `Rich widgets/EventCalendar/Resources`, `Rich widgets/EventCalendar/Resources on a phone`, `Rich widgets/EventCalendar/Resources a11y`, `Rich widgets/EventCalendar/Time zone`, `Rich widgets/EventCalendar/Back to back`, `Rich widgets/EventCalendar/Resource tone`, `Rich widgets/EventCalendar/Hydration`, `Rich widgets/EventCalendar/Template week`, `Rich widgets/EventCalendar/Spans`, `Rich widgets/EventCalendar/Day and week badges`, `Rich widgets/EventCalendar/Event badge`, `Rich widgets/EventCalendar/Event tone and cancelled`, `Rich widgets/EventCalendar/Read-only events` · **Vue:** `EventCalendar` (the new props and layouts, `resources`, `timeZone` and `mode="template"`: React only for now, #892, #1780 and #2458)
551
604
 
552
605
  ---
553
606
 
@@ -1108,6 +1161,21 @@ const [html, setHtml] = useState('<p></p>');
1108
1161
  `compactKit` and `chatKit` show bold, italic, strikethrough and inline code
1109
1162
  (`editorFeatures.inlineCode`) in the toolbar; underline, subscript and
1110
1163
  superscript stay readable in the content but have no button.
1164
+ Strikethrough can be left out. `strike` defaults to `true` and works on both
1165
+ the compact and the full editor: `editorFeatures.marks({ compact: true, strike: false })`
1166
+ (replacing the kit's `marks` feature) drops the mark and its button, `~~x~~`
1167
+ in pasted Markdown reads as plain `x`, and the
1168
+ mark buttons also hide any mark the editor's schema lacks (for example a
1169
+ starter kit configured with `strike: false`):
1170
+
1171
+ ```tsx
1172
+ <CompactEditor
1173
+ features={(kit) => [
1174
+ ...kit.filter((f) => f.name !== 'marks'),
1175
+ editorFeatures.marks({ compact: true, strike: false }),
1176
+ ]}
1177
+ />
1178
+ ```
1111
1179
  - The toolbar opens with undo and redo (one group, kept last when the row folds), and the block type is one menu (Paragraph, Heading 1 to 6) whose button names the block under the caret; its label shows from 64rem of width, an icon alone below.
1112
1180
  - The toolbar is one row on the library's `Toolbar` (one tab stop, arrow keys), each feature's group a `ToolbarGroup`: groups that do not fit fold into the `Toolbar`'s More menu as a unit, lowest `priority` first: a group of two or more rows is a section under its name (its `label`, else `material.editor.group.<id>`, translated; else its id), a group of one row lists that row alone, and a single-choice group (the alignments) stays a radio group under its name. In that menu a toggle is a checkbox row with its state (bold, a list), the alignments one radio group (`menuitemradio` rows, the current one checked), a button a row that runs it (a dialog it opens, the link, the table, the image or the video, keeps the focus, and gives it back to the document when it closes; in the bar a dialog gives it back to its own button, and the image address, which has no button of its own, to the document), a menu control a submenu (the block type and the font as radio rows, the current one checked and shown on the row; the callout types, translated; the image's upload and address), and a popover control (the text colour, the highlight, the emoji) a row that opens its popover at the More button; Escape there gives the focus back to More, a choice to the document. An editor panel opened from More (the outline, the comments) stays open while you use More, and its row turns it off, the focus then going to the document. `EditorRoot` takes `look` (`'classic'` by default for a root you compose; the presets pass `'expressive'`), which `EditorToolbar` reads (`useEditorContext().look`); `EditorToolbar` takes `density` (`'compact'`: 36 px tools in the expressive look), `variant` (`docked`, the default, or `floating`) and `layout="wrap"` to keep every group on screen. `orientation` is `'horizontal'` (the default) or `'vertical'`, a column with Up and Down for the arrow keys, which folds what does not fit its height into the same More menu, at its bottom; `layout="page"` uses it for its rail, and you can use it in your own layout:
1113
1181
 
@@ -0,0 +1,163 @@
1
+ # EventCalendar: spans, badges, tones and cancelled events
2
+
3
+ `EventCalendar` (`@nxgt/material/components`) shows more than events. It can
4
+ shade what the days themselves are (a closure, a term, a half day off), put a
5
+ short label on a day or a week, draw an event in a tone, mark one as cancelled,
6
+ and lock the whole schedule to reading and clicking.
7
+
8
+ - [Spans](#spans)
9
+ - [Day and week badges](#day-and-week-badges)
10
+ - [Event tone, badges and cancelled events](#event-tone-badges-and-cancelled-events)
11
+ - [Read-only events](#read-only-events)
12
+ - [In each view](#in-each-view)
13
+ - [weekStartsOn](#weekstartson)
14
+ - [Translations](#translations)
15
+ - [Exports](#exports)
16
+
17
+ ## Spans
18
+
19
+ `spans` shades stretches of time behind the events. A span never blocks a slot:
20
+ events can still be made and dropped over it.
21
+
22
+ ```tsx
23
+ import { EventCalendar, type EventCalendarSpan } from '@nxgt/material/components';
24
+
25
+ const spans: EventCalendarSpan[] = [
26
+ // Whole days: date-only values, `end` is exclusive (this is 24 December only).
27
+ { id: 'closed', start: '2026-12-24', end: '2026-12-25', label: 'Closed', tone: 'warning' },
28
+ // A range of days.
29
+ { id: 'term', start: '2026-12-28', end: '2027-01-04', label: 'Break', tone: 'info' },
30
+ // A half day: a value with a time is an instant.
31
+ { id: 'half', start: '2026-12-23T12:00:00', end: '2026-12-24', label: 'Half day' },
32
+ ];
33
+
34
+ <EventCalendar defaultEvents={events} spans={spans} timeZone="Europe/Paris" />;
35
+ ```
36
+
37
+ - A date-only `start` / `end` means whole days, read in the calendar's
38
+ `timeZone`. `end` is always exclusive.
39
+ - `tone` is a tone of the library (default `'neutral'`).
40
+ - With `resources`, a span with a `resourceId` shades only its column; one with
41
+ none shades every column; one with an unknown id shades none.
42
+ - The shading is a thin hatch drawn with CSS classes (no inline gradient). It is
43
+ `aria-hidden`, takes no pointer event and no tab stop; its label is read in
44
+ the name of the day or column it falls on.
45
+ - `spans` is not a prop of `mode="template"`, which has no dates.
46
+
47
+ ## Day and week badges
48
+
49
+ `dayBadges` and `weekBadges` are records of `{ label, tone? }` keyed by a
50
+ `YYYY-MM-DD` date.
51
+
52
+ ```tsx
53
+ <EventCalendar
54
+ defaultEvents={events}
55
+ weekStartsOn={1}
56
+ dayBadges={{
57
+ '2026-12-24': { label: 'Eve', tone: 'info' },
58
+ '2026-12-25': { label: 'Holiday', tone: 'warning' },
59
+ }}
60
+ weekBadges={{
61
+ // The key is the first day of the week, per `weekStartsOn` (a Monday here).
62
+ '2026-12-21': { label: 'Week 52', tone: 'neutral' },
63
+ }}
64
+ />
65
+ ```
66
+
67
+ A day badge is read in the name of its day (the day header, or the month cell); a
68
+ week badge in the name of the week's first day. Where the
69
+ room is short (a phone's week column or month cell), a badge becomes a small
70
+ tone bar, distinct from the event dots. Neither prop exists in `mode="template"`.
71
+
72
+ ## Event tone, badges and cancelled events
73
+
74
+ A `CalendarEvent` takes a `tone`, several `badges` and a `status`.
75
+
76
+ ```tsx
77
+ const events: CalendarEvent[] = [
78
+ {
79
+ id: 'a',
80
+ title: 'Planning',
81
+ start: '2026-12-22T09:00:00',
82
+ end: '2026-12-22T10:00:00',
83
+ tone: 'success', // a `color` still wins, then the tone, then the resource's
84
+ badge: { label: 'Team', tone: 'info' },
85
+ badges: [{ label: '2/5', tone: 'neutral' }],
86
+ },
87
+ {
88
+ id: 'b',
89
+ title: 'Review',
90
+ start: '2026-12-22T11:00:00',
91
+ end: '2026-12-22T12:00:00',
92
+ status: 'cancelled', // struck through, muted, dashed outline; still draggable
93
+ },
94
+ ];
95
+ ```
96
+
97
+ A cancelled event strikes its title (`<del>`) and adds "Cancelled" to its
98
+ accessible name, so the state is never carried by style alone. The preview
99
+ shows such an event's title struck and named the same way (and read-only, since
100
+ its title is not an input then). `tone` and
101
+ `badges` work in every view and in `mode="template"`. `EventChip` takes the same
102
+ `tone`, `badges` and `cancelled`.
103
+
104
+ ## Read-only events
105
+
106
+ `readOnlyEvents` forbids dragging, resizing, key moves, and edits or deletes
107
+ from the preview, for every event. Events stay focusable, clickable
108
+ (`onEventClick`) and at full strength, and `onSlotClick` still fires.
109
+
110
+ ```tsx
111
+ <EventCalendar events={events} readOnlyEvents onEventClick={(event) => open(event.id)} />
112
+ ```
113
+
114
+ No drag instruction is announced. The calendar is always named "Event calendar"
115
+ (`material.event-calendar.label`); a calendar whose events can be dragged adds
116
+ "Drag event" (`material.event-calendar.drag`) as its description, which a
117
+ read-only one leaves out. The preview shows no Edit or Delete button, so
118
+ `onEventEdit` and `onEventDelete` are not offered either.
119
+
120
+ ## In each view
121
+
122
+ | View | Spans | Day badge | Week badge | Event tone and cancelled |
123
+ | --- | --- | --- | --- | --- |
124
+ | Month | shades the cell, or its half for a half day; the label shows from 7rem of cell width, with a dot under it | next to the day number | on the first cell of the row, with room below its events | chip tone; struck title, dashed outline |
125
+ | Week / workweek | hatched band under the hours with its label, and a bar in the all-day strip (a half day only the band) | in the day's header | in the gutter corner | block tone; struck title, dashed outline |
126
+ | Day | the same as the week; with `resources`, a span shades its own column | in the day's header | in the gutter corner | the same |
127
+ | Agenda, phone day list | a plain, non-clickable row | in the day's heading | in the week's heading | tone dot; struck title, "Cancelled" in words |
128
+
129
+ ## weekStartsOn
130
+
131
+ `weekStartsOn` (`0` Sunday to `6`) sets the first day of the week. Besides the
132
+ month grid, the week view starts its days on it, and a week badge's key is that
133
+ first day: with `weekStartsOn={1}`, the Monday.
134
+
135
+ This is a change: the week view used to start on the locale's first day whatever
136
+ `weekStartsOn` said. An app that set a `weekStartsOn` unlike its locale sees its
137
+ week view shift.
138
+
139
+ ## Translations
140
+
141
+ | Key | English | Used for |
142
+ | --- | --- | --- |
143
+ | `material.event-calendar.cancelled` | Cancelled | a cancelled event's accessible name |
144
+ | `material.event-chip.cancelled` | Cancelled | the hidden word after a cancelled `EventChip`'s title, and in the preview and the agenda row |
145
+ | `material.event-calendar.drag` | Drag event | the description of a calendar whose events can be dragged |
146
+ | `material.event-calendar.week-badge` | Week: {label} | a week badge, read in the name of the week's first day |
147
+ | `material.event-calendar.title` | Title | the placeholder of the preview's title field |
148
+ | `material.event-calendar.label` | Event calendar | the calendar's accessible name |
149
+
150
+ English and French ship. Override them through the `I18nProvider`
151
+ ([i18n guide](i18n.md)).
152
+
153
+ ## Exports
154
+
155
+ From `@nxgt/material/components`:
156
+
157
+ - `EventCalendarSpan`: the shape of one entry of `spans`.
158
+ - `EventCalendarBadges`: `Record<string, { label: string; tone?: Tone }>`, the
159
+ type of `dayBadges` and `weekBadges`.
160
+ - `EventCalendarDayMarksProps`: the props `spans`, `dayBadges` and `weekBadges`,
161
+ for a wrapper that forwards them.
162
+ - `CalendarEventStatus`: `'scheduled' | 'cancelled'`, the type of an event's
163
+ `status`.
@@ -644,7 +644,8 @@ export function SupplierForm({ onSave }: { onSave: (values: Values) => void }) {
644
644
  a `reset()` or `setValue()`), so `defaultValues` is only the fallback while
645
645
  the form value is empty (`undefined`, `null` or `{}`). Its fields fill the row, and `hideLabel` keeps
646
646
  `label` as the group's accessible name without drawing it, under a
647
- `FormSection` that already has the title.
647
+ `FormSection` that already has the title. `control` and `name` are typed from your
648
+ form (see [Attributes](../components/form-fields.md#attributes)).
648
649
 
649
650
  ### Rows a user adds and removes
650
651
 
@@ -227,6 +227,8 @@ The package's own strings live under one top-level namespace per language,
227
227
  either side are kept, and where both define the same leaf, **your value
228
228
  wins**.
229
229
 
230
+ `EventCalendar`'s strings (`material.event-calendar.*`) and `EventChip`'s hidden "Cancelled" (`material.event-chip.cancelled`) are listed in the [EventCalendar guide](event-calendar.md#translations).
231
+
230
232
  The copy components render on their own comes from this namespace: empty
231
233
  states, dialogs, pickers, the rich-text editor's toolbar, menus, node dialogs,
232
234
  slash menu, font names and table-caption alignment
package/docs/roadmap.md CHANGED
@@ -389,6 +389,18 @@ version they shipped in, and planned entries may name the major they target.
389
389
 
390
390
  ## Shipped
391
391
 
392
+ - **EventCalendar background spans, badges, tones and cancelled events** —
393
+ `EventCalendar` shows what the days themselves are: `spans` draw closures,
394
+ half days and other labelled, toned stretches behind the events in every
395
+ view (a hatched band in the time views, a shaded cell or half cell in the
396
+ month, a non-clickable row in the agenda and phone list), `dayBadges` and
397
+ `weekBadges` put a short toned label on a day or a week, each event takes a
398
+ `tone` and several `badges` (a status, a priority, a progress count), and a
399
+ `status: 'cancelled'` event is struck through, muted and
400
+ announced as cancelled in words, and `readOnlyEvents` makes every event
401
+ undraggable and unresizable while it stays clickable and in full colour
402
+ ([guide](guides/event-calendar.md), [#2372](https://github.com/softistx/nxgt-material/issues/2372)).
403
+
392
404
  - **Cells driven by their value** — in `DataTable`, `ServerTable` and
393
405
  `DataGrid`, `meta.cellClassName(value, row)` computes a class per cell from
394
406
  its value; `meta.tone(value, row)` colours a cell as coloured text after a
@@ -216,5 +216,6 @@
216
216
  @import "./background-shared.css";
217
217
  @import "./ui/layout/app-search/app-search.css"; /* AppSearchBar, SearchView */
218
218
  @import "./ui/widgets/drawing/drawing.css"; /* @nxgt/material/draw: role colours, focus ring */
219
+ @import "./ui/widgets/event-calendar/event-calendar-backdrop.css"; /* EventCalendar spans: the hatch and its label */
219
220
  @import "./ui/widgets/drawing/drawing-animate.css";
220
221
  @import "./ui/widgets/barcode/barcode.css"; /* @nxgt/material/barcode: symbol colours, label sheet */
@@ -0,0 +1,43 @@
1
+ /* EventCalendar spans (holidays, terms, closures): the thin hatch of direction
2
+ * A Refined, as CSS classes (no inline gradient, so the CSP holds). The
3
+ * shading is decoration under the events; the label sits on an opaque pill in
4
+ * the tone's text colour, which keeps it AA on the hatch. The tone comes from
5
+ * the nearest `data-tone`. */
6
+ @layer components {
7
+ .nxgt-ec-backdrop {
8
+ background-image: repeating-linear-gradient(
9
+ 135deg,
10
+ color-mix(in oklab, var(--nxgt-tone) 42%, transparent) 0 1px,
11
+ transparent 1px 7px
12
+ );
13
+ }
14
+ .nxgt-ec-backdrop-bar {
15
+ box-shadow: inset 0 0 0 1px
16
+ color-mix(in oklab, var(--nxgt-tone) 28%, transparent);
17
+ }
18
+ .nxgt-ec-backdrop-label {
19
+ display: block;
20
+ width: fit-content;
21
+ max-width: 100%;
22
+ overflow: hidden;
23
+ text-overflow: ellipsis;
24
+ white-space: nowrap;
25
+ padding: 2px 6px;
26
+ border-radius: 4px;
27
+ border: 1px solid var(--border);
28
+ background: var(--card);
29
+ color: var(--nxgt-tone-text);
30
+ font-size: 11px;
31
+ font-weight: 500;
32
+ line-height: 1.2;
33
+ }
34
+ .nxgt-ec-backdrop-label-css::before {
35
+ content: attr(data-label);
36
+ }
37
+ .nxgt-ec-backdrop-dot {
38
+ width: 0.375rem;
39
+ height: 0.375rem;
40
+ border-radius: 9999px;
41
+ background: var(--nxgt-tone);
42
+ }
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.91.0",
3
+ "version": "3.93.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"
@@ -390,7 +390,7 @@
390
390
  "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"
391
391
  },
392
392
  "dependencies": {
393
- "@nxgt/material-core": "^0.53.0",
393
+ "@nxgt/material-core": "^0.54.0",
394
394
  "@base-ui/react": "^1.6.0",
395
395
  "@dnd-kit/core": "^6.3.1",
396
396
  "@dnd-kit/sortable": "^10.0.0",
@@ -477,7 +477,7 @@
477
477
  "@fontsource-variable/inter": "^5",
478
478
  "@fortawesome/fontawesome-free": "7.3.1",
479
479
  "@nxgt/material-testing": "0.0.0",
480
- "@nxgt/playwright": "^0.12.0",
480
+ "@nxgt/playwright": "^0.17.0",
481
481
  "@react-leaflet/core": "^3.0.0",
482
482
  "@react-pdf/renderer": "^4.9.0",
483
483
  "@storybook/addon-a11y": "10.6.0",