@nxgt/material 2.5.0 → 2.6.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 (115) hide show
  1. package/README.md +5 -7
  2. package/dist/{_Uint8Array-DuTT6911.js → _Uint8Array-CDlDeQmw.js} +1 -1
  3. package/dist/{_overRest-93z6TD9V.js → _overRest-CWIWQwDJ.js} +1 -1
  4. package/dist/{async-slice-B8Xv2BLH.js → async-slice-Qoen0Mqm.js} +2 -2
  5. package/dist/{blockDiagram-BEXU5L5S-C8UXdLfB.js → blockDiagram-BEXU5L5S-_6EVgQ2-.js} +2 -2
  6. package/dist/{chunk-3FUC2YCW-4gCRt6fO.js → chunk-3FUC2YCW-CRQHl-Jx.js} +2 -2
  7. package/dist/{chunk-7M6MHVWA-DnPXbiTM.js → chunk-7M6MHVWA-DqXpf6CM.js} +1 -1
  8. package/dist/{chunk-GNY47TPC-DLqgU2SJ.js → chunk-GNY47TPC-BgMsLbCS.js} +4 -4
  9. package/dist/{chunk-NETBCI7D-CBowDvwz.js → chunk-NETBCI7D-CsyH43bj.js} +1 -1
  10. package/dist/{chunk-Z7XXMR3K-dRJc1Z30.js → chunk-Z7XXMR3K-CoCjTVVx.js} +1 -1
  11. package/dist/{classDiagram-v2-NBCMYWYE-CQmePeL4.js → classDiagram-v2-NBCMYWYE-j4vk04t-.js} +2 -2
  12. package/dist/{components-CUkJhBwK.js → components-C3wIUrWw.js} +25959 -25227
  13. package/dist/components.js +5 -5
  14. package/dist/{dagre-6A5THRUB-BhyJENrD.js → dagre-6A5THRUB-DXq_YBNL.js} +54 -54
  15. package/dist/{diagram-22UHCM2B-CJc0JoTV.js → diagram-22UHCM2B-He8NDldw.js} +2 -2
  16. package/dist/{diagram-3UASUU5V-0P3Cnq5H.js → diagram-3UASUU5V-CeILva4U.js} +1 -1
  17. package/dist/dnd.js +1 -1
  18. package/dist/{elk-276RUBZZ-CvgDuHoY.js → elk-276RUBZZ-DFn4kTey.js} +3 -3
  19. package/dist/{erDiagram-OPXOYQCR-BFgRy8E9.js → erDiagram-OPXOYQCR-BzVUcUwh.js} +2 -2
  20. package/dist/{field-blur-D1eQk-49.js → field-blur-BlrE9fOD.js} +1 -1
  21. package/dist/{flowDiagram-KWPJA3E3-DGaa9iT2.js → flowDiagram-KWPJA3E3-B4pJCj2Q.js} +3 -3
  22. package/dist/{ganttDiagram-FUAMR5RP-CDGrtGHY.js → ganttDiagram-FUAMR5RP-B4A4UFFi.js} +1 -1
  23. package/dist/{graphlib-Dt-isUVV.js → graphlib-CQ3hLS1N.js} +6 -6
  24. package/dist/hooks.js +2 -2
  25. package/dist/{i18n-provider-Drsc2YXX.js → i18n-provider-CbYD2KxP.js} +1 -1
  26. package/dist/i18n.js +6 -6
  27. package/dist/{isArrayLikeObject-BhWbq65y.js → isArrayLikeObject-5rnYwEK7.js} +3 -3
  28. package/dist/{isEmpty-DdlzV8Ue.js → isEmpty-DChvniYe.js} +3 -3
  29. package/dist/{journeyDiagram-ZHPQQLJL-BuLKqWS3.js → journeyDiagram-ZHPQQLJL-C91SPPkY.js} +1 -1
  30. package/dist/lib/components/ui/collections/tree/use-tree.d.ts +2 -0
  31. package/dist/lib/components/ui/dates/date-range-field/date-range-field-trigger.d.ts +1 -1
  32. package/dist/lib/components/ui/dates/date-range-field/date-range-field.d.ts +10 -1
  33. package/dist/lib/components/ui/dates/date-range-field/date-range-field.utils.d.ts +13 -0
  34. package/dist/lib/components/ui/dates/date-range-field/index.d.ts +1 -0
  35. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-field-content.d.ts +25 -0
  36. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-presets.d.ts +11 -0
  37. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-times.d.ts +11 -0
  38. package/dist/lib/components/ui/dates/date-range-field/use-date-range-presets.d.ts +22 -0
  39. package/dist/lib/components/ui/dates/time-picker/time-picker-utils.d.ts +7 -0
  40. package/dist/lib/components/ui/fields/number-field/number-field.d.ts +3 -1
  41. package/dist/lib/components/ui/fields/slider/slider-header.d.ts +5 -1
  42. package/dist/lib/components/ui/fields/slider/slider-readout.d.ts +5 -1
  43. package/dist/lib/components/ui/media/file-preview/file-preview-pdf.lazy.d.ts +9 -0
  44. package/dist/lib/components/ui/media/file-preview/file-preview.d.ts +12 -0
  45. package/dist/lib/components/ui/media/file-preview/index.d.ts +3 -0
  46. package/dist/lib/components/ui/media/file-preview/partials/file-preview-body.d.ts +9 -0
  47. package/dist/lib/components/ui/media/file-preview/partials/file-preview-card.d.ts +20 -0
  48. package/dist/lib/components/ui/media/file-preview/partials/file-preview-media.d.ts +11 -0
  49. package/dist/lib/components/ui/media/file-preview/partials/file-preview-pdf.d.ts +10 -0
  50. package/dist/lib/components/ui/media/file-preview/partials/file-preview-status.d.ts +17 -0
  51. package/dist/lib/components/ui/media/file-preview/partials/file-preview-text.d.ts +13 -0
  52. package/dist/lib/components/ui/media/file-preview/types.d.ts +23 -0
  53. package/dist/lib/components/ui/media/file-preview/use-file-preview.d.ts +22 -0
  54. package/dist/lib/components/ui/media/file-preview/use-text-preview.d.ts +15 -0
  55. package/dist/lib/components/ui/media/index.d.ts +1 -0
  56. package/dist/lib/components/ui/media/upload/network-upload-field/use-image-preview.d.ts +6 -0
  57. package/dist/lib/components/ui/selection/index.d.ts +1 -0
  58. package/dist/lib/components/ui/selection/tree-select-field/index.d.ts +2 -0
  59. package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-content.d.ts +13 -0
  60. package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-panel.d.ts +19 -0
  61. package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-trigger.d.ts +24 -0
  62. package/dist/lib/components/ui/selection/tree-select-field/tree-select-field.d.ts +9 -0
  63. package/dist/lib/components/ui/selection/tree-select-field/tree-select-form-field.d.ts +8 -0
  64. package/dist/lib/components/ui/selection/tree-select-field/tree-select.utils.d.ts +35 -0
  65. package/dist/lib/components/ui/selection/tree-select-field/types.d.ts +37 -0
  66. package/dist/lib/components/ui/selection/tree-select-field/use-tree-select-field.d.ts +20 -0
  67. package/dist/lib/i18n/resources/en/en.d.ts +33 -0
  68. package/dist/lib/i18n/resources/en/material.json.d.ts +36 -3
  69. package/dist/lib/i18n/resources/fr/fr.d.ts +33 -0
  70. package/dist/lib/i18n/resources/fr/material.json.d.ts +36 -3
  71. package/dist/lib/i18n/resources/resources.d.ts +66 -0
  72. package/dist/lib/i18n/translator.d.ts +1 -1
  73. package/dist/lib.js +3 -3
  74. package/dist/main.js +15 -15
  75. package/dist/map.js +2 -2
  76. package/dist/material.css +1 -1
  77. package/dist/{merge-a7J0YkZX.js → merge-_Awk4ywA.js} +4 -4
  78. package/dist/{mermaid.core-CE34byhz.js → mermaid.core-DciYB1MV.js} +21 -21
  79. package/dist/{mindmap-definition-NLK3R4M7-emoij-nW.js → mindmap-definition-NLK3R4M7-Brf_2jIE.js} +2 -2
  80. package/dist/{pieDiagram-5QR66LMP-BdG1tWLn.js → pieDiagram-5QR66LMP-MPh-EWf-.js} +1 -1
  81. package/dist/print.js +2 -2
  82. package/dist/{quadrantDiagram-O4NWA36T-BCd-NwsO.js → quadrantDiagram-O4NWA36T-CwDeE9KB.js} +1 -1
  83. package/dist/{requirementDiagram-PLB6GJNP-CCcH5uSr.js → requirementDiagram-PLB6GJNP-CCP3YtvB.js} +2 -2
  84. package/dist/{sankeyDiagram-IPEJSGJF-78cK-bfe.js → sankeyDiagram-IPEJSGJF-vgVchd2a.js} +1 -1
  85. package/dist/{sortable-provider-VCxPasNp.js → sortable-provider-CzSnl6It.js} +1 -1
  86. package/dist/{stateDiagram-v2-GCMORJYK-B4ghJrhD.js → stateDiagram-v2-GCMORJYK-T-oIXh-8.js} +2 -2
  87. package/dist/{stored-language-CeD7kHui.js → stored-language-DmUUhRb5.js} +72 -6
  88. package/dist/{swimlanes-2SLR337P-DmHm2yJS.js → swimlanes-2SLR337P-tW3_wBWO.js} +3 -3
  89. package/dist/{swimlanesDiagram-TC7HE7FX-Dq3gGsPj.js → swimlanesDiagram-TC7HE7FX-B1lWzHp1.js} +3 -3
  90. package/dist/{timeline-definition-EJHVYXUP-EqJV_QKn.js → timeline-definition-EJHVYXUP-SdA6wt2-.js} +1 -1
  91. package/dist/{translate-material-DgRdhz5d.js → translate-material-DuY12xca.js} +2 -2
  92. package/dist/{translator-B4zUVm7j.js → translator-CaIYjyFP.js} +1 -1
  93. package/dist/{use-heading-spy-1BHMXjIn.js → use-heading-spy-Crdz4OH5.js} +2 -2
  94. package/dist/{use-material-translation-UbARR81K.js → use-material-translation-Od0QsFPA.js} +2 -2
  95. package/dist/{usecaseDiagram-POWQR4AR-CvCl0p5N.js → usecaseDiagram-POWQR4AR-B3rBcR4E.js} +2 -2
  96. package/dist/{xychartDiagram-PMCCYNJV-BphsHFKA.js → xychartDiagram-PMCCYNJV-stQWLgCx.js} +1 -1
  97. package/docs/components/README.md +2 -1
  98. package/docs/components/data-display.md +3 -3
  99. package/docs/components/data-table-filter-and-lists.md +5 -0
  100. package/docs/components/date-and-time.md +106 -6
  101. package/docs/components/feedback-and-status.md +1 -1
  102. package/docs/components/form-fields.md +8 -2
  103. package/docs/components/media-and-files.md +71 -1
  104. package/docs/components/primitives.md +1 -1
  105. package/docs/components/rich-widgets.md +1 -1
  106. package/docs/components/selection-and-choice.md +79 -2
  107. package/docs/guides/forms.md +2 -1
  108. package/docs/guides/i18n.md +47 -4
  109. package/docs/previews/date-time-daterangefield.webp +0 -0
  110. package/docs/previews/media-files-filepreview.webp +0 -0
  111. package/docs/previews/selection-choice-treeselectfield.webp +0 -0
  112. package/docs/roadmap.md +32 -27
  113. package/docs/troubleshooting.md +58 -0
  114. package/package.json +2 -2
  115. package/dist/lib/components/ui/fields/slider/slider-ticks.d.ts +0 -1
