@nxgt/material-vue 0.27.0 → 0.28.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 (57) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +2 -2
  3. package/dist/{Button-DEUkxkrJ.js → Button-D1uzdbOJ.js} +1 -1
  4. package/dist/{HoverCardTrigger-TDll55LP.js → HoverCardTrigger-DaM5d4hE.js} +2 -2
  5. package/dist/{camera-UJXnnFeb.js → camera-CxXijySa.js} +4 -4
  6. package/dist/{components-BZ1XAK37.js → components-Db9OdMfQ.js} +12929 -12870
  7. package/dist/components.js +5 -5
  8. package/dist/composables.js +2 -2
  9. package/dist/dnd.js +1 -1
  10. package/dist/{form-scope-BFGca0h6.js → form-scope-BILi3ke-.js} +1 -1
  11. package/dist/{i18n-provider-DBusa725.js → i18n-provider-BPK68eqM.js} +1 -1
  12. package/dist/i18n.js +4 -4
  13. package/dist/{icon-button-jHB4MhQ5.js → icon-button-D60G5B_Z.js} +1 -1
  14. package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
  15. package/dist/lib/components/ui/primitives/tabs/Tabs.vue.d.ts +6 -2
  16. package/dist/lib/components/ui/primitives/tabs/TabsList.vue.d.ts +2 -2
  17. package/dist/lib/components/ui/primitives/tabs/TabsTrigger.vue.d.ts +6 -4
  18. package/dist/lib/components/ui/primitives/tabs/tabs-classes.d.ts +27 -0
  19. package/dist/lib/components/ui/primitives/tabs/tabs-indicator.vue.d.ts +25 -0
  20. package/dist/lib/components/ui/primitives/tabs/tabs-variant.d.ts +5 -8
  21. package/dist/lib/components/ui/widgets/emoji/types.d.ts +1 -6
  22. package/dist/lib/i18n/resources/en/en.d.ts +14 -0
  23. package/dist/lib/i18n/resources/en/material.json.d.ts +15 -1
  24. package/dist/lib/i18n/resources/fr/fr.d.ts +14 -0
  25. package/dist/lib/i18n/resources/fr/material.json.d.ts +15 -1
  26. package/dist/lib/i18n/resources/resources.d.ts +28 -0
  27. package/dist/lib/i18n/translator.d.ts +1 -1
  28. package/dist/lib.js +2 -2
  29. package/dist/main.js +10 -10
  30. package/dist/map.js +4 -4
  31. package/dist/material-vue.css +1 -1
  32. package/dist/{pdf-outline-sidebar-ChjAXoUX.js → pdf-outline-sidebar-BXGTDISI.js} +2 -2
  33. package/dist/{pdf-page-D4OTPcpF.js → pdf-page-BR4G03kN.js} +1 -1
  34. package/dist/{pdf-page-list-CFgKYLur.js → pdf-page-list-bjQm6_kf.js} +2 -2
  35. package/dist/{pdf-reader-B1hw81cG.js → pdf-reader-DGVEFNc0.js} +8 -8
  36. package/dist/{pdf-sidebar-Do5HzrDq.js → pdf-sidebar-CiM6dwAm.js} +3 -3
  37. package/dist/{pdf-thumbnail-sidebar-CMge0C9-.js → pdf-thumbnail-sidebar-fM3DGJzD.js} +3 -3
  38. package/dist/{pdf-toolbar-BBio9baU.js → pdf-toolbar-mWlGTWU1.js} +4 -4
  39. package/dist/pdf.js +2 -2
  40. package/dist/{sortable-provider-DMVbbmUU.js → sortable-provider-Dml11nQY.js} +2 -2
  41. package/dist/{stored-language-AJpwOMsA.js → stored-language-UnInBB6T.js} +30 -2
  42. package/dist/{stx-player-gtyStl7e.js → stx-player-BS7-CXFx.js} +2 -2
  43. package/dist/{translator-D2_swsMz.js → translator-J3_vaV_A.js} +1 -1
  44. package/dist/{use-heading-spy-BbEbAfPK.js → use-heading-spy-_dk8kGwL.js} +1 -1
  45. package/dist/{use-material-translation-BHtgyMz3.js → use-material-translation-Do6ztdtV.js} +3 -3
  46. package/docs/components/data-display.md +1 -1
  47. package/docs/components/primitives.md +81 -18
  48. package/docs/components/rich-widgets.md +10 -0
  49. package/docs/guides/i18n.md +19 -2
  50. package/docs/guides/theming.md +17 -3
  51. package/docs/previews/data-display-codegroup.webp +0 -0
  52. package/docs/previews/primitives-tabs.webp +0 -0
  53. package/docs/previews/rich-widgets-emojipicker.webp +0 -0
  54. package/docs/roadmap.md +9 -1
  55. package/docs/troubleshooting.md +35 -0
  56. package/package.json +2 -2
  57. package/dist/lib/components/ui/widgets/emoji/emoji.groups.d.ts +0 -6
