@bmxc/pami-elements 0.1.0-beta.1 → 0.1.0-beta.2

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 (949) hide show
  1. package/README.md +11 -28
  2. package/bin/templates/astro/package.json +2 -2
  3. package/bin/templates/html/index.html +2 -2
  4. package/bin/templates/html/package.json +2 -2
  5. package/bin/templates/next/package.json +3 -3
  6. package/bin/templates/nuxt/package.json +2 -2
  7. package/bin/templates/sveltekit/package.json +2 -2
  8. package/custom-elements.json +1359 -227
  9. package/dist/cjs/{a11y-Ca42WC0-.js → a11y-BkZcUjqf.js} +3 -3
  10. package/dist/cjs/{a11y-Ca42WC0-.js.map → a11y-BkZcUjqf.js.map} +1 -1
  11. package/dist/cjs/{bar-chart-C5fkmmAE.js → bar-chart-H044QgXk.js} +4 -4
  12. package/dist/cjs/{bar-chart-C5fkmmAE.js.map → bar-chart-H044QgXk.js.map} +1 -1
  13. package/dist/cjs/{chart-CHUt-2H0.js → chart-XXwCCL0v.js} +4 -4
  14. package/dist/cjs/{chart-CHUt-2H0.js.map → chart-XXwCCL0v.js.map} +1 -1
  15. package/dist/cjs/{hit-test-ChmAe1Nv.js → hit-test-C-8-_ADP.js} +3 -3
  16. package/dist/cjs/{hit-test-ChmAe1Nv.js.map → hit-test-C-8-_ADP.js.map} +1 -1
  17. package/dist/cjs/isolation-escape-DfVN8s6G.js +92 -0
  18. package/dist/cjs/isolation-escape-DfVN8s6G.js.map +1 -0
  19. package/dist/cjs/loader.cjs.js +1 -1
  20. package/dist/cjs/pami-app-bar.cjs.entry.js +2 -2
  21. package/dist/cjs/pami-app-bar.cjs.entry.js.map +1 -1
  22. package/dist/cjs/pami-area-chart.cjs.entry.js +4 -4
  23. package/dist/cjs/pami-avatar_2.cjs.entry.js +2 -2
  24. package/dist/cjs/pami-avatar_2.cjs.entry.js.map +1 -1
  25. package/dist/cjs/pami-bar-chart.cjs.entry.js +4 -4
  26. package/dist/cjs/pami-bottom-sheet.cjs.entry.js +2 -2
  27. package/dist/cjs/pami-bottom-sheet.cjs.entry.js.map +1 -1
  28. package/dist/cjs/pami-breadcrumb-item.cjs.entry.js +2 -2
  29. package/dist/cjs/pami-breadcrumb-item.cjs.entry.js.map +1 -1
  30. package/dist/cjs/pami-button_7.cjs.entry.js +23 -39
  31. package/dist/cjs/pami-button_7.cjs.entry.js.map +1 -1
  32. package/dist/cjs/pami-callout.cjs.entry.js +30 -0
  33. package/dist/cjs/pami-callout.cjs.entry.js.map +1 -0
  34. package/dist/cjs/pami-checkbox.cjs.entry.js +5 -5
  35. package/dist/cjs/pami-checkbox.cjs.entry.js.map +1 -1
  36. package/dist/cjs/pami-chip.cjs.entry.js +5 -5
  37. package/dist/cjs/pami-chip.cjs.entry.js.map +1 -1
  38. package/dist/cjs/pami-date-picker.cjs.entry.js +4 -5
  39. package/dist/cjs/pami-date-picker.cjs.entry.js.map +1 -1
  40. package/dist/cjs/pami-dialog.cjs.entry.js +4 -4
  41. package/dist/cjs/pami-dialog.cjs.entry.js.map +1 -1
  42. package/dist/cjs/pami-divider.cjs.entry.js +2 -2
  43. package/dist/cjs/pami-fab-menu-item.cjs.entry.js +5 -5
  44. package/dist/cjs/pami-fab-menu-item.cjs.entry.js.map +1 -1
  45. package/dist/cjs/pami-fab-menu.cjs.entry.js +2 -2
  46. package/dist/cjs/pami-fab.cjs.entry.js +5 -5
  47. package/dist/cjs/pami-fab.cjs.entry.js.map +1 -1
  48. package/dist/cjs/pami-line-chart.cjs.entry.js +6 -6
  49. package/dist/cjs/pami-list-item.cjs.entry.js +2 -2
  50. package/dist/cjs/pami-list-item.cjs.entry.js.map +1 -1
  51. package/dist/cjs/pami-menu-item-group.cjs.entry.js +2 -2
  52. package/dist/cjs/pami-menu-item-group.cjs.entry.js.map +1 -1
  53. package/dist/cjs/pami-menu_2.cjs.entry.js +5 -88
  54. package/dist/cjs/pami-menu_2.cjs.entry.js.map +1 -1
  55. package/dist/cjs/pami-meter.cjs.entry.js +2 -2
  56. package/dist/cjs/pami-multi-select.cjs.entry.js +3 -3
  57. package/dist/cjs/pami-multi-select.cjs.entry.js.map +1 -1
  58. package/dist/cjs/pami-navigation-bar.cjs.entry.js +2 -2
  59. package/dist/cjs/pami-navigation-bar.cjs.entry.js.map +1 -1
  60. package/dist/cjs/pami-navigation-group.cjs.entry.js +24 -0
  61. package/dist/cjs/pami-navigation-group.cjs.entry.js.map +1 -0
  62. package/dist/cjs/pami-navigation-rail-tab.cjs.entry.js +156 -9
  63. package/dist/cjs/pami-navigation-rail-tab.cjs.entry.js.map +1 -1
  64. package/dist/cjs/pami-navigation-rail.cjs.entry.js +211 -29
  65. package/dist/cjs/pami-navigation-rail.cjs.entry.js.map +1 -1
  66. package/dist/cjs/pami-navigation-tab.cjs.entry.js +3 -3
  67. package/dist/cjs/pami-navigation-tab.cjs.entry.js.map +1 -1
  68. package/dist/cjs/pami-organization-chart.cjs.entry.js +1 -1
  69. package/dist/cjs/pami-organization-chart.cjs.entry.js.map +1 -1
  70. package/dist/cjs/{pami-painter-CEq_kp4Z.js → pami-painter-WpO-HKN2.js} +260 -57
  71. package/dist/cjs/pami-painter-WpO-HKN2.js.map +1 -0
  72. package/dist/cjs/pami-pie-chart.cjs.entry.js +4 -4
  73. package/dist/cjs/pami-progress-indicator.cjs.entry.js +1 -1
  74. package/dist/cjs/pami-rating.cjs.entry.js +3 -3
  75. package/dist/cjs/pami-rating.cjs.entry.js.map +1 -1
  76. package/dist/cjs/pami-search.cjs.entry.js +1 -1
  77. package/dist/cjs/pami-search.cjs.entry.js.map +1 -1
  78. package/dist/cjs/pami-segmented-button-set.cjs.entry.js +2 -2
  79. package/dist/cjs/pami-segmented-button.cjs.entry.js +6 -6
  80. package/dist/cjs/pami-segmented-button.cjs.entry.js.map +1 -1
  81. package/dist/cjs/pami-select.cjs.entry.js +2 -2
  82. package/dist/cjs/pami-side-sheet.cjs.entry.js +49 -22
  83. package/dist/cjs/pami-side-sheet.cjs.entry.js.map +1 -1
  84. package/dist/cjs/pami-skeleton.cjs.entry.js +1 -1
  85. package/dist/cjs/pami-slider.cjs.entry.js +2 -2
  86. package/dist/cjs/pami-slider.cjs.entry.js.map +1 -1
  87. package/dist/cjs/pami-sparkline.cjs.entry.js +4 -4
  88. package/dist/cjs/pami-split-button.cjs.entry.js +6 -6
  89. package/dist/cjs/pami-split-button.cjs.entry.js.map +1 -1
  90. package/dist/cjs/pami-step.cjs.entry.js +7 -7
  91. package/dist/cjs/pami-stepper.cjs.entry.js +3 -3
  92. package/dist/cjs/pami-sub-menu-item.cjs.entry.js +4 -4
  93. package/dist/cjs/pami-sub-menu-item.cjs.entry.js.map +1 -1
  94. package/dist/cjs/pami-switch.cjs.entry.js +4 -4
  95. package/dist/cjs/pami-switch.cjs.entry.js.map +1 -1
  96. package/dist/cjs/pami-tab-panel.cjs.entry.js +1 -1
  97. package/dist/cjs/pami-tab-panels.cjs.entry.js +1 -1
  98. package/dist/cjs/pami-tab.cjs.entry.js +5 -5
  99. package/dist/cjs/pami-table-body.cjs.entry.js +1 -1
  100. package/dist/cjs/pami-table-cell.cjs.entry.js +2 -2
  101. package/dist/cjs/pami-table-container.cjs.entry.js +2 -2
  102. package/dist/cjs/pami-table-expand-toggle.cjs.entry.js +2 -2
  103. package/dist/cjs/pami-table-foot.cjs.entry.js +1 -1
  104. package/dist/cjs/pami-table-head.cjs.entry.js +1 -1
  105. package/dist/cjs/pami-table-pagination.cjs.entry.js +2 -2
  106. package/dist/cjs/pami-table-row.cjs.entry.js +4 -4
  107. package/dist/cjs/pami-table-sort-label.cjs.entry.js +2 -2
  108. package/dist/cjs/pami-table-toolbar.cjs.entry.js +2 -2
  109. package/dist/cjs/pami-tabs.cjs.entry.js +2 -2
  110. package/dist/cjs/pami-tag.cjs.entry.js +27 -0
  111. package/dist/cjs/pami-tag.cjs.entry.js.map +1 -0
  112. package/dist/cjs/pami-text-field.cjs.entry.js +2 -2
  113. package/dist/cjs/pami-text-field.cjs.entry.js.map +1 -1
  114. package/dist/cjs/pami-toolbar.cjs.entry.js +3 -3
  115. package/dist/cjs/pami-transfer-list.cjs.entry.js +1 -1
  116. package/dist/cjs/pami-transfer-list.cjs.entry.js.map +1 -1
  117. package/dist/cjs/pami.cjs.js +1 -1
  118. package/dist/cjs/{ripple-CiICEyeg.js → ripple-xSbG6X8P.js} +7 -2
  119. package/dist/cjs/ripple-xSbG6X8P.js.map +1 -0
  120. package/dist/cjs/{rtl-D4GO_8Co.js → rtl-Dof3JElE.js} +27 -5
  121. package/dist/cjs/rtl-Dof3JElE.js.map +1 -0
  122. package/dist/cjs/status-surface-BWKxIZPo.js +13 -0
  123. package/dist/cjs/status-surface-BWKxIZPo.js.map +1 -0
  124. package/dist/cjs/virtual-select-controller-BwjMiADh.js.map +1 -1
  125. package/dist/collection/collection-manifest.json +3 -0
  126. package/dist/collection/components/pami-app-bar/pami-app-bar.css +85 -86
  127. package/dist/collection/components/pami-bottom-sheet/pami-bottom-sheet.css +85 -86
  128. package/dist/collection/components/pami-breadcrumb-item/pami-breadcrumb-item.css +85 -86
  129. package/dist/collection/components/pami-button/pami-button.css +85 -86
  130. package/dist/collection/components/pami-callout/pami-callout.css +298 -0
  131. package/dist/collection/components/pami-callout/pami-callout.js +94 -0
  132. package/dist/collection/components/pami-callout/pami-callout.js.map +1 -0
  133. package/dist/collection/components/pami-card/pami-card.css +85 -86
  134. package/dist/collection/components/pami-checkbox/pami-checkbox.css +85 -86
  135. package/dist/collection/components/pami-checkbox/pami-checkbox.js +2 -2
  136. package/dist/collection/components/pami-chip/pami-chip.css +85 -86
  137. package/dist/collection/components/pami-chip/pami-chip.js +2 -2
  138. package/dist/collection/components/pami-date-picker/pami-date-picker.js +3 -4
  139. package/dist/collection/components/pami-date-picker/pami-date-picker.js.map +1 -1
  140. package/dist/collection/components/pami-dialog/pami-dialog.css +85 -86
  141. package/dist/collection/components/pami-dialog/pami-dialog.js +2 -2
  142. package/dist/collection/components/pami-divider/pami-divider.js +2 -2
  143. package/dist/collection/components/pami-fab/pami-fab.css +85 -86
  144. package/dist/collection/components/pami-fab/pami-fab.js +2 -2
  145. package/dist/collection/components/pami-fab-menu/pami-fab-menu.js +2 -2
  146. package/dist/collection/components/pami-fab-menu-item/pami-fab-menu-item.css +85 -86
  147. package/dist/collection/components/pami-fab-menu-item/pami-fab-menu-item.js +2 -2
  148. package/dist/collection/components/pami-icon/pami-icon.js +1 -1
  149. package/dist/collection/components/pami-icon-button/pami-icon-button.css +85 -86
  150. package/dist/collection/components/pami-line-chart/pami-line-chart.js +2 -2
  151. package/dist/collection/components/pami-list-item/pami-list-item.css +1597 -1599
  152. package/dist/collection/components/pami-menu/pami-menu.css +1 -1
  153. package/dist/collection/components/pami-menu-item/pami-menu-item.css +5 -5
  154. package/dist/collection/components/pami-menu-item-group/pami-menu-item-group.css +2 -2
  155. package/dist/collection/components/pami-menu-item-group/pami-menu-item-group.js +1 -1
  156. package/dist/collection/components/pami-meter/pami-meter.js +2 -2
  157. package/dist/collection/components/pami-multi-select/pami-multi-select.css +4 -4
  158. package/dist/collection/components/pami-multi-select/pami-multi-select.js +2 -2
  159. package/dist/collection/components/pami-navigation-bar/pami-navigation-bar.css +85 -86
  160. package/dist/collection/components/pami-navigation-group/pami-navigation-group.css +30 -0
  161. package/dist/collection/components/pami-navigation-group/pami-navigation-group.js +76 -0
  162. package/dist/collection/components/pami-navigation-group/pami-navigation-group.js.map +1 -0
  163. package/dist/collection/components/pami-navigation-rail/pami-navigation-rail.css +70 -1
  164. package/dist/collection/components/pami-navigation-rail/pami-navigation-rail.js +452 -42
  165. package/dist/collection/components/pami-navigation-rail/pami-navigation-rail.js.map +1 -1
  166. package/dist/collection/components/pami-navigation-rail-tab/pami-navigation-rail-tab.css +186 -98
  167. package/dist/collection/components/pami-navigation-rail-tab/pami-navigation-rail-tab.js +282 -6
  168. package/dist/collection/components/pami-navigation-rail-tab/pami-navigation-rail-tab.js.map +1 -1
  169. package/dist/collection/components/pami-navigation-tab/pami-navigation-tab.css +85 -86
  170. package/dist/collection/components/pami-organization-chart/pami-organization-chart.css +1 -1
  171. package/dist/collection/components/pami-pie-chart/pami-pie-chart.js +2 -2
  172. package/dist/collection/components/pami-progress-indicator/pami-progress-indicator.js +1 -1
  173. package/dist/collection/components/pami-radio/pami-radio.css +85 -86
  174. package/dist/collection/components/pami-radio/pami-radio.js +2 -2
  175. package/dist/collection/components/pami-rating/pami-rating.css +3 -3
  176. package/dist/collection/components/pami-rating/pami-rating.js +2 -2
  177. package/dist/collection/components/pami-ripple/pami-ripple.css +6 -5
  178. package/dist/collection/components/pami-ripple/pami-ripple.js +2 -9
  179. package/dist/collection/components/pami-ripple/pami-ripple.js.map +1 -1
  180. package/dist/collection/components/pami-search/pami-search.css +3 -3
  181. package/dist/collection/components/pami-segmented-button/pami-segmented-button.css +85 -86
  182. package/dist/collection/components/pami-segmented-button/pami-segmented-button.js +3 -3
  183. package/dist/collection/components/pami-segmented-button-set/pami-segmented-button-set.js +2 -2
  184. package/dist/collection/components/pami-select/pami-select.js +2 -2
  185. package/dist/collection/components/pami-side-sheet/pami-side-sheet.css +85 -86
  186. package/dist/collection/components/pami-side-sheet/pami-side-sheet.js +10 -20
  187. package/dist/collection/components/pami-side-sheet/pami-side-sheet.js.map +1 -1
  188. package/dist/collection/components/pami-skeleton/pami-skeleton.js +1 -1
  189. package/dist/collection/components/pami-slider/pami-slider.css +87 -88
  190. package/dist/collection/components/pami-snackbar/pami-snackbar.css +93 -92
  191. package/dist/collection/components/pami-snackbar/pami-snackbar.js +2 -2
  192. package/dist/collection/components/pami-split-button/pami-split-button.css +85 -86
  193. package/dist/collection/components/pami-split-button/pami-split-button.js +3 -3
  194. package/dist/collection/components/pami-step/pami-step.js +6 -6
  195. package/dist/collection/components/pami-stepper/pami-stepper.js +3 -3
  196. package/dist/collection/components/pami-sub-menu-item/pami-sub-menu-item.css +4 -4
  197. package/dist/collection/components/pami-sub-menu-item/pami-sub-menu-item.js +2 -2
  198. package/dist/collection/components/pami-switch/pami-switch.css +85 -86
  199. package/dist/collection/components/pami-switch/pami-switch.js +2 -2
  200. package/dist/collection/components/pami-tab/pami-tab.js +4 -4
  201. package/dist/collection/components/pami-tab-panel/pami-tab-panel.js +1 -1
  202. package/dist/collection/components/pami-tab-panels/pami-tab-panels.js +1 -1
  203. package/dist/collection/components/pami-table-body/pami-table-body.js +1 -1
  204. package/dist/collection/components/pami-table-cell/pami-table-cell.js +2 -2
  205. package/dist/collection/components/pami-table-container/pami-table-container.js +2 -2
  206. package/dist/collection/components/pami-table-expand-toggle/pami-table-expand-toggle.js +2 -2
  207. package/dist/collection/components/pami-table-foot/pami-table-foot.js +1 -1
  208. package/dist/collection/components/pami-table-head/pami-table-head.js +1 -1
  209. package/dist/collection/components/pami-table-pagination/pami-table-pagination.js +2 -2
  210. package/dist/collection/components/pami-table-row/pami-table-row.js +4 -4
  211. package/dist/collection/components/pami-table-sort-label/pami-table-sort-label.js +2 -2
  212. package/dist/collection/components/pami-table-toolbar/pami-table-toolbar.js +2 -2
  213. package/dist/collection/components/pami-tabs/pami-tabs.js +2 -2
  214. package/dist/collection/components/pami-tag/pami-tag.css +298 -0
  215. package/dist/collection/components/pami-tag/pami-tag.js +68 -0
  216. package/dist/collection/components/pami-tag/pami-tag.js.map +1 -0
  217. package/dist/collection/components/pami-text-field/pami-text-field.css +87 -88
  218. package/dist/collection/components/pami-toolbar/pami-toolbar.js +3 -3
  219. package/dist/collection/components/pami-tooltip/pami-tooltip.css +92 -93
  220. package/dist/collection/components/pami-transfer-list/pami-transfer-list.css +2 -2
  221. package/dist/collection/utils/charts/theme.js +25 -3
  222. package/dist/collection/utils/charts/theme.js.map +1 -1
  223. package/dist/collection/utils/focusable.js +38 -0
  224. package/dist/collection/utils/focusable.js.map +1 -0
  225. package/dist/collection/utils/pami-dots.js.map +1 -1
  226. package/dist/collection/utils/pami-material-defaults.js +194 -0
  227. package/dist/collection/utils/pami-material-defaults.js.map +1 -0
  228. package/dist/collection/utils/pami-material.js +58 -49
  229. package/dist/collection/utils/pami-material.js.map +1 -1
  230. package/dist/collection/utils/pami-motion-defaults.js +9 -0
  231. package/dist/collection/utils/pami-motion-defaults.js.map +1 -0
  232. package/dist/collection/utils/pami-painter.js +9 -7
  233. package/dist/collection/utils/pami-painter.js.map +1 -1
  234. package/dist/collection/utils/ripple.js +5 -0
  235. package/dist/collection/utils/ripple.js.map +1 -1
  236. package/dist/collection/utils/status-surface.js +7 -0
  237. package/dist/collection/utils/status-surface.js.map +1 -0
  238. package/dist/collection/wasm/engine-abi.js.map +1 -1
  239. package/dist/components/p-8OtaKJiC.js +2 -0
  240. package/dist/components/{p-DWSD26x3.js.map → p-8OtaKJiC.js.map} +1 -1
  241. package/dist/components/{p-DkVOc0wm.js → p-8v8oq2Gq.js} +2 -2
  242. package/dist/{pami/p-BFrljlvu.js → components/p-AeIwPqCK.js} +2 -2
  243. package/dist/components/p-BG--_h1M.js +2 -0
  244. package/dist/{components-csr/p-CKh3uxJF.js.map → components/p-BG--_h1M.js.map} +1 -1
  245. package/dist/components/{p-C3VyQE8n.js → p-BHjV4ckR.js} +2 -2
  246. package/dist/components/p-BHqq4sFe.js.map +1 -1
  247. package/dist/components/p-BOfpnjA1.js +2 -0
  248. package/dist/components/p-BOfpnjA1.js.map +1 -0
  249. package/dist/components/p-BcrEx_cg.js +2 -0
  250. package/dist/components/p-BcrEx_cg.js.map +1 -0
  251. package/dist/components/p-BhHms8Pb.js +2 -0
  252. package/dist/components/p-BhHms8Pb.js.map +1 -0
  253. package/dist/components/p-CKqNm_Q4.js +2 -0
  254. package/dist/components/p-CKqNm_Q4.js.map +1 -0
  255. package/dist/components/p-CMZVEmTF.js +2 -0
  256. package/dist/components/p-CMZVEmTF.js.map +1 -0
  257. package/dist/components/p-CaX5Betz.js +2 -0
  258. package/dist/components/p-CaX5Betz.js.map +1 -0
  259. package/dist/components/{p-Dh4RKEYp.js → p-Cf7x7Pbw.js} +2 -2
  260. package/dist/components/{p-BKlel-AP.js → p-CsGff_Ta.js} +2 -2
  261. package/dist/components/p-D-9rjUCJ.js +2 -0
  262. package/dist/components/p-D-9rjUCJ.js.map +1 -0
  263. package/dist/components/p-D5YKcPYj.js +2 -0
  264. package/dist/components/p-D5YKcPYj.js.map +1 -0
  265. package/dist/components/p-DDCz_UhF.js +2 -0
  266. package/dist/components/{p-BT8CI4i3.js.map → p-DDCz_UhF.js.map} +1 -1
  267. package/dist/components/p-DFOfsObx.js +2 -0
  268. package/dist/{components-csr/p-PG3r1Ywi.js.map → components/p-DFOfsObx.js.map} +1 -1
  269. package/dist/components/{p-CFpk8pnq.js → p-DKXYFRHy.js} +2 -2
  270. package/dist/components/{p-BnCqDe23.js → p-DKhFTr-2.js} +2 -2
  271. package/dist/components/{p-BnCqDe23.js.map → p-DKhFTr-2.js.map} +1 -1
  272. package/dist/components/p-DYYnx9b0.js +2 -0
  273. package/dist/components/{p-CKrq0VhQ.js.map → p-DYYnx9b0.js.map} +1 -1
  274. package/dist/components/p-DcS5GdsQ.js +2 -0
  275. package/dist/components/{p-DD2A_AfS.js.map → p-DcS5GdsQ.js.map} +1 -1
  276. package/dist/components/{p-Bf1Bx-JV.js → p-DuoeMUTq.js} +2 -2
  277. package/dist/{components-csr/p-g4sA3hAp.js → components/p-DzxH9m7D.js} +2 -2
  278. package/dist/components/pami-accordion-item.js +1 -1
  279. package/dist/components/pami-app-bar.js +1 -1
  280. package/dist/components/pami-app-bar.js.map +1 -1
  281. package/dist/components/pami-area-chart.js +1 -1
  282. package/dist/components/pami-autocomplete.js +1 -1
  283. package/dist/components/pami-avatar.js +1 -1
  284. package/dist/components/pami-badge.js +1 -1
  285. package/dist/components/pami-bar-chart.js +1 -1
  286. package/dist/components/pami-bottom-sheet.js +1 -1
  287. package/dist/components/pami-bottom-sheet.js.map +1 -1
  288. package/dist/components/pami-breadcrumb-item.js +1 -1
  289. package/dist/components/pami-breadcrumb-item.js.map +1 -1
  290. package/dist/components/pami-button.js +1 -1
  291. package/dist/components/pami-callout.d.ts +11 -0
  292. package/dist/components/pami-callout.js +2 -0
  293. package/dist/components/pami-callout.js.map +1 -0
  294. package/dist/components/pami-card.js +1 -1
  295. package/dist/components/pami-card.js.map +1 -1
  296. package/dist/components/pami-checkbox.js +1 -1
  297. package/dist/components/pami-chip.js +1 -1
  298. package/dist/components/pami-date-picker.js +1 -1
  299. package/dist/components/pami-date-picker.js.map +1 -1
  300. package/dist/components/pami-dialog.js +1 -1
  301. package/dist/components/pami-dialog.js.map +1 -1
  302. package/dist/components/pami-divider.js +1 -1
  303. package/dist/components/pami-fab-menu-item.js +1 -1
  304. package/dist/components/pami-fab-menu-item.js.map +1 -1
  305. package/dist/components/pami-fab-menu.js +1 -1
  306. package/dist/components/pami-fab.js +1 -1
  307. package/dist/components/pami-fab.js.map +1 -1
  308. package/dist/components/pami-icon-button.js +1 -1
  309. package/dist/components/pami-icon.js +1 -1
  310. package/dist/components/pami-line-chart.js +1 -1
  311. package/dist/components/pami-list-item.js +1 -1
  312. package/dist/components/pami-list-item.js.map +1 -1
  313. package/dist/components/pami-menu-item-group.js +1 -1
  314. package/dist/components/pami-menu-item-group.js.map +1 -1
  315. package/dist/components/pami-menu-item.js +1 -1
  316. package/dist/components/pami-menu.js +1 -1
  317. package/dist/components/pami-meter.js +1 -1
  318. package/dist/components/pami-multi-select.js +1 -1
  319. package/dist/components/pami-multi-select.js.map +1 -1
  320. package/dist/components/pami-navigation-bar.js +1 -1
  321. package/dist/components/pami-navigation-bar.js.map +1 -1
  322. package/dist/components/pami-navigation-group.d.ts +11 -0
  323. package/dist/components/pami-navigation-group.js +2 -0
  324. package/dist/components/pami-navigation-group.js.map +1 -0
  325. package/dist/components/pami-navigation-rail-tab.js +1 -1
  326. package/dist/components/pami-navigation-rail-tab.js.map +1 -1
  327. package/dist/components/pami-navigation-rail.js +1 -1
  328. package/dist/components/pami-navigation-rail.js.map +1 -1
  329. package/dist/components/pami-navigation-tab.js +1 -1
  330. package/dist/components/pami-navigation-tab.js.map +1 -1
  331. package/dist/components/pami-number-field.js +1 -1
  332. package/dist/components/pami-organization-chart.js +1 -1
  333. package/dist/components/pami-organization-chart.js.map +1 -1
  334. package/dist/components/pami-pie-chart.js +1 -1
  335. package/dist/components/pami-progress-indicator.js +1 -1
  336. package/dist/components/pami-radio.js +1 -1
  337. package/dist/components/pami-radio.js.map +1 -1
  338. package/dist/components/pami-rating.js +1 -1
  339. package/dist/components/pami-rating.js.map +1 -1
  340. package/dist/components/pami-ripple.js +1 -1
  341. package/dist/components/pami-search.js +1 -1
  342. package/dist/components/pami-search.js.map +1 -1
  343. package/dist/components/pami-segmented-button-set.js +1 -1
  344. package/dist/components/pami-segmented-button.js +1 -1
  345. package/dist/components/pami-segmented-button.js.map +1 -1
  346. package/dist/components/pami-select.js +1 -1
  347. package/dist/components/pami-side-sheet.js +1 -1
  348. package/dist/components/pami-side-sheet.js.map +1 -1
  349. package/dist/components/pami-skeleton.js +1 -1
  350. package/dist/components/pami-slider.js +1 -1
  351. package/dist/components/pami-snackbar.js +1 -1
  352. package/dist/components/pami-snackbar.js.map +1 -1
  353. package/dist/components/pami-sparkline.js +1 -1
  354. package/dist/components/pami-split-button.js +1 -1
  355. package/dist/components/pami-split-button.js.map +1 -1
  356. package/dist/components/pami-step.js +1 -1
  357. package/dist/components/pami-stepper.js +1 -1
  358. package/dist/components/pami-sub-menu-item.js +1 -1
  359. package/dist/components/pami-sub-menu-item.js.map +1 -1
  360. package/dist/components/pami-switch.js +1 -1
  361. package/dist/components/pami-switch.js.map +1 -1
  362. package/dist/components/pami-tab-panel.js +1 -1
  363. package/dist/components/pami-tab-panels.js +1 -1
  364. package/dist/components/pami-tab.js +1 -1
  365. package/dist/components/pami-table-body.js +1 -1
  366. package/dist/components/pami-table-cell.js +1 -1
  367. package/dist/components/pami-table-container.js +1 -1
  368. package/dist/components/pami-table-expand-toggle.js +1 -1
  369. package/dist/components/pami-table-foot.js +1 -1
  370. package/dist/components/pami-table-head.js +1 -1
  371. package/dist/components/pami-table-pagination.js +1 -1
  372. package/dist/components/pami-table-row.js +1 -1
  373. package/dist/components/pami-table-sort-label.js +1 -1
  374. package/dist/components/pami-table-toolbar.js +1 -1
  375. package/dist/components/pami-table.js +1 -1
  376. package/dist/components/pami-tabs.js +1 -1
  377. package/dist/components/pami-tag.d.ts +11 -0
  378. package/dist/components/pami-tag.js +2 -0
  379. package/dist/components/pami-tag.js.map +1 -0
  380. package/dist/components/pami-text-field.js +1 -1
  381. package/dist/components/pami-time-picker.js +1 -1
  382. package/dist/components/pami-toolbar.js +1 -1
  383. package/dist/components/pami-tooltip.js +1 -1
  384. package/dist/components/pami-transfer-list.js +1 -1
  385. package/dist/components/pami-transfer-list.js.map +1 -1
  386. package/dist/{components/p-DneLEiFl.js → components-csr/p-AeIwPqCK.js} +2 -2
  387. package/dist/components-csr/p-BHqq4sFe.js.map +1 -1
  388. package/dist/components-csr/p-B_b8a4Fl.js +2 -0
  389. package/dist/components-csr/p-B_b8a4Fl.js.map +1 -0
  390. package/dist/components-csr/p-BhHms8Pb.js +2 -0
  391. package/dist/components-csr/p-BhHms8Pb.js.map +1 -0
  392. package/dist/components-csr/{p-Dq_XLtjQ.js → p-BubrJNco.js} +2 -2
  393. package/dist/components-csr/{p-Iozt_nIr.js → p-C1ChEady.js} +2 -2
  394. package/dist/components-csr/p-C7-2STYZ.js +2 -0
  395. package/dist/components-csr/{p-BN5fTT2p.js.map → p-C7-2STYZ.js.map} +1 -1
  396. package/dist/components-csr/{p-DYa7FJrs.js → p-CC0KCIVL.js} +2 -2
  397. package/dist/components-csr/{p-C2f3W2Bc.js → p-CCLyUnYm.js} +2 -2
  398. package/dist/components-csr/{p-C2f3W2Bc.js.map → p-CCLyUnYm.js.map} +1 -1
  399. package/dist/components-csr/p-CCjSxvVk.js +2 -0
  400. package/dist/{components/p-DQG2QiqW.js.map → components-csr/p-CCjSxvVk.js.map} +1 -1
  401. package/dist/components-csr/p-CEXhFms9.js +2 -0
  402. package/dist/components-csr/{p-BeWJtYZz.js.map → p-CEXhFms9.js.map} +1 -1
  403. package/dist/components-csr/{p-wjnroiZn.js → p-CYTOzIlz.js} +2 -2
  404. package/dist/components-csr/{p-BKlel-AP.js → p-CsGff_Ta.js} +2 -2
  405. package/dist/components-csr/p-D-9rjUCJ.js +2 -0
  406. package/dist/components-csr/p-D-9rjUCJ.js.map +1 -0
  407. package/dist/components-csr/p-D5YKcPYj.js +2 -0
  408. package/dist/components-csr/p-D5YKcPYj.js.map +1 -0
  409. package/dist/components-csr/{p-CFpk8pnq.js → p-DKXYFRHy.js} +2 -2
  410. package/dist/components-csr/p-DTQ249Fz.js +2 -0
  411. package/dist/components-csr/p-DTQ249Fz.js.map +1 -0
  412. package/dist/components-csr/p-DbpI0Jma.js +2 -0
  413. package/dist/components-csr/p-DbpI0Jma.js.map +1 -0
  414. package/dist/components-csr/p-DqlfsJFI.js +2 -0
  415. package/dist/components-csr/p-DqlfsJFI.js.map +1 -0
  416. package/dist/components-csr/p-DvPstOrO.js +2 -0
  417. package/dist/components-csr/{p-dksxS2yM.js.map → p-DvPstOrO.js.map} +1 -1
  418. package/dist/components-csr/p-DxiLsbpD.js +2 -0
  419. package/dist/components-csr/p-DxiLsbpD.js.map +1 -0
  420. package/dist/{components/p-g4sA3hAp.js → components-csr/p-DzxH9m7D.js} +2 -2
  421. package/dist/components-csr/p-F3cB-9hU.js +2 -0
  422. package/dist/{components/p-BZcBbRYY.js.map → components-csr/p-F3cB-9hU.js.map} +1 -1
  423. package/dist/components-csr/p-sSc4gYQy.js +2 -0
  424. package/dist/components-csr/{p-D4njrR9m.js.map → p-sSc4gYQy.js.map} +1 -1
  425. package/dist/components-csr/pami-accordion-item.js +1 -1
  426. package/dist/components-csr/pami-app-bar.js +1 -1
  427. package/dist/components-csr/pami-app-bar.js.map +1 -1
  428. package/dist/components-csr/pami-area-chart.js +1 -1
  429. package/dist/components-csr/pami-autocomplete.js +1 -1
  430. package/dist/components-csr/pami-avatar.js +1 -1
  431. package/dist/components-csr/pami-badge.js +1 -1
  432. package/dist/components-csr/pami-bar-chart.js +1 -1
  433. package/dist/components-csr/pami-bottom-sheet.js +1 -1
  434. package/dist/components-csr/pami-bottom-sheet.js.map +1 -1
  435. package/dist/components-csr/pami-breadcrumb-item.js +1 -1
  436. package/dist/components-csr/pami-breadcrumb-item.js.map +1 -1
  437. package/dist/components-csr/pami-button.js +1 -1
  438. package/dist/components-csr/pami-callout.js +2 -0
  439. package/dist/components-csr/pami-callout.js.map +1 -0
  440. package/dist/components-csr/pami-card.js +1 -1
  441. package/dist/components-csr/pami-card.js.map +1 -1
  442. package/dist/components-csr/pami-checkbox.js +1 -1
  443. package/dist/components-csr/pami-chip.js +1 -1
  444. package/dist/components-csr/pami-date-picker.js +1 -1
  445. package/dist/components-csr/pami-date-picker.js.map +1 -1
  446. package/dist/components-csr/pami-dialog.js +1 -1
  447. package/dist/components-csr/pami-dialog.js.map +1 -1
  448. package/dist/components-csr/pami-divider.js +1 -1
  449. package/dist/components-csr/pami-fab-menu-item.js +1 -1
  450. package/dist/components-csr/pami-fab-menu-item.js.map +1 -1
  451. package/dist/components-csr/pami-fab-menu.js +1 -1
  452. package/dist/components-csr/pami-fab.js +1 -1
  453. package/dist/components-csr/pami-fab.js.map +1 -1
  454. package/dist/components-csr/pami-icon-button.js +1 -1
  455. package/dist/components-csr/pami-icon.js +1 -1
  456. package/dist/components-csr/pami-line-chart.js +1 -1
  457. package/dist/components-csr/pami-list-item.js +1 -1
  458. package/dist/components-csr/pami-list-item.js.map +1 -1
  459. package/dist/components-csr/pami-menu-item-group.js +1 -1
  460. package/dist/components-csr/pami-menu-item-group.js.map +1 -1
  461. package/dist/components-csr/pami-menu-item.js +1 -1
  462. package/dist/components-csr/pami-menu.js +1 -1
  463. package/dist/components-csr/pami-meter.js +1 -1
  464. package/dist/components-csr/pami-multi-select.js +1 -1
  465. package/dist/components-csr/pami-multi-select.js.map +1 -1
  466. package/dist/components-csr/pami-navigation-bar.js +1 -1
  467. package/dist/components-csr/pami-navigation-bar.js.map +1 -1
  468. package/dist/components-csr/pami-navigation-group.js +2 -0
  469. package/dist/components-csr/pami-navigation-group.js.map +1 -0
  470. package/dist/components-csr/pami-navigation-rail-tab.js +1 -1
  471. package/dist/components-csr/pami-navigation-rail-tab.js.map +1 -1
  472. package/dist/components-csr/pami-navigation-rail.js +1 -1
  473. package/dist/components-csr/pami-navigation-rail.js.map +1 -1
  474. package/dist/components-csr/pami-navigation-tab.js +1 -1
  475. package/dist/components-csr/pami-navigation-tab.js.map +1 -1
  476. package/dist/components-csr/pami-number-field.js +1 -1
  477. package/dist/components-csr/pami-organization-chart.js +1 -1
  478. package/dist/components-csr/pami-organization-chart.js.map +1 -1
  479. package/dist/components-csr/pami-pie-chart.js +1 -1
  480. package/dist/components-csr/pami-progress-indicator.js +1 -1
  481. package/dist/components-csr/pami-radio.js +1 -1
  482. package/dist/components-csr/pami-radio.js.map +1 -1
  483. package/dist/components-csr/pami-rating.js +1 -1
  484. package/dist/components-csr/pami-rating.js.map +1 -1
  485. package/dist/components-csr/pami-ripple.js +1 -1
  486. package/dist/components-csr/pami-search.js +1 -1
  487. package/dist/components-csr/pami-search.js.map +1 -1
  488. package/dist/components-csr/pami-segmented-button-set.js +1 -1
  489. package/dist/components-csr/pami-segmented-button.js +1 -1
  490. package/dist/components-csr/pami-segmented-button.js.map +1 -1
  491. package/dist/components-csr/pami-select.js +1 -1
  492. package/dist/components-csr/pami-side-sheet.js +1 -1
  493. package/dist/components-csr/pami-side-sheet.js.map +1 -1
  494. package/dist/components-csr/pami-skeleton.js +1 -1
  495. package/dist/components-csr/pami-slider.js +1 -1
  496. package/dist/components-csr/pami-snackbar.js +1 -1
  497. package/dist/components-csr/pami-snackbar.js.map +1 -1
  498. package/dist/components-csr/pami-sparkline.js +1 -1
  499. package/dist/components-csr/pami-split-button.js +1 -1
  500. package/dist/components-csr/pami-split-button.js.map +1 -1
  501. package/dist/components-csr/pami-step.js +1 -1
  502. package/dist/components-csr/pami-stepper.js +1 -1
  503. package/dist/components-csr/pami-sub-menu-item.js +1 -1
  504. package/dist/components-csr/pami-sub-menu-item.js.map +1 -1
  505. package/dist/components-csr/pami-switch.js +1 -1
  506. package/dist/components-csr/pami-switch.js.map +1 -1
  507. package/dist/components-csr/pami-tab-panel.js +1 -1
  508. package/dist/components-csr/pami-tab-panels.js +1 -1
  509. package/dist/components-csr/pami-tab.js +1 -1
  510. package/dist/components-csr/pami-table-body.js +1 -1
  511. package/dist/components-csr/pami-table-cell.js +1 -1
  512. package/dist/components-csr/pami-table-container.js +1 -1
  513. package/dist/components-csr/pami-table-expand-toggle.js +1 -1
  514. package/dist/components-csr/pami-table-foot.js +1 -1
  515. package/dist/components-csr/pami-table-head.js +1 -1
  516. package/dist/components-csr/pami-table-pagination.js +1 -1
  517. package/dist/components-csr/pami-table-row.js +1 -1
  518. package/dist/components-csr/pami-table-sort-label.js +1 -1
  519. package/dist/components-csr/pami-table-toolbar.js +1 -1
  520. package/dist/components-csr/pami-table.js +1 -1
  521. package/dist/components-csr/pami-tabs.js +1 -1
  522. package/dist/components-csr/pami-tag.js +2 -0
  523. package/dist/components-csr/pami-tag.js.map +1 -0
  524. package/dist/components-csr/pami-text-field.js +1 -1
  525. package/dist/components-csr/pami-time-picker.js +1 -1
  526. package/dist/components-csr/pami-toolbar.js +1 -1
  527. package/dist/components-csr/pami-tooltip.js +1 -1
  528. package/dist/components-csr/pami-transfer-list.js +1 -1
  529. package/dist/components-csr/pami-transfer-list.js.map +1 -1
  530. package/dist/esm/{a11y-DF7yzz7s.js → a11y-CFk62WKO.js} +3 -3
  531. package/dist/esm/{a11y-DF7yzz7s.js.map → a11y-CFk62WKO.js.map} +1 -1
  532. package/dist/esm/{bar-chart-BNtUGWrj.js → bar-chart-lQiYsj4t.js} +4 -4
  533. package/dist/esm/{bar-chart-BNtUGWrj.js.map → bar-chart-lQiYsj4t.js.map} +1 -1
  534. package/dist/esm/{chart-C1fPeEiw.js → chart-DGgh0ehg.js} +4 -4
  535. package/dist/esm/{chart-C1fPeEiw.js.map → chart-DGgh0ehg.js.map} +1 -1
  536. package/dist/esm/{hit-test-VKGhXvU8.js → hit-test-CwC3GJmi.js} +3 -3
  537. package/dist/esm/{hit-test-VKGhXvU8.js.map → hit-test-CwC3GJmi.js.map} +1 -1
  538. package/dist/esm/isolation-escape-D19ZgNkU.js +90 -0
  539. package/dist/esm/isolation-escape-D19ZgNkU.js.map +1 -0
  540. package/dist/esm/loader.js +1 -1
  541. package/dist/esm/pami-app-bar.entry.js +2 -2
  542. package/dist/esm/pami-app-bar.entry.js.map +1 -1
  543. package/dist/esm/pami-area-chart.entry.js +4 -4
  544. package/dist/esm/pami-avatar_2.entry.js +2 -2
  545. package/dist/esm/pami-avatar_2.entry.js.map +1 -1
  546. package/dist/esm/pami-bar-chart.entry.js +4 -4
  547. package/dist/esm/pami-bottom-sheet.entry.js +2 -2
  548. package/dist/esm/pami-bottom-sheet.entry.js.map +1 -1
  549. package/dist/esm/pami-breadcrumb-item.entry.js +2 -2
  550. package/dist/esm/pami-breadcrumb-item.entry.js.map +1 -1
  551. package/dist/esm/pami-button_7.entry.js +23 -39
  552. package/dist/esm/pami-button_7.entry.js.map +1 -1
  553. package/dist/esm/pami-callout.entry.js +28 -0
  554. package/dist/esm/pami-callout.entry.js.map +1 -0
  555. package/dist/esm/pami-checkbox.entry.js +5 -5
  556. package/dist/esm/pami-checkbox.entry.js.map +1 -1
  557. package/dist/esm/pami-chip.entry.js +5 -5
  558. package/dist/esm/pami-chip.entry.js.map +1 -1
  559. package/dist/esm/pami-date-picker.entry.js +4 -5
  560. package/dist/esm/pami-date-picker.entry.js.map +1 -1
  561. package/dist/esm/pami-dialog.entry.js +4 -4
  562. package/dist/esm/pami-dialog.entry.js.map +1 -1
  563. package/dist/esm/pami-divider.entry.js +2 -2
  564. package/dist/esm/pami-fab-menu-item.entry.js +5 -5
  565. package/dist/esm/pami-fab-menu-item.entry.js.map +1 -1
  566. package/dist/esm/pami-fab-menu.entry.js +2 -2
  567. package/dist/esm/pami-fab.entry.js +5 -5
  568. package/dist/esm/pami-fab.entry.js.map +1 -1
  569. package/dist/esm/pami-line-chart.entry.js +6 -6
  570. package/dist/esm/pami-list-item.entry.js +2 -2
  571. package/dist/esm/pami-list-item.entry.js.map +1 -1
  572. package/dist/esm/pami-menu-item-group.entry.js +2 -2
  573. package/dist/esm/pami-menu-item-group.entry.js.map +1 -1
  574. package/dist/esm/pami-menu_2.entry.js +4 -87
  575. package/dist/esm/pami-menu_2.entry.js.map +1 -1
  576. package/dist/esm/pami-meter.entry.js +2 -2
  577. package/dist/esm/pami-multi-select.entry.js +3 -3
  578. package/dist/esm/pami-multi-select.entry.js.map +1 -1
  579. package/dist/esm/pami-navigation-bar.entry.js +2 -2
  580. package/dist/esm/pami-navigation-bar.entry.js.map +1 -1
  581. package/dist/esm/pami-navigation-group.entry.js +22 -0
  582. package/dist/esm/pami-navigation-group.entry.js.map +1 -0
  583. package/dist/esm/pami-navigation-rail-tab.entry.js +157 -10
  584. package/dist/esm/pami-navigation-rail-tab.entry.js.map +1 -1
  585. package/dist/esm/pami-navigation-rail.entry.js +211 -29
  586. package/dist/esm/pami-navigation-rail.entry.js.map +1 -1
  587. package/dist/esm/pami-navigation-tab.entry.js +3 -3
  588. package/dist/esm/pami-navigation-tab.entry.js.map +1 -1
  589. package/dist/esm/pami-organization-chart.entry.js +1 -1
  590. package/dist/esm/pami-organization-chart.entry.js.map +1 -1
  591. package/dist/esm/{pami-painter-BWqbBPaI.js → pami-painter-DOkewauC.js} +260 -57
  592. package/dist/esm/pami-painter-DOkewauC.js.map +1 -0
  593. package/dist/esm/pami-pie-chart.entry.js +4 -4
  594. package/dist/esm/pami-progress-indicator.entry.js +1 -1
  595. package/dist/esm/pami-rating.entry.js +3 -3
  596. package/dist/esm/pami-rating.entry.js.map +1 -1
  597. package/dist/esm/pami-search.entry.js +1 -1
  598. package/dist/esm/pami-search.entry.js.map +1 -1
  599. package/dist/esm/pami-segmented-button-set.entry.js +2 -2
  600. package/dist/esm/pami-segmented-button.entry.js +6 -6
  601. package/dist/esm/pami-segmented-button.entry.js.map +1 -1
  602. package/dist/esm/pami-select.entry.js +2 -2
  603. package/dist/esm/pami-side-sheet.entry.js +49 -22
  604. package/dist/esm/pami-side-sheet.entry.js.map +1 -1
  605. package/dist/esm/pami-skeleton.entry.js +1 -1
  606. package/dist/esm/pami-slider.entry.js +2 -2
  607. package/dist/esm/pami-slider.entry.js.map +1 -1
  608. package/dist/esm/pami-sparkline.entry.js +4 -4
  609. package/dist/esm/pami-split-button.entry.js +6 -6
  610. package/dist/esm/pami-split-button.entry.js.map +1 -1
  611. package/dist/esm/pami-step.entry.js +7 -7
  612. package/dist/esm/pami-stepper.entry.js +3 -3
  613. package/dist/esm/pami-sub-menu-item.entry.js +4 -4
  614. package/dist/esm/pami-sub-menu-item.entry.js.map +1 -1
  615. package/dist/esm/pami-switch.entry.js +4 -4
  616. package/dist/esm/pami-switch.entry.js.map +1 -1
  617. package/dist/esm/pami-tab-panel.entry.js +1 -1
  618. package/dist/esm/pami-tab-panels.entry.js +1 -1
  619. package/dist/esm/pami-tab.entry.js +5 -5
  620. package/dist/esm/pami-table-body.entry.js +1 -1
  621. package/dist/esm/pami-table-cell.entry.js +2 -2
  622. package/dist/esm/pami-table-container.entry.js +2 -2
  623. package/dist/esm/pami-table-expand-toggle.entry.js +2 -2
  624. package/dist/esm/pami-table-foot.entry.js +1 -1
  625. package/dist/esm/pami-table-head.entry.js +1 -1
  626. package/dist/esm/pami-table-pagination.entry.js +2 -2
  627. package/dist/esm/pami-table-row.entry.js +4 -4
  628. package/dist/esm/pami-table-sort-label.entry.js +2 -2
  629. package/dist/esm/pami-table-toolbar.entry.js +2 -2
  630. package/dist/esm/pami-tabs.entry.js +2 -2
  631. package/dist/esm/pami-tag.entry.js +25 -0
  632. package/dist/esm/pami-tag.entry.js.map +1 -0
  633. package/dist/esm/pami-text-field.entry.js +2 -2
  634. package/dist/esm/pami-text-field.entry.js.map +1 -1
  635. package/dist/esm/pami-toolbar.entry.js +3 -3
  636. package/dist/esm/pami-transfer-list.entry.js +1 -1
  637. package/dist/esm/pami-transfer-list.entry.js.map +1 -1
  638. package/dist/esm/pami.js +1 -1
  639. package/dist/esm/{ripple-DT5RL9GH.js → ripple-BcReJziW.js} +7 -2
  640. package/dist/esm/ripple-BcReJziW.js.map +1 -0
  641. package/dist/esm/{rtl-CC7FhM00.js → rtl-Cd87AK5r.js} +27 -5
  642. package/dist/esm/rtl-Cd87AK5r.js.map +1 -0
  643. package/dist/esm/status-surface-D5YKcPYj.js +11 -0
  644. package/dist/esm/status-surface-D5YKcPYj.js.map +1 -0
  645. package/dist/esm/virtual-select-controller-Dr_fPcoz.js.map +1 -1
  646. package/dist/pami/p-056cbfbc.entry.js +2 -0
  647. package/dist/pami/{p-2067b15d.entry.js.map → p-056cbfbc.entry.js.map} +1 -1
  648. package/dist/pami/p-0bf56063.entry.js +2 -0
  649. package/dist/pami/{p-f33d5f4a.entry.js.map → p-0bf56063.entry.js.map} +1 -1
  650. package/dist/pami/p-0e965950.entry.js +2 -0
  651. package/dist/pami/{p-0fcc82b3.entry.js.map → p-0e965950.entry.js.map} +1 -1
  652. package/dist/pami/p-105fff09.entry.js +2 -0
  653. package/dist/pami/{p-ec67197c.entry.js.map → p-105fff09.entry.js.map} +1 -1
  654. package/dist/pami/{p-bc63e548.entry.js → p-14668a82.entry.js} +2 -2
  655. package/dist/pami/{p-cdd36757.entry.js → p-1468d5c4.entry.js} +2 -2
  656. package/dist/pami/p-1cafa0bb.entry.js +2 -0
  657. package/dist/pami/p-1cafa0bb.entry.js.map +1 -0
  658. package/dist/pami/p-20fb765c.entry.js +2 -0
  659. package/dist/pami/{p-309b4e6d.entry.js.map → p-20fb765c.entry.js.map} +1 -1
  660. package/dist/pami/{p-a4a2f7e2.entry.js → p-230b51cc.entry.js} +2 -2
  661. package/dist/pami/{p-f6d50fc7.entry.js → p-253bb306.entry.js} +2 -2
  662. package/dist/pami/{p-c087aa2d.entry.js → p-27ba3c65.entry.js} +2 -2
  663. package/dist/pami/{p-3577517b.entry.js → p-2c9fef75.entry.js} +2 -2
  664. package/dist/pami/{p-2fa9e712.entry.js → p-3031787d.entry.js} +2 -2
  665. package/dist/pami/p-35c2a89b.entry.js +2 -0
  666. package/dist/pami/{p-688017eb.entry.js.map → p-35c2a89b.entry.js.map} +1 -1
  667. package/dist/pami/{p-27208b60.entry.js → p-39a6add3.entry.js} +2 -2
  668. package/dist/pami/{p-ed0554c3.entry.js → p-3fc31b91.entry.js} +2 -2
  669. package/dist/pami/p-475ee072.entry.js +2 -0
  670. package/dist/pami/{p-6753c7a1.entry.js.map → p-475ee072.entry.js.map} +1 -1
  671. package/dist/pami/p-511a1ee2.entry.js +2 -0
  672. package/dist/pami/{p-7415982c.entry.js.map → p-511a1ee2.entry.js.map} +1 -1
  673. package/dist/pami/{p-91d25664.entry.js → p-513685d7.entry.js} +2 -2
  674. package/dist/pami/p-59ddac87.entry.js +2 -0
  675. package/dist/pami/p-59ddac87.entry.js.map +1 -0
  676. package/dist/pami/p-5baf125c.entry.js +2 -0
  677. package/dist/pami/{p-bd2fb99f.entry.js.map → p-5baf125c.entry.js.map} +1 -1
  678. package/dist/pami/p-636faa29.entry.js +2 -0
  679. package/dist/pami/p-6bae2a7c.entry.js +2 -0
  680. package/dist/pami/{p-b2704345.entry.js.map → p-6bae2a7c.entry.js.map} +1 -1
  681. package/dist/pami/p-70dbf9e1.entry.js +2 -0
  682. package/dist/pami/{p-6cd18c0d.entry.js.map → p-70dbf9e1.entry.js.map} +1 -1
  683. package/dist/pami/{p-b193dd1d.entry.js → p-71d62a04.entry.js} +2 -2
  684. package/dist/pami/{p-3b859d3c.entry.js → p-72d9ed2c.entry.js} +2 -2
  685. package/dist/pami/{p-5202ded3.entry.js → p-74673292.entry.js} +2 -2
  686. package/dist/pami/p-76869b29.entry.js +2 -0
  687. package/dist/pami/p-80a613c4.entry.js +2 -0
  688. package/dist/pami/{p-dd4d87c2.entry.js.map → p-80a613c4.entry.js.map} +1 -1
  689. package/dist/pami/p-820ec742.entry.js +2 -0
  690. package/dist/pami/{p-6a29a776.entry.js.map → p-820ec742.entry.js.map} +1 -1
  691. package/dist/pami/p-837a6389.entry.js +2 -0
  692. package/dist/pami/{p-d7504084.entry.js.map → p-837a6389.entry.js.map} +1 -1
  693. package/dist/pami/p-8381c008.entry.js +2 -0
  694. package/dist/pami/{p-7788c931.entry.js → p-86b07f8c.entry.js} +2 -2
  695. package/dist/pami/p-9178ea2e.entry.js +2 -0
  696. package/dist/pami/{p-a304bc4f.entry.js.map → p-9178ea2e.entry.js.map} +1 -1
  697. package/dist/pami/p-98683da9.entry.js +2 -0
  698. package/dist/pami/p-98683da9.entry.js.map +1 -0
  699. package/dist/pami/p-9a353a79.entry.js +2 -0
  700. package/dist/pami/{p-19669ac1.entry.js.map → p-9a353a79.entry.js.map} +1 -1
  701. package/dist/pami/p-9be87f6a.entry.js +2 -0
  702. package/dist/pami/p-9be87f6a.entry.js.map +1 -0
  703. package/dist/pami/{p-B2g1f_O7.js → p-BBBPC79O.js} +2 -2
  704. package/dist/pami/{p-B2g1f_O7.js.map → p-BBBPC79O.js.map} +1 -1
  705. package/dist/pami/p-BHqq4sFe.js.map +1 -1
  706. package/dist/pami/p-BcReJziW.js +2 -0
  707. package/dist/pami/p-BcReJziW.js.map +1 -0
  708. package/dist/pami/{p-C9EuleXc.js → p-C0lgexyr.js} +2 -2
  709. package/dist/pami/{p-C9EuleXc.js.map → p-C0lgexyr.js.map} +1 -1
  710. package/dist/{components-csr/p-DneLEiFl.js → pami/p-CAbSnOPc.js} +2 -2
  711. package/dist/pami/{p-BFrljlvu.js.map → p-CAbSnOPc.js.map} +1 -1
  712. package/dist/pami/p-CO-2MY9L.js +2 -0
  713. package/dist/pami/p-CO-2MY9L.js.map +1 -0
  714. package/dist/pami/p-Cd87AK5r.js +2 -0
  715. package/dist/pami/p-Cd87AK5r.js.map +1 -0
  716. package/dist/pami/{p-BH7SGm-U.js → p-Cln3qKA1.js} +2 -2
  717. package/dist/pami/{p-BH7SGm-U.js.map → p-Cln3qKA1.js.map} +1 -1
  718. package/dist/pami/p-D-9rjUCJ.js +2 -0
  719. package/dist/pami/p-D-9rjUCJ.js.map +1 -0
  720. package/dist/pami/p-D5YKcPYj.js +2 -0
  721. package/dist/pami/p-D5YKcPYj.js.map +1 -0
  722. package/dist/pami/{p-a516fb19.entry.js → p-a019a982.entry.js} +2 -2
  723. package/dist/pami/{p-0435815b.entry.js → p-aa031eb5.entry.js} +2 -2
  724. package/dist/pami/p-b361c9df.entry.js +2 -0
  725. package/dist/pami/{p-4ba67b88.entry.js.map → p-b361c9df.entry.js.map} +1 -1
  726. package/dist/pami/p-b5ad00c7.entry.js +2 -0
  727. package/dist/pami/{p-3b5862ac.entry.js.map → p-b5ad00c7.entry.js.map} +1 -1
  728. package/dist/pami/{p-dcd9abf8.entry.js → p-b928a212.entry.js} +2 -2
  729. package/dist/pami/{p-dcd9abf8.entry.js.map → p-b928a212.entry.js.map} +1 -1
  730. package/dist/pami/p-bac3fd4b.entry.js +2 -0
  731. package/dist/pami/{p-542e81de.entry.js.map → p-bac3fd4b.entry.js.map} +1 -1
  732. package/dist/pami/{p-42cda324.entry.js → p-be632c39.entry.js} +2 -2
  733. package/dist/pami/p-bf2e4ee5.entry.js +2 -0
  734. package/dist/pami/p-bf2e4ee5.entry.js.map +1 -0
  735. package/dist/pami/{p-ea6e514b.entry.js → p-c02334c0.entry.js} +2 -2
  736. package/dist/pami/p-c2d67784.entry.js +2 -0
  737. package/dist/pami/{p-c0fe2248.entry.js.map → p-c2d67784.entry.js.map} +1 -1
  738. package/dist/pami/{p-2391ef6b.entry.js → p-c717cd31.entry.js} +2 -2
  739. package/dist/pami/{p-d3ad1da1.entry.js → p-cd63ef03.entry.js} +2 -2
  740. package/dist/pami/{p-0f29f2bd.entry.js → p-cfc88755.entry.js} +2 -2
  741. package/dist/pami/p-d4e1fa44.entry.js +2 -0
  742. package/dist/pami/{p-b6b7092b.entry.js.map → p-d4e1fa44.entry.js.map} +1 -1
  743. package/dist/pami/p-d540f586.entry.js +2 -0
  744. package/dist/pami/p-d540f586.entry.js.map +1 -0
  745. package/dist/pami/p-d6de57b2.entry.js +2 -0
  746. package/dist/pami/{p-f3798dc6.entry.js.map → p-d6de57b2.entry.js.map} +1 -1
  747. package/dist/pami/{p-14497ccf.entry.js → p-daf42aec.entry.js} +2 -2
  748. package/dist/pami/{p-b8234190.entry.js → p-db1ee1b9.entry.js} +2 -2
  749. package/dist/pami/p-db30e449.entry.js +2 -0
  750. package/dist/pami/{p-60beacc5.entry.js.map → p-db30e449.entry.js.map} +1 -1
  751. package/dist/pami/{p-836652ad.entry.js → p-df18bacb.entry.js} +2 -2
  752. package/dist/pami/p-e08729f9.entry.js +2 -0
  753. package/dist/pami/p-e08729f9.entry.js.map +1 -0
  754. package/dist/pami/p-e65964e6.entry.js +2 -0
  755. package/dist/pami/p-e65964e6.entry.js.map +1 -0
  756. package/dist/pami/{p-81c06d88.entry.js → p-eb41f4e0.entry.js} +2 -2
  757. package/dist/pami/{p-4c023e51.entry.js → p-f29f90b0.entry.js} +2 -2
  758. package/dist/pami/p-fdee2733.entry.js +2 -0
  759. package/dist/pami/p-fdee2733.entry.js.map +1 -0
  760. package/dist/pami/pami.css +1 -1
  761. package/dist/pami/pami.esm.js +1 -1
  762. package/dist/sources/0278a6f5523ac1971fe0eadaee435bb3fd1dab609b7ec764bb3ba27e6aa8fb9f/pami-tag.tsx +30 -0
  763. package/dist/sources/{2ca06a25aa09d16ee580ce4db2554dafa516510b11f32021ef8f6fb04f823f74 → 13a6bd84ea4ee85906df60baa09ea92c604bf646ce3185706eb1c0266895d4ed}/pami-dots.tsx +1 -1
  764. package/dist/sources/{3df1210c7755e2386ccdc6e29e251b9678dc7c26acc9889678e769f5d1e5fd42 → 1ca4bc0c0956feb952356552e336ba66adf3965c09f29c3789fec9cefa0c3544}/pami-tooltip.css_tag_pami-tooltip_encapsulation_shadow +7 -7
  765. package/dist/sources/{bab5cb1d4daef5470d47d7ab2d6a75eaccfea977da04caf9c3a95ba2faa3f44e → 22a900318c9e4ddcd6f822b3d01aef0ea4c8ff892de0523df9e150f102ac6e5c}/pami-navigation-rail.css_tag_pami-navigation-rail_encapsulation_shadow +70 -1
  766. package/dist/sources/23a624b39d421b326032df3fec7a6eb8efe63812913db4f295c846a801bcc2df/focusable.ts +30 -0
  767. package/dist/sources/{ad8dae24c0940d3d78e73c208a2174be0f44c17ad88d5c14bc2a8b63fc919a17 → 24aa796cdc2df026b1d4e1a916907dd4e7c027698a43fa800d853d6f21b753cb}/pami-organization-chart.css_tag_pami-organization-chart_encapsulation_shadow +1 -1
  768. package/dist/sources/282c6204b17cf224fa1c29c70b7eeca1f5026f4ca7d81056eef97db0249e4415/pami-callout.css_tag_pami-callout_encapsulation_shadow +21 -0
  769. package/dist/sources/31bcc0fc5bd4de92e30b1fd5d74fa98dc0049dfc15c6a020e71906684f155025/pami-callout.tsx +42 -0
  770. package/dist/sources/35e1ffdb7ade27d0dcc5f5a0b602351b4356ad348211a54bf9cdfb7ebef83787/pami-navigation-group.css_tag_pami-navigation-group_encapsulation_shadow +30 -0
  771. package/dist/sources/3a78d70fc3ef5cd9c2b84b578e8aa4375e3512fe678f067f38b2eeec94cfade4/status-surface.ts +7 -0
  772. package/dist/sources/{6c163582408b4d7bc04a9c1a1f80b01e5861719f85f7e9f35667a619e50f9a0d → 4e65fa3e48826997c92b075221b722d889fbb59033628dc409191a69bb0ef1e0}/pami-menu.css_tag_pami-menu_encapsulation_shadow +1 -1
  773. package/dist/sources/527cfd468257c872834df7758243d5de17f075578964fb4b2d854046eebf0b2e/pami-motion-defaults.ts +8 -0
  774. package/dist/sources/{f057ec9cc9b2bc271fc6cafb5a9e886c1f2f88b76678d917b60de199571abccd → 541eb7b972849c16a3b860f7ea1c30751a98f8fc521a6ca03791ce5d0fe9426e}/pami-menu-item-group.css_tag_pami-menu-item-group_encapsulation_shadow +2 -2
  775. package/dist/sources/{ae8a116d7a4ea11a820767e5165db1e532a538eb8ba9ed5f4dc5a47e806ae4e6 → 59e0809dd478584dd6e8662e903cd5a0186609577db7b77a0479bd247f0d0735}/pami-side-sheet.tsx +13 -27
  776. package/dist/sources/{23e3c0a6f1c4ed86fe96ca5d8788e5cf6464e2be07031fd644120ea4efc313bf → 655cbc888435fe150257bfbd2fe21a572779617ba76cd567ac7d78e06a1ae431}/ripple.ts +6 -2
  777. package/dist/sources/{fc66575830503cd73ba7d3bedde73217b0f304d317ca851afd9e791ddad97fb5 → 6562889930d75426b2d8c57a2a68e8cb5a1540c9cc7fc5ae289092574ae223d0}/pami-navigation-rail-tab.tsx +200 -15
  778. package/dist/sources/{dd8e7de0b6aeaafd88a8d13123e5d07588ab74d8773cd80f70de293e28041436 → 6bab0e0b67c3b4abbb85cf631ad2af114271f98b795e2f2644810bffe75d1522}/pami-sub-menu-item.css_tag_pami-sub-menu-item_encapsulation_shadow +4 -4
  779. package/dist/sources/7a4b29a22f5e14ab4f0918effe1b91ad9ae6076553b826cc90edf6e43879cba0/pami-material-defaults.ts +193 -0
  780. package/dist/sources/7e8a1b22f1a1cb54b4b7cdad4bbfad9606419cf010636f6174da980089144636/pami-navigation-group.tsx +26 -0
  781. package/dist/sources/{0d91fa3bea6a6c8c693b8dca19946aef1b86d6f793f181210e5863de09b4aebb → 89368cfde7ecd06ee05b5493ce0f0503fd48fd12c4d8f2cb47610eb38157fe71}/pami-material.ts +63 -59
  782. package/dist/sources/9259130eb26707816d2f73de6a6b83ded1d342166d4bee8d7c5799f47e0ce776/pami-tag.css_tag_pami-tag_encapsulation_shadow +21 -0
  783. package/dist/sources/{7b02ffe2929f3ab24d21441af70c419cc2a0ca0c729de1ab51220ae5dc096f43 → 99e17d776c986eca5093163516c22279037bdf5d42f009db8f128413ae5cdeb2}/pami-search.css_tag_pami-search_encapsulation_shadow +3 -3
  784. package/dist/sources/{9a58a561a902b8eb3fa212160fb365c303f6ea7d5687af2abbd199d33c031650 → a430938d1fedf6a7b604b1dc070760d52bd2733dd0ff8aed7a704d2b28374333}/pami-navigation-rail-tab.css_tag_pami-navigation-rail-tab_encapsulation_shadow +101 -12
  785. package/dist/sources/{d80b6e4787aedf6628772d776d5d57b77be707a870bb78623a294a319b40bb3e → b05e116ff2b2e46fa76f8b32a21147a5275ac6550d59caafe834aad82bb2eed0}/pami-text-field.css_tag_pami-text-field_encapsulation_shadow +2 -2
  786. package/dist/sources/{f6fe21d8ade03a04388b25dd1e4a67e8ac84e5266632336311b9baf5e3e84d69 → b9bac20e73b763e4fd71ade205acf3179f48016689659d32fc5e9f723ec85c0a}/pami-menu-item.css_tag_pami-menu-item_encapsulation_shadow +5 -5
  787. package/dist/sources/{5fe0a66f80f0c4e661475395d7877a25335c605cf4fb02649bd887ab73564259 → bd61b0a219bfab84d1e6663df7c8df2dcf7395ad6110036c14874aa788023c15}/pami-slider.css_tag_pami-slider_encapsulation_shadow +2 -2
  788. package/dist/sources/{4dfc9c9d5e8fa39922a949409e66b9109463b97f0216334358921d4359cb61d6 → c176f6ce79521b5b70160c1a13b338d00bb4a90ee56911e0e043d4357dcd7e2a}/pami-multi-select.css_tag_pami-multi-select_encapsulation_shadow +4 -4
  789. package/dist/sources/{401e8c4f1d9d32aa7fb3d874c070d5e22bec9ef7a8300826a07b4df525e3e8a8 → c519dd6bf9591ea0961eb52e22d71ceabf68824f19be3bc1320cd3b7d0d06a78}/engine-abi.ts +1 -1
  790. package/dist/sources/{9230de3e79e81a5d82c53463873054c838e407aaaa6b4d83adba3e6420e1b668 → cafd0118f482317824eba435efde10692a0127e2c8104a754ac33b2e7607ef96}/pami-snackbar.css_tag_pami-snackbar_encapsulation_shadow +8 -6
  791. package/dist/sources/{8889443144c58e5dc85b288bf6f749a4142b4193f110787d5c2daddd1bd83700 → d72b349c2c336f88909a4c9e1f34cfaa824d2ccecad96b73da0ab6749bc810dd}/pami-ripple.tsx +1 -8
  792. package/dist/sources/{11e2d73298037a1e448521a045b253837dc5dfbb94e72a1c8afdb506a4759743 → dafd4f816d3de4b66b9eb2595187284bdb6a77e48afdc32d7a5166a2616d38bd}/pami-painter.ts +17 -11
  793. package/dist/sources/{3f7b937a1eddf96604fddc1dc0d30b4772f761c6f8fbacf7fa7a8532d8b2481e → de0d8bdaad31567edd750b4698e1eb5fd8122dc20b6ace6785570a380c2423d4}/pami-date-picker.tsx +5 -6
  794. package/dist/sources/{7e5e96f6428bb444fa618169230fcdc578c80766ecab3eba809e4c32ba9a17f7 → ded76ce1309e48970e51b17c73d2644d34ea22e45bc1b28b88a1ad20868e6cb9}/pami-rating.css_tag_pami-rating_encapsulation_shadow +3 -3
  795. package/dist/sources/{c274c1a827c9a70c44cfd4799d9d6254dfc6c5bcc0ba7f6d8e1ddd8d353271e0 → e73037cc274dab6b17d817adbfa3e69990da7d34758566725e634d080a8f1b53}/pami-ripple.css_tag_pami-ripple_encapsulation_shadow +6 -5
  796. package/dist/sources/{641359b47e4118436db06f645b766217d40ae15f1c1a8d1f978bdb04be56ced5 → eb9bf841ae4f9b06494c9b3edb130c9813e19f74f6f62490d9211914f616629b}/pami-list-item.css_tag_pami-list-item_encapsulation_shadow +1597 -1599
  797. package/dist/sources/{1c5da4122976a320028f326a3d21ba0f34a7bef5a8b3c0876912f32fe88c73a9 → f72676b12f85fff0999352413beba9ff1088fdbb4f64d593d1bf1936cd773cc6}/theme.ts +24 -5
  798. package/dist/sources/{95750dc74c5c9bce73cb26819375b45bd7b0462d6d52509ed918081dce4f1a0a → fdf252d43e9d2be51be81717c61f5215924906cbd31c969ef9a064d0d53c0aaf}/pami-navigation-rail.tsx +970 -766
  799. package/dist/sources/{3dfe9c1f569325c20a35778ec0dcb5ade6a20004645962282432aa2a85782276 → fff81d2a74c0586d69a65f9a8fe1954f6e853cc8f98c6cdea75a07a9737061b3}/pami-transfer-list.css_tag_pami-transfer-list_encapsulation_shadow +2 -2
  800. package/dist/types/components/pami-callout/pami-callout.d.ts +22 -0
  801. package/dist/types/components/pami-date-picker/pami-date-picker.d.ts +1 -2
  802. package/dist/types/components/pami-navigation-group/pami-navigation-group.d.ts +14 -0
  803. package/dist/types/components/pami-navigation-rail/pami-navigation-rail.d.ts +38 -0
  804. package/dist/types/components/pami-navigation-rail-tab/pami-navigation-rail-tab.d.ts +39 -0
  805. package/dist/types/components/pami-tag/pami-tag.d.ts +17 -0
  806. package/dist/types/components.d.ts +336 -14
  807. package/dist/types/utils/charts/theme.d.ts +2 -0
  808. package/dist/types/utils/focusable.d.ts +4 -0
  809. package/dist/types/utils/pami-dots.d.ts +1 -1
  810. package/dist/types/utils/pami-material-defaults.d.ts +108 -0
  811. package/dist/types/utils/pami-material.d.ts +12 -11
  812. package/dist/types/utils/pami-motion-defaults.d.ts +7 -0
  813. package/dist/types/utils/status-surface.d.ts +2 -0
  814. package/hydrate/index.js +983 -267
  815. package/hydrate/index.mjs +983 -267
  816. package/main-llm.md +14 -13
  817. package/package.json +2 -2
  818. package/src/components/pami-callout/readme.md +48 -0
  819. package/src/components/pami-navigation-group/readme.md +53 -0
  820. package/src/components/pami-navigation-rail/readme.md +91 -3
  821. package/src/components/pami-navigation-rail-tab/readme.md +30 -1
  822. package/src/components/pami-tag/readme.md +38 -0
  823. package/dist/cjs/pami-painter-CEq_kp4Z.js.map +0 -1
  824. package/dist/cjs/ripple-CiICEyeg.js.map +0 -1
  825. package/dist/cjs/rtl-D4GO_8Co.js.map +0 -1
  826. package/dist/components/p-29VlWbeT.js +0 -2
  827. package/dist/components/p-29VlWbeT.js.map +0 -1
  828. package/dist/components/p-BT8CI4i3.js +0 -2
  829. package/dist/components/p-BZcBbRYY.js +0 -2
  830. package/dist/components/p-C1b-wwIb.js +0 -2
  831. package/dist/components/p-C1b-wwIb.js.map +0 -1
  832. package/dist/components/p-CKrq0VhQ.js +0 -2
  833. package/dist/components/p-DD2A_AfS.js +0 -2
  834. package/dist/components/p-DFhQRL_q.js +0 -2
  835. package/dist/components/p-DFhQRL_q.js.map +0 -1
  836. package/dist/components/p-DO-HSPrg.js +0 -2
  837. package/dist/components/p-DO-HSPrg.js.map +0 -1
  838. package/dist/components/p-DQG2QiqW.js +0 -2
  839. package/dist/components/p-DWSD26x3.js +0 -2
  840. package/dist/components/p-NaJ3tJav.js +0 -2
  841. package/dist/components/p-NaJ3tJav.js.map +0 -1
  842. package/dist/components-csr/p-BN5fTT2p.js +0 -2
  843. package/dist/components-csr/p-BeWJtYZz.js +0 -2
  844. package/dist/components-csr/p-C1b-wwIb.js +0 -2
  845. package/dist/components-csr/p-C1b-wwIb.js.map +0 -1
  846. package/dist/components-csr/p-CGmQZ1oO.js +0 -2
  847. package/dist/components-csr/p-CGmQZ1oO.js.map +0 -1
  848. package/dist/components-csr/p-CKh3uxJF.js +0 -2
  849. package/dist/components-csr/p-CwgbF4Z5.js +0 -2
  850. package/dist/components-csr/p-CwgbF4Z5.js.map +0 -1
  851. package/dist/components-csr/p-D4njrR9m.js +0 -2
  852. package/dist/components-csr/p-D8TTB-lO.js +0 -2
  853. package/dist/components-csr/p-D8TTB-lO.js.map +0 -1
  854. package/dist/components-csr/p-DVtt3xax.js +0 -2
  855. package/dist/components-csr/p-DVtt3xax.js.map +0 -1
  856. package/dist/components-csr/p-PG3r1Ywi.js +0 -2
  857. package/dist/components-csr/p-dksxS2yM.js +0 -2
  858. package/dist/esm/pami-painter-BWqbBPaI.js.map +0 -1
  859. package/dist/esm/ripple-DT5RL9GH.js.map +0 -1
  860. package/dist/esm/rtl-CC7FhM00.js.map +0 -1
  861. package/dist/pami/p-041d2685.entry.js +0 -2
  862. package/dist/pami/p-041d2685.entry.js.map +0 -1
  863. package/dist/pami/p-0fcc82b3.entry.js +0 -2
  864. package/dist/pami/p-19669ac1.entry.js +0 -2
  865. package/dist/pami/p-1hwLIlBx.js +0 -2
  866. package/dist/pami/p-1hwLIlBx.js.map +0 -1
  867. package/dist/pami/p-2067b15d.entry.js +0 -2
  868. package/dist/pami/p-309b4e6d.entry.js +0 -2
  869. package/dist/pami/p-37d827d8.entry.js +0 -2
  870. package/dist/pami/p-3b5862ac.entry.js +0 -2
  871. package/dist/pami/p-4ba67b88.entry.js +0 -2
  872. package/dist/pami/p-542e81de.entry.js +0 -2
  873. package/dist/pami/p-5c02cc99.entry.js +0 -2
  874. package/dist/pami/p-5c02cc99.entry.js.map +0 -1
  875. package/dist/pami/p-60beacc5.entry.js +0 -2
  876. package/dist/pami/p-6753c7a1.entry.js +0 -2
  877. package/dist/pami/p-688017eb.entry.js +0 -2
  878. package/dist/pami/p-6a29a776.entry.js +0 -2
  879. package/dist/pami/p-6cd18c0d.entry.js +0 -2
  880. package/dist/pami/p-7415982c.entry.js +0 -2
  881. package/dist/pami/p-CC7FhM00.js +0 -2
  882. package/dist/pami/p-CC7FhM00.js.map +0 -1
  883. package/dist/pami/p-DT5RL9GH.js +0 -2
  884. package/dist/pami/p-DT5RL9GH.js.map +0 -1
  885. package/dist/pami/p-a304bc4f.entry.js +0 -2
  886. package/dist/pami/p-b2704345.entry.js +0 -2
  887. package/dist/pami/p-b6b7092b.entry.js +0 -2
  888. package/dist/pami/p-bac4f96e.entry.js +0 -2
  889. package/dist/pami/p-bac4f96e.entry.js.map +0 -1
  890. package/dist/pami/p-bd2fb99f.entry.js +0 -2
  891. package/dist/pami/p-c0fe2248.entry.js +0 -2
  892. package/dist/pami/p-c1409913.entry.js +0 -2
  893. package/dist/pami/p-cd922613.entry.js +0 -2
  894. package/dist/pami/p-cd922613.entry.js.map +0 -1
  895. package/dist/pami/p-cf4fa448.entry.js +0 -2
  896. package/dist/pami/p-cf4fa448.entry.js.map +0 -1
  897. package/dist/pami/p-d6600bc9.entry.js +0 -2
  898. package/dist/pami/p-d6600bc9.entry.js.map +0 -1
  899. package/dist/pami/p-d7504084.entry.js +0 -2
  900. package/dist/pami/p-dd4d87c2.entry.js +0 -2
  901. package/dist/pami/p-ec67197c.entry.js +0 -2
  902. package/dist/pami/p-ef41fef7.entry.js +0 -2
  903. package/dist/pami/p-f33d5f4a.entry.js +0 -2
  904. package/dist/pami/p-f3798dc6.entry.js +0 -2
  905. /package/dist/components/{p-DkVOc0wm.js.map → p-8v8oq2Gq.js.map} +0 -0
  906. /package/dist/components/{p-DneLEiFl.js.map → p-AeIwPqCK.js.map} +0 -0
  907. /package/dist/components/{p-C3VyQE8n.js.map → p-BHjV4ckR.js.map} +0 -0
  908. /package/dist/components/{p-Dh4RKEYp.js.map → p-Cf7x7Pbw.js.map} +0 -0
  909. /package/dist/components/{p-BKlel-AP.js.map → p-CsGff_Ta.js.map} +0 -0
  910. /package/dist/components/{p-CFpk8pnq.js.map → p-DKXYFRHy.js.map} +0 -0
  911. /package/dist/components/{p-Bf1Bx-JV.js.map → p-DuoeMUTq.js.map} +0 -0
  912. /package/dist/components/{p-g4sA3hAp.js.map → p-DzxH9m7D.js.map} +0 -0
  913. /package/dist/components-csr/{p-DneLEiFl.js.map → p-AeIwPqCK.js.map} +0 -0
  914. /package/dist/components-csr/{p-Dq_XLtjQ.js.map → p-BubrJNco.js.map} +0 -0
  915. /package/dist/components-csr/{p-Iozt_nIr.js.map → p-C1ChEady.js.map} +0 -0
  916. /package/dist/components-csr/{p-DYa7FJrs.js.map → p-CC0KCIVL.js.map} +0 -0
  917. /package/dist/components-csr/{p-wjnroiZn.js.map → p-CYTOzIlz.js.map} +0 -0
  918. /package/dist/components-csr/{p-BKlel-AP.js.map → p-CsGff_Ta.js.map} +0 -0
  919. /package/dist/components-csr/{p-CFpk8pnq.js.map → p-DKXYFRHy.js.map} +0 -0
  920. /package/dist/components-csr/{p-g4sA3hAp.js.map → p-DzxH9m7D.js.map} +0 -0
  921. /package/dist/pami/{p-bc63e548.entry.js.map → p-14668a82.entry.js.map} +0 -0
  922. /package/dist/pami/{p-cdd36757.entry.js.map → p-1468d5c4.entry.js.map} +0 -0
  923. /package/dist/pami/{p-a4a2f7e2.entry.js.map → p-230b51cc.entry.js.map} +0 -0
  924. /package/dist/pami/{p-f6d50fc7.entry.js.map → p-253bb306.entry.js.map} +0 -0
  925. /package/dist/pami/{p-c087aa2d.entry.js.map → p-27ba3c65.entry.js.map} +0 -0
  926. /package/dist/pami/{p-3577517b.entry.js.map → p-2c9fef75.entry.js.map} +0 -0
  927. /package/dist/pami/{p-2fa9e712.entry.js.map → p-3031787d.entry.js.map} +0 -0
  928. /package/dist/pami/{p-27208b60.entry.js.map → p-39a6add3.entry.js.map} +0 -0
  929. /package/dist/pami/{p-ed0554c3.entry.js.map → p-3fc31b91.entry.js.map} +0 -0
  930. /package/dist/pami/{p-91d25664.entry.js.map → p-513685d7.entry.js.map} +0 -0
  931. /package/dist/pami/{p-c1409913.entry.js.map → p-636faa29.entry.js.map} +0 -0
  932. /package/dist/pami/{p-b193dd1d.entry.js.map → p-71d62a04.entry.js.map} +0 -0
  933. /package/dist/pami/{p-3b859d3c.entry.js.map → p-72d9ed2c.entry.js.map} +0 -0
  934. /package/dist/pami/{p-5202ded3.entry.js.map → p-74673292.entry.js.map} +0 -0
  935. /package/dist/pami/{p-37d827d8.entry.js.map → p-76869b29.entry.js.map} +0 -0
  936. /package/dist/pami/{p-ef41fef7.entry.js.map → p-8381c008.entry.js.map} +0 -0
  937. /package/dist/pami/{p-7788c931.entry.js.map → p-86b07f8c.entry.js.map} +0 -0
  938. /package/dist/pami/{p-a516fb19.entry.js.map → p-a019a982.entry.js.map} +0 -0
  939. /package/dist/pami/{p-0435815b.entry.js.map → p-aa031eb5.entry.js.map} +0 -0
  940. /package/dist/pami/{p-42cda324.entry.js.map → p-be632c39.entry.js.map} +0 -0
  941. /package/dist/pami/{p-ea6e514b.entry.js.map → p-c02334c0.entry.js.map} +0 -0
  942. /package/dist/pami/{p-2391ef6b.entry.js.map → p-c717cd31.entry.js.map} +0 -0
  943. /package/dist/pami/{p-d3ad1da1.entry.js.map → p-cd63ef03.entry.js.map} +0 -0
  944. /package/dist/pami/{p-0f29f2bd.entry.js.map → p-cfc88755.entry.js.map} +0 -0
  945. /package/dist/pami/{p-14497ccf.entry.js.map → p-daf42aec.entry.js.map} +0 -0
  946. /package/dist/pami/{p-b8234190.entry.js.map → p-db1ee1b9.entry.js.map} +0 -0
  947. /package/dist/pami/{p-836652ad.entry.js.map → p-df18bacb.entry.js.map} +0 -0
  948. /package/dist/pami/{p-81c06d88.entry.js.map → p-eb41f4e0.entry.js.map} +0 -0
  949. /package/dist/pami/{p-4c023e51.entry.js.map → p-f29f90b0.entry.js.map} +0 -0