@@ -0,0 +1,25 @@
1
+ import { DateRangePresetOption } from '@nxgt/material-core/date-range';
2
+ import { ComponentProps } from 'react';
3
+ import { Matcher } from 'react-day-picker';
4
+ import { Calendar, DateRange } from '../../calendar/calendar';
5
+ type CalendarProps = ComponentProps<typeof Calendar>;
6
+ type BodyProps = {
7
+ calendarProps: Omit<CalendarProps, 'mode' | 'label' | 'onSelect' | 'disabled'>;
8
+ dayRule?: Matcher | Matcher[];
9
+ required?: boolean;
10
+ value?: DateRange;
11
+ onValueChange?: (value?: DateRange) => void;
12
+ presets?: readonly DateRangePresetOption[];
13
+ withTime?: boolean;
14
+ onClose: () => void;
15
+ };
16
+ /**
17
+ * The open popover of a `DateRangeField`: the presets, the range calendar
18
+ * and, with `withTime`, the two times and OK. Its body is mounted only while
19
+ * the popover is open, so the presets are resolved (and "now" read) only
20
+ * then, as in the Vue sister.
21
+ */
22
+ export declare function DateRangeFieldContent({ triggerId, ...body }: BodyProps & {
23
+ triggerId: string;
24
+ }): import("react").JSX.Element;
25
+ export {};
@@ -0,0 +1,11 @@
1
+ import { DayRange } from '@nxgt/material-core/date-range';
2
+ import { DateRangePresetItem } from '../use-date-range-presets';
3
+ /**
4
+ * The one-click ranges beside the calendar: a group (a `<fieldset>`) of
5
+ * toggle buttons, the one whose range is the field's value pressed
6
+ * (`aria-pressed`). A preset the field's rules rule out is disabled.
7
+ */
8
+ export declare function DateRangePresets({ items, onPick, }: {
9
+ items: DateRangePresetItem[];
10
+ onPick: (range: DayRange) => void;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { DateRange } from '../../calendar/calendar';
2
+ /**
3
+ * A time of day for each end of the range, under the calendar. An end with
4
+ * no day yet has its time disabled. The end never comes before the start:
5
+ * on the same day, an earlier end time becomes the start time.
6
+ */
7
+ export declare function DateRangeTimes({ value, onValueChange, onDone, }: {
8
+ value?: DateRange;
9
+ onValueChange?: (value?: DateRange) => void;
10
+ onDone: () => void;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { DateRangePresetOption, DateRangeRules, DayRange, PartialDayRange } from '@nxgt/material-core/date-range';
2
+ /** One entry of the preset list, resolved for this render. */
3
+ export type DateRangePresetItem = {
4
+ key: string;
5
+ label: string;
6
+ range: DayRange;
7
+ /** Its range starts before `minDate`, ends after `maxDate`, or on a disabled day. */
8
+ disabled: boolean;
9
+ /** The field's value covers the same days. */
10
+ active: boolean;
11
+ };
12
+ /**
13
+ * The presets a `DateRangeField` lists, each with its range at this render,
14
+ * its label in the provider's language, and its state against the field's
15
+ * rules and value.
16
+ */
17
+ export declare function useDateRangePresets({ presets, value, rules, withTime, }: {
18
+ presets?: readonly DateRangePresetOption[];
19
+ value?: PartialDayRange;
20
+ rules: DateRangeRules;
21
+ withTime?: boolean;
22
+ }): DateRangePresetItem[];
@@ -1,3 +1,10 @@
1
1
  export declare function parseHours(value: string, period: 'AM' | 'PM'): number;
2
2
  export declare function parseMinutes(value?: string): number;
3
3
  export declare function formatValue(value: number): string;
4
+ /** The half of the day `date` is in. */
5
+ export declare function periodOf(date: Date): 'AM' | 'PM';
6
+ /**
7
+ * `date` moved into `period`'s half of the day, at the same hour on the
8
+ * 12-hour clock; a date already in it is returned unchanged (as a copy).
9
+ */
10
+ export declare function withPeriod(date: Date, period: 'AM' | 'PM'): Date;
@@ -20,5 +20,7 @@ export type NumberFieldProps = {
20
20
  suffix?: ReactNode;
21
21
  /** Names the input when it has no `label` of its own (a part of a larger field). */
22
22
  'aria-label'?: string;
23
+ /** Names the input by another element's id (a part of a larger field). */
24
+ 'aria-labelledby'?: string;
23
25
  };
24
- export declare function NumberField({ label, helperText, error, required, disabled, className, name, id, placeholder, value, defaultValue, onChange, onBlur, min, max, step, hideSteppers, suffix, 'aria-label': ariaLabel, }: NumberFieldProps): import("react").JSX.Element;
26
+ export declare function NumberField({ label, helperText, error, required, disabled, className, name, id, placeholder, value, defaultValue, onChange, onBlur, min, max, step, hideSteppers, suffix, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, }: NumberFieldProps): import("react").JSX.Element;
@@ -9,7 +9,11 @@ export type SliderHeaderProps = {
9
9
  max: number;
10
10
  step: number;
11
11
  disabled?: boolean;
12
+ /** The Slider's own name: it names a single value's readout as it names the thumbs. */
13
+ ariaLabel?: string;
14
+ /** As `ariaLabel`, and wins over it, as on the thumbs (`sliderThumbNames`). */
15
+ ariaLabelledBy?: string;
12
16
  onChange: (values: number[]) => void;
13
17
  };
14
18
  /** The Label and the value (editable inputs, or text) above the track. */
15
- export declare function SliderHeader({ label, labelId, required, showReadout, values, min, max, step, disabled, onChange, }: SliderHeaderProps): import("react").JSX.Element | null;
19
+ export declare function SliderHeader({ label, labelId, required, showReadout, values, min, max, step, disabled, ariaLabel, ariaLabelledBy, onChange, }: SliderHeaderProps): import("react").JSX.Element | null;
@@ -4,6 +4,10 @@ export type SliderReadoutProps = {
4
4
  max: number;
5
5
  step?: number;
6
6
  disabled?: boolean;
7
+ /** What names a single value's input: an element's id (the field's Label)… */
8
+ labelledBy?: string;
9
+ /** …else this name, else "Value". */
10
+ label?: string;
7
11
  onChange: (values: number[]) => void;
8
12
  };
9
- export declare function SliderReadout({ values, min, max, step, disabled, onChange, }: SliderReadoutProps): import("react").JSX.Element;
13
+ export declare function SliderReadout({ values, min, max, step, disabled, labelledBy, label, onChange, }: SliderReadoutProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { ComponentType } from 'react';
2
+ import { PdfReaderProps } from '../pdf-viewer/types';
3
+ /**
4
+ * `PdfReader`, imported on first use: a page that previews no PDF never
5
+ * loads the viewer, and an import that fails (a chunk that cannot be
6
+ * fetched, pdf.js missing from the bundle) rejects, so `FilePreview` falls
7
+ * back to its file card. A failure is not cached; the next call tries again.
8
+ */
9
+ export declare function loadPdfReader(): Promise<ComponentType<PdfReaderProps>>;
@@ -0,0 +1,12 @@
1
+ import { FilePreviewProps } from './types';
2
+ export type { FilePreviewProps } from './types';
3
+ /**
4
+ * Previews a file picked by its MIME type, else its extension: an image, a
5
+ * PDF (in `PdfReader`, loaded on demand), a video or audio file with the
6
+ * browser's controls, the text of a text, JSON, CSV or Markdown file, and
7
+ * for anything else a card with its name, size and a download link.
8
+ *
9
+ * Safe on a server: nothing is read and no object URL is made until it has
10
+ * mounted, and until then it renders a neutral placeholder.
11
+ */
12
+ export declare function FilePreview({ file, type, name, maxTextBytes, onError, className, ...props }: FilePreviewProps): import("react").JSX.Element | null;
@@ -0,0 +1,3 @@
1
+ export { type FileKind, FilePreviewHttpError, type FilePreviewSource, FilePreviewUnsafeUrlError, fileKind, TEXT_PREVIEW_MAX_BYTES, } from '@nxgt/material-core/file-preview';
2
+ export { FilePreview } from './file-preview';
3
+ export type { FilePreviewProps, FilePreviewStatus } from './types';
@@ -0,0 +1,9 @@
1
+ import { DescribedFile } from '@nxgt/material-core/file-preview';
2
+ import { FilePreviewState } from '../use-file-preview';
3
+ /** The part of `FilePreview` that depends on the file's kind and the status. */
4
+ export declare function FilePreviewBody({ state, described, displayName, maxTextBytes, }: {
5
+ state: FilePreviewState;
6
+ described: DescribedFile;
7
+ displayName: string;
8
+ maxTextBytes?: number;
9
+ }): import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { FileKind } from '@nxgt/material-core/file-preview';
2
+ /**
3
+ * A link that saves the file under `name` (the browser's choice when `''`).
4
+ * Nothing until `href` is known.
5
+ */
6
+ export declare function FilePreviewDownload({ href, name, }: {
7
+ href: string | undefined;
8
+ name: string;
9
+ }): import("react").JSX.Element | null;
10
+ /** Any other file: its icon, name, size and type, and a download link. */
11
+ export declare function FilePreviewCard({ kind, name, fileName, size, type, href, }: {
12
+ kind: FileKind;
13
+ /** What the card shows. */
14
+ name: string;
15
+ /** What the download saves as. */
16
+ fileName: string;
17
+ size?: number;
18
+ type: string;
19
+ href: string | undefined;
20
+ }): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * An image, a video or an audio file in the browser's own element: `<img>`
3
+ * named by the file name, `<video controls>` and `<audio controls>` labelled
4
+ * with it. `onError` fires when the element cannot load `src`.
5
+ */
6
+ export declare function FilePreviewMedia({ kind, src, name, onError, }: {
7
+ kind: 'image' | 'video' | 'audio';
8
+ src: string;
9
+ name: string;
10
+ onError: () => void;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * A PDF in `PdfReader`, loaded lazily; `fallback` (the file card) when the
4
+ * viewer cannot be loaded.
5
+ */
6
+ export declare function FilePreviewPdf({ file, fileName, fallback, }: {
7
+ file: Blob | string;
8
+ fileName: string;
9
+ fallback: ReactNode;
10
+ }): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ /** The server's and the first render's box: no text, nothing to mismatch. */
3
+ export declare function FilePreviewPlaceholder(): import("react").JSX.Element;
4
+ /**
5
+ * The live region that announces the loading: always mounted, from the
6
+ * server's render on, with its text put in while loading. A region that
7
+ * mounted with its text already in it would not be announced.
8
+ */
9
+ export declare function FilePreviewAnnouncer({ loading }: {
10
+ loading: boolean;
11
+ }): import("react").JSX.Element;
12
+ /** What is seen while loading; `FilePreviewAnnouncer` is what is heard. */
13
+ export declare function FilePreviewLoading(): import("react").JSX.Element;
14
+ /** The error message, and below it whatever can still be done (a download). */
15
+ export declare function FilePreviewError({ children }: {
16
+ children?: ReactNode;
17
+ }): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { FileKind, TextPreview } from '@nxgt/material-core/file-preview';
2
+ /**
3
+ * A text kind's content: JSON in `JsonViewer` and Markdown rendered when the
4
+ * whole file was read, else (and for text and CSV) as it is, in a `<pre>`.
5
+ * What scrolls is a region named after the file, and takes focus so a
6
+ * keyboard can scroll it.
7
+ */
8
+ export declare function FilePreviewText({ kind, name, preview, maxBytes, }: {
9
+ kind: FileKind;
10
+ name: string;
11
+ preview: TextPreview;
12
+ maxBytes: number;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { FilePreviewSource } from '@nxgt/material-core/file-preview';
2
+ import { ComponentProps } from 'react';
3
+ /** Where a preview is: server or first render, reading, shown, failed. */
4
+ export type FilePreviewStatus = 'pending' | 'loading' | 'ready' | 'error';
5
+ export type FilePreviewProps = Omit<ComponentProps<'figure'>, 'children' | 'onError'> & {
6
+ /**
7
+ * The file: a `File` or `Blob`, or a URL. Nothing renders without one. A
8
+ * URL must be `http(s):`, relative, `blob:`, or a `data:` URL of an
9
+ * image, video, audio, plain text, CSV, Markdown, JSON or PDF; any other (`javascript:`, …) shows the error state.
10
+ */
11
+ file: FilePreviewSource | null | undefined;
12
+ /** MIME type; overrides the `Blob`'s. Picks the kind before the extension does. */
13
+ type?: string;
14
+ /** Name shown, used as the image's alt text and the download's file name; overrides the `File`'s. */
15
+ name?: string;
16
+ /** How much of a text, JSON, CSV or Markdown file is read and shown. 256 KB by default. */
17
+ maxTextBytes?: number;
18
+ /**
19
+ * The file could not be read or shown: `FilePreviewHttpError`, a
20
+ * `FilePreviewUnsafeUrlError`, or an `Error` for a broken image or video.
21
+ */
22
+ onError?: (error: unknown) => void;
23
+ };
@@ -0,0 +1,22 @@
1
+ import { DescribedFile } from '@nxgt/material-core/file-preview';
2
+ import { FilePreviewProps, FilePreviewStatus } from './types';
3
+ import { TextPreviewState } from './use-text-preview';
4
+ type Options = Pick<FilePreviewProps, 'file' | 'type' | 'name' | 'maxTextBytes' | 'onError'>;
5
+ export type FilePreviewState = {
6
+ described: DescribedFile | null;
7
+ status: FilePreviewStatus;
8
+ /** What the media element and the download link point at, once known. */
9
+ href: string | undefined;
10
+ text: TextPreviewState;
11
+ /** For an `<img>`, `<video>` or `<audio>` that failed to load `href`. */
12
+ onMediaError: () => void;
13
+ };
14
+ /**
15
+ * Everything `FilePreview` decides: the file's kind, the object URL of a
16
+ * `Blob` (made after mount, revoked on change and unmount), the text of a
17
+ * text kind, and the status. On a server and in the first client render the
18
+ * status is `'pending'` and nothing is read; a URL `safePreviewUrl` refuses
19
+ * is `'error'` everywhere and is never used.
20
+ */
21
+ export declare function useFilePreview({ file, type, name, maxTextBytes, onError, }: Options): FilePreviewState;
22
+ export {};
@@ -0,0 +1,15 @@
1
+ import { TextPreview } from '@nxgt/material-core/file-preview';
2
+ export type TextPreviewState = {
3
+ status: 'loading';
4
+ } | {
5
+ status: 'ready';
6
+ preview: TextPreview;
7
+ } | {
8
+ status: 'error';
9
+ error: unknown;
10
+ };
11
+ /**
12
+ * The first `maxBytes` of `source` as text, read in an effect (never on a
13
+ * server). A new source aborts the previous read; `undefined` reads nothing.
14
+ */
15
+ export declare function useTextPreview(source: Blob | string | undefined, maxBytes: number | undefined): TextPreviewState;
@@ -1,6 +1,7 @@
1
1
  export * from './camera';
2
2
  export * from './carousel';
3
3
  export * from './file-list';
4
+ export * from './file-preview';
4
5
  export * from './files-form-field';
5
6
  export * from './galleries';
6
7
  export * from './image-cropper';
@@ -1,2 +1,8 @@
1
+ /**
2
+ * An object URL for `blob`, made in an effect (never on a server) and revoked
3
+ * when `blob` changes or the component unmounts. `undefined` until made, and
4
+ * never the previous blob's (already revoked) URL. `FilePreview` uses it.
5
+ */
6
+ export declare function useBlobUrl(blob: Blob | undefined): string | undefined;
1
7
  /** An object URL previewing `file` while it is an image, revoked on change. */
2
8
  export declare function useImagePreview(file?: File): string | undefined;
@@ -13,3 +13,4 @@ export * from './select-field';
13
13
  export * from './sortable-list';
14
14
  export * from './switcher';
15
15
  export * from './transfer-list';
16
+ export * from './tree-select-field';
@@ -0,0 +1,2 @@
1
+ export * from './tree-select-field';
2
+ export * from './tree-select-form-field';
@@ -0,0 +1,13 @@
1
+ import { useTreeSelectField } from '../use-tree-select-field';
2
+ export type TreeSelectContentProps = {
3
+ field: ReturnType<typeof useTreeSelectField>;
4
+ multiple?: boolean;
5
+ searchable?: boolean;
6
+ searchPlaceholder?: string;
7
+ /** Names the popover: the label's id when there is one, else the trigger's. */
8
+ labelledBy: string;
9
+ /** Names the tree: the field's label text. */
10
+ treeLabel?: string;
11
+ };
12
+ /** The popover under the field: the optional filter, then the tree. */
13
+ export declare function TreeSelectContent({ field, multiple, searchable, searchPlaceholder, labelledBy, treeLabel, }: TreeSelectContentProps): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { TreeNode } from '../../../collections/tree/types';
2
+ export type TreeSelectPanelProps = {
3
+ nodes: TreeNode[];
4
+ multiple?: boolean;
5
+ selectedIds: string[];
6
+ expandedIds: string[];
7
+ onExpandedIdsChange: (ids: string[]) => void;
8
+ onSelectedIdsChange: (ids: string[]) => void;
9
+ onSelect: (id: string) => void;
10
+ /** Names the tree: the field's label text. */
11
+ treeLabel?: string;
12
+ searchable?: boolean;
13
+ query: string;
14
+ onQueryChange: (query: string) => void;
15
+ searchLabel: string;
16
+ emptyText: string;
17
+ };
18
+ /** What the popover holds: the optional filter input, then the tree. */
19
+ export declare function TreeSelectPanel({ nodes, multiple, selectedIds, expandedIds, onExpandedIdsChange, onSelectedIdsChange, onSelect, treeLabel, searchable, query, onQueryChange, searchLabel, emptyText, }: TreeSelectPanelProps): import("react").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { ComponentProps } from 'react';
2
+ import { TreeNode } from '../../../collections/tree/types';
3
+ export type TreeSelectTriggerProps = {
4
+ open: boolean;
5
+ multiple?: boolean;
6
+ disabled?: boolean;
7
+ error?: boolean;
8
+ name?: string;
9
+ /** What the button shows while nothing is picked. */
10
+ placeholder: string;
11
+ /** What the button shows in multiple mode once something is picked. */
12
+ countText: string;
13
+ selectedNodes: TreeNode[];
14
+ onRemove: (id: string) => void;
15
+ /** The combobox's role, name, description and id (`pickerTriggerA11y`). */
16
+ a11y: ComponentProps<'button'>;
17
+ };
18
+ /**
19
+ * The field's box: in multiple mode, a chip per picked node, then the
20
+ * `combobox` button that opens the tree. The chips sit beside the button, not
21
+ * in it — a chip's remove button may not be nested in another button — and the
22
+ * box is the popover's anchor, so the tree opens under all of it.
23
+ */
24
+ export declare function TreeSelectTrigger({ open, multiple, disabled, error, name, placeholder, countText, selectedNodes, onRemove, a11y, }: TreeSelectTriggerProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { TreeSelectFieldProps } from './types';
2
+ export type { TreeSelectFieldBaseProps, TreeSelectFieldMultipleProps, TreeSelectFieldProps, TreeSelectFieldSingleProps, } from './types';
3
+ /**
4
+ * A form field that opens a `Tree` in a popover. Single: a pick closes it and
5
+ * the trigger shows the node. Multiple: checkboxes, the picks as chips.
6
+ * The trigger is a `combobox`; Escape closes and hands focus back to it.
7
+ * `id`, `aria-describedby` and `data-*` attributes go on the trigger.
8
+ */
9
+ export declare function TreeSelectField(props: TreeSelectFieldProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { UseControllerProps } from 'react-hook-form';
2
+ import { TreeSelectFieldBaseProps } from './types';
3
+ export type TreeSelectFormFieldProps<T extends Record<string, any>> = Pick<UseControllerProps<T>, 'control' | 'name'> & Omit<TreeSelectFieldBaseProps, 'name'> & {
4
+ /** The form value is a list of ids when set, else one id (or `null`). */
5
+ multiple?: boolean;
6
+ };
7
+ /** `TreeSelectField` bound to react-hook-form: touched when focus leaves it. */
8
+ export declare function TreeSelectFormField<T extends Record<string, any>>({ control, name, multiple, ...props }: TreeSelectFormFieldProps<T>): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ import { TreeNode } from '../../collections/tree/types';
2
+ /** The text a node shows, which the search matches against. */
3
+ export declare function treeNodeText(node: TreeNode): string;
4
+ export type FilteredTree = {
5
+ /** The matches, each under its ancestors; a match keeps its own subtree. */
6
+ nodes: TreeNode[];
7
+ /** The ancestors kept for a match below them: open, so the match shows. */
8
+ expandedIds: string[];
9
+ };
10
+ /**
11
+ * The tree narrowed to the nodes whose text contains `query` (case- and
12
+ * accent-insensitive), with every match's ancestors kept so it stays in place.
13
+ * An empty query keeps the whole tree, with nothing forced open.
14
+ */
15
+ export declare function filterTree(nodes: TreeNode[], query: string): FilteredTree;
16
+ /** The ids of the ancestors of `ids`: opened, so a picked node is in view. */
17
+ export declare function ancestorIds(nodes: TreeNode[], ids: string[]): string[];
18
+ /** The nodes of `ids`, in the order of `ids`; an id the tree lacks is skipped. */
19
+ export declare function treeNodesOf(nodes: TreeNode[], ids: string[]): TreeNode[];
20
+ /** The value as a list of ids, whatever the mode. */
21
+ export declare function toIds(value: string | string[] | null | undefined): string[];
22
+ /** The first tree item a keyboard user lands on: the roving one, else the first. */
23
+ export declare function treeEntry(root: ParentNode | null | undefined): HTMLElement | null;
24
+ /**
25
+ * `filterTree` with a one-entry memory: the search handler (for the branches
26
+ * to open) and the render (for the nodes) ask for the same filter, and the
27
+ * tree is walked once per keystroke.
28
+ */
29
+ export declare function memoFilterTree(): typeof filterTree;
30
+ /**
31
+ * Before a chip is removed, hand focus on, so a keyboard user is not dropped
32
+ * to `<body>` (which also blurs, so touches, the form field): the next chip's
33
+ * remove button, else the previous one's, else the combobox trigger.
34
+ */
35
+ export declare function focusAfterChipRemoval(box: ParentNode | null | undefined, index: number): void;
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from 'react';
2
+ import { TreeNode } from '../../collections/tree/types';
3
+ import { PickerTriggerAttrs } from '../../dates/picker-trigger/picker-trigger-attrs';
4
+ export type TreeSelectFieldBaseProps = {
5
+ /** The tree to pick from: `Tree`'s node shape. */
6
+ items: TreeNode[];
7
+ label?: ReactNode;
8
+ helperText?: ReactNode;
9
+ error?: boolean;
10
+ /** Shown while nothing is picked; `material.tree-select-field.placeholder` otherwise. */
11
+ placeholder?: string;
12
+ disabled?: boolean;
13
+ required?: boolean;
14
+ /** A filter input above the tree: matches stay under their ancestors. */
15
+ searchable?: boolean;
16
+ /** The filter input's placeholder and name; `material.tree-select-field.search` otherwise. */
17
+ searchPlaceholder?: string;
18
+ name?: string;
19
+ className?: string;
20
+ /** Names the trigger; it wins over `label`. */
21
+ 'aria-label'?: string;
22
+ 'aria-labelledby'?: string;
23
+ } & PickerTriggerAttrs;
24
+ export type TreeSelectFieldSingleProps = {
25
+ multiple?: false;
26
+ /** The picked node's id. */
27
+ value?: string | null;
28
+ onValueChange?: (value: string | null) => void;
29
+ };
30
+ export type TreeSelectFieldMultipleProps = {
31
+ /** Checkboxes in the tree, and the picked nodes as chips in the trigger. */
32
+ multiple: true;
33
+ /** The picked nodes' ids. */
34
+ value?: string[];
35
+ onValueChange?: (value: string[]) => void;
36
+ };
37
+ export type TreeSelectFieldProps = TreeSelectFieldBaseProps & (TreeSelectFieldSingleProps | TreeSelectFieldMultipleProps);
@@ -0,0 +1,20 @@
1
+ import { TreeSelectFieldProps } from './types';
2
+ /**
3
+ * A `TreeSelectField`'s chrome — open, the search query, the open branches —
4
+ * and what picking does. The value stays the caller's (`value` /
5
+ * `onValueChange`); three local values need no slice, as in `Autocomplete`.
6
+ */
7
+ export declare function useTreeSelectField(props: TreeSelectFieldProps): {
8
+ open: boolean;
9
+ setOpen: (next: boolean) => void;
10
+ query: string;
11
+ search: (next: string) => void;
12
+ nodes: import('../../collections').TreeNode[];
13
+ expandedIds: string[];
14
+ setExpandedIds: import('react').Dispatch<import('react').SetStateAction<string[]>>;
15
+ selectedIds: string[];
16
+ selectedNodes: import('../../collections').TreeNode[];
17
+ onSelectedIdsChange: (ids: string[]) => void;
18
+ onSelect: (id: string) => void;
19
+ remove: (id: string) => void;
20
+ };
@@ -48,6 +48,7 @@ export declare const en: {
48
48
  cancel: string;
49
49
  processing: string;
50
50
  failed: string;
51
+ "form-failed": string;
51
52
  };
52
53
  "scroll-progress": string;
53
54
  "skip-link": string;
@@ -626,6 +627,12 @@ export declare const en: {
626
627
  expand: string;
627
628
  collapse: string;
628
629
  };
630
+ "tree-select-field": {
631
+ placeholder: string;
632
+ search: string;
633
+ empty: string;
634
+ selected: string;
635
+ };
629
636
  "image-cropper": {
630
637
  title: string;
631
638
  zoom: string;
@@ -1170,6 +1177,7 @@ export declare const en: {
1170
1177
  slider: {
1171
1178
  minimum: string;
1172
1179
  maximum: string;
1180
+ value: string;
1173
1181
  };
1174
1182
  "scroll-to-top": {
1175
1183
  label: string;
@@ -1206,6 +1214,31 @@ export declare const en: {
1206
1214
  "time-picker": {
1207
1215
  am: string;
1208
1216
  pm: string;
1217
+ hours: string;
1218
+ minutes: string;
1219
+ };
1220
+ "date-range-field": {
1221
+ presets: string;
1222
+ preset: {
1223
+ today: string;
1224
+ yesterday: string;
1225
+ "last-7-days": string;
1226
+ "last-30-days": string;
1227
+ "this-month": string;
1228
+ "last-month": string;
1229
+ "this-year": string;
1230
+ };
1231
+ "start-time": string;
1232
+ "end-time": string;
1233
+ };
1234
+ "file-preview": {
1235
+ label: string;
1236
+ untitled: string;
1237
+ loading: string;
1238
+ error: string;
1239
+ download: string;
1240
+ truncated: string;
1241
+ content: string;
1209
1242
  };
1210
1243
  };
1211
1244
  };
@@ -37,7 +37,8 @@ declare const _default: {
37
37
  "confirm": "Confirm",
38
38
  "cancel": "Cancel",
39
39
  "processing": "Processing...",
40
- "failed": "The action failed."
40
+ "failed": "The action failed.",
41
+ "form-failed": "The form could not be loaded."
41
42
  },
42
43
  "scroll-progress": "Scroll progress",
43
44
  "skip-link": "Skip to content",
@@ -616,6 +617,12 @@ declare const _default: {
616
617
  "expand": "Expand",
617
618
  "collapse": "Collapse"
618
619
  },
620
+ "tree-select-field": {
621
+ "placeholder": "Select…",
622
+ "search": "Search",
623
+ "empty": "No match found.",
624
+ "selected": "{count} selected"
625
+ },
619
626
  "image-cropper": {
620
627
  "title": "Crop image",
621
628
  "zoom": "Zoom",
@@ -1159,7 +1166,8 @@ declare const _default: {
1159
1166
  },
1160
1167
  "slider": {
1161
1168
  "minimum": "Minimum",
1162
- "maximum": "Maximum"
1169
+ "maximum": "Maximum",
1170
+ "value": "Value"
1163
1171
  },
1164
1172
  "scroll-to-top": {
1165
1173
  "label": "Scroll to top"
@@ -1195,7 +1203,32 @@ declare const _default: {
1195
1203
  },
1196
1204
  "time-picker": {
1197
1205
  "am": "AM",
1198
- "pm": "PM"
1206
+ "pm": "PM",
1207
+ "hours": "Hours",
1208
+ "minutes": "Minutes"
1209
+ },
1210
+ "date-range-field": {
1211
+ "presets": "Presets",
1212
+ "preset": {
1213
+ "today": "Today",
1214
+ "yesterday": "Yesterday",
1215
+ "last-7-days": "Last 7 days",
1216
+ "last-30-days": "Last 30 days",
1217
+ "this-month": "This month",
1218
+ "last-month": "Last month",
1219
+ "this-year": "This year"
1220
+ },
1221
+ "start-time": "Start time",
1222
+ "end-time": "End time"
1223
+ },
1224
+ "file-preview": {
1225
+ "label": "Preview of {name}",
1226
+ "untitled": "Untitled file",
1227
+ "loading": "Loading preview…",
1228
+ "error": "This file could not be previewed.",
1229
+ "download": "Download",
1230
+ "truncated": "Showing the first {size} of this file.",
1231
+ "content": "Contents of {name}"
1199
1232
  }
1200
1233
  }
1201
1234
  ;