@@ -1,7 +1,7 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { Ef as n } from "./components-BZ1XAK37.js";
4
- import { t as r } from "./use-material-translation-BHtgyMz3.js";
3
+ import { Ef as n } from "./components-Db9OdMfQ.js";
4
+ import { t as r } from "./use-material-translation-Do6ztdtV.js";
5
5
  import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, defineComponent as u, normalizeClass as d, normalizeStyle as f, openBlock as p, ref as m, renderList as h, toDisplayString as g, unref as _, withCtx as v } from "vue";
6
6
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-outline-row.vue?vue&type=script&setup=true&lang.ts
7
7
  var y = {
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { kp as t } from "./components-BZ1XAK37.js";
2
+ import { kp as t } from "./components-Db9OdMfQ.js";
3
3
  import { computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, defineComponent as s, nextTick as c, normalizeClass as l, normalizeStyle as u, onBeforeUnmount as d, openBlock as f, ref as p, shallowRef as m, unref as h, watch as g } from "vue";
4
4
  import { DEFAULT_PAGE_SIZE as _, escapeHtml as v, findTextMatches as y, highlightItemHtml as b, placeholderSize as x, rotatedSize as S } from "@nxgt/material-core/pdf-viewer";
5
5
  //#region lib/components/ui/media/pdf-viewer/pdf-note-icons.ts
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
- import { Ef as t } from "./components-BZ1XAK37.js";
3
- import { t as n } from "./pdf-page-D4OTPcpF.js";
2
+ import { Ef as t } from "./components-Db9OdMfQ.js";
3
+ import { t as n } from "./pdf-page-BR4G03kN.js";
4
4
  import { Fragment as r, createBlock as i, createElementBlock as a, createElementVNode as o, defineComponent as s, openBlock as c, renderList as l, withCtx as u } from "vue";
5
5
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-page-list.vue?vue&type=script&setup=true&lang.ts
6
6
  var d = { class: "flex flex-col items-center gap-4 px-4 py-4" }, f = /*@__PURE__*/ s({
@@ -1,12 +1,12 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { On as t } from "./components-BZ1XAK37.js";
3
- import { t as n } from "./use-material-translation-BHtgyMz3.js";
4
- import { t as r } from "./Button-DEUkxkrJ.js";
5
- import { o as i } from "./HoverCardTrigger-TDll55LP.js";
6
- import { n as a } from "./pdf-page-D4OTPcpF.js";
7
- import { t as o } from "./pdf-page-list-CFgKYLur.js";
8
- import { t as s } from "./pdf-sidebar-Do5HzrDq.js";
9
- import { t as c } from "./pdf-toolbar-BBio9baU.js";
2
+ import { On as t } from "./components-Db9OdMfQ.js";
3
+ import { t as n } from "./use-material-translation-Do6ztdtV.js";
4
+ import { t as r } from "./Button-D1uzdbOJ.js";
5
+ import { o as i } from "./HoverCardTrigger-DaM5d4hE.js";
6
+ import { n as a } from "./pdf-page-BR4G03kN.js";
7
+ import { t as o } from "./pdf-page-list-bjQm6_kf.js";
8
+ import { t as s } from "./pdf-sidebar-CiM6dwAm.js";
9
+ import { t as c } from "./pdf-toolbar-mWlGTWU1.js";
10
10
  import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, nextTick as _, normalizeClass as v, onBeforeUnmount as y, onMounted as b, openBlock as x, reactive as S, ref as C, shallowRef as w, toDisplayString as T, toRef as E, unref as D, useId as O, watch as k, withCtx as A } from "vue";
11
11
  import { AlertCircle as j, FileX2 as M, KeyRound as N, Loader2 as P } from "@lucide/vue";
12
12
  import { pdfSourceKey as F, toPdfjsParams as I } from "@nxgt/material-core/pdf-source";
@@ -1,8 +1,8 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { t as n } from "./use-material-translation-BHtgyMz3.js";
4
- import { t as r } from "./pdf-outline-sidebar-ChjAXoUX.js";
5
- import { t as i } from "./pdf-thumbnail-sidebar-CMge0C9-.js";
3
+ import { t as n } from "./use-material-translation-Do6ztdtV.js";
4
+ import { t as r } from "./pdf-outline-sidebar-BXGTDISI.js";
5
+ import { t as i } from "./pdf-thumbnail-sidebar-fM3DGJzD.js";
6
6
  import { createElementBlock as a, createElementVNode as o, createVNode as s, defineComponent as c, normalizeClass as l, openBlock as u, toDisplayString as d, unref as f, useId as p, useTemplateRef as m } from "vue";
7
7
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-sidebar.vue?vue&type=script&setup=true&lang.ts
8
8
  var h = ["aria-label"], g = ["aria-label"], _ = [
@@ -1,8 +1,8 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { Ef as n } from "./components-BZ1XAK37.js";
4
- import { t as r } from "./use-material-translation-BHtgyMz3.js";
5
- import { t as i } from "./pdf-page-D4OTPcpF.js";
3
+ import { Ef as n } from "./components-Db9OdMfQ.js";
4
+ import { t as r } from "./use-material-translation-Do6ztdtV.js";
5
+ import { t as i } from "./pdf-page-BR4G03kN.js";
6
6
  import { Fragment as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createVNode as l, defineComponent as u, normalizeClass as d, openBlock as f, renderList as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
7
7
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-thumbnail-sidebar.vue?vue&type=script&setup=true&lang.ts
8
8
  var _ = ["aria-label"], v = {
@@ -1,10 +1,10 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { t as n } from "./use-material-translation-BHtgyMz3.js";
4
- import { d as r } from "./Button-DEUkxkrJ.js";
5
- import { t as i } from "./icon-button-jHB4MhQ5.js";
3
+ import { t as n } from "./use-material-translation-Do6ztdtV.js";
4
+ import { d as r } from "./Button-D1uzdbOJ.js";
5
+ import { t as i } from "./icon-button-D60G5B_Z.js";
6
6
  import { a, i as o, n as s, o as c, r as l, t as u } from "./DropdownMenuTrigger-BsuyNVzV.js";
7
- import { o as d } from "./HoverCardTrigger-TDll55LP.js";
7
+ import { o as d } from "./HoverCardTrigger-DaM5d4hE.js";
8
8
  import { Fragment as f, computed as p, createBlock as m, createCommentVNode as h, createElementBlock as g, createElementVNode as _, createTextVNode as v, createVNode as y, defineComponent as b, nextTick as x, normalizeClass as S, openBlock as C, ref as w, renderList as T, toDisplayString as E, unref as D, useTemplateRef as O, watch as k, withCtx as A } from "vue";
9
9
  import { ChevronDown as j, ChevronLeft as M, ChevronRight as N, ChevronUp as P, Download as F, Maximize2 as I, Minimize2 as L, Moon as R, Printer as z, RotateCw as B, Search as V, Sidebar as H, ZoomIn as U, ZoomOut as W } from "@lucide/vue";
10
10
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-toolbar-search.vue?vue&type=script&setup=true&lang.ts
package/dist/pdf.js CHANGED
@@ -1,5 +1,5 @@
1
- import { n as e, t } from "./use-material-translation-BHtgyMz3.js";
2
- import { t as n } from "./Button-DEUkxkrJ.js";
1
+ import { n as e, t } from "./use-material-translation-Do6ztdtV.js";
2
+ import { t as n } from "./Button-D1uzdbOJ.js";
3
3
  import { computed as r, createBlock as i, createTextVNode as a, defineComponent as o, getCurrentInstance as s, nextTick as c, onMounted as l, onScopeDispose as u, openBlock as d, ref as f, renderSlot as p, shallowRef as m, toDisplayString as ee, toValue as h, unref as g, watch as te, withCtx as ne } from "vue";
4
4
  import { contentDisposition as re, pdfBytesResponse as ie, toWebStream as ae } from "@nxgt/material-core/pdf/http";
5
5
  import { badge as oe, dataTable as se, defaultPdfTheme as ce, definePdfDocument as _, divider as v, header as y, heading as b, image as x, keyValue as S, keyValueOf as C, link as w, metric as T, page as E, pageBreak as D, pageNumber as O, pdfDocument as k, resolvePdfColor as A, resolvePdfTheme as j, row as M, section as N, spacer as P, stack as F, table as I, text as L, totals as R } from "@nxgt/material-core/pdf/model";
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { t } from "./use-material-translation-BHtgyMz3.js";
3
- import { t as n } from "./icon-button-jHB4MhQ5.js";
2
+ import { t } from "./use-material-translation-Do6ztdtV.js";
3
+ import { t as n } from "./icon-button-D60G5B_Z.js";
4
4
  import { Teleport as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createVNode as c, defineComponent as l, inject as u, mergeProps as d, normalizeStyle as f, onUnmounted as p, openBlock as m, provide as h, reactive as g, ref as _, renderSlot as v, toValue as y, unref as b, useAttrs as x, watch as S, watchEffect as C, withCtx as w, withModifiers as T } from "vue";
5
5
  import { GripVertical as E } from "@lucide/vue";
6
6
  import { Primitive as D } from "reka-ui";
@@ -55,7 +55,21 @@ var e = {
55
55
  picker: "Emoji",
56
56
  pick: "Choose an emoji",
57
57
  search: "Search emoji",
58
- empty: "No emoji match"
58
+ empty: "No emoji match",
59
+ groups: {
60
+ all: "All",
61
+ recent: "Recent",
62
+ general: "General",
63
+ people_body: "People & body",
64
+ components: "Components",
65
+ animals_nature: "Animals & nature",
66
+ food_drink: "Food & drink",
67
+ travel_places: "Travel & places",
68
+ activities: "Activities",
69
+ objects: "Objects",
70
+ symbols: "Symbols",
71
+ flags: "Flags"
72
+ }
59
73
  },
60
74
  mentions: { empty: "No matches" },
61
75
  cards: {
@@ -1240,7 +1254,21 @@ var e = {
1240
1254
  picker: "Emoji",
1241
1255
  pick: "Choisir un emoji",
1242
1256
  search: "Chercher un emoji",
1243
- empty: "Aucun emoji"
1257
+ empty: "Aucun emoji",
1258
+ groups: {
1259
+ all: "Tous",
1260
+ recent: "Récents",
1261
+ general: "Général",
1262
+ people_body: "Personnes et corps",
1263
+ components: "Composants",
1264
+ animals_nature: "Animaux et nature",
1265
+ food_drink: "Nourriture et boissons",
1266
+ travel_places: "Voyages et lieux",
1267
+ activities: "Activités",
1268
+ objects: "Objets",
1269
+ symbols: "Symboles",
1270
+ flags: "Drapeaux"
1271
+ }
1244
1272
  },
1245
1273
  mentions: { empty: "Aucun résultat" },
1246
1274
  cards: {
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { $t as t, Jt as n, Mp as r, Qt as i, Yt as a, Zt as o, en as s, qt as c } from "./components-BZ1XAK37.js";
3
- import { t as l } from "./use-material-translation-BHtgyMz3.js";
2
+ import { $t as t, Jt as n, Mp as r, Qt as i, Yt as a, Zt as o, en as s, qt as c } from "./components-Db9OdMfQ.js";
3
+ import { t as l } from "./use-material-translation-Do6ztdtV.js";
4
4
  import { createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, normalizeClass as _, openBlock as v, toDisplayString as y, unref as b, withCtx as x } from "vue";
5
5
  //#region lib/components/ui/media/stx-player/partials/stx-player-frame.vue?vue&type=script&setup=true&lang.ts
6
6
  var S = ["data-layout", "aria-label"], C = {
@@ -1,4 +1,4 @@
1
- import { a as e, i as t, r as n, t as r } from "./stored-language-AJpwOMsA.js";
1
+ import { a as e, i as t, r as n, t as r } from "./stored-language-UnInBB6T.js";
2
2
  import { t as i } from "./get-CTzJAwfc.js";
3
3
  //#region ../../node_modules/@formatjs/fast-memoize/index.js
4
4
  function a(e, t) {
@@ -1,4 +1,4 @@
1
- import { a as e } from "./i18n-provider-DBusa725.js";
1
+ import { a as e } from "./i18n-provider-BPK68eqM.js";
2
2
  import { c as t, d as n, f as r, l as i, n as a, u as o } from "./number.utils-Cy1z6qI7.js";
3
3
  import { computed as s, getCurrentInstance as c, onMounted as l, ref as u, toValue as d } from "vue";
4
4
  import { useIntersectionObserver as f, useMediaQuery as p, useSSRWidth as m, useStorage as h } from "@vueuse/core";
@@ -1,6 +1,6 @@
1
- import "./stored-language-AJpwOMsA.js";
2
- import { a as e } from "./i18n-provider-DBusa725.js";
3
- import { i as t, r as n } from "./translator-D2_swsMz.js";
1
+ import "./stored-language-UnInBB6T.js";
2
+ import { a as e } from "./i18n-provider-BPK68eqM.js";
3
+ import { i as t, r as n } from "./translator-J3_vaV_A.js";
4
4
  //#region lib/i18n/translate-material.ts
5
5
  function r(e, r, i, a) {
6
6
  if (e) for (let t of /* @__PURE__ */ new Set([e, e.split("-")[0]])) {
@@ -631,7 +631,7 @@ function openEvent() {
631
631
 
632
632
  ![CodeBlock](../previews/data-display-codeblock.webp)
633
633
 
634
- Highlighted code with line numbers and copy, a Monaco diff, a collapsible JSON tree, and tabbed samples (`Tabs variant="line"`).
634
+ Highlighted code with line numbers and copy, a Monaco diff, a collapsible JSON tree, and tabbed samples (`Tabs`, underlined).
635
635
 
636
636
  <img src="../previews/data-display-codegroup.webp" height="96" alt="CodeGroup">
637
637
  <img src="../previews/data-display-jsonviewer.webp" height="96" alt="JsonViewer">
@@ -584,12 +584,12 @@ use `DataTable` on the [Data table, filter & lists](data-table-filter-and-lists.
584
584
 
585
585
  ![Tabs](../previews/primitives-tabs.webp)
586
586
 
587
- Tabs whose triggers can take an icon. `variant="line"` is the quieter pill style.
587
+ Tabs whose triggers can take an icon, in two looks: `underline` (the default) and the `segmented` pill.
588
588
 
589
589
  ```vue
590
590
  <script setup lang="ts">
591
+ import { Calendar, User } from '@lucide/vue';
591
592
  import {
592
- Icon,
593
593
  Tabs,
594
594
  TabsContent,
595
595
  TabsList,
@@ -600,8 +600,11 @@ import {
600
600
  <template>
601
601
  <Tabs default-value="account" class="w-md">
602
602
  <TabsList>
603
- <TabsTrigger value="account"><Icon name="user" />Account</TabsTrigger>
604
- <TabsTrigger value="calendar"><Icon name="calendar" />Calendar</TabsTrigger>
603
+ <TabsTrigger value="account" :icon="User">Account</TabsTrigger>
604
+ <TabsTrigger value="calendar">
605
+ <template #icon><Calendar /></template>
606
+ Calendar
607
+ </TabsTrigger>
605
608
  </TabsList>
606
609
  <TabsContent value="account">Your profile.</TabsContent>
607
610
  <TabsContent value="calendar">Your events.</TabsContent>
@@ -609,36 +612,96 @@ import {
609
612
  </template>
610
613
  ```
611
614
 
612
- Parts: `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`. An icon goes in the
613
- trigger's slot, before the label; there is no `icon` prop in Vue. By default
614
- (`variant="bar"`) the list is one muted pill with the active trigger raised.
615
- `variant="line"` is React's quieter style: a full-width, scrolling strip of
616
- light tabs, the active one on the background — `TabsList` and `TabsTrigger`
617
- read it from `Tabs`.
615
+ Parts: `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`. `TabsList` and
616
+ `TabsTrigger` read the look from `Tabs`. A trigger's icon goes before its
617
+ label, as `@nxgt/material`'s `icon`: pass a component to the `icon` prop, or
618
+ fill the `#icon` slot. An icon written in the default slot still renders
619
+ beside the label.
620
+
621
+ **`underline`** (the default) lays the tabs over a border; the active one
622
+ takes the primary colour, and a bar under it slides to the tab clicked or
623
+ reached with the arrow keys. The list scrolls sideways when the tabs do not
624
+ fit (its scrollbar hidden), which suits a phone or a narrow popover.
625
+
626
+ **`segmented`** is a neutral pill track: the active tab sits on a raised
627
+ surface that slides between tabs, and its label turns to the foreground
628
+ colour and semibold — the state never rests on the surface alone. It suits a
629
+ few short choices, such as a view switch.
618
630
 
619
631
  ```vue
620
632
  <template>
621
- <Tabs default-value="ts" variant="line">
633
+ <Tabs default-value="week" variant="segmented">
622
634
  <TabsList>
623
- <TabsTrigger value="ts">TypeScript</TabsTrigger>
624
- <TabsTrigger value="bash">Bash</TabsTrigger>
635
+ <TabsTrigger value="day">Day</TabsTrigger>
636
+ <TabsTrigger value="week">Week</TabsTrigger>
637
+ <TabsTrigger value="month">Month</TabsTrigger>
625
638
  </TabsList>
626
- <TabsContent value="ts">const n = 1;</TabsContent>
627
- <TabsContent value="bash">bun install</TabsContent>
639
+ <TabsContent value="day">Today.</TabsContent>
640
+ <TabsContent value="week">This week.</TabsContent>
641
+ <TabsContent value="month">This month.</TabsContent>
628
642
  </Tabs>
629
643
  </template>
630
644
  ```
631
645
 
646
+ `orientation="vertical"` lays the tabs in a column, the indicator on their
647
+ left side; the arrow keys become Up and Down.
648
+
649
+ ```vue
650
+ <template>
651
+ <Tabs default-value="profile" orientation="vertical">
652
+ <TabsList>
653
+ <TabsTrigger value="profile">Profile</TabsTrigger>
654
+ <TabsTrigger value="security">Security</TabsTrigger>
655
+ </TabsList>
656
+ <TabsContent value="profile">Your profile.</TabsContent>
657
+ <TabsContent value="security">Your sessions.</TabsContent>
658
+ </Tabs>
659
+ </template>
660
+ ```
661
+
662
+ The sliding indicator is reka's `TabsIndicator`, which renders once mounted:
663
+ server HTML, and a page without JavaScript, show a static indicator under (or
664
+ behind) the active tab instead, and hydrating swaps one for the other without
665
+ a mismatch. The list then carries `data-indicator="ready"`. The focus ring is
666
+ an outline in the primary colour inside the tab, so a scrolling list never
667
+ clips it.
668
+
669
+ With `TabsList asChild`, only the static indicator is drawn.
670
+
671
+ `dir="rtl"` on `Tabs` (or reka's `ConfigProvider`) runs the tabs from the
672
+ right: the indicator follows them, and the Left arrow key moves to the next
673
+ tab. Under `prefers-reduced-motion: reduce` the indicator jumps to the active
674
+ tab instead of sliding.
675
+
676
+ **A tab with only an icon needs a name.** A screen reader announces a
677
+ `TabsTrigger` by its text; with an icon and no label it is only "tab". Give it
678
+ `aria-label`, and `title` for sighted users who hover it:
679
+
680
+ ```vue
681
+ <TabsTrigger value="recent" :icon="Clock" aria-label="Recent" title="Recent" />
682
+ ```
683
+
684
+ The emoji picker's group tabs are named this way, from
685
+ `material.emoji.groups.*`.
686
+
687
+ **The default look changed.** A `Tabs` with no `variant` used to render the
688
+ `bar` look (one muted pill with the active trigger raised); it now renders
689
+ `underline`. `variant="bar"` and `variant="line"` are deprecated aliases:
690
+ `bar` renders as `underline`, `line` as `segmented`. Both still type-check and
691
+ render; write `underline` or `segmented` instead.
692
+
632
693
  | Prop | Type | Default | Effect |
633
694
  | --- | --- | --- | --- |
634
- | `variant` (`Tabs`) | `'bar' \| 'line'` | `'bar'` | the look of the list and its triggers |
695
+ | `variant` (`Tabs`) | `'underline' \| 'segmented' \| 'bar' \| 'line'` | `'underline'` | the look; `bar` and `line` are deprecated aliases of `underline` and `segmented` |
635
696
  | `default-value` / `v-model` (`Tabs`) | `string \| number` | — | the selected tab, uncontrolled / controlled |
636
- | `orientation` (`Tabs`) | `'horizontal' \| 'vertical'` | `'horizontal'` | arrow-key direction |
697
+ | `orientation` (`Tabs`) | `'horizontal' \| 'vertical'` | `'horizontal'` | a row or a column, and the arrow keys' direction |
698
+ | `dir` (`Tabs`) | `'ltr' \| 'rtl'` | `'ltr'` | the reading direction: which way the tabs run and the arrow keys move |
637
699
  | `activation-mode` (`Tabs`) | `'automatic' \| 'manual'` | `'automatic'` | select on focus, or only on Enter / click |
638
700
  | `value` (`TabsTrigger`, `TabsContent`) | `string \| number` | — (required) | pairs a trigger with its panel |
701
+ | `icon` (`TabsTrigger`) | `Component` | — | shown before the label; or the `#icon` slot |
639
702
 
640
703
  **Emits:** `update:modelValue` on `Tabs` — `string | number`.
641
- **Storybook:** `Primitives/Tabs` (story `Line`) · **React:** `Tabs` (same parts)
704
+ **Storybook:** `Primitives/Tabs` (stories `Underline`, `Segmented`, `WithIcons`, `Scrolling`, `RightToLeft`, `Vertical`, `DeprecatedAliases`, `Hydrated`) · **React:** `Tabs` (same parts, the same variants)
642
705
 
643
706
  ---
644
707
 
@@ -272,6 +272,16 @@ const emojis: EmojiItem[] = [
272
272
  Parts: `EmojiPicker` (a button opening a popover), `EmojiList` (the searchable
273
273
  grid on its own, same `emojis` / `@select`), `expandEmojiShortcodes`.
274
274
 
275
+ The category tabs are icon-only. Each is named from
276
+ `material.emoji.groups.<group>` (for example `people_body`, `flags`): that name
277
+ is its `aria-label` and `title`, in the provider's language (see
278
+ [i18n](../guides/i18n.md)). An `EmojiItem` with no `group` falls under
279
+ `general`; a `group` is lowercased, with ` & ` and spaces turned into `_`
280
+ ("Food & Drink" becomes `food_drink`). A group the bundles do not name gets
281
+ its words, capitalised, as an English name (`hand_signs` becomes "Hand
282
+ signs"), and an icon of its own is not provided: it shows the generic grid
283
+ icon.
284
+
275
285
  | Prop | Type | Default | Effect |
276
286
  | --- | --- | --- | --- |
277
287
  | `emojis` | `EmojiItem[]` | — (required) | the set offered; `group` drives the category tabs, `shortcodes` the search |
@@ -405,10 +405,27 @@ and description and against the English ones, ignoring accents: in French,
405
405
 
406
406
  Some strings are still English in every language, among them the filter's
407
407
  validation messages, the camera's error messages, the editor's callout type
408
- names and default block content, and the names of the emoji picker's category
409
- tabs. File sizes (`2.0 KB`) and the filter chips' dates are not formatted for
408
+ names and default block content. File sizes (`2.0 KB`) and the filter chips' dates are not formatted for
410
409
  the provider's language.
411
410
 
411
+ The emoji picker's category tabs are icon-only; their name, read by screen
412
+ readers and shown as a tooltip, comes from `material.emoji.groups.<group>`.
413
+ Both languages ship `all`, `recent`, `general`, `people_body`, `components`,
414
+ `animals_nature`, `food_drink`, `travel_places`, `activities`, `objects`,
415
+ `symbols` and `flags`:
416
+
417
+ ```ts
418
+ // English / French values of the shipped keys
419
+ material.emoji.groups.people_body; // "People & body" / "Personnes et corps"
420
+ material.emoji.groups.food_drink; // "Food & drink" / "Nourriture et boissons"
421
+ material.emoji.groups.flags; // "Flags" / "Drapeaux"
422
+ ```
423
+
424
+ A group your `EmojiItem`s name that is not in this list (`hand_signs`) reads
425
+ as its words in English (`Hand signs`). As for every `material.*` key above,
426
+ the components read their own bundle: your own translator sees a key you add,
427
+ the tab does not.
428
+
412
429
  That override is visible only through **your** translator. The components
413
430
  translate through the package's own bundle, so defining
414
431
  `material.command.title` in your resources changes what
@@ -190,9 +190,23 @@ Storybook's `Guides/Theming/Contrast` measures all of this in both themes:
190
190
  the surfaces' text, the error text (`HelperText` and a field's message on
191
191
  `--background` and `--card`), the `Alert`s and the `Timeline`, `Button` and
192
192
  `IconButton` in every variant and colour, and a `Badge` link in every colour,
193
- at rest, hovered, focused and pressed, and the tracks; `Data display/ListTile`
194
- measures the selected tile. Run them against your own tokens after an
195
- override.
193
+ at rest, hovered, focused and pressed, the tracks and the tabs;
194
+ `Data display/ListTile` measures the selected tile. Run them against your own
195
+ tokens after an override.
196
+
197
+ **Tabs.** An `underline` tab's active label is `--primary` in the light
198
+ theme (7.3:1 on `--background` and `--card`, 6.7:1 on `--muted`) and
199
+ `--primary` mixed with 60 % white in the dark one (10.0:1, 9.0:1 and 7.4:1);
200
+ its bar and every tab's focus outline are `--primary` in the light theme and
201
+ `--track-fill` in the dark one (at least 6.7:1 and 9.0:1 on those surfaces).
202
+ An inactive label is `--muted-foreground`, and turns to `--foreground` when
203
+ hovered. A `segmented` tab's active label is `--foreground` on the raised
204
+ surface (19.9:1 light, 17.0:1 dark); that surface is only 1.1:1 to 1.2:1 on
205
+ the track, so it has a `--muted-foreground` border (5.0:1 light, 4.7:1 dark
206
+ on the track), and the label also changes colour and weight. Storybook's
207
+ `Guides/Theming/Contrast` story `Tabs` measures each label at rest, hovered
208
+ and focused, the outline, the bar and the border, on the three surfaces, in
209
+ both themes.
196
210
 
197
211
  `--muted-foreground` is 5.5:1 on `--background` and `--card`, 5.1:1 on the
198
212
  "paper" tint (`bg-background-paper`, 5 % primary) and 5.0:1 on `--muted` in
Binary file
package/docs/roadmap.md CHANGED
@@ -95,6 +95,13 @@ Nothing in progress right now; see Next.
95
95
 
96
96
  ## Shipped
97
97
 
98
+ - **Tabs in two looks** — `underline`, the new default, whose bar slides to
99
+ the active tab, and a neutral `segmented` pill; a list that scrolls
100
+ sideways on a phone instead of widening the page, right-to-left, a visible
101
+ focus ring, labels that read 4.5:1 in both themes, and an indicator that
102
+ stops sliding under `prefers-reduced-motion`. `bar` and `line` still work,
103
+ as deprecated aliases of `underline` and `segmented`. 0.28.0.
104
+
98
105
  - **Accessible by default** — error text in its own `--error-text` colour that
99
106
  reads 4.5:1 in both themes, the empty part of sliders and meters in a
100
107
  `--track` colour that reads 3:1, buttons, badges and status colours that
@@ -127,7 +134,8 @@ Nothing in progress right now; see Next.
127
134
  form, date fields that disable chosen days, `SliderField` ticks and
128
135
  leading/trailing content, a presence status on `Avatar`, a logo slot on the
129
136
  QR code, slots on `AccordionCard`, an option slot on `SelectField`, Monaco's
130
- own options on `CodeEditor` and a line variant for `Tabs`. 0.25.0.
137
+ own options on `CodeEditor` and a line variant for `Tabs` (`line` is now a
138
+ deprecated alias of `segmented`). 0.25.0.
131
139
  - **DateRangeField presets and time** — one-click ranges such as Today, Last 7
132
140
  days and This month, or your own, beside the calendar (`presets`), and a time
133
141
  of day on each end of the range (`with-time`), and `min-date` / `max-date`.
@@ -61,6 +61,8 @@ words in your error.
61
61
 
62
62
  - [A `ListTile` link reloads the whole page](#a-listtile-link-reloads-the-whole-page)
63
63
  - [The phone menu needs two Escapes to close, or a tooltip shows over it](#the-phone-menu-needs-two-escapes-to-close-or-a-tooltip-shows-over-it)
64
+ - [`Tabs` look different after upgrading](#tabs-look-different-after-upgrading)
65
+ - [A screen reader announces an icon-only tab as "tab", with no name](#a-screen-reader-announces-an-icon-only-tab-as-tab-with-no-name)
64
66
 
65
67
  **SSR & build**
66
68
 
@@ -1242,6 +1244,39 @@ the tooltip's own layer takes the first Escape.
1242
1244
  tooltip, since it shows its label; a collapsed one keeps it, and an explicit
1243
1245
  `tooltip` is always shown. A `SidebarMenuItem` of your own needs no change.
1244
1246
 
1247
+ ### `Tabs` look different after upgrading
1248
+
1249
+ **When:** a `Tabs` with no `variant`, or with `variant="bar"`, renders a row of
1250
+ tabs over a border with a bar under the active one, where it rendered
1251
+ one muted pill with the active trigger raised;
1252
+ one with `variant="line"` renders a rounded pill.
1253
+ **Why:** `underline` is now the default look. `bar` and `line` are deprecated
1254
+ aliases: `bar` renders as `underline`, `line` as `segmented`.
1255
+ **Fix:** write the look you want. `underline` needs no `variant`; for a pill,
1256
+ set `segmented`:
1257
+
1258
+ ```vue
1259
+ <Tabs default-value="week" variant="segmented">
1260
+ ```
1261
+
1262
+ A test that queried the old classes should query the state instead:
1263
+ `getByRole('tab', { selected: true })`, and `data-variant` on
1264
+ `[data-slot="tabs"]` for the look.
1265
+
1266
+ ### A screen reader announces an icon-only tab as "tab", with no name
1267
+
1268
+ **When:** a `TabsTrigger` holds only an icon; an accessibility audit reports a
1269
+ tab with no accessible name.
1270
+ **Why:** a tab is named by its text, and an icon has none.
1271
+ **Fix:** give the trigger `aria-label`, and `title` for a hover hint:
1272
+
1273
+ ```vue
1274
+ <TabsTrigger value="recent" :icon="Clock" aria-label="Recent" title="Recent" />
1275
+ ```
1276
+
1277
+ `EmojiList` and `EmojiPicker` name their group tabs themselves; update
1278
+ `@nxgt/material-vue` if yours read "tab" only.
1279
+
1245
1280
  ## SSR & build
1246
1281
 
1247
1282
  ### `ReferenceError: window is not defined`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material-vue",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"
@@ -119,7 +119,7 @@
119
119
  "docs:previews": "vitest run --project previews"
120
120
  },
121
121
  "dependencies": {
122
- "@nxgt/material-core": "^0.5.0",
122
+ "@nxgt/material-core": "^0.6.0",
123
123
  "@floating-ui/dom": "^1.8.0",
124
124
  "@fortawesome/fontawesome-common-types": "7.3.1",
125
125
  "@lucide/vue": "^1.45.0",
@@ -1,6 +0,0 @@
1
- import { EmojiItem } from './types';
2
- export declare function groupKey(group?: string | null): string;
3
- export declare function groupEmojis(emojis: EmojiItem[], recent: string[]): {
4
- [k: string]: EmojiItem[];
5
- };
6
- export declare function searchEmojis(emojis: EmojiItem[], query: string): EmojiItem[] | null;