@nxgt/material-vue 0.23.4 → 0.25.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.
- package/README.md +30 -28
- package/dist/{Button-CVIR6uLK.js → Button-C1aaI0Gw.js} +95 -72
- package/dist/{HoverCardTrigger-iAL5ALrL.js → HoverCardTrigger-JtHn0IFQ.js} +2 -2
- package/dist/{camera-Gvg5N956.js → camera-BacVyXl0.js} +6 -6
- package/dist/{components-AScwCcds.js → components-DRBKkOqk.js} +15764 -13833
- package/dist/components.js +8 -8
- package/dist/composables.js +2 -2
- package/dist/dnd.js +1 -1
- package/dist/form-scope-VxlJuvFe.js +43 -0
- package/dist/{i18n-provider-BqWxpaKu.js → i18n-provider-D0oYv0XS.js} +1 -1
- package/dist/i18n.js +4 -4
- package/dist/{icon-button-DbEME76t.js → icon-button-B2FQtIHS.js} +34 -37
- package/dist/lib/components/ui/actions/button/has-text-content.d.ts +10 -0
- package/dist/lib/components/ui/actions/copy-button/copy-value.vue.d.ts +21 -0
- package/dist/lib/components/ui/actions/copy-button/index.d.ts +2 -0
- package/dist/lib/components/ui/collections/data-table/data-table-context.d.ts +6 -0
- package/dist/lib/components/ui/collections/data-table/data-table-pagination.vue.d.ts +2 -0
- package/dist/lib/components/ui/collections/data-table/data-table.vue.d.ts +17 -27
- package/dist/lib/components/ui/collections/data-table/index.d.ts +1 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-body.vue.d.ts +10 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-empty.vue.d.ts +13 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-head.vue.d.ts +22 -0
- package/dist/lib/components/ui/collections/data-table/partials/data-table-skeleton-rows.vue.d.ts +10 -0
- package/dist/lib/components/ui/collections/data-table/use-data-table.d.ts +17 -0
- package/dist/lib/components/ui/collections/filter/partials/filter-field-slider-range.vue.d.ts +1 -4
- package/dist/lib/components/ui/collections/pagination/index.d.ts +5 -0
- package/dist/lib/components/ui/collections/pagination/pagination-bar.vue.d.ts +21 -0
- package/dist/lib/components/ui/collections/pagination/pagination-items.d.ts +2 -0
- package/dist/lib/components/ui/collections/pagination/pagination-link.vue.d.ts +18 -0
- package/dist/lib/components/ui/collections/tree/use-tree.d.ts +2 -0
- package/dist/lib/components/ui/dates/date-field/date-field.vue.d.ts +10 -1
- package/dist/lib/components/ui/dates/date-field/date-form-field.vue.d.ts +3 -1
- package/dist/lib/components/ui/dates/date-field/day-matcher.d.ts +26 -0
- package/dist/lib/components/ui/dates/date-field/index.d.ts +1 -0
- package/dist/lib/components/ui/dates/date-field/partials/date-field-content.vue.d.ts +2 -0
- package/dist/lib/components/ui/dates/date-range-field/date-range-field.utils.d.ts +11 -0
- package/dist/lib/components/ui/dates/date-range-field/date-range-field.vue.d.ts +26 -1
- package/dist/lib/components/ui/dates/date-range-field/date-range-form-field.vue.d.ts +3 -1
- package/dist/lib/components/ui/dates/date-range-field/index.d.ts +1 -0
- package/dist/lib/components/ui/dates/date-range-field/partials/date-range-calendar.vue.d.ts +5 -0
- package/dist/lib/components/ui/dates/date-range-field/partials/date-range-field-trigger.vue.d.ts +2 -0
- package/dist/lib/components/ui/dates/date-range-field/partials/date-range-presets.vue.d.ts +12 -0
- package/dist/lib/components/ui/dates/date-range-field/partials/date-range-times.vue.d.ts +13 -0
- package/dist/lib/components/ui/dates/date-range-field/use-date-range-presets.d.ts +23 -0
- package/dist/lib/components/ui/dates/time-picker/time-picker-utils.d.ts +7 -0
- package/dist/lib/components/ui/display/accordion-card/accordion-card.vue.d.ts +29 -1
- package/dist/lib/components/ui/display/avatar/Avatar.vue.d.ts +14 -3
- package/dist/lib/components/ui/display/avatar/index.d.ts +1 -0
- package/dist/lib/components/ui/display/cards/cards.gallery.d.ts +5 -9
- package/dist/lib/components/ui/display/markdown/index.d.ts +18 -0
- package/dist/lib/components/ui/display/qrcode/qrcode.vue.d.ts +5 -3
- package/dist/lib/components/ui/display/status-indicator/status-tone.d.ts +3 -0
- package/dist/lib/components/ui/feedback/confirmation-dialog/async-form-scope.d.ts +15 -0
- package/dist/lib/components/ui/feedback/confirmation-dialog/confirmation-dialog.vue.d.ts +37 -24
- package/dist/lib/components/ui/feedback/confirmation-dialog/index.d.ts +1 -1
- package/dist/lib/components/ui/feedback/confirmation-dialog/partials/confirmation-dialog-form-error.vue.d.ts +3 -0
- package/dist/lib/components/ui/feedback/skeleton/skeleton-text.vue.d.ts +1 -1
- package/dist/lib/components/ui/feedback/spinner/spinner.compound-variants.d.ts +4 -0
- package/dist/lib/components/ui/fields/attributes/form-schema.d.ts +24 -22
- package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
- package/dist/lib/components/ui/fields/inline-edit/index.d.ts +1 -0
- package/dist/lib/components/ui/fields/inline-edit/inline-edit-form-field.vue.d.ts +7 -0
- package/dist/lib/components/ui/fields/number-field/number-field.vue.d.ts +2 -0
- package/dist/lib/components/ui/fields/slider/partials/slider-field-row.vue.d.ts +32 -0
- package/dist/lib/components/ui/fields/slider/slider-field.vue.d.ts +22 -1
- package/dist/lib/components/ui/fields/slider/slider-form-field.vue.d.ts +13 -1
- package/dist/lib/components/ui/forms/form-scope-schema.d.ts +43 -0
- package/dist/lib/components/ui/forms/form-scope.vue.d.ts +33 -0
- package/dist/lib/components/ui/layout/doc/doc.vue.d.ts +5 -5
- package/dist/lib/components/ui/layout/doc/index.d.ts +8 -1
- package/dist/lib/components/ui/layout/doc/partials/default-doc-link.vue.d.ts +14 -0
- package/dist/lib/components/ui/layout/doc/partials/doc-copy-page.vue.d.ts +6 -0
- package/dist/lib/components/ui/layout/doc/partials/doc-link.vue.d.ts +3 -7
- package/dist/lib/components/ui/layout/doc/types.d.ts +6 -1
- package/dist/lib/components/ui/media/file-preview/file-preview-pdf.lazy.d.ts +8 -0
- package/dist/lib/components/ui/media/file-preview/file-preview.vue.d.ts +9 -0
- package/dist/lib/components/ui/media/file-preview/index.d.ts +3 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-body.vue.d.ts +21 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-card.vue.d.ts +15 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-download.vue.d.ts +11 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-media.vue.d.ts +17 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-pdf.vue.d.ts +21 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-status.vue.d.ts +22 -0
- package/dist/lib/components/ui/media/file-preview/partials/file-preview-text.vue.d.ts +16 -0
- package/dist/lib/components/ui/media/file-preview/types.d.ts +19 -0
- package/dist/lib/components/ui/media/file-preview/use-file-preview.d.ts +21 -0
- package/dist/lib/components/ui/media/file-preview/use-text-preview.d.ts +17 -0
- package/dist/lib/components/ui/media/files-form-field/files-form-field.vue.d.ts +29 -0
- package/dist/lib/components/ui/media/files-form-field/index.d.ts +2 -0
- package/dist/lib/components/ui/media/image-cropper/partials/image-cropper-canvas.vue.d.ts +1 -1
- package/dist/lib/components/ui/media/index.d.ts +2 -0
- package/dist/lib/components/ui/media/pdf-viewer/index.d.ts +6 -6
- package/dist/lib/components/ui/media/pdf-viewer/partials/pdf-page.vue.d.ts +1 -1
- package/dist/lib/components/ui/media/pdf-viewer/partials/pdf-reader-body.vue.d.ts +2 -2
- package/dist/lib/components/ui/media/pdf-viewer/pdf-reader.vue.d.ts +2 -2
- package/dist/lib/components/ui/media/upload/network-upload-field/use-image-preview.d.ts +9 -1
- package/dist/lib/components/ui/primitives/icon/icon-context.d.ts +1 -1
- package/dist/lib/components/ui/primitives/tabs/Tabs.vue.d.ts +3 -0
- package/dist/lib/components/ui/primitives/tabs/index.d.ts +1 -0
- package/dist/lib/components/ui/primitives/tabs/tabs-variant.d.ts +9 -0
- package/dist/lib/components/ui/selection/autocomplete/autocomplete-form-field.vue.d.ts +31 -5
- package/dist/lib/components/ui/selection/autocomplete/autocomplete-items.d.ts +23 -0
- package/dist/lib/components/ui/selection/autocomplete/autocomplete.vue.d.ts +48 -13
- package/dist/lib/components/ui/selection/autocomplete/filter-options.d.ts +2 -1
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-box.vue.d.ts +13 -1
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-list.vue.d.ts +17 -3
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-items.d.ts +15 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-open.d.ts +15 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-texts.d.ts +14 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete.d.ts +34 -0
- package/dist/lib/components/ui/selection/checkbox/Checkbox.vue.d.ts +21 -5
- package/dist/lib/components/ui/selection/checkbox/checkbox-form-field.vue.d.ts +17 -0
- package/dist/lib/components/ui/selection/checkbox/index.d.ts +2 -0
- package/dist/lib/components/ui/selection/index.d.ts +1 -0
- package/dist/lib/components/ui/selection/select-field/select-field.vue.d.ts +16 -1
- package/dist/lib/components/ui/selection/select-field/select-form-field.vue.d.ts +16 -2
- package/dist/lib/components/ui/selection/tree-select-field/index.d.ts +3 -0
- package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-panel.vue.d.ts +27 -0
- package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-trigger.vue.d.ts +28 -0
- package/dist/lib/components/ui/selection/tree-select-field/tree-select-field.vue.d.ts +8 -0
- package/dist/lib/components/ui/selection/tree-select-field/tree-select-form-field.vue.d.ts +8 -0
- package/dist/lib/components/ui/selection/tree-select-field/tree-select.utils.d.ts +29 -0
- package/dist/lib/components/ui/selection/tree-select-field/types.d.ts +28 -0
- package/dist/lib/components/ui/selection/tree-select-field/use-tree-select-field.d.ts +19 -0
- package/dist/lib/components/ui/widgets/charts/chart-container.vue.d.ts +1 -1
- package/dist/lib/components/ui/widgets/code-editor/code-editor-form-field.vue.d.ts +13 -0
- package/dist/lib/components/ui/widgets/code-editor/code-editor-options.d.ts +4 -1
- package/dist/lib/components/ui/widgets/code-editor/code-editor.vue.d.ts +7 -0
- package/dist/lib/components/ui/widgets/code-editor/index.d.ts +2 -0
- package/dist/lib/components/ui/widgets/code-editor/monaco-editor.vue.d.ts +3 -0
- package/dist/lib/i18n/resources/en/en.d.ts +40 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +43 -3
- package/dist/lib/i18n/resources/fr/fr.d.ts +40 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +43 -3
- package/dist/lib/i18n/resources/resources.d.ts +80 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib/nuxt/component-names.d.ts +1 -1
- package/dist/lib.js +2 -2
- package/dist/main.js +17 -17
- package/dist/map.js +4 -4
- package/dist/material-vue.css +1 -1
- package/dist/{pdf-outline-sidebar-oz9wdBhB.js → pdf-outline-sidebar-jJfhNjnN.js} +2 -2
- package/dist/{pdf-page-0rlq1Lo6.js → pdf-page-BW1hXzPu.js} +1 -1
- package/dist/{pdf-page-list-DfhjNHoI.js → pdf-page-list-D277RtWS.js} +2 -2
- package/dist/{pdf-reader-Dr8RVcs4.js → pdf-reader-BReUTsn_.js} +73 -71
- package/dist/{pdf-sidebar-VXPQbC_R.js → pdf-sidebar-Bk6PowY1.js} +3 -3
- package/dist/{pdf-thumbnail-sidebar-BpgXrVBj.js → pdf-thumbnail-sidebar-BcNDFsks.js} +3 -3
- package/dist/{pdf-toolbar-B6gRRcsv.js → pdf-toolbar-CHjaMhH9.js} +4 -4
- package/dist/pdf.js +2 -2
- package/dist/{sortable-provider-oEVjQiCl.js → sortable-provider-C83VBfGl.js} +2 -2
- package/dist/{stored-language-rjOMJkyX.js → stored-language-CC_vdcCN.js} +90 -6
- package/dist/{stx-player-DNADkQ31.js → stx-player-BMQ1D2Li.js} +20 -20
- package/dist/{translator-BCSJSO1-.js → translator-B-X_1taI.js} +1 -1
- package/dist/{use-heading-spy-d50_nxgR.js → use-heading-spy-C_ySuvTl.js} +1 -1
- package/dist/{use-material-translation-C5zPFhbk.js → use-material-translation-B6sIk0mF.js} +3 -3
- package/docs/components/README.md +2 -1
- package/docs/components/buttons-and-actions.md +19 -3
- package/docs/components/data-display.md +65 -11
- package/docs/components/data-table-filter-and-lists.md +94 -8
- package/docs/components/date-and-time.md +116 -9
- package/docs/components/feedback-and-status.md +57 -5
- package/docs/components/form-fields.md +21 -9
- package/docs/components/media-and-files.md +120 -6
- package/docs/components/navigation-and-layout.md +68 -7
- package/docs/components/primitives.md +25 -6
- package/docs/components/rich-widgets.md +21 -3
- package/docs/components/selection-and-choice.md +151 -22
- package/docs/guides/forms.md +16 -8
- package/docs/guides/i18n.md +50 -6
- package/docs/guides/ssr.md +2 -0
- package/docs/previews/buttons-actions-copybutton.webp +0 -0
- package/docs/previews/data-table-filter-lists-pagination.webp +0 -0
- package/docs/previews/date-time-daterangefield.webp +0 -0
- package/docs/previews/form-fields-slider.webp +0 -0
- package/docs/previews/media-files-filepreview.webp +0 -0
- package/docs/previews/navigation-layout-stepper.webp +0 -0
- package/docs/previews/selection-choice-checkbox.webp +0 -0
- package/docs/previews/selection-choice-treeselectfield.webp +0 -0
- package/docs/roadmap.md +47 -1
- package/docs/troubleshooting.md +213 -0
- package/lib/nuxt/component-names.ts +16 -0
- package/package.json +2 -2
|
@@ -240,14 +240,66 @@ function archive() {}
|
|
|
240
240
|
| --- | --- | --- | --- |
|
|
241
241
|
| `#trigger` slot | — | — | becomes the dialog trigger (`as-child`, no extra button): pass one element, such as a `Button` |
|
|
242
242
|
| `v-model:open` | `boolean` | uncontrolled | open state; without it the dialog keeps its own |
|
|
243
|
-
| `@confirm` | `() => void` | — | emitted on confirm; the dialog then closes |
|
|
243
|
+
| `@confirm` | `(values?) => void` | — | emitted on confirm, with the form's parsed values when there is one; the dialog then closes |
|
|
244
|
+
| `form-options` | `ConfirmationDialogFormOptions` (`{ schema, defaultValues? }`) | — | a form in the dialog, below the default slot — see below |
|
|
244
245
|
| `color` | `IconButton` colour | `'warning'` | icon and both buttons |
|
|
245
246
|
| `variant` | `IconButton` variant | `'tonal'` | the icon's button style |
|
|
246
247
|
| `#icon` slot | — | info icon, in a decorative `aria-hidden` badge | replaces the badge: keep yours decorative (`<IconButton as="span" aria-hidden="true">`), not a button that does nothing |
|
|
247
248
|
| `confirm-text` / `cancel-text` | `string` | "Confirm" / "Cancel", translated (`material.confirm-dialog.confirm` / `.cancel`) | button text |
|
|
248
249
|
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
`form-options` puts a form in the confirmation, as React's `formOptions`:
|
|
251
|
+
`schema` is a Zod 4 schema (any Standard Schema, or a vee-validate typed
|
|
252
|
+
schema), `defaultValues` its initial values, and the `#form` slot renders the
|
|
253
|
+
fields — `*-form-field` wrappers in it join the form. The confirm button stays
|
|
254
|
+
disabled until the form is valid, and `@confirm` receives the schema's output
|
|
255
|
+
(transforms applied). The component is generic, so that payload is typed from
|
|
256
|
+
the schema; to type the options apart from the template, import
|
|
257
|
+
`ConfirmationDialogFormOptions<TInput, TOutput>` from
|
|
258
|
+
`@nxgt/material-vue/components`. Being generic, its ref is typed with
|
|
259
|
+
`ComponentExposed`, not `InstanceType`
|
|
260
|
+
([troubleshooting](../troubleshooting.md#does-not-satisfy-the-constraint-abstract-new-args-any--any)).
|
|
261
|
+
|
|
262
|
+
```vue
|
|
263
|
+
<script setup lang="ts">
|
|
264
|
+
import { z } from 'zod';
|
|
265
|
+
import { Button, ConfirmationDialog, TextFormField } from '@nxgt/material-vue/components';
|
|
266
|
+
|
|
267
|
+
const formOptions = {
|
|
268
|
+
schema: z.object({ project: z.string().trim().pipe(z.literal('my-project')) }),
|
|
269
|
+
defaultValues: { project: '' },
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
function remove(values?: { project: 'my-project' }) {
|
|
273
|
+
console.log('deleting', values?.project);
|
|
274
|
+
}
|
|
275
|
+
</script>
|
|
276
|
+
|
|
277
|
+
<template>
|
|
278
|
+
<ConfirmationDialog
|
|
279
|
+
title="Delete project"
|
|
280
|
+
description='Type "my-project" to confirm.'
|
|
281
|
+
color="error"
|
|
282
|
+
confirm-text="Delete"
|
|
283
|
+
:form-options="formOptions"
|
|
284
|
+
@confirm="remove"
|
|
285
|
+
>
|
|
286
|
+
<template #trigger>
|
|
287
|
+
<Button color="error">Delete project</Button>
|
|
288
|
+
</template>
|
|
289
|
+
<template #form>
|
|
290
|
+
<TextFormField name="project" label="Project name" />
|
|
291
|
+
</template>
|
|
292
|
+
</ConfirmationDialog>
|
|
293
|
+
</template>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`#form` also receives `{ values, errors, meta, setFieldValue }` for fields
|
|
297
|
+
that are not form wrappers. The form lives with the dialog's content, so it
|
|
298
|
+
starts again from `defaultValues` each time the dialog opens. The form's code
|
|
299
|
+
(and vee-validate) loads only when a dialog has `form-options`; confirm stays
|
|
300
|
+
disabled until it has loaded and first validated. If it cannot load, after one
|
|
301
|
+
retry, a translated message takes its place
|
|
302
|
+
(`material.confirm-dialog.form-failed`).
|
|
251
303
|
|
|
252
304
|

|
|
253
305
|
|
|
@@ -257,7 +309,7 @@ but built on `AlertDialog`, so it does not close on an outside click. Put
|
|
|
257
309
|
`AlertDialogCancel` / `AlertDialogAction` in its `#footer`. Its trigger is
|
|
258
310
|
`as-child`, so a `Button` goes straight in.
|
|
259
311
|
|
|
260
|
-
**Storybook:** `Feedback & status/ConfirmDialog`, `Feedback & status/ConfirmationDialog
|
|
312
|
+
**Storybook:** `Feedback & status/ConfirmDialog`, `Feedback & status/ConfirmationDialog` (story `WithForm`),
|
|
261
313
|
`Feedback & status/CustomAlertDialog` · **React:** `ConfirmDialog`, `ConfirmationDialog`, `CustomAlertDialog`
|
|
262
314
|
|
|
263
315
|
---
|
|
@@ -523,7 +575,7 @@ compiled stylesheet). `Toast` is the component each toast
|
|
|
523
575
|
renders, and `sonnerToast` is vue-sonner's own `toast`, for anything the
|
|
524
576
|
presets do not cover.
|
|
525
577
|
|
|
526
|
-
**Storybook:** `Feedback & status/Toast` · **React:** `Toaster`, `toast`, `toasts`, `Toast`
|
|
578
|
+
**Storybook:** `Feedback & status/Toast` · **React:** `Toaster`, `toast`, `toasts`, `Toast` (`ToastAction` type)
|
|
527
579
|
|
|
528
580
|
---
|
|
529
581
|
|
|
@@ -267,6 +267,7 @@ const quantity = ref<number | null>(2);
|
|
|
267
267
|
| `hide-steppers` | `boolean` | `false` | hides the +/− buttons |
|
|
268
268
|
| `#suffix` | slot | — | unit after the input |
|
|
269
269
|
| `aria-label` | `string` | — | names the input when it has no `label` (a part of a larger field) |
|
|
270
|
+
| `aria-labelledby` | `string` | — | names the input by another element's id (a part of a larger field) |
|
|
270
271
|
|
|
271
272
|
**Emits:** `update:modelValue` with `number | null`.
|
|
272
273
|
**Form wrapper:** `NumberFormField` — `name` inside a vee-validate form, see
|
|
@@ -529,7 +530,7 @@ const pin = ref('');
|
|
|
529
530
|
**Emits:** `update:modelValue` with `string` (the digits typed so far).
|
|
530
531
|
**Form wrapper:** `OtpFormField` — `name` inside a vee-validate form, see
|
|
531
532
|
[forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
|
|
532
|
-
**Storybook:** `Form fields/OtpField` · **React:** `OtpField`, `OtpFormField`
|
|
533
|
+
**Storybook:** `Form fields/OtpField` · **React:** `OtpField`, `OtpFormField`, `InputOTP` (same parts)
|
|
533
534
|
|
|
534
535
|
---
|
|
535
536
|
|
|
@@ -600,13 +601,18 @@ const title = ref('Spring catalogue');
|
|
|
600
601
|
| --- | --- | --- | --- |
|
|
601
602
|
| `v-model` | `string` | `''` | the committed text; updated on save only |
|
|
602
603
|
| `@save` | `(value: string) => void` | — | on save (Enter or the check button), not on each key |
|
|
604
|
+
| `label` | `string` | — | shown above the text; names the input while editing |
|
|
605
|
+
| `name` | `string` | — | the input's `name` while editing, and the field's `data-pw` |
|
|
603
606
|
| `placeholder` | `string` | "Click to edit" | shown while empty |
|
|
604
607
|
| `disabled` | `boolean` | `false` | read-only text |
|
|
605
608
|
|
|
609
|
+
Enter, Escape, Save and Cancel return focus to the field, while a click
|
|
610
|
+
elsewhere saves and leaves focus where it went.
|
|
611
|
+
|
|
606
612
|
**Emits:** `update:modelValue` and `save`, both `string`, trimmed, on save
|
|
607
613
|
only.
|
|
608
|
-
**Form wrapper:**
|
|
609
|
-
[forms](../guides/forms.md#the-pair).
|
|
614
|
+
**Form wrapper:** `InlineEditFormField` (`name` plus the same props; the form
|
|
615
|
+
value changes on save, not while typing), see [forms](../guides/forms.md#the-pair).
|
|
610
616
|
**Storybook:** `Form fields/InlineEdit` · **React:** `InlineEdit`, `InlineEditFormField`
|
|
611
617
|
|
|
612
618
|
---
|
|
@@ -720,7 +726,7 @@ name: 'Satisfaction' })`.
|
|
|
720
726
|
|
|
721
727
|

|
|
722
728
|
|
|
723
|
-
Labelled single or range slider with a value readout.
|
|
729
|
+
Labelled single or range slider with a value readout, ticks and leading / trailing content.
|
|
724
730
|
|
|
725
731
|
```vue
|
|
726
732
|
<script setup lang="ts">
|
|
@@ -731,25 +737,31 @@ const price = ref<number[]>([20, 70]);
|
|
|
731
737
|
</script>
|
|
732
738
|
|
|
733
739
|
<template>
|
|
734
|
-
<SliderField v-model="price" label="Price" :min="0" :max="100" />
|
|
740
|
+
<SliderField v-model="price" label="Price" :min="0" :max="100" :ticks="5" leading="0" trailing="100" />
|
|
735
741
|
</template>
|
|
736
742
|
```
|
|
737
743
|
|
|
738
744
|
In Vue the labelled field is `SliderField`; `Slider` is the bare Reka UI
|
|
739
745
|
slider (track, range and thumbs, `v-model` always `number[]`) it is built on.
|
|
740
|
-
React's
|
|
741
|
-
|
|
746
|
+
React's editable readout inputs are not in `SliderField`: its readout is
|
|
747
|
+
text. `ticks`, `leading` and `trailing` are; for markup on either side of the
|
|
748
|
+
track, use the `#leading` / `#trailing` slots (`SliderFormField` passes them
|
|
749
|
+
through).
|
|
742
750
|
|
|
743
751
|
| Prop | Type | Default | Effect |
|
|
744
752
|
| --- | --- | --- | --- |
|
|
745
753
|
| `v-model` | `number \| number[]` | `[min]` shown when unset | a number for one thumb, an array for one thumb per entry: `[20, 70]` |
|
|
746
754
|
| `min`, `max`, `step` | `number` | `0`, `100`, `1` | range and increment |
|
|
747
755
|
| `show-readout` | `boolean` | `true` | the value(s) next to the label |
|
|
756
|
+
| `ticks` | `boolean \| number` | — | marks under the track: `true` one per `step` (at most 21), a number that many, ends included |
|
|
757
|
+
| `leading`, `trailing` | `string \| number` | — | small muted text before / after the track; the `#leading` / `#trailing` slots take markup |
|
|
748
758
|
| `required` | `boolean` | — | the asterisk, and `aria-required` on every thumb |
|
|
749
759
|
| `aria-invalid` | `boolean \| 'true' \| 'false'` | follows `error` | on every thumb; wins over `error` |
|
|
750
760
|
|
|
751
761
|
Each thumb (`role="slider"`) is named by the label; a range's thumbs add
|
|
752
762
|
"Minimum" and "Maximum": `getByRole('slider', { name: 'Price Minimum' })`.
|
|
763
|
+
A labelled range is also a `role="group"` named by the label, so two range
|
|
764
|
+
sliders are told apart.
|
|
753
765
|
The bare `Slider` does the same with `label-id` (the id of your label) and
|
|
754
766
|
`required`, or with an `aria-labelledby` or `aria-label` you pass (they win
|
|
755
767
|
over `label-id`): a vertical `Slider`, which has no field label, needs one.
|
|
@@ -762,7 +774,7 @@ wins over `error` as on React's `Slider`) goes on every thumb, not on the root
|
|
|
762
774
|
stores the same — the initial value decides.
|
|
763
775
|
**Form wrapper:** `SliderFormField` — `name` inside a vee-validate form, see
|
|
764
776
|
[forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
|
|
765
|
-
**Storybook:** `Form fields/Slider` · **React:** `Slider`, `SliderFormField`
|
|
777
|
+
**Storybook:** `Form fields/Slider` (story `TicksAndEnds`) · **React:** `Slider`, `SliderField` (an alias of `Slider`), `SliderFormField`
|
|
766
778
|
|
|
767
779
|
---
|
|
768
780
|
|
|
@@ -835,7 +847,7 @@ const updates = ref(false);
|
|
|
835
847
|
**Emits:** `update:modelValue` with `boolean`.
|
|
836
848
|
**Form wrapper:** `SwitchFormField` — `name` inside a vee-validate form, see
|
|
837
849
|
[forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
|
|
838
|
-
**Storybook:** `Form fields/Switch`, `Form fields/SwitchField` · **React:** `Switch`, `SwitchFormField`
|
|
850
|
+
**Storybook:** `Form fields/Switch`, `Form fields/SwitchField` · **React:** `Switch`, `SwitchField` (an alias of `Switch`), `SwitchFormField`
|
|
839
851
|
|
|
840
852
|
---
|
|
841
853
|
|
|
@@ -10,7 +10,8 @@ printable documents — plus Leaflet maps, which live outside the barrel in
|
|
|
10
10
|
| <img src="../previews/media-files-s3uploadfield.webp" width="96" alt=""> | [S3UploadField, NetworkUploadField](#s3uploadfield-networkuploadfield) | Drag-and-drop uploader with progress, retry, previews and size / count limits |
|
|
11
11
|
| <img src="../previews/media-files-uploadfield.webp" width="96" alt=""> | [UploadField](#uploadfield) | Labelled file input holding the chosen `File` |
|
|
12
12
|
| <img src="../previews/media-files-filelist.webp" width="96" alt=""> | [FileList](#filelist) | File list with type icons, size, download and remove |
|
|
13
|
-
| | [
|
|
13
|
+
| <img src="../previews/media-files-filepreview.webp" width="96" alt=""> | [FilePreview](#filepreview) | One file previewed by its type: image, PDF, video, audio, text, or a download card |
|
|
14
|
+
| | [FilesFormField](#filesformfield) | Free-solo autocomplete of file URLs, with image thumbnails |
|
|
14
15
|
| <img src="../previews/media-files-imagefield.webp" width="96" alt=""> | [ImageField](#imagefield) | Single image upload with preview and progress |
|
|
15
16
|
| <img src="../previews/media-files-imagecropper.webp" width="96" alt=""> | [ImageCropper](#imagecropper) | Crop with zoom, rotation, aspect presets and a round shape |
|
|
16
17
|
| <img src="../previews/media-files-gallery.webp" width="96" alt=""> | [Gallery, LightboxGallery, MiniGallery](#gallery-lightboxgallery-minigallery) | Image / video gallery with a lightbox and selection |
|
|
@@ -231,13 +232,126 @@ dropzone as well read the error twice, and the group still says it once
|
|
|
231
232
|
|
|
232
233
|
---
|
|
233
234
|
|
|
235
|
+
## FilePreview
|
|
236
|
+
|
|
237
|
+

|
|
238
|
+
|
|
239
|
+
Previews one file, picked by its MIME type (else its extension): an image, a PDF, a video or audio file, the text of a text, JSON, CSV or Markdown file, and a download card for anything else.
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<script setup lang="ts">
|
|
243
|
+
import { ref } from 'vue';
|
|
244
|
+
import { FilePreview } from '@nxgt/material-vue/components';
|
|
245
|
+
|
|
246
|
+
const file = ref<File | null>(null);
|
|
247
|
+
|
|
248
|
+
function pick(event: Event) {
|
|
249
|
+
file.value = (event.target as HTMLInputElement).files?.[0] ?? null;
|
|
250
|
+
}
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<template>
|
|
254
|
+
<input type="file" @change="pick" />
|
|
255
|
+
<!-- A File or Blob: shown through an object URL, revoked on change and unmount. -->
|
|
256
|
+
<FilePreview :file="file" @error="(error) => console.warn(error)" />
|
|
257
|
+
<!-- A URL: the kind comes from `type`, else the extension; `name` is the alt text. -->
|
|
258
|
+
<FilePreview file="/api/files/42" type="application/pdf" name="contract.pdf" />
|
|
259
|
+
</template>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
| Prop | Type | Default | Effect |
|
|
263
|
+
| --- | --- | --- | --- |
|
|
264
|
+
| `file` | `File \| Blob \| string \| null` | — | the file, or its URL; nothing renders without one. A URL must be `http(s):`, relative, `blob:`, or a `data:` URL of an image, video, audio, plain text, CSV, Markdown, JSON or PDF; any other (`javascript:`, `data:text/html`, and also a `data:` URL of XML, TSV or YAML) shows the error state, with no link and nothing loaded |
|
|
265
|
+
| `type` | `string` | the `Blob`'s, or a `data:` URL's | MIME type; picks the kind before the extension does |
|
|
266
|
+
| `name` | `string` | the `File`'s, else the URL's last segment | shown on the card, the image's alt text and the download's file name; "Untitled file" when there is none |
|
|
267
|
+
| `max-text-bytes` | `number` | `262144` (`TEXT_PREVIEW_MAX_BYTES`, 256 KB) | how much of a text kind is read; past it, the preview shows the beginning and says so |
|
|
268
|
+
| `class`, other attributes | | | on the root `<figure>` |
|
|
269
|
+
|
|
270
|
+
| Kind | Picked by | Renders |
|
|
271
|
+
| --- | --- | --- |
|
|
272
|
+
| `image` | `image/*`; `.png` `.jpg` `.jpeg` `.gif` `.webp` `.avif` `.svg` `.bmp` `.ico` | `<img>`, its alt text the file name |
|
|
273
|
+
| `pdf` | `application/pdf`; `.pdf` | [`PdfReader`](#pdfreader), imported the first time a PDF is previewed; the card when the viewer cannot be loaded. A PDF the reader fails to open leaves the preview `ready`: `PdfReader` shows its own error, and the `error` event is not emitted |
|
|
274
|
+
| `video` | `video/*`; `.mp4` `.m4v` `.webm` `.ogv` `.mov` | `<video controls>` |
|
|
275
|
+
| `audio` | `audio/*`; `.mp3` `.wav` `.ogg` `.oga` `.m4a` `.aac` `.flac` `.opus` | `<audio controls>` |
|
|
276
|
+
| `json` | `application/json`, `text/json`, `*+json`; `.json` | [`JsonViewer`](data-display.md#codeblock) |
|
|
277
|
+
| `markdown` | `text/markdown`, `text/x-markdown`; `.md` `.markdown` | [`Markdown`](data-display.md#markdown), rendered; its links are sanitized like any `Markdown`, but a remote image in it still loads, so an untrusted `.md` can make the browser request a URL of its choosing |
|
|
278
|
+
| `csv` | `text/csv`, `application/csv`, `text/tab-separated-values`; `.csv` `.tsv` | the text, in a `<pre>` |
|
|
279
|
+
| `text` | any other `text/*`, `application/xml`, `application/yaml`, `application/javascript`…; `.txt` `.log` `.xml` `.yaml` `.yml` `.ini` `.toml` | the text, in a `<pre>` |
|
|
280
|
+
| `other` | anything else, `application/octet-stream` without a known extension | a [`FileCard`](data-display.md#card-presets): icon, name, size and type, and a Download link |
|
|
281
|
+
|
|
282
|
+
A text kind is fetched (a URL) or read (a `Blob`) up to `max-text-bytes` and
|
|
283
|
+
decoded with the `charset` of the response's `Content-Type` (or of the
|
|
284
|
+
`Blob`'s `type`) when the browser's `TextDecoder` supports it, else as UTF-8;
|
|
285
|
+
a JSON or Markdown file cut by the cap is shown as plain text, with "Showing
|
|
286
|
+
the first 256.0 KB of this file." below it. The `<pre>` and the Markdown box
|
|
287
|
+
are regions named "Contents of {name}"; they scroll and take focus, so a
|
|
288
|
+
keyboard can scroll them.
|
|
289
|
+
|
|
290
|
+
The root is a `<figure>` named "Preview of {name}", with `data-kind` and
|
|
291
|
+
`data-state`: `pending` on the server and before mount — an empty
|
|
292
|
+
placeholder, with no object URL made and nothing fetched, so it hydrates
|
|
293
|
+
without a mismatch — then `loading` ("Loading preview…", put into a `status` live region that
|
|
294
|
+
stays mounted, so it is announced), `ready`
|
|
295
|
+
or `error` ("This file could not be previewed.", an `alert`, with a Download
|
|
296
|
+
link when there is something to download). The kind comes from
|
|
297
|
+
`fileKind({ type, name, url })`, exported too, from
|
|
298
|
+
[`@nxgt/material-core/file-preview`](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/README.md#a-files-preview-file-preview).
|
|
299
|
+
Every string is translated (`material.file-preview.*`, see the
|
|
300
|
+
[i18n guide](../guides/i18n.md)).
|
|
301
|
+
|
|
302
|
+
**Emits:** `error` — `unknown`: the file could not be read (an HTTP error: `FilePreviewHttpError`, with its `status`; a refused URL: `FilePreviewUnsafeUrlError`) or shown (a broken image, video or audio file).
|
|
303
|
+
**Storybook:** `Media & files/FilePreview` · **React:** `FilePreview`
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
234
307
|
## FilesFormField
|
|
235
308
|
|
|
236
|
-
|
|
237
|
-
[`
|
|
238
|
-
|
|
309
|
+
No preview: it has no story title of its own. It is an
|
|
310
|
+
[`AutocompleteFormField`](selection-and-choice.md#autocomplete) bound to
|
|
311
|
+
vee-validate, free-solo by default.
|
|
312
|
+
|
|
313
|
+
Free-solo autocomplete of file URLs, with image thumbnails.
|
|
314
|
+
|
|
315
|
+
```vue
|
|
316
|
+
<script setup lang="ts">
|
|
317
|
+
import { useForm } from 'vee-validate';
|
|
318
|
+
import { FilesFormField } from '@nxgt/material-vue/components';
|
|
319
|
+
|
|
320
|
+
useForm({ initialValues: { photos: [] as string[] } });
|
|
321
|
+
</script>
|
|
322
|
+
|
|
323
|
+
<template>
|
|
324
|
+
<FilesFormField
|
|
325
|
+
name="photos"
|
|
326
|
+
mode="multiple"
|
|
327
|
+
label="Photos"
|
|
328
|
+
placeholder="Paste an image URL"
|
|
329
|
+
image
|
|
330
|
+
:image-link-builder="(key) => `https://cdn.example.com/${key}`"
|
|
331
|
+
/>
|
|
332
|
+
</template>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
| Prop | Type | Default | Effect |
|
|
336
|
+
| --- | --- | --- | --- |
|
|
337
|
+
| `name` | `string` | — | required; the vee-validate field |
|
|
338
|
+
| `mode` | `'single' \| 'multiple'` | `'single'` | one URL or a list |
|
|
339
|
+
| `image` | `boolean` | — | selected values show a thumbnail instead of a file icon |
|
|
340
|
+
| `image-link-builder` | `(value) => string` | — | maps a stored key to the thumbnail `src` |
|
|
341
|
+
| `options` | `T[]`, `T extends { value: string; label: string }` | `[]` | suggestions, typed by your own option type; any typed value is accepted too |
|
|
342
|
+
| `get-option-value` / `get-option-label` | `(option: T) => string` | `option.value` / `option.label` | read another field of your option as its value or label, as on `Autocomplete` |
|
|
343
|
+
| `free-solo` | `boolean` | `true` | accept values that are not in `options` |
|
|
344
|
+
|
|
345
|
+
Like `Autocomplete`, it is generic over `T`, inferred from `options`; it has
|
|
346
|
+
no slots of its own (the chip's leading thumbnail or file icon is its
|
|
347
|
+
`#selected-leading`). Its ref is typed with
|
|
348
|
+
`ComponentExposed`, not `InstanceType`
|
|
349
|
+
([troubleshooting](../troubleshooting.md#does-not-satisfy-the-constraint-abstract-new-args-any--any)).
|
|
350
|
+
|
|
351
|
+
For uploads rather than typed URLs, use [`FileListFormField`](#filelist).
|
|
239
352
|
|
|
240
|
-
**
|
|
353
|
+
**Form wrapper:** it is one — `name` inside a vee-validate form, see [forms](../guides/forms.md#the-pair).
|
|
354
|
+
**Storybook:** `Selection & choice/Autocomplete` (story `FilesFormField`) · **React:** `FilesFormField`
|
|
241
355
|
|
|
242
356
|
---
|
|
243
357
|
|
|
@@ -677,7 +791,7 @@ and emits nothing: the capture stays inside the component. The helpers
|
|
|
677
791
|
`isCameraSupported`, `getCameraDevices`, `requestCameraPermissions` and
|
|
678
792
|
`capturePhotoFromVideo` are exported for building your own.
|
|
679
793
|
|
|
680
|
-
**Storybook:** `Media & files/Camera` · **React:**
|
|
794
|
+
**Storybook:** `Media & files/Camera` · **React:** `Camera`, `useCamera`, `capturePhotoFromVideo` (`createCameraStore` for the store)
|
|
681
795
|
|
|
682
796
|
---
|
|
683
797
|
|
|
@@ -521,6 +521,11 @@ step has no `icon`, and there is no separate `StepperIndicator`.
|
|
|
521
521
|
| `active` | `number` | `0` | current step; its `description` is shown as helper text below, and in a hover tooltip on a decorative info icon |
|
|
522
522
|
| `@change` | `(index: number) => void` | — | a step was clicked |
|
|
523
523
|
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | vertical from `md` only; phones get the compact bar |
|
|
524
|
+
| `name` | `string` | — | the stepper's `data-pw` (`stepper` without it), and the prefix of each step's: `<name>-step-N` instead of `step-N` |
|
|
525
|
+
|
|
526
|
+
Each step is an `<li>` with `data-pw="step-N"` (`<name>-step-N` with `name`),
|
|
527
|
+
N counted from 0, for tests to select; the current step's button carries
|
|
528
|
+
`aria-current="step"`, and a completed or failed step is announced as such.
|
|
524
529
|
|
|
525
530
|
**Storybook:** `Navigation & layout/Stepper` · **React:** `Stepper`
|
|
526
531
|
|
|
@@ -629,11 +634,67 @@ const toc: DocTocItem[] = [{ id: 'what', title: 'What it is', level: 2 }];
|
|
|
629
634
|
```
|
|
630
635
|
|
|
631
636
|
Parts: `Doc` (the shell), `DocPage` (header, content, see also and pager);
|
|
632
|
-
the pieces it composes — `DocTopbar`, `DocSidebar`, `
|
|
633
|
-
`
|
|
634
|
-
`
|
|
637
|
+
the pieces it composes — `DocTopbar`, `DocSidebar`, `DocNav`, `DocArticle`,
|
|
638
|
+
`DocToc`, `DocPager`, `DocSearch`, `DocSeeAlso`, `DocChildCards`,
|
|
639
|
+
`DocProgress`, `DocSkipLink`, `DocHeader`, `DocCopyPage`, `DocCopyMarkdown`,
|
|
640
|
+
`DocLink` — and `DocEmpty` for a 404.
|
|
635
641
|
`useDoc` / `provideDoc` / `useDocContext` expose the state for a shell of
|
|
636
|
-
your own
|
|
642
|
+
your own, built from those parts:
|
|
643
|
+
|
|
644
|
+
```vue
|
|
645
|
+
<script setup lang="ts">
|
|
646
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
647
|
+
import {
|
|
648
|
+
DocArticle,
|
|
649
|
+
type DocNavItem,
|
|
650
|
+
DocLink,
|
|
651
|
+
DocNav,
|
|
652
|
+
provideDoc,
|
|
653
|
+
useDoc,
|
|
654
|
+
} from '@nxgt/material-vue/components';
|
|
655
|
+
|
|
656
|
+
const route = useRoute();
|
|
657
|
+
const router = useRouter();
|
|
658
|
+
|
|
659
|
+
const items: DocNavItem[] = [
|
|
660
|
+
{
|
|
661
|
+
id: 'start',
|
|
662
|
+
title: 'Start',
|
|
663
|
+
items: [
|
|
664
|
+
{ id: 'intro', title: 'Introduction', href: '/docs' },
|
|
665
|
+
{ id: 'install', title: 'Install', href: '/docs/install' },
|
|
666
|
+
],
|
|
667
|
+
},
|
|
668
|
+
];
|
|
669
|
+
|
|
670
|
+
provideDoc(
|
|
671
|
+
useDoc({
|
|
672
|
+
items,
|
|
673
|
+
get pathname() {
|
|
674
|
+
return route.path;
|
|
675
|
+
},
|
|
676
|
+
onNavigate: (href) => router.push(href),
|
|
677
|
+
}),
|
|
678
|
+
);
|
|
679
|
+
</script>
|
|
680
|
+
|
|
681
|
+
<template>
|
|
682
|
+
<div class="flex">
|
|
683
|
+
<DocNav class="w-64" />
|
|
684
|
+
<DocArticle>
|
|
685
|
+
<slot />
|
|
686
|
+
<DocLink href="/docs/install">Next: Install</DocLink>
|
|
687
|
+
</DocArticle>
|
|
688
|
+
</div>
|
|
689
|
+
</template>
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
`DocLink` is an anchor that navigates through `onNavigate` for an internal
|
|
693
|
+
`href` (an external one opens in a new tab); without `@navigate`, it and the
|
|
694
|
+
sidebar are plain anchors that load the page. `DefaultDocLink` is the same
|
|
695
|
+
anchor without the navigation. `DocCopyPage` (`title`) copies the title and
|
|
696
|
+
the page URL; `DocArticle` is the `#doc-content` landmark the skip link and
|
|
697
|
+
copy-as-markdown target. Search, the phone sheet and the active heading live in a Pinia
|
|
637
698
|
store, so the app needs `app.use(createPinia())`.
|
|
638
699
|
|
|
639
700
|
| Prop | Type | Default | Effect |
|
|
@@ -649,10 +710,10 @@ store, so the app needs `app.use(createPinia())`.
|
|
|
649
710
|
On `DocPage`: `title`, `description`, `crumbs`, `editHref`, `updatedAt`,
|
|
650
711
|
`copyPage` / `copyMarkdown` (default: shown) with `markdown` for the copy
|
|
651
712
|
buttons, and a
|
|
652
|
-
`#badge` slot. There is no `linkComponent` on `Doc`
|
|
653
|
-
|
|
713
|
+
`#badge` slot. There is no `linkComponent` on `Doc` in Vue: wire your
|
|
714
|
+
router with `@navigate`.
|
|
654
715
|
|
|
655
|
-
**Storybook:** `Navigation & layout/Doc`, `Navigation & layout/Doc/Api`, `Navigation & layout/Doc/Blocks` · **React:** `Doc`, `DocPage`, `DocTopbar`, `DocSidebar`, `DocToc`, `DocPager`, `DocSearch`, `DocChildCards`, `DocSeeAlso`, `DocEmpty`, `DocProgress`
|
|
716
|
+
**Storybook:** `Navigation & layout/Doc`, `Navigation & layout/Doc/Api`, `Navigation & layout/Doc/Blocks` · **React:** `Doc`, `DocPage`, `DocTopbar`, `DocSidebar`, `DocToc`, `DocPager`, `DocSearch`, `DocChildCards`, `DocSeeAlso`, `DocEmpty`, `DocProgress`, `DocNav`, `DocArticle`, `DocLink`, `DefaultDocLink`, `DocCopyPage`
|
|
656
717
|
|
|
657
718
|
---
|
|
658
719
|
|
|
@@ -557,10 +557,12 @@ const invoices = [{ id: 'INV001', amount: '$250.00' }];
|
|
|
557
557
|
Parts: `Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`,
|
|
558
558
|
`TableHead`, `TableCell`, `TableCaption` — each takes its HTML element's
|
|
559
559
|
attributes — plus `TableEmpty`, a full-width row for "nothing here" (`colspan`
|
|
560
|
-
defaults to `1`: set it to the column count).
|
|
560
|
+
defaults to `1`: set it to the column count). The attributes you put on
|
|
561
|
+
`Table` (`id`, `aria-*`, `style`, listeners) go on the `<table>`, not on its
|
|
562
|
+
scrolling container; `class` too. For sorting, paging and selection
|
|
561
563
|
use `DataTable` on the [Data table, filter & lists](data-table-filter-and-lists.md) page.
|
|
562
564
|
|
|
563
|
-
**Storybook:** `Primitives/Table` · **React:** `Table` (same parts
|
|
565
|
+
**Storybook:** `Primitives/Table` · **React:** `Table` (same parts)
|
|
564
566
|
|
|
565
567
|
---
|
|
566
568
|
|
|
@@ -568,7 +570,7 @@ use `DataTable` on the [Data table, filter & lists](data-table-filter-and-lists.
|
|
|
568
570
|
|
|
569
571
|

|
|
570
572
|
|
|
571
|
-
Tabs whose triggers can take an icon.
|
|
573
|
+
Tabs whose triggers can take an icon. `variant="line"` is the quieter pill style.
|
|
572
574
|
|
|
573
575
|
```vue
|
|
574
576
|
<script setup lang="ts">
|
|
@@ -594,18 +596,35 @@ import {
|
|
|
594
596
|
```
|
|
595
597
|
|
|
596
598
|
Parts: `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`. An icon goes in the
|
|
597
|
-
trigger's slot, before the label
|
|
598
|
-
|
|
599
|
+
trigger's slot, before the label; there is no `icon` prop in Vue. By default
|
|
600
|
+
(`variant="bar"`) the list is one muted pill with the active trigger raised.
|
|
601
|
+
`variant="line"` is React's quieter style: a full-width, scrolling strip of
|
|
602
|
+
light tabs, the active one on the background — `TabsList` and `TabsTrigger`
|
|
603
|
+
read it from `Tabs`.
|
|
604
|
+
|
|
605
|
+
```vue
|
|
606
|
+
<template>
|
|
607
|
+
<Tabs default-value="ts" variant="line">
|
|
608
|
+
<TabsList>
|
|
609
|
+
<TabsTrigger value="ts">TypeScript</TabsTrigger>
|
|
610
|
+
<TabsTrigger value="bash">Bash</TabsTrigger>
|
|
611
|
+
</TabsList>
|
|
612
|
+
<TabsContent value="ts">const n = 1;</TabsContent>
|
|
613
|
+
<TabsContent value="bash">bun install</TabsContent>
|
|
614
|
+
</Tabs>
|
|
615
|
+
</template>
|
|
616
|
+
```
|
|
599
617
|
|
|
600
618
|
| Prop | Type | Default | Effect |
|
|
601
619
|
| --- | --- | --- | --- |
|
|
620
|
+
| `variant` (`Tabs`) | `'bar' \| 'line'` | `'bar'` | the look of the list and its triggers |
|
|
602
621
|
| `default-value` / `v-model` (`Tabs`) | `string \| number` | — | the selected tab, uncontrolled / controlled |
|
|
603
622
|
| `orientation` (`Tabs`) | `'horizontal' \| 'vertical'` | `'horizontal'` | arrow-key direction |
|
|
604
623
|
| `activation-mode` (`Tabs`) | `'automatic' \| 'manual'` | `'automatic'` | select on focus, or only on Enter / click |
|
|
605
624
|
| `value` (`TabsTrigger`, `TabsContent`) | `string \| number` | — (required) | pairs a trigger with its panel |
|
|
606
625
|
|
|
607
626
|
**Emits:** `update:modelValue` on `Tabs` — `string | number`.
|
|
608
|
-
**Storybook:** `Primitives/Tabs` · **React:** `Tabs` (same parts)
|
|
627
|
+
**Storybook:** `Primitives/Tabs` (story `Line`) · **React:** `Tabs` (same parts)
|
|
609
628
|
|
|
610
629
|
---
|
|
611
630
|
|
|
@@ -442,11 +442,29 @@ Monaco mounts on the client only.
|
|
|
442
442
|
| `filename` | `string` | — | shown in the header |
|
|
443
443
|
| `required` | `boolean` | — | the asterisk, and `aria-required` on Monaco's textarea (its `ariaRequired` option) |
|
|
444
444
|
| `label` | `string` | — | shown above the editor, and the name of Monaco's textarea (its `ariaLabel` option) |
|
|
445
|
+
| `options` | `CodeEditorOptions` | — | Monaco's own construction options (`IStandaloneEditorConstructionOptions`), passed as they are; they win over the editor's defaults, and a change reaches the mounted editor |
|
|
445
446
|
|
|
446
|
-
|
|
447
|
-
|
|
447
|
+
```vue
|
|
448
|
+
<script setup lang="ts">
|
|
449
|
+
import { ref } from 'vue';
|
|
450
|
+
import { CodeEditor, type CodeEditorOptions } from '@nxgt/material-vue/components';
|
|
448
451
|
|
|
449
|
-
|
|
452
|
+
const source = ref('const greeting = "hello";\n');
|
|
453
|
+
const options: CodeEditorOptions = { lineNumbers: 'off', fontSize: 16, minimap: { enabled: false } };
|
|
454
|
+
</script>
|
|
455
|
+
|
|
456
|
+
<template>
|
|
457
|
+
<CodeEditor v-model="source" label="Snippet" :options="options" />
|
|
458
|
+
</template>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
`CodeEditorOptions` is a type-only import: Monaco still loads on the client
|
|
462
|
+
only.
|
|
463
|
+
|
|
464
|
+
**Emits:** `update:modelValue` — `string`; `languageChange` — `string`.
|
|
465
|
+
**Form wrapper:** `CodeEditorFormField` (`name` plus the same props, `options`
|
|
466
|
+
included; the error message replaces `helper-text`), see
|
|
467
|
+
[forms](../guides/forms.md#the-pair).
|
|
450
468
|
**Storybook:** `Rich widgets/CodeEditor` · **React:** `CodeEditor`, `CodeEditorFormField`
|
|
451
469
|
|
|
452
470
|
---
|