@nxgt/material 3.70.0 → 3.72.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 (151) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +9 -6
  3. package/dist/{alert-dialog-CBkWG32g.js → alert-dialog-A8K8zai1.js} +1 -1
  4. package/dist/{async-slice-CNZ3N55P.js → async-slice-B8933IHY.js} +1 -1
  5. package/dist/{button-D3qzqDY_.js → button-C8moFnIT.js} +1 -1
  6. package/dist/charts.js +3 -3
  7. package/dist/{chip-CMTe4sQd.js → chip-B6AY1E91.js} +2 -2
  8. package/dist/{code-editor-Cs7mz1J-.js → code-editor-DQZIKL54.js} +5 -5
  9. package/dist/code-editor.js +5 -5
  10. package/dist/{code-language-items-D_QMgjVy.js → code-language-items-8VL0aMKG.js} +2 -2
  11. package/dist/components/ui/collections/server-table/server-table-phone-row.css +6 -0
  12. package/dist/components/ui/display/code/code-moonlight.css +37 -0
  13. package/dist/components/ui/fields/attributes/attribute-values-form/attribute-values-form.css +5 -0
  14. package/dist/{components-BbWcozcj.js → components-EHdmrvV4.js} +20862 -19924
  15. package/dist/components.js +28 -28
  16. package/dist/{dialog-B3BSdRci.js → dialog-WuLTwxkr.js} +5 -5
  17. package/dist/dnd.js +1 -1
  18. package/dist/{dropdown-menu-BaupOWgS.js → dropdown-menu-tadySeGH.js} +1 -1
  19. package/dist/editor.js +35 -35
  20. package/dist/{empty-state-B2Um5UpI.js → empty-state-ZYiFSSBQ.js} +2 -2
  21. package/dist/{field-blur-1XLyxRPr.js → field-blur-BYR0yE5L.js} +1 -1
  22. package/dist/{field-blur-context-XNvCDnMT.js → field-blur-context-bEhByoK-.js} +1 -1
  23. package/dist/{hooks-BU21Jpaa.js → hooks-GpwD8iDu.js} +2 -2
  24. package/dist/hooks.js +3 -3
  25. package/dist/{hover-card-Bvm3svX9.js → hover-card-BowaI_ra.js} +1 -1
  26. package/dist/i18n.js +3 -3
  27. package/dist/{icon-badge-wip9bfa2.js → icon-badge-B1B0Lg02.js} +3 -3
  28. package/dist/{icon-button-QwIeBTdw.js → icon-button-BbGU17cb.js} +1 -1
  29. package/dist/lib/components/ui/actions/fab/fab-dock-inset.d.ts +29 -0
  30. package/dist/lib/components/ui/actions/fab/fab-dock.d.ts +6 -1
  31. package/dist/lib/components/ui/collections/data-table/select-checkbox.d.ts +3 -2
  32. package/dist/lib/components/ui/collections/filter/use-filter-field-config.d.ts +3 -0
  33. package/dist/lib/components/ui/collections/index.d.ts +1 -0
  34. package/dist/lib/components/ui/collections/record-actions-menu/index.d.ts +2 -0
  35. package/dist/lib/components/ui/collections/record-actions-menu/record-actions-dialogs.d.ts +15 -0
  36. package/dist/lib/components/ui/collections/record-actions-menu/record-actions-menu.d.ts +72 -0
  37. package/dist/lib/components/ui/collections/record-actions-menu/record-actions-rules.d.ts +68 -0
  38. package/dist/lib/components/ui/collections/record-actions-menu/record-actions-words.d.ts +52 -0
  39. package/dist/lib/components/ui/collections/record-actions-menu/use-record-actions.d.ts +51 -0
  40. package/dist/lib/components/ui/collections/record-actions-menu/use-record-flight.d.ts +16 -0
  41. package/dist/lib/components/ui/collections/row-menu/row-menu-column.d.ts +4 -0
  42. package/dist/lib/components/ui/collections/row-menu/row-menu.d.ts +1 -1
  43. package/dist/lib/components/ui/collections/server-table/partials/server-table-band-classes.d.ts +7 -5
  44. package/dist/lib/components/ui/collections/server-table/partials/server-table-column-sorting.d.ts +7 -0
  45. package/dist/lib/components/ui/collections/server-table/types.d.ts +3 -1
  46. package/dist/lib/components/ui/display/markdown/markdown.d.ts +12 -1
  47. package/dist/lib/components/ui/display/markdown/markdown.utils.d.ts +2 -0
  48. package/dist/lib/components/ui/display/markdown/mermaid-csp-scope.d.ts +8 -0
  49. package/dist/lib/components/ui/display/markdown/mermaid-markup.d.ts +20 -0
  50. package/dist/lib/components/ui/display/markdown/partials/markdown-code.d.ts +5 -1
  51. package/dist/lib/components/ui/feedback/confirm-dialog/action-refusal.d.ts +24 -0
  52. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-alert.d.ts +17 -0
  53. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-description.d.ts +10 -0
  54. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-dialog.d.ts +24 -2
  55. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-refusal.d.ts +7 -0
  56. package/dist/lib/components/ui/feedback/confirm-dialog/index.d.ts +1 -0
  57. package/dist/lib/components/ui/feedback/confirm-dialog/use-confirm-action.d.ts +6 -0
  58. package/dist/lib/components/ui/feedback/index.d.ts +1 -0
  59. package/dist/lib/components/ui/feedback/stale-notice/index.d.ts +1 -0
  60. package/dist/lib/components/ui/feedback/stale-notice/stale-notice.d.ts +15 -0
  61. package/dist/lib/components/ui/fields/attributes/attribute-values-form-field-set/attribute-values-form-field-set.d.ts +5 -1
  62. package/dist/lib/components/ui/fields/contacts/contact-dialog.d.ts +8 -2
  63. package/dist/lib/components/ui/fields/contacts/contacts-dialog-form-field.d.ts +4 -1
  64. package/dist/lib/components/ui/fields/contacts/contacts-editor.d.ts +15 -2
  65. package/dist/lib/components/ui/fields/contacts/contacts-form-field.d.ts +6 -1
  66. package/dist/lib/components/ui/fields/contacts/logic/offered-types.d.ts +3 -0
  67. package/dist/lib/components/ui/fields/contacts/models.d.ts +2 -0
  68. package/dist/lib/components/ui/fields/contacts/partials/contact-fields.d.ts +4 -2
  69. package/dist/lib/components/ui/fields/contacts/partials/contact-groups.d.ts +4 -2
  70. package/dist/lib/components/ui/fields/contacts/partials/contact-row.d.ts +4 -2
  71. package/dist/lib/components/ui/fields/contacts/partials/phone-sheet.d.ts +4 -2
  72. package/dist/lib/components/ui/fields/contacts/partials/quick-add.d.ts +4 -2
  73. package/dist/lib/components/ui/fields/contacts/partials/row-actions.d.ts +3 -1
  74. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  75. package/dist/lib/components/ui/forms/index.d.ts +1 -0
  76. package/dist/lib/components/ui/forms/use-server-field-errors.d.ts +21 -0
  77. package/dist/lib/components/ui/layout/index.d.ts +1 -0
  78. package/dist/lib/components/ui/layout/record-page/index.d.ts +2 -0
  79. package/dist/lib/components/ui/layout/record-page/record-details.d.ts +40 -0
  80. package/dist/lib/components/ui/layout/record-page/record-page.d.ts +27 -0
  81. package/dist/lib/components/ui/media/upload/network-upload-field/network-upload-field.d.ts +5 -0
  82. package/dist/lib/components/ui/media/upload/network-upload-field/partials/network-upload-field-items.d.ts +2 -1
  83. package/dist/lib/components/ui/media/upload/network-upload-field/upload-constraints.d.ts +10 -2
  84. package/dist/lib/components/ui/overlays/dialog/dialog-body-overflow.d.ts +7 -0
  85. package/dist/lib/components/ui/overlays/dialog/dialog-body.d.ts +10 -0
  86. package/dist/lib/components/ui/overlays/dialog/dialog-variants.d.ts +4 -0
  87. package/dist/lib/components/ui/overlays/dialog/dialog.d.ts +1 -0
  88. package/dist/lib/components/ui/widgets/chat/chat-conversation-item.d.ts +8 -2
  89. package/dist/lib/components/ui/widgets/chat/chat-markdown.d.ts +4 -0
  90. package/dist/lib/components/ui/widgets/chat/chat-message-list.d.ts +8 -1
  91. package/dist/lib/components/ui/widgets/chat/index.d.ts +2 -0
  92. package/dist/lib/components/ui/widgets/chat/partials/chat-conversation-item-text.d.ts +2 -1
  93. package/dist/lib/components/ui/widgets/chat/partials/chat-empty-thread.d.ts +2 -0
  94. package/dist/lib/components/ui/widgets/chat/proposal/chat-action-proposal-parts.d.ts +24 -0
  95. package/dist/lib/components/ui/widgets/chat/proposal/chat-action-proposal.d.ts +39 -0
  96. package/dist/lib/components/ui/widgets/chat/proposal/chat-action-proposal.rules.d.ts +17 -0
  97. package/dist/lib/components/ui/widgets/chat/proposal/chat-tool-activity.d.ts +16 -0
  98. package/dist/lib/i18n/resources/en/en.d.ts +47 -0
  99. package/dist/lib/i18n/resources/en/material.json.d.ts +47 -0
  100. package/dist/lib/i18n/resources/fr/fr.d.ts +47 -0
  101. package/dist/lib/i18n/resources/fr/material.json.d.ts +47 -0
  102. package/dist/lib/i18n/resources/resources.d.ts +94 -0
  103. package/dist/lib/i18n/translator.d.ts +1 -1
  104. package/dist/lib/print/output/to-pdf-element.d.ts +6 -0
  105. package/dist/lib.js +1 -1
  106. package/dist/main.js +42 -42
  107. package/dist/map.js +8 -8
  108. package/dist/material.css +1 -1
  109. package/dist/pdf-reader.js +1 -1
  110. package/dist/print.js +135 -131
  111. package/dist/{public-BuGgOtAl.js → public-CFj2qn7l.js} +9 -9
  112. package/dist/{rich-code-block-DdHqzzek.js → rich-code-block-B7Teg7-e.js} +5 -5
  113. package/dist/{sortable-provider-DMyaSfZZ.js → sortable-provider-y5sFhRDj.js} +2 -2
  114. package/dist/{spinner-ByYdcukU.js → spinner-C5Kb6MWu.js} +1 -1
  115. package/dist/theme-picker.js +2 -2
  116. package/dist/{theme-toggle-DB3aZZnO.js → theme-toggle-B1JZg7mU.js} +1 -1
  117. package/dist/{toolbar-items-DbzIKjo7.js → toolbar-items-m_1FTFPQ.js} +3 -3
  118. package/dist/{translate-material-Dh7MYkHT.js → translate-material-D1ndrd7a.js} +1 -1
  119. package/dist/{translator-Byhohi1S.js → translator-CtEC_AQa.js} +94 -0
  120. package/dist/{typography-rUf0mE5a.js → typography-prQHb3gI.js} +1 -1
  121. package/dist/{use-chat-composer-uUUTRB3Z.js → use-chat-composer-DBiyNXvL.js} +107 -107
  122. package/dist/{use-heading-spy-CVzW2NM3.js → use-heading-spy-Bzj5mIUZ.js} +179 -87
  123. package/dist/{use-material-translation-BAYyZOcH.js → use-material-translation-C6H0B4kE.js} +1 -1
  124. package/dist/{use-return-focus-CQAuk9kh.js → use-return-focus-CkUX1HFl.js} +1 -1
  125. package/docs/components/buttons-and-actions.md +24 -0
  126. package/docs/components/data-display.md +33 -0
  127. package/docs/components/data-table-filter-and-lists.md +117 -5
  128. package/docs/components/feedback-and-status.md +58 -2
  129. package/docs/components/form-fields.md +63 -3
  130. package/docs/components/media-and-files.md +4 -1
  131. package/docs/components/navigation-and-layout.md +58 -0
  132. package/docs/components/overlays-and-menus.md +20 -1
  133. package/docs/components/rich-widgets.md +35 -2
  134. package/docs/guides/cards-and-tiles.md +4 -2
  135. package/docs/guides/csp.md +44 -6
  136. package/docs/guides/forms.md +59 -7
  137. package/docs/guides/i18n.md +7 -6
  138. package/docs/guides/printing.md +17 -7
  139. package/docs/previews/data-table-filter-lists-recordactionsmenu.webp +0 -0
  140. package/docs/previews/feedback-status-stalenotice.webp +0 -0
  141. package/docs/previews/media-files-networkuploadfield.webp +0 -0
  142. package/docs/previews/media-files-s3uploadfield.webp +0 -0
  143. package/docs/previews/media-files-uploadfield.webp +0 -0
  144. package/docs/previews/navigation-layout-recordpage.webp +0 -0
  145. package/docs/previews/rich-widgets-chat-action-proposal.webp +0 -0
  146. package/docs/roadmap.md +11 -1
  147. package/docs/troubleshooting.md +126 -8
  148. package/lib/components/ui/collections/server-table/server-table-phone-row.css +6 -0
  149. package/lib/components/ui/display/code/code-moonlight.css +37 -0
  150. package/lib/components/ui/fields/attributes/attribute-values-form/attribute-values-form.css +5 -0
  151. package/package.json +3 -2