@@ -1,766 +1,970 @@
1
- import { createId } from '../../utils/id';
2
- import {
3
- Component,
4
- Host,
5
- h,
6
- Prop,
7
- Event,
8
- EventEmitter,
9
- Element,
10
- State,
11
- Watch,
12
- Listen,
13
- Method,
14
- } from '@stencil/core';
15
- import { prepareRailTabTransition } from '../../utils/navigation-rail-motion';
16
-
17
- /**
18
- * Material Design 3 — Navigation Rail
19
- *
20
- * A vertical navigation surface for the left or right edge of medium / large
21
- * window sizes. Holds 3–7 top-level destinations and optionally a header
22
- * (menu / brand), a FAB, and a footer.
23
- *
24
- * Implements MD3 specs:
25
- * - https://m3.material.io/components/navigation-rail/overview
26
- * - https://m3.material.io/components/navigation-rail/specs
27
- * - https://m3.material.io/components/navigation-rail/guidelines
28
- * - https://m3.material.io/components/navigation-rail/accessibility
29
- */
30
- @Component({
31
- tag: 'pami-navigation-rail',
32
- styleUrl: 'pami-navigation-rail.css',
33
- shadow: true,
34
- })
35
- export class PamiNavigationRail {
36
- @Element() el!: HTMLElement;
37
-
38
- /**
39
- * Visual variant — `standard` (the spec's *collapsed* rail: 80px wide,
40
- * stacked icon + label) or `expanded` (icons + label inline, 220–360px wide).
41
- */
42
- @Prop({ mutable: true, reflect: true }) variant: 'standard' | 'expanded' = 'standard';
43
-
44
- /**
45
- * Modal styling for the expanded variant per spec: `surface-container`
46
- * background, level-2 elevation, large corner shape. Use when the expanded
47
- * rail floats over content instead of being docked; positioning and the
48
- * scrim are the host app's responsibility. No effect while collapsed.
49
- */
50
- @Prop({ reflect: true }) modal: boolean = false;
51
-
52
- /**
53
- * Stretch the rail to the full viewport height (`100dvh`) instead of filling
54
- * its parent container. Opt-in: by default the rail fills whatever height its
55
- * container gives it (`100%`), which keeps it embeddable in split-pane /
56
- * nested / modal-docked layouts. Set this when the rail is the app's
57
- * top-level side navigation and should always span the screen.
58
- */
59
- @Prop({ reflect: true, attribute: 'full-height' }) fullHeight: boolean = false;
60
-
61
- /** Vertical alignment of destinations relative to the rail. */
62
- @Prop({ reflect: true }) alignment: 'top' | 'middle' | 'bottom' = 'top';
63
-
64
- /**
65
- * Render a built-in leading menu button that toggles between the collapsed
66
- * (`standard`) and `expanded` variants. The icon animates between `menu`
67
- * (collapsed) and `menu_open` (expanded) per the MD3 navigation rail figure.
68
- * When you'd rather supply your own control, leave this `false` and place a
69
- * button in the `header` slot wired to the `expand()` / `collapse()` /
70
- * `toggle()` methods.
71
- */
72
- @Prop({ reflect: true }) expandable: boolean = false;
73
-
74
- /**
75
- * Accessible label for the built-in toggle button (only rendered when
76
- * `expandable` is set). Announced to assistive tech as the button's name.
77
- */
78
- @Prop({ attribute: 'toggle-label' }) toggleLabel: string = 'Toggle navigation';
79
-
80
- /**
81
- * Controls whether destination labels are shown.
82
- * - `all`: every destination shows its label (default — recommended by MD3 for 3–7 destinations)
83
- * - `selected`: only the active destination shows its label
84
- * - `none`: icons only
85
- */
86
- @Prop({ reflect: true, attribute: 'label-visibility' })
87
- labelVisibility: 'all' | 'selected' | 'none' = 'all';
88
-
89
- /**
90
- * Index of the currently active destination. -1 means no destination is
91
- * active. Two-way bound: updates when the user selects a destination and
92
- * can be set externally to programmatically change the active destination.
93
- */
94
- @Prop({ mutable: true, reflect: true, attribute: 'active-index' })
95
- activeIndex: number = -1;
96
-
97
- /**
98
- * Accessible name announced for the rail's `navigation` landmark.
99
- * Required for screen reader users (WAI-ARIA APG / WCAG 2.4.1).
100
- */
101
- @Prop() label: string = 'Navigation';
102
-
103
- /**
104
- * Set to `true` to disable focus management (roving tabindex + arrow keys).
105
- * Use when embedding inside a custom focus management system.
106
- */
107
- @Prop() disableFocusManagement: boolean = false;
108
-
109
- /**
110
- * Local density rung. Drives the same `--md-sys-density-scale` signal that a
111
- * global `data-density` ancestor sets, so a local value simply overrides the
112
- * inherited one. 0 = default, -4 = ultra-compact.
113
- */
114
- @Prop({ reflect: true }) density: 0 | -1 | -2 | -3 | -4 = 0;
115
-
116
- /** Emitted when the user selects a destination. */
117
- @Event() pamiTabChange: EventEmitter<{ index: number; value: string }>;
118
-
119
- /** Emitted when the rail transitions from collapsed → expanded. */
120
- @Event() pamiExpand: EventEmitter<void>;
121
-
122
- /** Emitted when the rail transitions from expanded → collapsed. */
123
- @Event() pamiCollapse: EventEmitter<void>;
124
-
125
- @State() private hasLogo = false;
126
- @State() private hasLogoExpanded = false;
127
- @State() private hasHeader = false;
128
- @State() private hasFab = false;
129
- @State() private hasFooter = false;
130
- @State() private hasFooterLeading = false;
131
- @State() private hasFooterContent = false;
132
-
133
- /**
134
- * True when one or more destinations render as links (`href` set). A `tablist`
135
- * may only contain `tab` children per ARIA, so when destinations are links the
136
- * container drops its `tablist` semantics and is just a grouping element inside
137
- * the `navigation` landmark.
138
- */
139
- @State() private hasLinkDestinations = false;
140
- @State() private overflowCount = 0;
141
- /** True while any destination's dropdown is open — lifts the rail's stacking
142
- * context so the fixed-position menu is not trapped inside it. */
143
- @State() private submenuOpen = false;
144
-
145
- /**
146
- * Destination target layout, synchronized with the variant before rendering.
147
- * Tabs capture their current geometry before this changes, then animate to the
148
- * new layout while the rail changes width.
149
- */
150
- @State() private tabsExpanded = false;
151
-
152
- /** Programmatically expand the rail (shows labels inline with icons). */
153
- @Method()
154
- async expand(): Promise<void> {
155
- if (this.variant !== 'expanded') {
156
- this.variant = 'expanded';
157
- }
158
- }
159
-
160
- /** Programmatically collapse the rail (standard 80px width). */
161
- @Method()
162
- async collapse(): Promise<void> {
163
- if (this.variant !== 'standard') {
164
- this.variant = 'standard';
165
- }
166
- }
167
-
168
- /** Toggle between expanded and standard. */
169
- @Method()
170
- async toggle(): Promise<void> {
171
- this.variant = this.variant === 'expanded' ? 'standard' : 'expanded';
172
- }
173
-
174
- /** Move keyboard focus to the destination at `index`. */
175
- @Method()
176
- async focusTab(index: number): Promise<void> {
177
- const tabs = this.getTabs();
178
- const target = tabs[index];
179
- if (target) {
180
- this.setRovingTabindex(index);
181
- target.focus();
182
- }
183
- }
184
-
185
- componentWillLoad() {
186
- this.tabsExpanded = this.variant === 'expanded';
187
- /*
188
- * Seed the slot-presence flags from the light DOM BEFORE the first render —
189
- * the same technique the active-tab adoption below already uses. They used
190
- * to be written only by each slot's `slotchange`, which fires after first
191
- * render, so every rail's first painted frame had no `--with-fab` host
192
- * class, a `hidden` FAB wrapper, and no header-space padding on the
193
- * destinations. Measured on a cold load: the destinations painted at y=114
194
- * and dropped to y=213 one frame later when the band opened — a 99px shift
195
- * on every load, which a consumer could only pre-pad from outside with
196
- * hand copies of this component's internal expressions. Whether a slot is
197
- * filled is a fact of the light DOM and is readable here; `slotchange`
198
- * still owns every later change.
199
- */
200
- // Direct-children iteration rather than `:scope >` — same pattern as the
201
- // active-tab adoption below, and mock-doc's selector engine has no :scope.
202
- const slotted = (name: string) =>
203
- Array.from(this.el.children).some((child) => child.getAttribute('slot') === name);
204
- this.hasLogo = slotted('logo');
205
- this.hasLogoExpanded = slotted('logo-expanded');
206
- this.hasHeader = slotted('header');
207
- this.hasFab = slotted('fab');
208
- this.hasFooter = slotted('footer');
209
- this.hasFooterLeading = slotted('footer-leading');
210
- this.hasFooterContent = slotted('footer-content');
211
- // Adopt a pre-marked destination: authors can write `active` directly on a
212
- // child tab instead of `active-index` on the rail. This MUST run before the
213
- // first slotchange-driven syncTabs(), which (with activeIndex still -1)
214
- // would clear the child's `active` attribute before we could read it. Read
215
- // the light-DOM children directly since the shadow slot isn't assigned yet.
216
- if (this.activeIndex < 0) {
217
- const tabs = Array.from(this.el.children).filter(
218
- (el) => el.tagName.toLowerCase() === 'pami-navigation-rail-tab',
219
- );
220
- const marked = tabs.findIndex((t) => t.hasAttribute('active'));
221
- if (marked >= 0) this.activeIndex = marked;
222
- }
223
- }
224
-
225
- componentDidLoad() {
226
- this.syncTabs();
227
- this.syncFab();
228
- this.wireSlottedMenus();
229
- }
230
-
231
- @Watch('variant')
232
- onVariantChange(newVal: 'standard' | 'expanded', oldVal: 'standard' | 'expanded') {
233
- if (newVal === oldVal) return;
234
-
235
- // Capture destinations before the rail's padding or target layout changes.
236
- // A child watcher alone can run after the parent has already moved its icon.
237
- this.getTabs().forEach(prepareRailTabTransition);
238
- this.tabsExpanded = newVal === 'expanded';
239
- this.syncTabs();
240
- this.syncFab();
241
-
242
- // Consumers can synchronously update label visibility in these listeners;
243
- // publish only after every destination and the FAB have the target state.
244
- if (newVal === 'expanded') this.pamiExpand.emit();
245
- else this.pamiCollapse.emit();
246
- }
247
-
248
- /**
249
- * Mirror the rail's expanded state onto a slotted FAB's `extended` prop so it
250
- * morphs between the extended (icon + label) and icon-only forms. No-op for
251
- * slotted content that doesn't expose `extended`.
252
- */
253
- private syncFab() {
254
- const slot = this.el.shadowRoot?.querySelector(
255
- 'slot[name="fab"]',
256
- ) as HTMLSlotElement | null;
257
- slot?.assignedElements().forEach((el) => {
258
- this.setProp(el as HTMLElement, 'extended', this.variant === 'expanded');
259
- });
260
- }
261
-
262
- @Watch('labelVisibility')
263
- onLabelVisibilityChange() {
264
- this.syncTabs();
265
- }
266
-
267
- @Watch('activeIndex')
268
- onActiveIndexChange() {
269
- this.syncTabs();
270
- }
271
-
272
- @Listen('pamiTabClick')
273
- handleTabClick(e: CustomEvent<{ value: string }>) {
274
- const target = e.target as HTMLElement | null;
275
- if (!target) return;
276
- const tabs = this.getTabs();
277
- const index = tabs.indexOf(target);
278
- if (index < 0) return;
279
-
280
- if (this.isTabDisabled(target)) {
281
- e.stopPropagation();
282
- return;
283
- }
284
-
285
- // `pamiTabClick` (from the tab) fires on every activation — including
286
- // re-clicking the already-active destination (which replays the ripple).
287
- // `pamiTabChange` is the higher-level *selection changed* event, so only
288
- // emit it when the active index actually moves.
289
- const changed = index !== this.activeIndex;
290
- this.activeIndex = index;
291
- this.setRovingTabindex(index);
292
- this.clearOtherSubmenuSelections(target);
293
- if (changed) {
294
- this.pamiTabChange.emit({ index, value: e.detail?.value ?? '' });
295
- }
296
- }
297
-
298
- /**
299
- * A destination whose dropdown row is chosen wears the same pill as the
300
- * active one, so a stale selection in *another* dropdown reads as a second
301
- * active destination. Only one destination can be current, so activating any
302
- * of them clears the rest.
303
- */
304
- private clearOtherSubmenuSelections(active: HTMLElement | null) {
305
- this.getTabs().forEach((tab) => {
306
- if (tab === active) return;
307
- const clear = (tab as HTMLPamiNavigationRailTabElement).clearSubmenuSelection;
308
- if (typeof clear === 'function') void clear.call(tab);
309
- });
310
- }
311
-
312
- private isTabDisabled(tab: HTMLElement): boolean {
313
- // A destination collapsed into the overflow menu is no longer in the rail,
314
- // so arrow keys must skip it exactly as they skip a disabled one.
315
- return (
316
- tab.hasAttribute('disabled') ||
317
- tab.getAttribute('aria-disabled') === 'true' ||
318
- tab.hasAttribute('data-overflowed')
319
- );
320
- }
321
-
322
- private getTabs(): HTMLElement[] {
323
- const slot = this.el.shadowRoot?.querySelector(
324
- 'slot:not([name])',
325
- ) as HTMLSlotElement | null;
326
- if (!slot) return [];
327
- return slot
328
- .assignedElements()
329
- .filter((el) => el.tagName.toLowerCase() === 'pami-navigation-rail-tab') as HTMLElement[];
330
- }
331
-
332
- private syncTabs() {
333
- const tabs = this.getTabs();
334
- // Detect link-style destinations so the container can shed its invalid
335
- // `tablist` role (a tablist must only contain `tab` children).
336
- this.hasLinkDestinations = tabs.some(
337
- (tab) => !!(tab as HTMLElement & { href?: string }).href || !!tab.getAttribute('href'),
338
- );
339
- tabs.forEach((tab, i) => {
340
- const active = i === this.activeIndex;
341
- this.setProp(tab, 'active', active);
342
- this.setProp(tab, 'labelVisibility', this.labelVisibility);
343
- this.setProp(tab, 'expanded', this.tabsExpanded);
344
- // The tab styles its own indicator, and shadow DOM keeps the rail out of
345
- // it — so hand the axis down as an attribute it can key off.
346
- tab.setAttribute('data-orientation', this.orientation);
347
-
348
- if (!this.disableFocusManagement) {
349
- const focusable = !this.isTabDisabled(tab);
350
- const isRoving =
351
- (this.activeIndex >= 0 && active) ||
352
- (this.activeIndex < 0 && i === tabs.findIndex((t) => !this.isTabDisabled(t)));
353
- tab.tabIndex = focusable && isRoving ? 0 : -1;
354
- }
355
- });
356
-
357
- // Recompute the overflow set from every sync path, not just slotchange.
358
- this.applyOverflow();
359
- }
360
-
361
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
362
- private setProp(el: HTMLElement, key: string, value: any) {
363
- try {
364
- (el as any)[key] = value;
365
- } catch {
366
- /* property may not be defined yet */
367
- }
368
- }
369
-
370
- private setRovingTabindex(index: number) {
371
- if (this.disableFocusManagement) return;
372
- const tabs = this.getTabs();
373
- tabs.forEach((tab, i) => {
374
- tab.tabIndex = i === index && !this.isTabDisabled(tab) ? 0 : -1;
375
- });
376
- }
377
-
378
- /**
379
- * Layout axis.
380
- *
381
- * - `vertical` (default) — the MD3 rail: a fixed-width column on the leading
382
- * edge.
383
- * - `horizontal` — the same parts laid out as a top-of-page bar: logo
384
- * leading, destinations in a row, FAB and footer trailing. For wide layouts
385
- * where a side rail would spend width the content wants.
386
- *
387
- * The expand/collapse affordance is vertical-only — a bar has nowhere to grow
388
- * — so `expandable` is ignored while horizontal.
389
- */
390
- @Prop({ reflect: true }) orientation: 'vertical' | 'horizontal' = 'vertical';
391
-
392
- /**
393
- * Cap on how many destinations stay in the rail. Any beyond it collapse into
394
- * an overflow trigger that opens a menu of the rest; choosing one activates
395
- * that destination. Leave unset for no overflow.
396
- *
397
- * The trigger is a `button` with `aria-haspopup="menu"`, deliberately OUTSIDE
398
- * the `tablist` — a tablist may only contain tabs.
399
- */
400
- @Prop({ attribute: 'max-visible' }) maxVisible?: number;
401
-
402
- /** Accessible name and label for the overflow trigger. Localize per page. */
403
- @Prop({ attribute: 'overflow-label' }) overflowLabel: string = 'More';
404
-
405
- /** Lucide ligature for the overflow trigger. */
406
- @Prop({ attribute: 'overflow-icon' }) overflowIcon: string = 'more_horiz';
407
-
408
- /** Nearest explicit `dir`, matching pami-button-group / pami-sub-menu-item. */
409
- private resolveDirection(): 'ltr' | 'rtl' {
410
- let node: HTMLElement | null = this.el;
411
- while (node) {
412
- const dir = node.getAttribute?.('dir');
413
- if (dir === 'rtl' || dir === 'ltr') return dir;
414
- node = node.parentElement;
415
- }
416
- return 'ltr';
417
- }
418
-
419
- // pami-menu's own pamiOpen/pamiClose are non-bubbling and non-composed, so the rail
420
- // listens for the destination's re-announcement instead.
421
- @Listen('pamiSubmenuToggle')
422
- onDescendantSubmenuToggle(e: CustomEvent<{ open: boolean }>) {
423
- this.submenuOpen = e.detail?.open ? true : this.anyMenuOpen();
424
- }
425
-
426
- /**
427
- * A menu can also be slotted straight into the rail — an account avatar in
428
- * the `footer` that opens a dropdown, say. That menu is not owned by a
429
- * destination, so it never emits `pamiSubmenuToggle`, and without this the
430
- * rail keeps its `isolation: isolate` and the page paints straight over the
431
- * open menu. Listening on the element itself is the only option: pami-menu's
432
- * own events are non-bubbling and non-composed.
433
- */
434
- private wiredMenus = new WeakSet<Element>();
435
-
436
- private wireSlottedMenus() {
437
- this.el.querySelectorAll('pami-menu').forEach((menu) => {
438
- if (this.wiredMenus.has(menu)) return;
439
- this.wiredMenus.add(menu);
440
- menu.addEventListener('pamiOpen', this.handleSlottedMenuOpen);
441
- menu.addEventListener('pamiClose', this.handleSlottedMenuClose);
442
- });
443
- }
444
-
445
- private handleSlottedMenuOpen = () => {
446
- this.submenuOpen = true;
447
- };
448
-
449
- private handleSlottedMenuClose = () => {
450
- this.submenuOpen = this.anyMenuOpen();
451
- };
452
-
453
- /**
454
- * Read the `open` *property*, never the `[open]` attribute: reflection lands
455
- * a tick after the menu emits `pamiOpen`, so an attribute query run from that
456
- * handler reports every menu closed and stamps the rail shut again.
457
- */
458
- private anyMenuOpen(): boolean {
459
- return Array.from(this.el.querySelectorAll('pami-menu')).some(
460
- (menu) => (menu as HTMLPamiMenuElement).open,
461
- );
462
- }
463
-
464
- private overflowId = createId('pami-rail-overflow');
465
-
466
- /** Destinations pushed past `max-visible`, in author order. */
467
- private get overflowedTabs(): HTMLElement[] {
468
- const cap = this.maxVisible;
469
- const tabs = this.getTabs();
470
- if (!cap || cap < 1 || tabs.length <= cap) return [];
471
- return tabs.slice(cap);
472
- }
473
-
474
- /** Mark the collapsed destinations so CSS hides them and nav skips them. */
475
- private applyOverflow() {
476
- const overflowed = this.overflowedTabs;
477
- const set = new Set(overflowed);
478
- this.getTabs().forEach((tab) => {
479
- if (set.has(tab)) tab.setAttribute('data-overflowed', '');
480
- else tab.removeAttribute('data-overflowed');
481
- });
482
- this.overflowCount = overflowed.length;
483
- }
484
-
485
- @Watch('maxVisible')
486
- onMaxVisibleChange() {
487
- this.applyOverflow();
488
- }
489
-
490
- private overflowMenu(): (HTMLElement & { show(): Promise<void>; close(): Promise<void>; open: boolean }) | null {
491
- return this.el.shadowRoot?.querySelector('pami-menu') as never;
492
- }
493
-
494
- private toggleOverflow = () => {
495
- const menu = this.overflowMenu();
496
- if (!menu) return;
497
- if (menu.open) void menu.close();
498
- else void menu.show();
499
- };
500
-
501
- private selectOverflowed(tab: HTMLElement) {
502
- // NOT by re-dispatching pamiTabClick: a collapsed destination reads as
503
- // disabled (so arrow keys skip it), and handleTabClick drops clicks from
504
- // disabled tabs. Drive the selection directly instead.
505
- const index = this.getTabs().indexOf(tab);
506
- if (index < 0) return;
507
- const changed = index !== this.activeIndex;
508
- this.activeIndex = index;
509
- this.setRovingTabindex(index);
510
- this.clearOtherSubmenuSelections(tab);
511
- if (changed) {
512
- this.pamiTabChange.emit({ index, value: tab.getAttribute('value') ?? '' });
513
- }
514
- void this.overflowMenu()?.close();
515
- }
516
-
517
- private handleKeyDown = (e: KeyboardEvent) => {
518
- // Escape dismisses the modal overlay (standard modal behaviour).
519
- if (e.key === 'Escape' && this.modal && this.variant === 'expanded') {
520
- e.preventDefault();
521
- this.collapse();
522
- this.focusToggle();
523
- return;
524
- }
525
- if (this.disableFocusManagement) return;
526
- const tabs = this.getTabs().filter((t) => !this.isTabDisabled(t));
527
- if (tabs.length === 0) return;
528
-
529
- const current = e.composedPath().find((node) => {
530
- return node instanceof HTMLElement && tabs.includes(node);
531
- }) as HTMLElement | undefined;
532
- const currentIndex = current ? tabs.indexOf(current) : -1;
533
-
534
- let nextIndex: number | null = null;
535
-
536
- // A horizontal rail reads along the inline axis, so Left/Right must follow
537
- // the writing direction — in RTL, ArrowRight moves toward the START.
538
- const rtl = this.orientation === 'horizontal' && this.resolveDirection() === 'rtl';
539
- const forward = (key: string) =>
540
- key === 'ArrowDown' || (rtl ? key === 'ArrowLeft' : key === 'ArrowRight');
541
- const backward = (key: string) =>
542
- key === 'ArrowUp' || (rtl ? key === 'ArrowRight' : key === 'ArrowLeft');
543
-
544
- switch (true) {
545
- case forward(e.key):
546
- nextIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % tabs.length;
547
- break;
548
- case backward(e.key):
549
- nextIndex = currentIndex < 0 ? tabs.length - 1 : (currentIndex - 1 + tabs.length) % tabs.length;
550
- break;
551
- case e.key === 'Home':
552
- nextIndex = 0;
553
- break;
554
- case e.key === 'End':
555
- nextIndex = tabs.length - 1;
556
- break;
557
- default:
558
- return;
559
- }
560
-
561
- e.preventDefault();
562
- const target = tabs[nextIndex!];
563
- if (!target) return;
564
- const allTabs = this.getTabs();
565
- this.setRovingTabindex(allTabs.indexOf(target));
566
- target.focus();
567
- };
568
-
569
- private handleToggleClick = () => {
570
- this.toggle();
571
- };
572
-
573
- /** Dismiss the modal overlay when its scrim is clicked. */
574
- private handleScrimClick = () => {
575
- if (this.modal && this.variant === 'expanded') {
576
- this.collapse();
577
- this.focusToggle();
578
- }
579
- };
580
-
581
- /** Return focus to the built-in toggle after a modal dismiss (a11y). */
582
- private focusToggle() {
583
- const toggle = this.el.shadowRoot?.querySelector(
584
- '.pami-navigation-rail__toggle-button',
585
- ) as HTMLElement | null;
586
- toggle?.focus();
587
- }
588
-
589
- private handleSlotChange = () => {
590
- this.syncTabs();
591
- };
592
-
593
- private handleLogoSlotChange = (e: Event) => {
594
- this.hasLogo = (e.target as HTMLSlotElement).assignedElements().length > 0;
595
- };
596
-
597
- private handleLogoExpandedSlotChange = (e: Event) => {
598
- this.hasLogoExpanded = (e.target as HTMLSlotElement).assignedElements().length > 0;
599
- };
600
-
601
- private handleHeaderSlotChange = (e: Event) => {
602
- this.hasHeader = (e.target as HTMLSlotElement).assignedElements().length > 0;
603
- };
604
-
605
- private handleFabSlotChange = (e: Event) => {
606
- this.hasFab = (e.target as HTMLSlotElement).assignedElements().length > 0;
607
- this.syncFab();
608
- };
609
-
610
- private handleFooterSlotChange = (e: Event) => {
611
- this.hasFooter = (e.target as HTMLSlotElement).assignedElements().length > 0;
612
- this.wireSlottedMenus();
613
- };
614
-
615
- private handleFooterProfileSlotChange = (e: Event) => {
616
- const slot = e.target as HTMLSlotElement;
617
- const populated = slot.assignedElements().length > 0;
618
- if (slot.name === 'footer-leading') this.hasFooterLeading = populated;
619
- else this.hasFooterContent = populated;
620
- this.wireSlottedMenus();
621
- };
622
-
623
- render() {
624
- const hasFooterProfile = this.hasFooterLeading || this.hasFooterContent;
625
- const footerContentVisible = this.variant === 'expanded' || this.orientation === 'horizontal';
626
- return (
627
- <Host
628
- class={{
629
- 'pami-navigation-rail': true,
630
- [`pami-navigation-rail--${this.variant}`]: true,
631
- 'pami-navigation-rail--tabs-expanded': this.tabsExpanded,
632
- 'pami-navigation-rail--horizontal': this.orientation === 'horizontal',
633
- 'pami-navigation-rail--submenu-open': this.submenuOpen,
634
- 'pami-navigation-rail--modal': this.modal,
635
- 'pami-navigation-rail--full-height': this.fullHeight,
636
- [`pami-navigation-rail--align-${this.alignment}`]: true,
637
- [`pami-navigation-rail--labels-${this.labelVisibility}`]: true,
638
- 'pami-navigation-rail--with-logo': this.hasLogo || this.hasLogoExpanded,
639
- 'pami-navigation-rail--with-logo-expanded': this.hasLogoExpanded,
640
- 'pami-navigation-rail--with-header': this.hasHeader,
641
- 'pami-navigation-rail--with-fab': this.hasFab,
642
- 'pami-navigation-rail--with-footer': this.hasFooter || hasFooterProfile,
643
- }}
644
- role="navigation"
645
- aria-label={this.label}
646
- onKeyDown={this.handleKeyDown}
647
- >
648
- {/* Scrim — only interactive/visible when the rail is a modal overlay
649
- (modal + expanded). Clicking it collapses the rail. */}
650
- <div
651
- class="pami-navigation-rail__scrim"
652
- part="scrim"
653
- aria-hidden="true"
654
- onClick={this.handleScrimClick}
655
- ></div>
656
-
657
- <div class="pami-navigation-rail__container" part="container">
658
- {/* Logo / brand — topmost slot. Two variants cross-fade IN PLACE (no
659
- drift): `logo` is the contracted mark (centred, shown collapsed),
660
- `logo-expanded` is the full mark (leading, shown expanded). If only
661
- `logo` is provided it shows in both states. */}
662
- <div
663
- class="pami-navigation-rail__logo"
664
- part="logo"
665
- hidden={!this.hasLogo && !this.hasLogoExpanded}
666
- >
667
- <span class="pami-navigation-rail__logo-contracted" part="logo-contracted">
668
- <slot name="logo" onSlotchange={this.handleLogoSlotChange} />
669
- </span>
670
- <span class="pami-navigation-rail__logo-expanded" part="logo-expanded">
671
- <slot name="logo-expanded" onSlotchange={this.handleLogoExpandedSlotChange} />
672
- </span>
673
- </div>
674
-
675
- {this.expandable && this.orientation === 'vertical' && (
676
- <div class="pami-navigation-rail__toggle" part="toggle">
677
- <pami-icon-button
678
- class="pami-navigation-rail__toggle-button"
679
- icon={this.variant === 'expanded' ? 'menu_open' : 'menu'}
680
- aria-label={this.toggleLabel}
681
- aria-expanded={this.variant === 'expanded' ? 'true' : 'false'}
682
- onClick={this.handleToggleClick}
683
- ></pami-icon-button>
684
- </div>
685
- )}
686
-
687
- <div class="pami-navigation-rail__header" part="header" hidden={!this.hasHeader}>
688
- <slot name="header" onSlotchange={this.handleHeaderSlotChange} />
689
- </div>
690
-
691
- <div class="pami-navigation-rail__fab" part="fab" hidden={!this.hasFab}>
692
- <slot name="fab" onSlotchange={this.handleFabSlotChange} />
693
- </div>
694
-
695
- <div
696
- class="pami-navigation-rail__destinations"
697
- part="destinations"
698
- role={this.hasLinkDestinations ? undefined : 'tablist'}
699
- aria-orientation={this.hasLinkDestinations ? undefined : this.orientation}
700
- aria-label={this.hasLinkDestinations ? undefined : this.label}
701
- >
702
- <slot onSlotchange={this.handleSlotChange} />
703
- </div>
704
-
705
- {this.overflowCount > 0 && (
706
- <div class="pami-navigation-rail__overflow" part="overflow">
707
- <button
708
- id={this.overflowId}
709
- type="button"
710
- class="pami-navigation-rail__overflow-trigger"
711
- part="overflow-trigger"
712
- aria-haspopup="menu"
713
- aria-label={this.overflowLabel}
714
- onClick={this.toggleOverflow}
715
- >
716
- <pami-icon class="pami-navigation-rail__overflow-icon" aria-hidden="true" name={this.overflowIcon}></pami-icon>
717
- <span class="pami-navigation-rail__overflow-label">{this.overflowLabel}</span>
718
- </button>
719
- {/* pami-menu resolves `anchor` against its own root first, so an id
720
- inside this shadow root is enough. */}
721
- {/* The trigger sits at the END of the destinations, so a vertical
722
- rail opens UPWARD — downward would run off the bottom of a
723
- bounded rail and be clipped. */}
724
- <pami-menu
725
- anchor={this.overflowId}
726
- placement={this.orientation === 'horizontal' ? 'bottom-end' : 'top-start'}
727
- >
728
- {this.overflowedTabs.map((tab) => (
729
- <pami-menu-item
730
- key={tab.getAttribute('value') || tab.getAttribute('label') || ''}
731
- headline={tab.getAttribute('label') || ''}
732
- onClick={() => this.selectOverflowed(tab)}
733
- >
734
- {tab.getAttribute('icon') && (
735
- <pami-icon slot="leading-icon" name={tab.getAttribute('icon') ?? undefined}></pami-icon>
736
- )}
737
- </pami-menu-item>
738
- ))}
739
- </pami-menu>
740
- </div>
741
- )}
742
-
743
- <div class="pami-navigation-rail__footer" part="footer" hidden={!this.hasFooter && !hasFooterProfile}>
744
- {/* Keep one leading item and one persistent text layout through
745
- width transitions. The library owns anchoring and concealment;
746
- consumers do not need variant-dependent footer styles. */}
747
- <div class="pami-navigation-rail__footer-profile" part="footer-profile" hidden={!hasFooterProfile}>
748
- <div class="pami-navigation-rail__footer-leading" part="footer-leading">
749
- <slot name="footer-leading" onSlotchange={this.handleFooterProfileSlotChange} />
750
- </div>
751
- <div
752
- class="pami-navigation-rail__footer-content"
753
- part="footer-content"
754
- aria-hidden={footerContentVisible ? undefined : 'true'}
755
- inert={!footerContentVisible}
756
- >
757
- <slot name="footer-content" onSlotchange={this.handleFooterProfileSlotChange} />
758
- </div>
759
- </div>
760
- <slot name="footer" onSlotchange={this.handleFooterSlotChange} />
761
- </div>
762
- </div>
763
- </Host>
764
- );
765
- }
766
- }
1
+ import { createId } from '../../utils/id';
2
+ import {
3
+ Component,
4
+ Host,
5
+ h,
6
+ Prop,
7
+ Event,
8
+ EventEmitter,
9
+ Element,
10
+ State,
11
+ Watch,
12
+ Listen,
13
+ Method,
14
+ } from '@stencil/core';
15
+ import { prepareRailTabTransition } from '../../utils/navigation-rail-motion';
16
+
17
+ /**
18
+ * Material Design 3 — Navigation Rail
19
+ *
20
+ * A vertical navigation surface for the left or right edge of medium / large
21
+ * window sizes. Holds 3–7 top-level destinations and optionally a header
22
+ * (menu / brand), a FAB, and a footer.
23
+ *
24
+ * Implements MD3 specs:
25
+ * - https://m3.material.io/components/navigation-rail/overview
26
+ * - https://m3.material.io/components/navigation-rail/specs
27
+ * - https://m3.material.io/components/navigation-rail/guidelines
28
+ * - https://m3.material.io/components/navigation-rail/accessibility
29
+ */
30
+ @Component({
31
+ tag: 'pami-navigation-rail',
32
+ styleUrl: 'pami-navigation-rail.css',
33
+ shadow: true,
34
+ })
35
+ export class PamiNavigationRail {
36
+ @Element() el!: HTMLElement;
37
+
38
+ /**
39
+ * Visual variant — `standard` (the spec's *collapsed* rail: 80px wide,
40
+ * stacked icon + label) or `expanded` (icons + label inline, 220–360px wide).
41
+ */
42
+ @Prop({ mutable: true, reflect: true }) variant: 'standard' | 'expanded' = 'standard';
43
+
44
+ /**
45
+ * Modal styling for the expanded variant per spec: `surface-container`
46
+ * background, level-2 elevation, large corner shape. Use when the expanded
47
+ * rail floats over content instead of being docked; positioning and the
48
+ * scrim are the host app's responsibility. No effect while collapsed.
49
+ */
50
+ @Prop({ reflect: true }) modal: boolean = false;
51
+
52
+ /**
53
+ * Stretch the rail to the full viewport height (`100dvh`) instead of filling
54
+ * its parent container. Opt-in: by default the rail fills whatever height its
55
+ * container gives it (`100%`), which keeps it embeddable in split-pane /
56
+ * nested / modal-docked layouts. Set this when the rail is the app's
57
+ * top-level side navigation and should always span the screen.
58
+ */
59
+ @Prop({ reflect: true, attribute: 'full-height' }) fullHeight: boolean = false;
60
+
61
+ /** Vertical alignment of destinations relative to the rail. */
62
+ @Prop({ reflect: true }) alignment: 'top' | 'middle' | 'bottom' = 'top';
63
+
64
+ /**
65
+ * Render a built-in leading menu button that toggles between the collapsed
66
+ * (`standard`) and `expanded` variants. The icon animates between `menu`
67
+ * (collapsed) and `menu_open` (expanded) per the MD3 navigation rail figure.
68
+ * When you'd rather supply your own control, leave this `false` and place a
69
+ * button in the `header` slot wired to the `expand()` / `collapse()` /
70
+ * `toggle()` methods.
71
+ */
72
+ @Prop({ reflect: true }) expandable: boolean = false;
73
+
74
+ /**
75
+ * Accessible label for the built-in toggle button (only rendered when
76
+ * `expandable` is set). Announced to assistive tech as the button's name.
77
+ */
78
+ @Prop({ attribute: 'toggle-label' }) toggleLabel: string = 'Toggle navigation';
79
+
80
+ /**
81
+ * Controls whether destination labels are shown.
82
+ * - `all`: every destination shows its label (default — recommended by MD3 for 3–7 destinations)
83
+ * - `selected`: only the active destination shows its label
84
+ * - `none`: icons only
85
+ */
86
+ @Prop({ reflect: true, attribute: 'label-visibility' })
87
+ labelVisibility: 'all' | 'selected' | 'none' = 'all';
88
+
89
+ /**
90
+ * Index of the currently active destination. -1 means no destination is
91
+ * active. Two-way bound: updates when the user selects a destination and
92
+ * can be set externally to programmatically change the active destination.
93
+ */
94
+ @Prop({ mutable: true, reflect: true, attribute: 'active-index' })
95
+ activeIndex: number = -1;
96
+
97
+ /**
98
+ * Accessible name announced for the rail's `navigation` landmark.
99
+ * Required for screen reader users (WAI-ARIA APG / WCAG 2.4.1).
100
+ */
101
+ @Prop() label: string = 'Navigation';
102
+
103
+ /** Platform name, shown above the tool name in the brand area. */
104
+ @Prop({ attribute: 'platform-name' }) platformName?: string;
105
+
106
+ /** Short name of the tool within the platform. */
107
+ @Prop({ attribute: 'app-name' }) appName?: string;
108
+
109
+ /** Optional functional description, available in the brand tooltip. */
110
+ @Prop() description?: string;
111
+
112
+ /** Controlled destination value. When supplied, takes precedence over activeIndex. */
113
+ @Prop({ attribute: 'active-value' }) activeValue?: string;
114
+
115
+ /** Docked rail or modal navigation drawer using the same authored content. */
116
+ @Prop({ reflect: true }) presentation: 'rail' | 'drawer' = 'rail';
117
+
118
+ /** Drawer visibility. Does not change the rail variant. */
119
+ @Prop({ mutable: true, reflect: true }) open: boolean = false;
120
+
121
+ /** Accessible drawer close-control name. */
122
+ @Prop({ attribute: 'close-label' }) closeLabel: string = 'Close navigation';
123
+
124
+ @Event() pamiOpen: EventEmitter<void>;
125
+ @Event() pamiClose: EventEmitter<void>;
126
+
127
+ @Method()
128
+ async show(): Promise<void> {
129
+ this.open = true;
130
+ }
131
+
132
+ @Method()
133
+ async close(): Promise<void> {
134
+ this.open = false;
135
+ }
136
+
137
+ @Method()
138
+ async whenClosed(): Promise<void> {
139
+ await this.el.shadowRoot?.querySelector<HTMLPamiSideSheetElement>('pami-side-sheet')?.whenClosed();
140
+ }
141
+
142
+ /**
143
+ * Set to `true` to disable focus management (roving tabindex + arrow keys).
144
+ * Use when embedding inside a custom focus management system.
145
+ */
146
+ @Prop() disableFocusManagement: boolean = false;
147
+
148
+ /**
149
+ * Local density rung. Drives the same `--md-sys-density-scale` signal that a
150
+ * global `data-density` ancestor sets, so a local value simply overrides the
151
+ * inherited one. 0 = default, -4 = ultra-compact.
152
+ */
153
+ @Prop({ reflect: true }) density: 0 | -1 | -2 | -3 | -4 = 0;
154
+
155
+ /** Emitted when the user selects a destination. */
156
+ @Event() pamiTabChange: EventEmitter<{ index: number; value: string; path?: string[] }>;
157
+
158
+ /** Emitted when the rail transitions from collapsed → expanded. */
159
+ @Event() pamiExpand: EventEmitter<void>;
160
+
161
+ /** Emitted when the rail transitions from expanded → collapsed. */
162
+ @Event() pamiCollapse: EventEmitter<void>;
163
+
164
+ @State() private hasLogo = false;
165
+ @State() private hasLogoExpanded = false;
166
+ @State() private hasHeader = false;
167
+ @State() private hasFab = false;
168
+ @State() private hasFooter = false;
169
+ @State() private hasFooterLeading = false;
170
+ @State() private hasFooterContent = false;
171
+
172
+ /**
173
+ * True when one or more destinations render as links (`href` set). A `tablist`
174
+ * may only contain `tab` children per ARIA, so when destinations are links the
175
+ * container drops its `tablist` semantics and is just a grouping element inside
176
+ * the `navigation` landmark.
177
+ */
178
+ @State() private hasLinkDestinations = false;
179
+ @State() private hasGroups = false;
180
+ @State() private hasHierarchy = false;
181
+ @State() private selectedChildValue?: string;
182
+ private destinationObserver?: MutationObserver;
183
+ @State() private overflowCount = 0;
184
+ /** True while any destination's dropdown is open — lifts the rail's stacking
185
+ * context so the fixed-position menu is not trapped inside it. */
186
+ @State() private submenuOpen = false;
187
+
188
+ /**
189
+ * Destination target layout, synchronized with the variant before rendering.
190
+ * Tabs capture their current geometry before this changes, then animate to the
191
+ * new layout while the rail changes width.
192
+ */
193
+ @State() private tabsExpanded = false;
194
+
195
+ /** Programmatically expand the rail (shows labels inline with icons). */
196
+ @Method()
197
+ async expand(): Promise<void> {
198
+ if (this.variant !== 'expanded') {
199
+ this.variant = 'expanded';
200
+ }
201
+ }
202
+
203
+ /** Programmatically collapse the rail (standard 80px width). */
204
+ @Method()
205
+ async collapse(): Promise<void> {
206
+ if (this.variant !== 'standard') {
207
+ this.variant = 'standard';
208
+ }
209
+ }
210
+
211
+ /** Toggle between expanded and standard. */
212
+ @Method()
213
+ async toggle(): Promise<void> {
214
+ this.variant = this.variant === 'expanded' ? 'standard' : 'expanded';
215
+ }
216
+
217
+ /** Move keyboard focus to the destination at `index`. */
218
+ @Method()
219
+ async focusTab(index: number): Promise<void> {
220
+ const tabs = this.getTabs();
221
+ const target = tabs[index];
222
+ if (target) {
223
+ this.setRovingTabindex(index);
224
+ this.focusDestination(target);
225
+ }
226
+ }
227
+
228
+ componentWillLoad() {
229
+ this.tabsExpanded = this.variant === 'expanded' || this.presentation === 'drawer';
230
+ /*
231
+ * Seed the slot-presence flags from the light DOM BEFORE the first render —
232
+ * the same technique the active-tab adoption below already uses. They used
233
+ * to be written only by each slot's `slotchange`, which fires after first
234
+ * render, so every rail's first painted frame had no `--with-fab` host
235
+ * class, a `hidden` FAB wrapper, and no header-space padding on the
236
+ * destinations. Measured on a cold load: the destinations painted at y=114
237
+ * and dropped to y=213 one frame later when the band opened — a 99px shift
238
+ * on every load, which a consumer could only pre-pad from outside with
239
+ * hand copies of this component's internal expressions. Whether a slot is
240
+ * filled is a fact of the light DOM and is readable here; `slotchange`
241
+ * still owns every later change.
242
+ */
243
+ // Direct-children iteration rather than `:scope >` — same pattern as the
244
+ // active-tab adoption below, and mock-doc's selector engine has no :scope.
245
+ const slotted = (name: string) =>
246
+ Array.from(this.el.children).some((child) => child.getAttribute('slot') === name);
247
+ this.hasLogo = slotted('logo');
248
+ this.hasLogoExpanded = slotted('logo-expanded');
249
+ this.hasHeader = slotted('header');
250
+ this.hasFab = slotted('fab');
251
+ this.hasFooter = slotted('footer');
252
+ this.hasFooterLeading = slotted('footer-leading');
253
+ this.hasFooterContent = slotted('footer-content');
254
+ // Adopt a pre-marked destination: authors can write `active` directly on a
255
+ // child tab instead of `active-index` on the rail. This MUST run before the
256
+ // first slotchange-driven syncTabs(), which (with activeIndex still -1)
257
+ // would clear the child's `active` attribute before we could read it. Read
258
+ // the light-DOM children directly since the shadow slot isn't assigned yet.
259
+ if (this.activeIndex < 0) {
260
+ const tabs = this.collectTabs(Array.from(this.el.children));
261
+ const marked = tabs.findIndex((t) => t.hasAttribute('active'));
262
+ if (marked >= 0) this.activeIndex = marked;
263
+ }
264
+ }
265
+
266
+ componentDidLoad() {
267
+ this.syncTabs();
268
+ this.syncFab();
269
+ this.wireSlottedMenus();
270
+ this.observeDestinations();
271
+ }
272
+
273
+ connectedCallback() {
274
+ if (this.el.shadowRoot) this.observeDestinations();
275
+ }
276
+
277
+ disconnectedCallback() {
278
+ this.destinationObserver?.disconnect();
279
+ this.el.querySelectorAll('pami-menu').forEach((menu) => {
280
+ menu.removeEventListener('pamiOpen', this.handleSlottedMenuOpen);
281
+ menu.removeEventListener('pamiClose', this.handleSlottedMenuClose);
282
+ });
283
+ this.wiredMenus = new WeakSet<Element>();
284
+ }
285
+
286
+ private observeDestinations() {
287
+ if (typeof MutationObserver === 'undefined') return;
288
+ this.destinationObserver?.disconnect();
289
+ this.destinationObserver = new MutationObserver(() => {
290
+ this.syncTabs();
291
+ this.wireSlottedMenus();
292
+ });
293
+ this.destinationObserver.observe(this.el, {
294
+ childList: true, subtree: true, attributes: true,
295
+ attributeFilter: ['value', 'href', 'disabled', 'hidden'],
296
+ });
297
+ this.syncTabs();
298
+ this.wireSlottedMenus();
299
+ }
300
+
301
+ @Watch('variant')
302
+ onVariantChange(newVal: 'standard' | 'expanded', oldVal: 'standard' | 'expanded') {
303
+ if (newVal === oldVal) return;
304
+
305
+ // Capture destinations before the rail's padding or target layout changes.
306
+ // A child watcher alone can run after the parent has already moved its icon.
307
+ this.getTabs().forEach(prepareRailTabTransition);
308
+ this.tabsExpanded = newVal === 'expanded' || this.presentation === 'drawer';
309
+ this.syncTabs();
310
+ this.syncFab();
311
+
312
+ // Consumers can synchronously update label visibility in these listeners;
313
+ // publish only after every destination and the FAB have the target state.
314
+ if (newVal === 'expanded') this.pamiExpand.emit();
315
+ else this.pamiCollapse.emit();
316
+ }
317
+
318
+ /**
319
+ * Mirror the rail's expanded state onto a slotted FAB's `extended` prop so it
320
+ * morphs between the extended (icon + label) and icon-only forms. No-op for
321
+ * slotted content that doesn't expose `extended`.
322
+ */
323
+ private syncFab() {
324
+ const slot = this.el.shadowRoot?.querySelector(
325
+ 'slot[name="fab"]',
326
+ ) as HTMLSlotElement | null;
327
+ slot?.assignedElements().forEach((el) => {
328
+ this.setProp(el as HTMLElement, 'extended', this.variant === 'expanded');
329
+ });
330
+ }
331
+
332
+ @Watch('labelVisibility')
333
+ onLabelVisibilityChange() {
334
+ this.syncTabs();
335
+ }
336
+
337
+ @Watch('activeIndex')
338
+ onActiveIndexChange() {
339
+ this.selectedChildValue = undefined;
340
+ this.syncTabs();
341
+ }
342
+
343
+ @Watch('presentation')
344
+ onPresentationChange() {
345
+ this.tabsExpanded = this.variant === 'expanded' || this.presentation === 'drawer';
346
+ this.syncTabs();
347
+ }
348
+
349
+ @Watch('activeValue')
350
+ onActiveValueChange() { this.syncTabs(); }
351
+
352
+ @Listen('pamiTabClick')
353
+ handleTabClick(e: CustomEvent<{ value: string }>) {
354
+ const target = e.target as HTMLElement | null;
355
+ if (!target) return;
356
+ const tabs = this.getTabs();
357
+ const path = this.destinationPath(target);
358
+ const index = tabs.indexOf(path[0]);
359
+ if (index < 0) return;
360
+
361
+ if (path.some(tab => this.isTabDisabled(tab))) {
362
+ e.stopPropagation();
363
+ return;
364
+ }
365
+
366
+ // `pamiTabClick` (from the tab) fires on every activation — including
367
+ // re-clicking the already-active destination (which replays the ripple).
368
+ // `pamiTabChange` is the higher-level *selection changed* event, so only
369
+ // emit it when the active index actually moves.
370
+ const value = e.detail?.value ?? '';
371
+ const changed = this.activeValue !== undefined ? value !== this.activeValue
372
+ : this.hasHierarchy ? value !== this.selectedChildValue : index !== this.activeIndex;
373
+ if (this.activeValue === undefined) this.activeIndex = index;
374
+ if (this.activeValue === undefined && this.hasHierarchy) this.selectedChildValue = value;
375
+ this.syncTabs();
376
+ this.setRovingTabindex(index);
377
+ this.clearOtherSubmenuSelections(target);
378
+ if (changed) {
379
+ this.pamiTabChange.emit({ index, value, ...(this.hasHierarchy ? { path: path.map(tab => this.tabValue(tab)) } : {}) });
380
+ }
381
+ path.filter(tab => !(tab as HTMLPamiNavigationRailTabElement).expanded).forEach(tab => {
382
+ void (tab as HTMLPamiNavigationRailTabElement & { setChildrenOpen?(open: boolean): Promise<void> }).setChildrenOpen?.(false);
383
+ });
384
+ if (this.presentation === 'drawer') this.open = false;
385
+ }
386
+
387
+ /**
388
+ * A destination whose dropdown row is chosen wears the same pill as the
389
+ * active one, so a stale selection in *another* dropdown reads as a second
390
+ * active destination. Only one destination can be current, so activating any
391
+ * of them clears the rest.
392
+ */
393
+ private clearOtherSubmenuSelections(active: HTMLElement | null) {
394
+ this.getTabs().forEach((tab) => {
395
+ if (tab === active) return;
396
+ const clear = (tab as HTMLPamiNavigationRailTabElement).clearSubmenuSelection;
397
+ if (typeof clear === 'function') void clear.call(tab);
398
+ });
399
+ }
400
+
401
+ private isTabDisabled(tab: HTMLElement): boolean {
402
+ // A destination collapsed into the overflow menu is no longer in the rail,
403
+ // so arrow keys must skip it exactly as they skip a disabled one.
404
+ return (
405
+ tab.hasAttribute('disabled') ||
406
+ tab.getAttribute('aria-disabled') === 'true' ||
407
+ tab.hasAttribute('data-overflowed')
408
+ || tab.hidden || !!tab.parentElement?.closest('[hidden]')
409
+ );
410
+ }
411
+
412
+ private getTabs(): HTMLElement[] {
413
+ const slot = this.el.shadowRoot?.querySelector(
414
+ 'slot:not([name])',
415
+ ) as HTMLSlotElement | null;
416
+ if (!slot) return [];
417
+ return this.collectTabs(slot.assignedElements());
418
+ }
419
+
420
+ private collectTabs(elements: Element[]): HTMLElement[] {
421
+ return elements.flatMap((element) => {
422
+ if (element.tagName.toLowerCase() === 'pami-navigation-rail-tab') return [element as HTMLElement];
423
+ if (element.tagName.toLowerCase() === 'pami-navigation-group') return this.collectTabs(Array.from(element.children));
424
+ return [];
425
+ });
426
+ }
427
+
428
+ private tabValue(tab: HTMLElement): string {
429
+ return (tab as HTMLPamiNavigationRailTabElement).value ?? tab.getAttribute('value') ?? '';
430
+ }
431
+
432
+ private allTabs(): HTMLElement[] {
433
+ const descend = (tabs: HTMLElement[]): HTMLElement[] => tabs.flatMap(tab => [tab, ...descend(this.collectTabs(
434
+ Array.from(tab.children).filter(child => child.getAttribute('slot') === 'children'),
435
+ ))]);
436
+ return descend(this.getTabs());
437
+ }
438
+
439
+ private destinationPath(tab: HTMLElement): HTMLElement[] {
440
+ const path = [tab];
441
+ let parent = tab.parentElement?.closest('pami-navigation-rail-tab') as HTMLElement | null;
442
+ while (parent && parent.closest('pami-navigation-rail') === this.el) {
443
+ path.unshift(parent);
444
+ parent = parent.parentElement?.closest('pami-navigation-rail-tab') as HTMLElement | null;
445
+ }
446
+ return path;
447
+ }
448
+
449
+ private visibleTabs(): HTMLElement[] {
450
+ return this.allTabs().filter(tab => !this.isTabDisabled(tab) && this.destinationPath(tab).slice(0, -1)
451
+ .every(parent => !this.isTabDisabled(parent) && (parent as HTMLPamiNavigationRailTabElement & { childrenOpen?: boolean }).childrenOpen));
452
+ }
453
+
454
+ private focusDestination(tab: HTMLElement) {
455
+ const method = (tab as HTMLPamiNavigationRailTabElement & { focusDestination?(): Promise<void> }).focusDestination;
456
+ if (this.hasHierarchy && typeof method === 'function') void method.call(tab);
457
+ else tab.focus();
458
+ }
459
+
460
+ @Listen('pamiChildrenToggle')
461
+ onChildrenToggle(event: CustomEvent<{ open: boolean }>) {
462
+ if (event.detail.open) {
463
+ const target = event.target as HTMLPamiNavigationRailTabElement;
464
+ if (!target.expanded) this.getTabs().filter(tab => tab !== target).forEach(tab => {
465
+ if (!(tab as HTMLPamiNavigationRailTabElement).expanded) {
466
+ void (tab as HTMLPamiNavigationRailTabElement & { setChildrenOpen?(open: boolean): Promise<void> }).setChildrenOpen?.(false);
467
+ }
468
+ });
469
+ }
470
+ this.submenuOpen = this.allTabs().some(tab => !(tab as HTMLPamiNavigationRailTabElement).expanded
471
+ && (tab as HTMLPamiNavigationRailTabElement & { childrenOpen?: boolean }).childrenOpen);
472
+ this.syncTabs();
473
+ }
474
+
475
+ private syncTabs() {
476
+ const roots = this.getTabs();
477
+ const tabs = this.allTabs();
478
+ this.hasHierarchy = tabs.length !== roots.length || roots.some(tab => Array.from(tab.children).some(child => child.getAttribute('slot') === 'children'));
479
+ const groups = Array.from(this.el.querySelectorAll('pami-navigation-group'))
480
+ .filter((group) => group.closest('pami-navigation-rail') === this.el);
481
+ this.hasGroups = groups.length > 0;
482
+ groups.forEach((group) => this.setProp(group as HTMLElement, 'expanded', this.tabsExpanded || this.orientation === 'horizontal'));
483
+ // Detect link-style destinations so the container can shed its invalid
484
+ // `tablist` role (a tablist must only contain `tab` children).
485
+ this.hasLinkDestinations = tabs.some(
486
+ (tab) => !!(tab as HTMLElement & { href?: string }).href || !!tab.getAttribute('href'),
487
+ );
488
+ const routeValue = this.activeValue ?? this.selectedChildValue;
489
+ tabs.forEach((tab, i) => {
490
+ const active = routeValue !== undefined ? this.tabValue(tab) === routeValue
491
+ : roots.indexOf(tab) === this.activeIndex;
492
+ this.setProp(tab, 'active', active);
493
+ this.setProp(tab, 'labelVisibility', this.labelVisibility);
494
+ this.setProp(tab, 'expanded', !roots.includes(tab) || this.tabsExpanded);
495
+ this.setProp(tab, 'navigation', this.hasGroups || this.hasHierarchy);
496
+ // The tab styles its own indicator, and shadow DOM keeps the rail out of
497
+ // it — so hand the axis down as an attribute it can key off.
498
+ tab.setAttribute('data-orientation', this.orientation);
499
+
500
+ if (!this.disableFocusManagement) {
501
+ const focusable = !this.isTabDisabled(tab);
502
+ const isRoving =
503
+ active ||
504
+ (!tabs.some((t, j) => this.activeValue !== undefined
505
+ ? ((t as HTMLPamiNavigationRailTabElement).value ?? t.getAttribute('value')) === this.activeValue && !this.isTabDisabled(t)
506
+ : j === this.activeIndex && !this.isTabDisabled(t)) && i === tabs.findIndex((t) => !this.isTabDisabled(t)));
507
+ tab.tabIndex = focusable && (this.hasHierarchy || isRoving) ? 0 : -1;
508
+ if (Array.from(tab.children).some(child => child.getAttribute('slot') === 'children')) tab.tabIndex = -1;
509
+ }
510
+ });
511
+
512
+ // Recompute the overflow set from every sync path, not just slotchange.
513
+ this.applyOverflow();
514
+ }
515
+
516
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
517
+ private setProp(el: HTMLElement, key: string, value: any) {
518
+ try {
519
+ (el as any)[key] = value;
520
+ } catch {
521
+ /* property may not be defined yet */
522
+ }
523
+ }
524
+
525
+ private setRovingTabindex(index: number) {
526
+ if (this.disableFocusManagement) return;
527
+ if (this.hasHierarchy) return;
528
+ const tabs = this.getTabs();
529
+ tabs.forEach((tab, i) => {
530
+ tab.tabIndex = i === index && !this.isTabDisabled(tab) ? 0 : -1;
531
+ });
532
+ }
533
+
534
+ /**
535
+ * Layout axis.
536
+ *
537
+ * - `vertical` (default) — the MD3 rail: a fixed-width column on the leading
538
+ * edge.
539
+ * - `horizontal` — the same parts laid out as a top-of-page bar: logo
540
+ * leading, destinations in a row, FAB and footer trailing. For wide layouts
541
+ * where a side rail would spend width the content wants.
542
+ *
543
+ * The expand/collapse affordance is vertical-only — a bar has nowhere to grow
544
+ * — so `expandable` is ignored while horizontal.
545
+ */
546
+ @Prop({ reflect: true }) orientation: 'vertical' | 'horizontal' = 'vertical';
547
+
548
+ /**
549
+ * Cap on how many destinations stay in the rail. Any beyond it collapse into
550
+ * an overflow trigger that opens a menu of the rest; choosing one activates
551
+ * that destination. Leave unset for no overflow.
552
+ *
553
+ * The trigger is a `button` with `aria-haspopup="menu"`, deliberately OUTSIDE
554
+ * the `tablist` — a tablist may only contain tabs.
555
+ */
556
+ @Prop({ attribute: 'max-visible' }) maxVisible?: number;
557
+
558
+ /** Accessible name and label for the overflow trigger. Localize per page. */
559
+ @Prop({ attribute: 'overflow-label' }) overflowLabel: string = 'More';
560
+
561
+ /** Lucide ligature for the overflow trigger. */
562
+ @Prop({ attribute: 'overflow-icon' }) overflowIcon: string = 'more_horiz';
563
+
564
+ /** Nearest explicit `dir`, matching pami-button-group / pami-sub-menu-item. */
565
+ private resolveDirection(): 'ltr' | 'rtl' {
566
+ let node: HTMLElement | null = this.el;
567
+ while (node) {
568
+ const dir = node.getAttribute?.('dir');
569
+ if (dir === 'rtl' || dir === 'ltr') return dir;
570
+ node = node.parentElement;
571
+ }
572
+ return 'ltr';
573
+ }
574
+
575
+ // pami-menu's own pamiOpen/pamiClose are non-bubbling and non-composed, so the rail
576
+ // listens for the destination's re-announcement instead.
577
+ @Listen('pamiSubmenuToggle')
578
+ onDescendantSubmenuToggle(e: CustomEvent<{ open: boolean }>) {
579
+ this.submenuOpen = e.detail?.open ? true : this.anyMenuOpen();
580
+ }
581
+
582
+ /**
583
+ * A menu can also be slotted straight into the rail — an account avatar in
584
+ * the `footer` that opens a dropdown, say. That menu is not owned by a
585
+ * destination, so it never emits `pamiSubmenuToggle`, and without this the
586
+ * rail keeps its `isolation: isolate` and the page paints straight over the
587
+ * open menu. Listening on the element itself is the only option: pami-menu's
588
+ * own events are non-bubbling and non-composed.
589
+ */
590
+ private wiredMenus = new WeakSet<Element>();
591
+
592
+ private wireSlottedMenus() {
593
+ this.el.querySelectorAll('pami-menu').forEach((menu) => {
594
+ if (this.wiredMenus.has(menu)) return;
595
+ this.wiredMenus.add(menu);
596
+ menu.addEventListener('pamiOpen', this.handleSlottedMenuOpen);
597
+ menu.addEventListener('pamiClose', this.handleSlottedMenuClose);
598
+ });
599
+ }
600
+
601
+ private handleSlottedMenuOpen = () => {
602
+ this.submenuOpen = true;
603
+ };
604
+
605
+ private handleSlottedMenuClose = () => {
606
+ this.submenuOpen = this.anyMenuOpen();
607
+ };
608
+
609
+ /**
610
+ * Read the `open` *property*, never the `[open]` attribute: reflection lands
611
+ * a tick after the menu emits `pamiOpen`, so an attribute query run from that
612
+ * handler reports every menu closed and stamps the rail shut again.
613
+ */
614
+ private anyMenuOpen(): boolean {
615
+ return Array.from(this.el.querySelectorAll('pami-menu')).some(
616
+ (menu) => (menu as HTMLPamiMenuElement).open,
617
+ );
618
+ }
619
+
620
+ private overflowId = createId('pami-rail-overflow');
621
+
622
+ /** Destinations pushed past `max-visible`, in author order. */
623
+ private get overflowedTabs(): HTMLElement[] {
624
+ if (this.hasGroups || this.hasHierarchy) return [];
625
+ const cap = this.maxVisible;
626
+ const tabs = this.getTabs();
627
+ if (!cap || cap < 1 || tabs.length <= cap) return [];
628
+ return tabs.slice(cap);
629
+ }
630
+
631
+ /** Mark the collapsed destinations so CSS hides them and nav skips them. */
632
+ private applyOverflow() {
633
+ const overflowed = this.overflowedTabs;
634
+ const set = new Set(overflowed);
635
+ this.getTabs().forEach((tab) => {
636
+ if (set.has(tab)) tab.setAttribute('data-overflowed', '');
637
+ else tab.removeAttribute('data-overflowed');
638
+ });
639
+ this.overflowCount = overflowed.length;
640
+ }
641
+
642
+ @Watch('maxVisible')
643
+ onMaxVisibleChange() {
644
+ this.applyOverflow();
645
+ }
646
+
647
+ private overflowMenu(): (HTMLElement & { show(): Promise<void>; close(): Promise<void>; open: boolean }) | null {
648
+ return this.el.shadowRoot?.querySelector('pami-menu') as never;
649
+ }
650
+
651
+ private toggleOverflow = () => {
652
+ const menu = this.overflowMenu();
653
+ if (!menu) return;
654
+ if (menu.open) void menu.close();
655
+ else void menu.show();
656
+ };
657
+
658
+ private selectOverflowed(tab: HTMLElement) {
659
+ // NOT by re-dispatching pamiTabClick: a collapsed destination reads as
660
+ // disabled (so arrow keys skip it), and handleTabClick drops clicks from
661
+ // disabled tabs. Drive the selection directly instead.
662
+ const index = this.getTabs().indexOf(tab);
663
+ if (index < 0) return;
664
+ const value = (tab as HTMLPamiNavigationRailTabElement).value ?? tab.getAttribute('value') ?? '';
665
+ const changed = this.activeValue !== undefined ? value !== this.activeValue : index !== this.activeIndex;
666
+ if (this.activeValue === undefined) this.activeIndex = index;
667
+ this.setRovingTabindex(index);
668
+ this.clearOtherSubmenuSelections(tab);
669
+ if (changed) {
670
+ this.pamiTabChange.emit({ index, value });
671
+ }
672
+ void this.overflowMenu()?.close();
673
+ }
674
+
675
+ private handleKeyDown = (e: KeyboardEvent) => {
676
+ // Escape dismisses the modal overlay (standard modal behaviour).
677
+ if (e.key === 'Escape' && this.modal && this.variant === 'expanded') {
678
+ e.preventDefault();
679
+ this.collapse();
680
+ this.focusToggle();
681
+ return;
682
+ }
683
+ if (this.disableFocusManagement) return;
684
+ const tabs = this.hasHierarchy ? this.visibleTabs() : this.getTabs().filter((t) => !this.isTabDisabled(t));
685
+ if (tabs.length === 0) return;
686
+
687
+ const current = e.composedPath().find((node) => {
688
+ return node instanceof HTMLElement && tabs.includes(node);
689
+ }) as HTMLElement | undefined;
690
+ const currentIndex = current ? tabs.indexOf(current) : -1;
691
+
692
+ if (this.hasHierarchy && current) {
693
+ const rtl = this.resolveDirection() === 'rtl';
694
+ const branch = current as HTMLPamiNavigationRailTabElement & { childrenOpen?: boolean; setChildrenOpen?(open: boolean): Promise<void> };
695
+ const hasChildren = Array.from(current.children).some(child => child.getAttribute('slot') === 'children');
696
+ if (e.key === (rtl ? 'ArrowLeft' : 'ArrowRight') && hasChildren) {
697
+ e.preventDefault();
698
+ if (!branch.childrenOpen) void branch.setChildrenOpen?.(true);
699
+ else if (tabs[currentIndex + 1]) this.focusDestination(tabs[currentIndex + 1]);
700
+ return;
701
+ }
702
+ if (e.key === (rtl ? 'ArrowRight' : 'ArrowLeft')) {
703
+ const parent = this.destinationPath(current).at(-2);
704
+ if (hasChildren && branch.childrenOpen) { e.preventDefault(); void branch.setChildrenOpen?.(false); return; }
705
+ if (parent) { e.preventDefault(); this.focusDestination(parent); return; }
706
+ }
707
+ if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') return;
708
+ }
709
+
710
+ let nextIndex: number | null = null;
711
+
712
+ // A horizontal rail reads along the inline axis, so Left/Right must follow
713
+ // the writing direction — in RTL, ArrowRight moves toward the START.
714
+ const rtl = this.orientation === 'horizontal' && this.resolveDirection() === 'rtl';
715
+ const forward = (key: string) =>
716
+ key === 'ArrowDown' || (rtl ? key === 'ArrowLeft' : key === 'ArrowRight');
717
+ const backward = (key: string) =>
718
+ key === 'ArrowUp' || (rtl ? key === 'ArrowRight' : key === 'ArrowLeft');
719
+
720
+ switch (true) {
721
+ case forward(e.key):
722
+ nextIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % tabs.length;
723
+ break;
724
+ case backward(e.key):
725
+ nextIndex = currentIndex < 0 ? tabs.length - 1 : (currentIndex - 1 + tabs.length) % tabs.length;
726
+ break;
727
+ case e.key === 'Home':
728
+ nextIndex = 0;
729
+ break;
730
+ case e.key === 'End':
731
+ nextIndex = tabs.length - 1;
732
+ break;
733
+ default:
734
+ return;
735
+ }
736
+
737
+ e.preventDefault();
738
+ const target = tabs[nextIndex!];
739
+ if (!target) return;
740
+ const allTabs = this.getTabs();
741
+ this.setRovingTabindex(allTabs.indexOf(target));
742
+ this.focusDestination(target);
743
+ };
744
+
745
+ private handleToggleClick = () => {
746
+ this.toggle();
747
+ };
748
+
749
+ /** Dismiss the modal overlay when its scrim is clicked. */
750
+ private handleScrimClick = () => {
751
+ if (this.modal && this.variant === 'expanded') {
752
+ this.collapse();
753
+ this.focusToggle();
754
+ }
755
+ };
756
+
757
+ /** Return focus to the built-in toggle after a modal dismiss (a11y). */
758
+ private focusToggle() {
759
+ const toggle = this.el.shadowRoot?.querySelector(
760
+ '.pami-navigation-rail__toggle-button',
761
+ ) as HTMLElement | null;
762
+ toggle?.focus();
763
+ }
764
+
765
+ private handleSlotChange = () => {
766
+ this.syncTabs();
767
+ };
768
+
769
+ private handleLogoSlotChange = (e: Event) => {
770
+ this.hasLogo = (e.target as HTMLSlotElement).assignedElements().length > 0;
771
+ };
772
+
773
+ private handleLogoExpandedSlotChange = (e: Event) => {
774
+ this.hasLogoExpanded = (e.target as HTMLSlotElement).assignedElements().length > 0;
775
+ };
776
+
777
+ private handleHeaderSlotChange = (e: Event) => {
778
+ this.hasHeader = (e.target as HTMLSlotElement).assignedElements().length > 0;
779
+ };
780
+
781
+ private handleFabSlotChange = (e: Event) => {
782
+ this.hasFab = (e.target as HTMLSlotElement).assignedElements().length > 0;
783
+ this.syncFab();
784
+ };
785
+
786
+ private handleFooterSlotChange = (e: Event) => {
787
+ this.hasFooter = (e.target as HTMLSlotElement).assignedElements().length > 0;
788
+ this.wireSlottedMenus();
789
+ };
790
+
791
+ private handleFooterProfileSlotChange = (e: Event) => {
792
+ const slot = e.target as HTMLSlotElement;
793
+ const populated = slot.assignedElements().length > 0;
794
+ if (slot.name === 'footer-leading') this.hasFooterLeading = populated;
795
+ else this.hasFooterContent = populated;
796
+ this.wireSlottedMenus();
797
+ };
798
+
799
+ render() {
800
+ const hasFooterProfile = this.hasFooterLeading || this.hasFooterContent;
801
+ const footerContentVisible = this.tabsExpanded || this.orientation === 'horizontal';
802
+ const brandName = [this.platformName, this.appName].filter(Boolean).join(' — ');
803
+ const content = (
804
+ <div class="pami-navigation-rail__container" part="container">
805
+ {/* Logo / brand — topmost slot. Two variants cross-fade IN PLACE (no
806
+ drift): `logo` is the contracted mark (centred, shown collapsed),
807
+ `logo-expanded` is the full mark (leading, shown expanded). If only
808
+ `logo` is provided it shows in both states. */}
809
+ <div
810
+ class="pami-navigation-rail__logo"
811
+ part="logo"
812
+ hidden={!this.hasLogo && !this.hasLogoExpanded && !brandName}
813
+ role={brandName ? 'group' : undefined}
814
+ aria-label={brandName || undefined}
815
+ title={[brandName, this.description].filter(Boolean).join('\n') || undefined}
816
+ >
817
+ <span class="pami-navigation-rail__logo-contracted" part="logo-contracted">
818
+ <slot name="logo" onSlotchange={this.handleLogoSlotChange} />
819
+ </span>
820
+ <span class="pami-navigation-rail__logo-expanded" part="logo-expanded">
821
+ <slot name="logo-expanded" onSlotchange={this.handleLogoExpandedSlotChange} />
822
+ </span>
823
+ {brandName && (
824
+ <span class="pami-navigation-rail__identity" part="identity" aria-hidden="true">
825
+ {this.platformName && <span part="platform-name">{this.platformName}</span>}
826
+ {this.appName && <span part="app-name">{this.appName}</span>}
827
+ </span>
828
+ )}
829
+ </div>
830
+
831
+ {this.expandable && this.orientation === 'vertical' && this.presentation !== 'drawer' && (
832
+ <div class="pami-navigation-rail__toggle" part="toggle">
833
+ <pami-icon-button
834
+ class="pami-navigation-rail__toggle-button"
835
+ icon={this.variant === 'expanded' ? 'menu_open' : 'menu'}
836
+ aria-label={this.toggleLabel}
837
+ aria-expanded={this.variant === 'expanded' ? 'true' : 'false'}
838
+ onClick={this.handleToggleClick}
839
+ ></pami-icon-button>
840
+ </div>
841
+ )}
842
+
843
+ <div class="pami-navigation-rail__header" part="header" hidden={!this.hasHeader}>
844
+ <slot name="header" onSlotchange={this.handleHeaderSlotChange} />
845
+ </div>
846
+
847
+ <div class="pami-navigation-rail__fab" part="fab" hidden={!this.hasFab}>
848
+ <slot name="fab" onSlotchange={this.handleFabSlotChange} />
849
+ </div>
850
+
851
+ <div
852
+ class="pami-navigation-rail__destinations"
853
+ part="destinations"
854
+ role={this.hasLinkDestinations || this.hasGroups || this.hasHierarchy ? undefined : 'tablist'}
855
+ aria-orientation={this.hasLinkDestinations || this.hasGroups || this.hasHierarchy ? undefined : this.orientation}
856
+ aria-label={this.hasLinkDestinations || this.hasGroups || this.hasHierarchy ? undefined : this.label}
857
+ >
858
+ <slot onSlotchange={this.handleSlotChange} />
859
+ </div>
860
+
861
+ {this.overflowCount > 0 && (
862
+ <div class="pami-navigation-rail__overflow" part="overflow">
863
+ <button
864
+ id={this.overflowId}
865
+ type="button"
866
+ class="pami-navigation-rail__overflow-trigger"
867
+ part="overflow-trigger"
868
+ aria-haspopup="menu"
869
+ aria-label={this.overflowLabel}
870
+ onClick={this.toggleOverflow}
871
+ >
872
+ <pami-icon class="pami-navigation-rail__overflow-icon" aria-hidden="true" name={this.overflowIcon}></pami-icon>
873
+ <span class="pami-navigation-rail__overflow-label">{this.overflowLabel}</span>
874
+ </button>
875
+ {/* pami-menu resolves `anchor` against its own root first, so an id
876
+ inside this shadow root is enough. */}
877
+ {/* The trigger sits at the END of the destinations, so a vertical
878
+ rail opens UPWARD — downward would run off the bottom of a
879
+ bounded rail and be clipped. */}
880
+ <pami-menu
881
+ anchor={this.overflowId}
882
+ placement={this.orientation === 'horizontal' ? 'bottom-end' : 'top-start'}
883
+ >
884
+ {this.overflowedTabs.map((tab) => (
885
+ <pami-menu-item
886
+ key={tab.getAttribute('value') || tab.getAttribute('label') || ''}
887
+ headline={tab.getAttribute('label') || ''}
888
+ onClick={() => this.selectOverflowed(tab)}
889
+ >
890
+ {tab.getAttribute('icon') && (
891
+ <pami-icon slot="leading-icon" name={tab.getAttribute('icon') ?? undefined}></pami-icon>
892
+ )}
893
+ </pami-menu-item>
894
+ ))}
895
+ </pami-menu>
896
+ </div>
897
+ )}
898
+
899
+ <div class="pami-navigation-rail__footer" part="footer" hidden={!this.hasFooter && !hasFooterProfile}>
900
+ {/* Keep one leading item and one persistent text layout through
901
+ width transitions. The library owns anchoring and concealment;
902
+ consumers do not need variant-dependent footer styles. */}
903
+ <div class="pami-navigation-rail__footer-profile" part="footer-profile" hidden={!hasFooterProfile}>
904
+ <div class="pami-navigation-rail__footer-leading" part="footer-leading">
905
+ <slot name="footer-leading" onSlotchange={this.handleFooterProfileSlotChange} />
906
+ </div>
907
+ <div
908
+ class="pami-navigation-rail__footer-content"
909
+ part="footer-content"
910
+ aria-hidden={footerContentVisible ? undefined : 'true'}
911
+ inert={!footerContentVisible}
912
+ >
913
+ <slot name="footer-content" onSlotchange={this.handleFooterProfileSlotChange} />
914
+ </div>
915
+ </div>
916
+ <slot name="footer" onSlotchange={this.handleFooterSlotChange} />
917
+ </div>
918
+ </div>
919
+ );
920
+ return (
921
+ <Host
922
+ class={{
923
+ 'pami-navigation-rail': true,
924
+ [`pami-navigation-rail--${this.presentation === 'drawer' ? 'expanded' : this.variant}`]: true,
925
+ 'pami-navigation-rail--drawer': this.presentation === 'drawer',
926
+ 'pami-navigation-rail--tabs-expanded': this.tabsExpanded,
927
+ 'pami-navigation-rail--horizontal': this.orientation === 'horizontal',
928
+ 'pami-navigation-rail--submenu-open': this.submenuOpen,
929
+ 'pami-navigation-rail--modal': this.modal,
930
+ 'pami-navigation-rail--full-height': this.fullHeight,
931
+ [`pami-navigation-rail--align-${this.alignment}`]: true,
932
+ [`pami-navigation-rail--labels-${this.labelVisibility}`]: true,
933
+ 'pami-navigation-rail--with-logo': this.hasLogo || this.hasLogoExpanded,
934
+ 'pami-navigation-rail--with-logo-expanded': this.hasLogoExpanded,
935
+ 'pami-navigation-rail--with-identity': !!brandName,
936
+ 'pami-navigation-rail--with-header': this.hasHeader,
937
+ 'pami-navigation-rail--with-fab': this.hasFab,
938
+ 'pami-navigation-rail--with-footer': this.hasFooter || hasFooterProfile,
939
+ }}
940
+ role="navigation"
941
+ aria-label={this.label}
942
+ onKeyDown={this.handleKeyDown}
943
+ >
944
+ {/* Scrim — only interactive/visible when the rail is a modal overlay
945
+ (modal + expanded). Clicking it collapses the rail. */}
946
+ <div
947
+ class="pami-navigation-rail__scrim"
948
+ part="scrim"
949
+ aria-hidden="true"
950
+ onClick={this.handleScrimClick}
951
+ ></div>
952
+
953
+ {this.presentation === 'drawer' ? (
954
+ <pami-side-sheet variant="modal" side="start" open={this.open} aria-label={this.label}
955
+ onPamiOpen={event => {
956
+ if (event.target !== event.currentTarget) return;
957
+ event.stopPropagation(); this.pamiOpen.emit();
958
+ }}
959
+ onPamiClose={event => {
960
+ if (event.target !== event.currentTarget) return;
961
+ event.stopPropagation(); this.open = false; this.pamiClose.emit();
962
+ }}>
963
+ <pami-icon-button slot="close" icon="close" aria-label={this.closeLabel} onClick={() => this.close()} />
964
+ {content}
965
+ </pami-side-sheet>
966
+ ) : content}
967
+ </Host>
968
+ );
969
+ }
970
+ }