@@ -13,5 +13,10 @@ export type FabDockProps = ComponentProps<'div'> & {
13
13
  * (`env(safe-area-inset-bottom)`) and above a docked bar that sets
14
14
  * `--nxgt-media-dock` (0 otherwise). Several FABs stack, the main one last.
15
15
  * While an expressive `FabMenu` in it is open, a light scrim covers the page.
16
+ *
17
+ * While a viewport dock shows its button it sets `--fab-dock-inset` on the
18
+ * document: the space the button covers at the end of the page. Pad the
19
+ * scroller with `padding-block-end: var(--fab-dock-inset, 0px)`. The
20
+ * property is removed where the dock is hidden (`display: none`).
16
21
  */
17
- export declare function FabDock({ contained, className, ...props }: FabDockProps): import("react").JSX.Element;
22
+ export declare function FabDock({ contained, className, ref, ...props }: FabDockProps): import("react").JSX.Element;
@@ -16,8 +16,9 @@ export declare const SELECT_CHECKBOX_CLASS = "relative before:absolute before:to
16
16
  export declare const SELECT_CHECKBOX_LABEL_CLASS = "ms-2 me-3 flex w-fit items-center justify-center pointer-coarse:size-11 pointer-coarse:-ms-1 pointer-coarse:me-2 pointer-coarse:-my-2";
17
17
  /** The same label with its text beside the box (`SelectAllCheckbox`'s
18
18
  * `visibleLabel`): on a coarse pointer it is as tall and at least as wide as
19
- * the 44px box, the text inside it, so a tap on the words toggles the box. */
20
- export declare const SELECT_CHECKBOX_LABELLED_CLASS = "ms-2 me-3 flex w-fit items-center gap-2 pointer-coarse:min-h-11 pointer-coarse:min-w-11 pointer-coarse:-ms-1 pointer-coarse:me-2 pointer-coarse:-my-2 pointer-coarse:ps-3.5 pointer-coarse:pe-2";
19
+ * the 44px box, the text inside it, so a tap on the words toggles the box. It
20
+ * shrinks with its row, the text truncating (#2168). */
21
+ export declare const SELECT_CHECKBOX_LABELLED_CLASS = "ms-2 me-3 flex w-fit max-w-full min-w-0 items-center gap-2 pointer-coarse:min-h-11 pointer-coarse:min-w-11 pointer-coarse:-ms-1 pointer-coarse:me-2 pointer-coarse:-my-2 pointer-coarse:ps-3.5 pointer-coarse:pe-2";
21
22
  /** The `select` column's header: disabled while the table loads, when the
22
23
  * rows it would select are inert, and when no row on the page can be
23
24
  * selected (`enableRowSelection`). Its state counts only selectable rows. */
@@ -4877,6 +4877,7 @@ export declare function useFilterFieldConfig({ field, value, onChange, error, di
4877
4877
  maxSize?: number | undefined;
4878
4878
  helperText?: import('react').ReactNode;
4879
4879
  onRemove?: ((value: string) => void | Promise<void>) | undefined;
4880
+ acceptLabel?: string | undefined;
4880
4881
  maxFiles?: number | undefined;
4881
4882
  resolveUrl?: ((value: string) => string | null | undefined) | undefined;
4882
4883
  onUpload: (file: File, onProgress?: (percent: number) => void, signal?: AbortSignal) => Promise<string>;
@@ -5211,6 +5212,7 @@ export declare function useFilterFieldConfig({ field, value, onChange, error, di
5211
5212
  error?: boolean;
5212
5213
  disabled?: boolean;
5213
5214
  accept?: string;
5215
+ acceptLabel?: string;
5214
5216
  maxSize?: number;
5215
5217
  maxFiles?: number;
5216
5218
  onUpload: (file: File, onProgress?: (percent: number) => void, signal?: AbortSignal) => Promise<string>;
@@ -5508,6 +5510,7 @@ export declare function useFilterFieldConfig({ field, value, onChange, error, di
5508
5510
  error?: boolean;
5509
5511
  disabled?: boolean;
5510
5512
  accept?: string;
5513
+ acceptLabel?: string;
5511
5514
  maxSize?: number;
5512
5515
  maxFiles?: number;
5513
5516
  onUpload: (file: File, onProgress?: (percent: number) => void, signal?: AbortSignal) => Promise<string>;
@@ -8,6 +8,7 @@ export * from './list-empty/index.js';
8
8
  export * from './list-pane/index.js';
9
9
  export * from './page-footer/index.js';
10
10
  export * from './pagination/index.js';
11
+ export * from './record-actions-menu/index.js';
11
12
  export * from './row-menu/index.js';
12
13
  export * from './server-table/index.js';
13
14
  export * from './tree/index.js';
@@ -0,0 +1,2 @@
1
+ export * from './record-actions-menu.js';
2
+ export * from './use-record-actions.js';
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ import { ConfirmRefusalContext } from '../../feedback/confirm-dialog/confirm-dialog.js';
3
+ import { ArchivePolicy, RecordConsequence } from './record-actions-rules.js';
4
+ import { useRecordActions } from './use-record-actions.js';
5
+ /**
6
+ * The confirm dialogs of `RecordActionsMenu`: archive (under `'confirm'`) and
7
+ * delete. They stay mounted while open, even once the record's state no
8
+ * longer offers their action, so closing returns the focus to the trigger.
9
+ */
10
+ export declare function RecordActionsDialogs({ actions, archivePolicy, consequence, refusal, }: {
11
+ actions: ReturnType<typeof useRecordActions>;
12
+ archivePolicy: ArchivePolicy;
13
+ consequence?: RecordConsequence;
14
+ refusal?: (refusal: ConfirmRefusalContext) => ReactNode;
15
+ }): import("react").JSX.Element;
@@ -0,0 +1,72 @@
1
+ import { ReactNode } from 'react';
2
+ import { ConfirmRefusalContext } from '../../feedback/confirm-dialog/confirm-dialog.js';
3
+ import { RowMenuItem, RowMenuTriggerAttrs } from '../row-menu/row-menu.js';
4
+ import { ArchivePolicy, RecordConsequence, RecordIntent, RecordSuccessActions } from './record-actions-rules.js';
5
+ import { RecordActionsMessages } from './use-record-actions.js';
6
+ export type { ArchivePolicy, ConsequenceIntent, RecordConsequence, RecordIntent, RecordSuccessActions, } from './record-actions-rules.js';
7
+ export type { RecordActionsMessages } from './use-record-actions.js';
8
+ export type RecordActionsMenuProps = {
9
+ /** What the record is called: the button's name ("Actions for {name}"), the toasts' and the dialog's text. */
10
+ name: string;
11
+ /** `true` offers Restore, then Delete permanently; `false` offers Archive. */
12
+ archived: boolean;
13
+ /** Whether the user may do an action; the ones refused are left out. Everything by default. */
14
+ can?: (intent: RecordIntent) => boolean;
15
+ /**
16
+ * How Archive goes: `'undo'` (default) archives at once with an Undo toast;
17
+ * `'confirm'` asks in a dialog first, and its success toast has no Undo.
18
+ */
19
+ archivePolicy?: ArchivePolicy;
20
+ /**
21
+ * A note of what the action entails, shown in the confirm dialog (delete,
22
+ * and archive under `'confirm'`): one for all, or one per intent.
23
+ */
24
+ consequence?: RecordConsequence;
25
+ /**
26
+ * An action on the success toast of an archive or a restore, such as a
27
+ * "View archive" link. Beside Undo it is shown in the toast's text.
28
+ */
29
+ successAction?: RecordSuccessActions;
30
+ /**
31
+ * Does the action. A rejection's message is shown in a toast for archive
32
+ * and restore, and inside the dialog for delete (and a confirmed archive).
33
+ * Reject with an `ActionRefusal` to add an action to that message.
34
+ */
35
+ send: (intent: RecordIntent) => Promise<unknown>;
36
+ /**
37
+ * Runs once an action succeeded (after an archive's Undo too, with
38
+ * `'restore'`): refresh a list, or leave a deleted record's route.
39
+ */
40
+ onDone?: (intent: RecordIntent) => void;
41
+ /** Items of your own, before the record's actions. */
42
+ items?: RowMenuItem[];
43
+ /** Menu content of your own (submenus, groups), above `items`. */
44
+ children?: ReactNode;
45
+ /** Wording overrides, for grammatical agreement; `{name}` is the record's name. */
46
+ messages?: RecordActionsMessages;
47
+ /**
48
+ * Renders a refusal inside the delete dialog and the archive dialog
49
+ * (`archivePolicy="confirm"`), instead of `ConfirmDialog`'s default (the
50
+ * message, and the `ActionRefusal`'s details and action when it has them).
51
+ */
52
+ refusal?: (refusal: ConfirmRefusalContext) => ReactNode;
53
+ /** As `RowMenu`'s. */
54
+ rowId?: string;
55
+ triggerProps?: RowMenuTriggerAttrs;
56
+ className?: string;
57
+ };
58
+ /**
59
+ * The archive / restore / delete menu of a record, over `RowMenu`.
60
+ *
61
+ * - Archive runs at once and shows a toast with an Undo action that stays
62
+ * until dismissed; Undo restores.
63
+ * - With `archivePolicy="confirm"` Archive asks first and leaves no Undo.
64
+ * - Restore runs at once.
65
+ * - Delete permanently is offered only for an archived record, after a
66
+ * separator, in the error colour, and always asks first; a refusal stays in
67
+ * the dialog, whose confirm button is then locked.
68
+ *
69
+ * It renders nothing when `can` leaves no action and there is no item of
70
+ * your own.
71
+ */
72
+ export declare function RecordActionsMenu({ name, archived, can, send, onDone, items, children, messages, refusal, archivePolicy, consequence, successAction, rowId, triggerProps, className, }: RecordActionsMenuProps): import("react").JSX.Element | null;
@@ -0,0 +1,68 @@
1
+ import { ReactNode } from 'react';
2
+ import { RecordAction } from '../../feedback/confirm-dialog/action-refusal.js';
3
+ /** What a record's menu can do. */
4
+ export type RecordIntent = 'archive' | 'restore' | 'delete';
5
+ /** Whether Archive applies at once with an Undo toast, or asks first in a dialog. */
6
+ export type ArchivePolicy = 'undo' | 'confirm';
7
+ /** The actions a success toast offers, per intent (delete leaves no toast: the record is gone). */
8
+ export type RecordSuccessActions = Partial<Record<'archive' | 'restore', RecordAction>>;
9
+ /** The intents whose confirm dialog can carry a note (restore has no dialog). */
10
+ export type ConsequenceIntent = 'archive' | 'delete';
11
+ /** A note of what an action entails: one for every dialog, or one per intent (`archive`, `delete`). */
12
+ export type RecordConsequence = ReactNode | Partial<Record<ConsequenceIntent, ReactNode>>;
13
+ /**
14
+ * The note for `intent`: `consequence` itself, or its entry when it is a map
15
+ * of intents (a plain object, not a React element or an array).
16
+ */
17
+ export declare function consequenceFor(consequence: RecordConsequence, intent: ConsequenceIntent): ReactNode;
18
+ /** Which record actions the menu offers: an archived record is restored or deleted, any other archived. */
19
+ export declare function allowedIntents(archived: boolean, can?: (intent: RecordIntent) => boolean): RecordIntent[];
20
+ /** The message of a refusal, or `fallback` when it carries none. */
21
+ export declare function messageOf(thrown: unknown, fallback: string): string;
22
+ /** What the actions tell the user, apart from the delete dialog (which the dialog itself shows). */
23
+ export type RecordNotifier = {
24
+ /** The record is archived; `undo` restores it (absent when the archive was confirmed first). */
25
+ archived: (outcome: {
26
+ undo?: () => void;
27
+ action?: RecordAction;
28
+ }) => void;
29
+ restored: (action?: RecordAction) => void;
30
+ /** An archive, a restore or an undo was refused; `action` is the one the refusal carries. */
31
+ failed: (message: string, intent: RecordIntent, action?: RecordAction) => void;
32
+ };
33
+ export type RecordActionsDeps = {
34
+ send: (intent: RecordIntent) => Promise<unknown>;
35
+ onDone?: (intent: RecordIntent) => void;
36
+ notify: RecordNotifier;
37
+ /** `'confirm'` archives only after the user confirmed: no Undo then. */
38
+ archivePolicy?: ArchivePolicy;
39
+ successAction?: RecordSuccessActions;
40
+ /**
41
+ * Runs the Undo through the caller's flight (so the menu is busy
42
+ * meanwhile); the Undo runs on its own when absent. The task resolves
43
+ * `true` when the record was restored.
44
+ */
45
+ runUndo?: (task: () => Promise<boolean>) => Promise<unknown>;
46
+ /** The text of a refusal that has no message. */
47
+ fallbackMessage: string;
48
+ /** Where a throwing `onDone` is reported. `console.error` by default. */
49
+ reportError?: (error: unknown) => void;
50
+ };
51
+ /** Runs `task` unless a previous one has not ended: a second call returns `undefined`. */
52
+ export declare function singleFlight(): <T>(task: () => Promise<T>) => Promise<T | undefined>;
53
+ /**
54
+ * The actions' logic, free of React. `archive` and `restore` run at once and
55
+ * tell the outcome through `notify`; `remove` lets a refusal throw so the
56
+ * confirm dialog shows it. `onDone` runs after the outcome is shown, and a
57
+ * throw of it is reported, never taken for a refusal.
58
+ */
59
+ export declare function createRecordActions(deps: RecordActionsDeps): {
60
+ /** Resolves `true` when the record was archived. */
61
+ archive(): Promise<boolean>;
62
+ /** The confirmed archive: a refusal throws, for the dialog to show. */
63
+ archiveConfirmed(): Promise<void>;
64
+ /** Resolves `true` when the record was restored. */
65
+ restore(): Promise<boolean>;
66
+ remove(): Promise<void>;
67
+ undo: () => Promise<void>;
68
+ };
@@ -0,0 +1,52 @@
1
+ import { RecordNotifier } from './record-actions-rules.js';
2
+ /**
3
+ * The words of a record's actions, for grammatical agreement in your
4
+ * language. `{name}` is replaced by the record's name. Anything left out is
5
+ * the translated `material.record-actions.*` default.
6
+ */
7
+ export type RecordActionsMessages = Partial<{
8
+ /** Menu items. */
9
+ archive: string;
10
+ restore: string;
11
+ delete: string;
12
+ /** Toasts: "{name} archived", "{name} restored", the Undo button, a refused action. */
13
+ archived: string;
14
+ restored: string;
15
+ undo: string;
16
+ failed: string;
17
+ /** The archive dialog (`archivePolicy="confirm"`). */
18
+ archiveTitle: string;
19
+ archiveDescription: string;
20
+ archiveConfirm: string;
21
+ /** The delete dialog. */
22
+ deleteTitle: string;
23
+ deleteDescription: string;
24
+ deleteConfirm: string;
25
+ }>;
26
+ /** The words of the menu, the dialog and the toasts, from `messages` or the translated defaults. */
27
+ export declare function useRecordWords(name: string, messages?: RecordActionsMessages): {
28
+ text: {
29
+ archive: string;
30
+ restore: string;
31
+ delete: string;
32
+ archiveTitle: string;
33
+ archiveDescription: string;
34
+ archiveConfirm: string;
35
+ deleteTitle: string;
36
+ deleteDescription: string;
37
+ deleteConfirm: string;
38
+ };
39
+ toastText: {
40
+ archived: string;
41
+ restored: string;
42
+ undo: string;
43
+ failed: string;
44
+ };
45
+ };
46
+ export type RecordToastText = ReturnType<typeof useRecordWords>['toastText'];
47
+ /**
48
+ * The outcome toasts. A toast has one button: the archive's is Undo, and a
49
+ * success action then goes in the description as a link; without Undo (or for
50
+ * a restore or a refusal) the action is the toast's button.
51
+ */
52
+ export declare function toastNotifier(toastText: RecordToastText): RecordNotifier;
@@ -0,0 +1,51 @@
1
+ import { ArchivePolicy, RecordIntent, RecordSuccessActions } from './record-actions-rules.js';
2
+ import { RecordActionsMessages } from './record-actions-words.js';
3
+ export type { RecordActionsMessages } from './record-actions-words.js';
4
+ export type UseRecordActionsOptions = {
5
+ name: string;
6
+ archived: boolean;
7
+ can?: (intent: RecordIntent) => boolean;
8
+ send: (intent: RecordIntent) => Promise<unknown>;
9
+ onDone?: (intent: RecordIntent) => void;
10
+ messages?: RecordActionsMessages;
11
+ /** `'confirm'` asks in a dialog before archiving, with no Undo. Default `'undo'`. */
12
+ archivePolicy?: ArchivePolicy;
13
+ /** An action on the success toast of an archive or a restore. */
14
+ successAction?: RecordSuccessActions;
15
+ };
16
+ /**
17
+ * The logic of `RecordActionsMenu`: which actions are offered, the running
18
+ * one, the dialogs' state and the words. Archive and restore run at
19
+ * once and report through toasts (an archive's Undo stays until dismissed);
20
+ * delete goes through the confirm dialog, whose `onConfirm` is `deleteConfirmed`.
21
+ */
22
+ export declare function useRecordActions({ name, archived, can, send, onDone, messages, archivePolicy, successAction, }: UseRecordActionsOptions): {
23
+ intents: RecordIntent[];
24
+ running: ("archive" | "restore") | null;
25
+ /** The delete dialog's open state. */
26
+ confirmingDelete: boolean;
27
+ setConfirmingDelete: import('react').Dispatch<import('react').SetStateAction<boolean>>;
28
+ /** The archive dialog's open state (`archivePolicy="confirm"`). */
29
+ confirmingArchive: boolean;
30
+ setConfirmingArchive: import('react').Dispatch<import('react').SetStateAction<boolean>>;
31
+ /** Archives the first time `archive` is chosen: asks first under `'confirm'`, else runs at once. */
32
+ chooseArchive: () => void;
33
+ run: (intent: "archive" | "restore") => Promise<void>;
34
+ /** The archive toast's Undo: restores through the same single flight, so `running` is set meanwhile. */
35
+ runUndo: () => Promise<void>;
36
+ /** The archive dialog's `onConfirm`: sends `archive`, throws a refusal. */
37
+ archiveConfirmed: () => Promise<void>;
38
+ /** The delete dialog's `onConfirm`: sends `delete`, throws a refusal. */
39
+ deleteConfirmed: () => Promise<void>;
40
+ text: {
41
+ archive: string;
42
+ restore: string;
43
+ delete: string;
44
+ archiveTitle: string;
45
+ archiveDescription: string;
46
+ archiveConfirm: string;
47
+ deleteTitle: string;
48
+ deleteDescription: string;
49
+ deleteConfirm: string;
50
+ };
51
+ };
@@ -0,0 +1,16 @@
1
+ type Flight = 'archive' | 'restore';
2
+ /**
3
+ * The record's one action in flight: an archive, a restore or an Undo. A
4
+ * second archive or restore started while one is pending is ignored;
5
+ * `running` names the pending one. An Undo is queued instead: it runs once the
6
+ * pending action ends, and only if the record is archived by then, as the
7
+ * settled outcomes tell (a failed archive or a successful restore leaves
8
+ * nothing to undo): the hook owns that state, so a late update of `archived`
9
+ * does not matter. Another Undo while one waits or runs is ignored.
10
+ */
11
+ export declare function useRecordFlight(archived: boolean): {
12
+ running: Flight | null;
13
+ inFlight: (intent: Flight, task: () => Promise<unknown>) => Promise<void | undefined>;
14
+ runUndo: (task: () => Promise<boolean>) => Promise<void>;
15
+ };
16
+ export {};
@@ -19,6 +19,10 @@ export type RowMenuColumnOptions<T extends RowData> = {
19
19
  * (`material.row-menu.column`). Call it once, outside the render (or in a
20
20
  * `useMemo`), so the cells keep their identity and a dialog opened from an
21
21
  * item is not remounted with the table.
22
+ *
23
+ * A row whose `items(row)` is empty (or absent) and whose `menu(row)` is
24
+ * `null`, `undefined` or `false` (`cond && <X />`) renders nothing in its cell;
25
+ * the column keeps its width. A fragment counts as content, even an empty one.
22
26
  */
23
27
  export declare function rowMenuColumn<T extends RowData>({ label, items, menu, id, className, }: RowMenuColumnOptions<T>): import('@tanstack/table-core').DisplayColumnDef<{
24
28
  columnFilteringFeature: import('@tanstack/table-core').TableFeature;
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { RowMenuTriggerProps } from './row-menu-trigger.js';
3
- /** One action of a `RowMenu`. */
3
+ /** One action of a `RowMenu`. When any item has an `icon`, those without one are inset to keep the labels aligned. */
4
4
  export type RowMenuItem = {
5
5
  /** The key; the label when it is a string. */
6
6
  id?: string;
@@ -15,13 +15,15 @@ export declare const SERVER_TABLE_SEARCH_INLINE_CLASS = "max-md:order-none max-m
15
15
  /** Below 768px with a list in cards or tiles (#1719): the band's second row,
16
16
  * after the search's (both are `order-last`, the DOM order breaks the tie):
17
17
  * the list bar's start group (the room left), then the sort, "Filters (N)"
18
- * and the page's actions. */
19
- export declare const SERVER_TABLE_PHONE_ROW_CLASS = "order-last flex min-w-0 basis-full items-center gap-1 md:hidden";
20
- /** The row's start slot: "Select all", or the count and "Clear selection". */
21
- export declare const SERVER_TABLE_PHONE_ROW_START_CLASS = "min-w-0 flex-1";
18
+ * and the page's actions. The row wraps: wide actions drop to a line of their own
19
+ * (#2168) rather than crushing the start group. */
20
+ export declare const SERVER_TABLE_PHONE_ROW_CLASS = "order-last flex min-w-0 basis-full flex-wrap items-center gap-1 md:hidden";
21
+ /** The row's start slot: "Select all", or the count and "Clear selection".
22
+ * Never under 6rem (the box and a clipped label); a wider end wraps below. */
23
+ export declare const SERVER_TABLE_PHONE_ROW_START_CLASS = "min-w-24 flex-1";
22
24
  /** The row's end: the sort slot (`contents`, its child is the item), then
23
25
  * "Filters (N)" and the actions. */
24
- export declare const SERVER_TABLE_PHONE_ROW_END_CLASS = "flex shrink-0 items-center gap-1";
26
+ export declare const SERVER_TABLE_PHONE_ROW_END_CLASS = "flex max-w-full shrink-0 items-center gap-1";
25
27
  /** The bar's search floor in the band: from md the band lowers it to 8rem,
26
28
  * though `SERVER_TABLE_BAR_CLASS` (shared with Vue, so left as is) says 10rem:
27
29
  * the search gives up that much more room before "Add filter" wraps alone to
@@ -0,0 +1,7 @@
1
+ import { RowData } from '@tanstack/react-table';
2
+ import { DataTableProps } from '../../data-table/types.js';
3
+ type Columns<T extends RowData> = DataTableProps<T>['columns'];
4
+ /** Without `sorting` the URL holds no sort, so no column offers one (neither
5
+ * the header's menu nor the cards' sort band), unless it sets `enableSorting`. */
6
+ export declare function defaultColumnSorting<T extends RowData>(columns: Columns<T>, hasSorting: boolean): Columns<T>;
7
+ export {};
@@ -35,7 +35,9 @@ export type ServerTableProps<T extends RowData> = PassedThrough<T> & ServerTable
35
35
  pageSize: number;
36
36
  /** A row's id: the selection's key. */
37
37
  getRowId: (row: T) => string;
38
- /** `createSorting(...)`: the headers' sort, read from and written to the URL. */
38
+ /** `createSorting(...)`: the headers' sort, read from and written to the URL.
39
+ * Without it, no column is sortable (the server sorts, so pass `sorting`
40
+ * to let people sort), and the phone list bar shows only for selection. */
39
41
  sorting?: Pick<TableSorting, 'readSort' | 'withSort'>;
40
42
  /** The list's Filter, in the band and in the URL. */
41
43
  filter?: ServerTableFilter;
@@ -3,5 +3,16 @@ import { EmojiItem } from '../../widgets/emoji/types.js';
3
3
  export type MarkdownProps = {
4
4
  children: string;
5
5
  emojis?: EmojiItem[];
6
+ /**
7
+ * Render `$...$` and `$$...$$` with KaTeX. Default `true`. Under a strict CSP
8
+ * it needs nothing on a client render; server-rendered math needs
9
+ * `style-src-attr 'unsafe-inline'` (csp.md).
10
+ */
11
+ math?: boolean;
12
+ /**
13
+ * Draw ```` ```mermaid ```` fences as diagrams. Default `true`. Off, they
14
+ * show as code blocks and `mermaid` is never loaded.
15
+ */
16
+ mermaid?: boolean;
6
17
  } & Omit<ComponentProps<'div'>, 'children'>;
7
- export declare function Markdown({ children, emojis, className, ...props }: MarkdownProps): import("react").JSX.Element;
18
+ export declare function Markdown({ children, emojis, math, mermaid, className, ...props }: MarkdownProps): import("react").JSX.Element;
@@ -1 +1,3 @@
1
1
  export declare function sanitizeHref(href: string | undefined): string | null;
2
+ /** An absolute `http(s):` or protocol-relative URL: it leaves the page. */
3
+ export declare function isExternalHref(href: string): boolean;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Opens the scope of the render of diagram `id` (the id given to
3
+ * `mermaid.render`). Returns its `end`, safe to call more than once: call it
4
+ * when the render settles and when the component unmounts.
5
+ */
6
+ export declare function beginMermaidScope(id: string, nonce: string | undefined): () => void;
7
+ /** Runs `render` inside the scope of diagram `id`. */
8
+ export declare function withMermaidCspScope<T>(id: string, nonce: string | undefined, render: () => Promise<T>): Promise<T>;
@@ -0,0 +1,20 @@
1
+ /** The name `style` is parked under while a strict CSP would report it. */
2
+ export declare const PARKED_STYLE = "data-nxgt-style";
3
+ /** Renames the attribute `from` to `to` in every start tag of `markup`. */
4
+ export declare function renameAttribute(markup: string, from: string, to: string): string;
5
+ /** `style` attributes parked, so parsing the markup reports nothing. */
6
+ export declare function parkStyles(markup: string): string;
7
+ /** The reverse, for the sanitised SVG that becomes an image. */
8
+ export declare function unparkStyles(markup: string): string;
9
+ /**
10
+ * mermaid serialises its labels as HTML (`<img src=…>`), which is not
11
+ * well-formed XML: as an image the SVG would not load. Self-closes the void
12
+ * elements, drops `<img>` and unparks the `style` attributes.
13
+ */
14
+ export declare function toImageSvg(markup: string): string;
15
+ /**
16
+ * An `<img>` in a label: mermaid draws the diagram in the page first, where the
17
+ * request would go out (and be reported by `img-src`), and the final image
18
+ * could not show it. Removed from the source before the render.
19
+ */
20
+ export declare function stripChartImages(chart: string): string;
@@ -1,2 +1,6 @@
1
1
  import { ComponentPropsWithoutRef } from 'react';
2
- export declare function MarkdownCode({ className, children, ...props }: ComponentPropsWithoutRef<'code'>): import("react").JSX.Element;
2
+ export declare function MarkdownCodeNoMermaid(props: ComponentPropsWithoutRef<'code'>): import("react").JSX.Element;
3
+ export declare function MarkdownCode({ className, children, mermaid, node: _node, ...props }: ComponentPropsWithoutRef<'code'> & {
4
+ mermaid?: boolean;
5
+ node?: unknown;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { ReactNode } from 'react';
2
+ /** An action offered beside a message: a link (`href`, a full page load) or a handler (`onAction`, for client-side navigation), with its label. `onAction` wins when both are given. */
3
+ export type RecordAction = {
4
+ label: string;
5
+ href?: string;
6
+ onAction?: () => void;
7
+ };
8
+ /**
9
+ * A refusal that carries an action ("Remove the 3 invoices", "View what
10
+ * blocks it") and optional details. An `onConfirm` (or a record action's `send`) rejects with it; a plain
11
+ * `Error` keeps showing its message only.
12
+ */
13
+ export declare class ActionRefusal extends Error {
14
+ readonly action: RecordAction;
15
+ readonly details?: ReactNode;
16
+ constructor(message: string, options: {
17
+ action: RecordAction;
18
+ details?: ReactNode;
19
+ });
20
+ }
21
+ /** Whether `thrown` is an `ActionRefusal` (also one from another copy of the package). */
22
+ export declare function isActionRefusal(thrown: unknown): thrown is ActionRefusal;
23
+ /** The action a refusal carries, if any. */
24
+ export declare function refusalActionOf(thrown: unknown): RecordAction | undefined;
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ /** What `ConfirmDialog`'s `refusal` receives when `onConfirm` has refused. */
3
+ export interface ConfirmRefusalContext {
4
+ /** The thrown error's message, or the translated `material.confirm-dialog.failed` text. */
5
+ message: string;
6
+ /** What `onConfirm` threw. */
7
+ cause: unknown;
8
+ /** Closes the dialog, so a link in the refusal can dismiss it on navigation. */
9
+ close: () => void;
10
+ }
11
+ /**
12
+ * The error alert of a refused confirm: the message, or what `refusal` makes
13
+ * of it.
14
+ */
15
+ export declare function ConfirmAlert({ message, cause, close, refusal, }: ConfirmRefusalContext & {
16
+ refusal?: (refusal: ConfirmRefusalContext) => ReactNode;
17
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * What describes a confirm dialog (`aria-describedby`): the description and
4
+ * the `details` note. A plain string alone is a paragraph; block content or a
5
+ * note goes in a `div`, so block children are valid HTML.
6
+ */
7
+ export declare function ConfirmDescription({ children, details, }: {
8
+ children: ReactNode;
9
+ details?: ReactNode;
10
+ }): import("react").JSX.Element;
@@ -1,9 +1,23 @@
1
+ import { ReactNode } from 'react';
1
2
  import { ButtonVariant } from '../../actions/button/button.js';
3
+ import { ConfirmRefusalContext } from './confirm-alert.js';
4
+ export type { ConfirmRefusalContext };
2
5
  export interface ConfirmDialogProps {
3
6
  open: boolean;
4
7
  onOpenChange: (open: boolean) => void;
5
8
  title: string;
6
- description: string;
9
+ /**
10
+ * The text under the title. A string renders in a paragraph; any other node
11
+ * (several paragraphs, a list, a link) renders in a `div`, so block children
12
+ * are valid HTML. Either way it names the dialog (`aria-describedby`).
13
+ */
14
+ description: ReactNode;
15
+ /**
16
+ * A note under the description, for what the user should know before
17
+ * confirming (what else is affected, what cannot be undone). It is part of
18
+ * what describes the dialog.
19
+ */
20
+ details?: ReactNode;
7
21
  confirmLabel?: string;
8
22
  cancelLabel?: string;
9
23
  /**
@@ -28,6 +42,14 @@ export interface ConfirmDialogProps {
28
42
  * dialog reopens. Off by default: the refused action may be retried.
29
43
  */
30
44
  lockOnRefusal?: boolean;
45
+ /**
46
+ * Renders the refusal inside the dialog's error alert instead of the plain
47
+ * message, so it can carry a link (to the records that block a delete, for
48
+ * example). Receives the message, what `onConfirm` threw and `close()`. The alert keeps `role="alert"`.
49
+ * By default an `ActionRefusal` thrown by `onConfirm` shows its details and
50
+ * its action under the message; any other error shows its message.
51
+ */
52
+ refusal?: (refusal: ConfirmRefusalContext) => ReactNode;
31
53
  /**
32
54
  * Called as the dialog closes, before the focus goes back to what opened
33
55
  * it. `event.preventDefault()` places the focus yourself, for example
@@ -36,4 +58,4 @@ export interface ConfirmDialogProps {
36
58
  */
37
59
  onCloseAutoFocus?: (event: Event) => void;
38
60
  }
39
- export declare function ConfirmDialog({ open, onOpenChange, title, description, confirmLabel, cancelLabel, cancelVariant, onConfirm, variant, loading, confirmDisabled, lockOnRefusal, onCloseAutoFocus, }: ConfirmDialogProps): import("react").JSX.Element;
61
+ export declare function ConfirmDialog({ open, onOpenChange, title, description, details, confirmLabel, cancelLabel, cancelVariant, onConfirm, variant, loading, confirmDisabled, lockOnRefusal, refusal, onCloseAutoFocus, }: ConfirmDialogProps): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { ConfirmRefusalContext } from './confirm-alert.js';
2
+ /**
3
+ * The default refusal of `ConfirmDialog`: the message, and for an
4
+ * `ActionRefusal` its details and its action. Any other error is its
5
+ * message alone.
6
+ */
7
+ export declare function ConfirmRefusal({ message, cause, close, }: ConfirmRefusalContext): import("react").JSX.Element;
@@ -1 +1,2 @@
1
+ export { ActionRefusal, isActionRefusal, type RecordAction, } from './action-refusal.js';
1
2
  export * from './confirm-dialog.js';
@@ -11,6 +11,12 @@ export declare function useConfirmAction({ open, onOpenChange, onConfirm, }: {
11
11
  }): {
12
12
  pending: boolean;
13
13
  error: string | null;
14
+ cause: unknown;
14
15
  handleOpenChange: (value: boolean) => void;
15
16
  handleConfirm: (event: MouseEvent<HTMLButtonElement>) => Promise<void>;
16
17
  };
18
+ /**
19
+ * A ref for a modal's content that takes the focus while `pending`: the
20
+ * buttons it disables would otherwise drop the focus to the page behind it.
21
+ */
22
+ export declare function useKeepFocusWhile(pending: boolean): import('react').RefObject<HTMLDivElement | null>;
@@ -18,6 +18,7 @@ export * from './progress/index.js';
18
18
  export * from './scroll-progress/index.js';
19
19
  export * from './skeleton/index.js';
20
20
  export * from './spinner/index.js';
21
+ export * from './stale-notice/index.js';
21
22
  export * from './step-dots/index.js';
22
23
  export * from './step-up-dialog/index.js';
23
24
  export * from './toast/index.js';
@@ -0,0 +1 @@
1
+ export * from './stale-notice.js';
@@ -0,0 +1,15 @@
1
+ export interface StaleNoticeProps {
2
+ /** Runs on "Reload the record": read the record again. */
3
+ onReload: () => void;
4
+ /** Shows the reload button as loading while the record is read again. */
5
+ busy?: boolean;
6
+ /** Replaces the description (translated by default). */
7
+ message?: string;
8
+ className?: string;
9
+ }
10
+ /**
11
+ * Another write came first (a `stale-version` refusal): what was typed stays,
12
+ * a warning alert takes the focus and scrolls into view when it mounts, and
13
+ * the only way out is to read the record again. There is no "overwrite".
14
+ */
15
+ export declare function StaleNotice({ onReload, busy, message, className, }: StaleNoticeProps): import("react").JSX.Element;