frappe-ui 1.0.0-beta.2 → 1.0.0-beta.21

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 (692) hide show
  1. package/experimental/FloatingWindow/FloatingWindow.cy.ts +328 -0
  2. package/experimental/FloatingWindow/FloatingWindow.vue +303 -0
  3. package/experimental/FloatingWindow/index.ts +8 -0
  4. package/experimental/FloatingWindow/types.ts +31 -0
  5. package/experimental/FloatingWindow/useFloatingWindow.ts +236 -0
  6. package/experimental/MultiEmailInput/MultiEmailInput.cy.ts +155 -0
  7. package/experimental/MultiEmailInput/MultiEmailInput.vue +472 -0
  8. package/experimental/MultiEmailInput/index.ts +17 -0
  9. package/experimental/MultiEmailInput/stories/AsyncSuggestions.vue +54 -0
  10. package/experimental/MultiEmailInput/stories/Basic.vue +18 -0
  11. package/experimental/MultiEmailInput/stories/CustomChip.vue +39 -0
  12. package/experimental/MultiEmailInput/stories/Labeling.vue +28 -0
  13. package/experimental/MultiEmailInput/types.ts +138 -0
  14. package/experimental/MultiEmailInput/utils.ts +60 -0
  15. package/experimental.ts +12 -0
  16. package/frappe/Billing/SignupBanner.vue +1 -1
  17. package/frappe/Billing/TrialBanner.vue +1 -1
  18. package/frappe/DataImport/DataImport.vue +1 -1
  19. package/frappe/DataImport/DataImportList.vue +1 -1
  20. package/frappe/DataImport/ImportSteps.vue +6 -6
  21. package/frappe/DataImport/MappingStep.vue +1 -1
  22. package/frappe/DataImport/PreviewStep.vue +9 -9
  23. package/frappe/DataImport/TemplateModal.vue +1 -1
  24. package/frappe/DataImport/UploadStep.vue +5 -5
  25. package/frappe/Filter/Filter.vue +1 -1
  26. package/frappe/Help/HelpModal.vue +1 -1
  27. package/frappe/Link/stories/Suffix.vue +2 -2
  28. package/frappe/Onboarding/GettingStartedBanner.vue +1 -1
  29. package/frappe/drive/components/AppSwitcher.vue +1 -1
  30. package/frappe/drive/components/InfoDialog.vue +3 -3
  31. package/frappe/drive/components/MoveDialog.vue +2 -2
  32. package/frappe/drive/components/Select/Select.vue +2 -2
  33. package/frappe/drive/components/ShareDialog.vue +1 -1
  34. package/frappe/telemetry/index.ts +88 -14
  35. package/frappe/telemetry/pulse.ts +78 -164
  36. package/frappe/telemetry/telemetry.test.ts +13 -79
  37. package/icons/IconPicker.vue +1 -1
  38. package/package.json +104 -34
  39. package/src/components/Alert/Alert.md +4 -0
  40. package/src/components/Alert/Alert.vue +4 -4
  41. package/src/components/Autocomplete/Autocomplete.vue +6 -6
  42. package/src/components/Avatar/Avatar.md +4 -0
  43. package/src/components/Avatar/Avatar.vue +23 -4
  44. package/src/components/Badge/Badge.api.md +1 -1
  45. package/src/components/Badge/Badge.cy.ts +34 -16
  46. package/src/components/Badge/Badge.md +20 -4
  47. package/src/components/Badge/Badge.vue +60 -45
  48. package/src/components/Badge/stories/CallMeta.vue +35 -0
  49. package/src/components/Badge/stories/EventStatus.vue +16 -0
  50. package/src/components/Badge/stories/ListStatus.vue +91 -0
  51. package/src/components/Badge/stories/Reactions.vue +33 -0
  52. package/src/components/Badge/stories/RowTags.vue +39 -0
  53. package/src/components/Badge/types.ts +1 -2
  54. package/src/components/BottomSheet/BottomSheet.api.md +57 -0
  55. package/src/components/BottomSheet/BottomSheet.vue +232 -0
  56. package/src/components/BottomSheet/index.ts +6 -0
  57. package/src/components/BottomSheet/types.ts +23 -0
  58. package/src/components/Breadcrumbs/Breadcrumbs.md +4 -0
  59. package/src/components/Breadcrumbs/Breadcrumbs.vue +3 -3
  60. package/src/components/Button/Button.api.md +37 -32
  61. package/src/components/Button/Button.cy.ts +18 -2
  62. package/src/components/Button/Button.md +20 -8
  63. package/src/components/Button/Button.vue +304 -284
  64. package/src/components/Button/stories/InlineActions.vue +10 -0
  65. package/src/components/Button/stories/LiveClassCard.vue +34 -0
  66. package/src/components/Button/stories/SectionAction.vue +17 -0
  67. package/src/components/Button/stories/SectionControls.vue +28 -0
  68. package/src/components/Button/stories/SelectionToolbar.vue +20 -0
  69. package/src/components/Button/stories/StackedActions.vue +10 -0
  70. package/src/components/Button/types.ts +38 -32
  71. package/src/components/Calendar/Calendar.api.md +16 -16
  72. package/src/components/Calendar/Calendar.vue +100 -73
  73. package/src/components/Calendar/CalendarDaily.vue +21 -20
  74. package/src/components/Calendar/CalendarMonthEvent.vue +30 -9
  75. package/src/components/Calendar/CalendarMonthly.vue +60 -39
  76. package/src/components/Calendar/CalendarTimeMarker.vue +9 -8
  77. package/src/components/Calendar/CalendarWeekDayEvent.vue +98 -42
  78. package/src/components/Calendar/CalendarWeekly.vue +77 -41
  79. package/src/components/Calendar/EventModalContent.vue +32 -16
  80. package/src/components/Calendar/NewEventModal.vue +19 -16
  81. package/src/components/Calendar/ShowMoreCalendarEvent.vue +11 -17
  82. package/src/components/Calendar/{calendarUtils.js → calendarUtils.ts} +76 -52
  83. package/src/components/Calendar/composables/{useCalendarData.js → useCalendarData.ts} +23 -11
  84. package/src/components/Calendar/composables/{useEventModal.js → useEventModal.ts} +16 -12
  85. package/src/components/Calendar/index.ts +12 -2
  86. package/src/components/Calendar/stories/CustomHeader.vue +1 -1
  87. package/src/components/Calendar/types.ts +106 -0
  88. package/src/components/Calendar/{useEventBase.js → useEventBase.ts} +40 -26
  89. package/src/components/Card.vue +2 -2
  90. package/src/components/Charts/ECharts.vue +1 -1
  91. package/src/components/Charts/NumberChart.vue +7 -7
  92. package/src/components/Charts/eChartOptions.ts +28 -13
  93. package/src/components/Checkbox/Checkbox.api.md +6 -0
  94. package/src/components/Checkbox/Checkbox.cy.ts +10 -2
  95. package/src/components/Checkbox/Checkbox.md +28 -0
  96. package/src/components/Checkbox/Checkbox.vue +9 -22
  97. package/src/components/Checkbox/stories/Group.vue +27 -0
  98. package/src/components/Checkbox/stories/HorizontalGroup.vue +24 -0
  99. package/src/components/Checkbox/stories/SettingRow.vue +23 -0
  100. package/src/components/Checkbox/stories/WithDescription.vue +27 -0
  101. package/src/components/Checkbox/types.ts +7 -0
  102. package/src/components/CodeEditor/CodeEditor.api.md +139 -0
  103. package/src/components/CodeEditor/CodeEditor.cy.ts +160 -0
  104. package/src/components/CodeEditor/CodeEditor.md +104 -0
  105. package/src/components/CodeEditor/CodeEditor.vue +556 -0
  106. package/src/components/CodeEditor/CodePreview.test.ts +49 -0
  107. package/src/components/CodeEditor/CodePreview.vue +45 -0
  108. package/src/components/CodeEditor/index.ts +17 -0
  109. package/src/components/CodeEditor/languages.ts +63 -0
  110. package/src/components/CodeEditor/stories/Default.vue +16 -0
  111. package/src/components/CodeEditor/stories/Labeling.vue +25 -0
  112. package/src/components/CodeEditor/stories/MaxHeight.vue +24 -0
  113. package/src/components/CodeEditor/stories/Preview.vue +36 -0
  114. package/src/components/CodeEditor/stories/Sizes.vue +15 -0
  115. package/src/components/CodeEditor/stories/Variants.vue +13 -0
  116. package/src/components/CodeEditor/theme.ts +272 -0
  117. package/src/components/CodeEditor/types.ts +69 -0
  118. package/src/components/Combobox/Combobox.api.md +19 -20
  119. package/src/components/Combobox/Combobox.cy.ts +54 -14
  120. package/src/components/Combobox/Combobox.md +4 -0
  121. package/src/components/Combobox/Combobox.vue +233 -247
  122. package/src/components/Combobox/ComboboxResults.vue +1 -1
  123. package/src/components/Combobox/stories/Clearable.vue +2 -2
  124. package/src/components/Combobox/stories/CreateNew.vue +1 -1
  125. package/src/components/Combobox/stories/Footer.vue +10 -2
  126. package/src/components/Combobox/stories/InDialog.vue +1 -1
  127. package/src/components/Combobox/types.ts +8 -29
  128. package/src/components/CommandPalette/CommandPaletteItem.vue +1 -1
  129. package/src/components/ContextMenu/ContextMenu.api.md +52 -0
  130. package/src/components/ContextMenu/ContextMenu.cy.ts +191 -0
  131. package/src/components/ContextMenu/ContextMenu.md +25 -0
  132. package/src/components/ContextMenu/ContextMenu.vue +106 -0
  133. package/src/components/ContextMenu/index.ts +2 -0
  134. package/src/components/ContextMenu/stories/FileList.vue +105 -0
  135. package/src/components/ContextMenu/stories/Groups.vue +95 -0
  136. package/src/components/ContextMenu/stories/Simple.vue +72 -0
  137. package/src/components/ContextMenu/types.ts +39 -0
  138. package/src/components/DatePicker/CalendarPanel.vue +128 -86
  139. package/src/components/DatePicker/DatePicker.vue +3 -9
  140. package/src/components/DatePicker/DateRangePicker.vue +4 -8
  141. package/src/components/DatePicker/DateTimePicker.cy.ts +4 -2
  142. package/src/components/DatePicker/DateTimePicker.vue +3 -9
  143. package/src/components/DatePicker/composables.ts +15 -37
  144. package/src/components/DatePicker/stories/Range.vue +1 -1
  145. package/src/components/DatePicker/types.ts +1 -1
  146. package/src/components/DesktopShell/DesktopShell.api.md +40 -0
  147. package/src/components/DesktopShell/DesktopShell.cy.ts +39 -0
  148. package/src/components/DesktopShell/DesktopShell.md +31 -0
  149. package/src/components/DesktopShell/DesktopShell.vue +81 -0
  150. package/src/components/DesktopShell/index.ts +3 -0
  151. package/src/components/DesktopShell/stories/Default.vue +97 -0
  152. package/src/components/DesktopShell/types.ts +2 -0
  153. package/src/components/Dialog/Dialog.api.md +7 -8
  154. package/src/components/Dialog/Dialog.md +4 -0
  155. package/src/components/Dialog/Dialog.vue +8 -7
  156. package/src/components/Dialog/stories/CommandPalette.vue +1 -1
  157. package/src/components/Dialog/stories/Wizard.vue +1 -1
  158. package/src/components/Dialogs.vue +11 -9
  159. package/src/components/Divider/Divider.api.md +1 -1
  160. package/src/components/Divider/Divider.md +4 -0
  161. package/src/components/Dropdown/Dropdown.api.md +10 -35
  162. package/src/components/Dropdown/Dropdown.md +10 -6
  163. package/src/components/Dropdown/Dropdown.vue +33 -47
  164. package/src/components/Dropdown/stories/{05_KebabMenu.vue → KebabMenu.vue} +3 -1
  165. package/src/components/Dropdown/stories/{06_UserMenu.vue → UserMenu.vue} +1 -1
  166. package/src/components/Dropdown/types.ts +25 -189
  167. package/src/components/Duration/Duration.api.md +92 -0
  168. package/src/components/Duration/Duration.cy.ts +183 -0
  169. package/src/components/Duration/Duration.md +98 -0
  170. package/src/components/Duration/Duration.vue +114 -0
  171. package/src/components/Duration/duration.ts +185 -0
  172. package/src/components/Duration/index.ts +8 -0
  173. package/src/components/Duration/stories/Default.vue +10 -0
  174. package/src/components/Duration/stories/Formats.vue +16 -0
  175. package/src/components/Duration/stories/RealWorld.vue +50 -0
  176. package/src/components/Duration/stories/Sizes.vue +15 -0
  177. package/src/components/Duration/stories/States.vue +21 -0
  178. package/src/components/Duration/types.ts +52 -0
  179. package/src/components/ErrorMessage/ErrorMessage.cy.ts +1 -1
  180. package/src/components/ErrorMessage/ErrorMessage.md +4 -0
  181. package/src/components/ErrorMessage/ErrorMessage.vue +1 -1
  182. package/src/components/FileUploader/FileUploader.api.md +36 -11
  183. package/src/components/FileUploader/FileUploader.cy.ts +66 -0
  184. package/src/components/FileUploader/FileUploader.md +4 -1
  185. package/src/components/FileUploader/FileUploader.vue +147 -106
  186. package/src/components/FileUploader/index.ts +6 -0
  187. package/src/components/FileUploader/types.ts +43 -0
  188. package/src/components/FormControl/FormControl.api.md +3 -4
  189. package/src/components/FormControl/FormControl.md +4 -0
  190. package/src/components/FormControl/stories/RealForm.vue +3 -3
  191. package/src/components/FormLabel.vue +5 -8
  192. package/src/components/HoverCard/HoverCard.api.md +100 -0
  193. package/src/components/HoverCard/HoverCard.cy.ts +103 -0
  194. package/src/components/HoverCard/HoverCard.md +52 -0
  195. package/src/components/HoverCard/HoverCard.vue +91 -0
  196. package/src/components/HoverCard/index.ts +2 -0
  197. package/src/components/HoverCard/stories/Arrow.vue +28 -0
  198. package/src/components/HoverCard/stories/Delays.vue +16 -0
  199. package/src/components/HoverCard/stories/Example.vue +28 -0
  200. package/src/components/HoverCard/types.ts +47 -0
  201. package/src/components/Icon/Icon.cy.ts +78 -0
  202. package/src/components/Icon/Icon.vue +50 -0
  203. package/src/components/Icon/index.ts +1 -0
  204. package/src/components/InputLabeling/InputDescription.vue +1 -1
  205. package/src/components/InputLabeling/InputError.vue +1 -1
  206. package/src/components/InputLabeling/InputLabel.vue +21 -7
  207. package/src/components/InputLabeling/RequiredIndicator.vue +1 -1
  208. package/src/components/ItemListRow/ItemListRow.vue +1 -1
  209. package/src/components/ItemListRow/stories/RowStates.vue +1 -1
  210. package/src/components/KeyboardShortcut.vue +4 -8
  211. package/src/components/KeyboardShortcutsModal/KeyboardShortcutsModal.api.md +22 -14
  212. package/src/components/KeyboardShortcutsModal/KeyboardShortcutsModal.vue +2 -2
  213. package/src/components/ListFilter/ListFilter.api.md +5 -6
  214. package/src/components/ListFilter/ListFilter.vue +161 -57
  215. package/src/components/ListFilter/NestedPopover.vue +17 -10
  216. package/src/components/ListFilter/SearchComplete.vue +31 -38
  217. package/src/components/ListItem.vue +1 -1
  218. package/src/components/ListView/ListEmptyState.vue +1 -1
  219. package/src/components/ListView/ListGroupHeader.vue +2 -2
  220. package/src/components/ListView/ListRow.vue +1 -1
  221. package/src/components/ListView/ListSelectBanner.vue +1 -1
  222. package/src/components/ListView/ListView.api.md +322 -6
  223. package/src/components/ListView/index.ts +25 -0
  224. package/src/components/ListView/stories/CustomList.vue +1 -1
  225. package/src/components/ListView/stories/GroupedRows.vue +1 -1
  226. package/src/components/LoadingIndicator.vue +13 -22
  227. package/src/components/LoadingText.vue +3 -13
  228. package/src/components/{Dropdown/DropdownMenuList.vue → Menu/Menu.vue} +110 -75
  229. package/src/components/{Dropdown/DropdownMenuItemContent.vue → Menu/MenuItemContent.vue} +23 -33
  230. package/src/components/{Dropdown/DropdownRenderContent.vue → Menu/MenuRenderContent.vue} +1 -1
  231. package/src/components/Menu/types.ts +225 -0
  232. package/src/components/{Dropdown → Menu}/utils.ts +36 -40
  233. package/src/components/MobileNav/MobileNav.api.md +70 -0
  234. package/src/components/MobileNav/MobileNav.cy.ts +89 -0
  235. package/src/components/MobileNav/MobileNav.md +34 -0
  236. package/src/components/MobileNav/MobileNav.vue +15 -0
  237. package/src/components/MobileNav/MobileNavItem.vue +125 -0
  238. package/src/components/MobileNav/index.ts +4 -0
  239. package/src/components/MobileNav/stories/Default.vue +40 -0
  240. package/src/components/MobileNav/types.ts +33 -0
  241. package/src/components/MobileShell/MobileShell.api.md +23 -0
  242. package/src/components/MobileShell/MobileShell.cy.ts +25 -0
  243. package/src/components/MobileShell/MobileShell.md +24 -0
  244. package/src/components/MobileShell/MobileShell.vue +41 -0
  245. package/src/components/MobileShell/index.ts +3 -0
  246. package/src/components/MobileShell/stories/Default.vue +75 -0
  247. package/src/components/MobileShell/types.ts +7 -0
  248. package/src/components/MonthPicker/MonthPicker.cy.ts +16 -0
  249. package/src/components/MonthPicker/MonthPicker.vue +19 -8
  250. package/src/components/MultiSelect/MultiSelect.api.md +3 -4
  251. package/src/components/MultiSelect/MultiSelect.md +42 -10
  252. package/src/components/MultiSelect/MultiSelect.vue +199 -227
  253. package/src/components/MultiSelect/MultiSelectResults.vue +1 -1
  254. package/src/components/MultiSelect/stories/Members.vue +1 -1
  255. package/src/components/MultiSelect/stories/TagsTrigger.vue +3 -3
  256. package/src/components/MultiSelect/types.ts +3 -3
  257. package/src/components/PageHeader/PageHeader.api.md +112 -0
  258. package/src/components/PageHeader/PageHeader.cy.ts +68 -0
  259. package/src/components/PageHeader/PageHeader.md +25 -0
  260. package/src/components/PageHeader/PageHeader.vue +13 -0
  261. package/src/components/PageHeader/PageHeaderBackButton.vue +29 -0
  262. package/src/components/PageHeader/PageHeaderBase.vue +51 -0
  263. package/src/components/PageHeader/PageHeaderMobile.vue +68 -0
  264. package/src/components/PageHeader/PageHeaderMobileTitle.vue +16 -0
  265. package/src/components/PageHeader/PageHeaderTarget.vue +13 -0
  266. package/src/components/PageHeader/PageHeaderTitle.vue +12 -0
  267. package/src/components/PageHeader/index.ts +7 -0
  268. package/src/components/PageHeader/stories/Default.vue +19 -0
  269. package/src/components/PageHeader/stories/Mobile.vue +24 -0
  270. package/src/components/PageHeader/target.ts +19 -0
  271. package/src/components/PageHeader/types.ts +19 -0
  272. package/src/components/Password/Password.md +4 -0
  273. package/src/components/Password/Password.vue +2 -2
  274. package/src/components/Popover/Popover.api.md +126 -42
  275. package/src/components/Popover/Popover.cy.ts +425 -41
  276. package/src/components/Popover/Popover.md +99 -4
  277. package/src/components/Popover/Popover.vue +288 -215
  278. package/src/components/Popover/index.ts +8 -1
  279. package/src/components/Popover/stories/Arrow.vue +16 -0
  280. package/src/components/Popover/stories/Bare.vue +20 -0
  281. package/src/components/Popover/stories/Click.vue +7 -4
  282. package/src/components/Popover/stories/Controlled.vue +22 -0
  283. package/src/components/Popover/stories/Dismissible.vue +19 -0
  284. package/src/components/Popover/stories/MatchTriggerWidth.vue +16 -0
  285. package/src/components/Popover/stories/SideAlign.vue +17 -0
  286. package/src/components/Popover/types.ts +101 -23
  287. package/src/components/Progress/Progress.cy.ts +2 -2
  288. package/src/components/Progress/Progress.md +4 -0
  289. package/src/components/Progress/Progress.vue +4 -4
  290. package/src/components/Rail/Rail.api.md +91 -0
  291. package/src/components/Rail/Rail.cy.ts +84 -0
  292. package/src/components/Rail/Rail.md +30 -0
  293. package/src/components/Rail/Rail.vue +16 -0
  294. package/src/components/Rail/RailItem.vue +134 -0
  295. package/src/components/Rail/RailItemBadge.vue +64 -0
  296. package/src/components/Rail/index.ts +2 -0
  297. package/src/components/Rail/stories/Default.vue +44 -0
  298. package/src/components/Rail/types.ts +37 -0
  299. package/src/components/Rating/Rating.md +4 -0
  300. package/src/components/Rating/Rating.vue +5 -8
  301. package/src/components/Rating/stories/CustomSlot.vue +2 -2
  302. package/src/components/ScrollArea/ScrollArea.api.md +59 -0
  303. package/src/components/ScrollArea/ScrollArea.vue +46 -0
  304. package/src/components/ScrollArea/ScrollBar.vue +101 -0
  305. package/src/components/ScrollArea/index.ts +2 -0
  306. package/src/components/Select/Select.cy.ts +16 -15
  307. package/src/components/Select/Select.md +4 -0
  308. package/src/components/Select/Select.vue +217 -203
  309. package/src/components/Select/stories/Example.vue +4 -3
  310. package/src/components/Select/stories/States.vue +1 -1
  311. package/src/components/Select/stories/TriggerSlots.vue +2 -2
  312. package/src/components/Select/utils.ts +4 -3
  313. package/src/components/SettingsDialog/SettingsBody.vue +23 -0
  314. package/src/components/SettingsDialog/SettingsContent.vue +7 -0
  315. package/src/components/SettingsDialog/SettingsDialog.api.md +273 -0
  316. package/src/components/SettingsDialog/SettingsDialog.cy.ts +126 -0
  317. package/src/components/SettingsDialog/SettingsDialog.md +43 -0
  318. package/src/components/SettingsDialog/SettingsDialog.vue +76 -0
  319. package/src/components/SettingsDialog/SettingsHeader.vue +36 -0
  320. package/src/components/SettingsDialog/SettingsNavGroup.vue +20 -0
  321. package/src/components/SettingsDialog/SettingsNavItem.vue +33 -0
  322. package/src/components/SettingsDialog/SettingsPanel.cy.ts +77 -0
  323. package/src/components/SettingsDialog/SettingsPanel.vue +26 -0
  324. package/src/components/SettingsDialog/SettingsRow.vue +52 -0
  325. package/src/components/SettingsDialog/SettingsSidebar.vue +16 -0
  326. package/src/components/SettingsDialog/index.ts +10 -0
  327. package/src/components/SettingsDialog/stories/Default.vue +99 -0
  328. package/src/components/SettingsDialog/stories/PanelBasic.vue +52 -0
  329. package/src/components/SettingsDialog/stories/panels/NotificationsPanel.vue +57 -0
  330. package/src/components/SettingsDialog/stories/panels/PreferencesPanel.vue +57 -0
  331. package/src/components/SettingsDialog/stories/panels/ProfilePanel.vue +38 -0
  332. package/src/components/SettingsDialog/stories/panels/UsersPanel.vue +83 -0
  333. package/src/components/SettingsDialog/types.ts +21 -0
  334. package/src/components/Sidebar/Sidebar.api.md +124 -65
  335. package/src/components/Sidebar/Sidebar.cy.ts +127 -76
  336. package/src/components/Sidebar/Sidebar.md +47 -3
  337. package/src/components/Sidebar/Sidebar.vue +64 -56
  338. package/src/components/Sidebar/SidebarCollapseToggle.vue +23 -0
  339. package/src/components/Sidebar/SidebarHeader.vue +76 -52
  340. package/src/components/Sidebar/SidebarItem.vue +159 -95
  341. package/src/components/Sidebar/SidebarItemIcon.vue +25 -0
  342. package/src/components/Sidebar/SidebarLabel.vue +34 -0
  343. package/src/components/Sidebar/SidebarSection.vue +29 -14
  344. package/src/components/Sidebar/index.ts +13 -2
  345. package/src/components/Sidebar/stories/Collapsed.vue +40 -0
  346. package/src/components/Sidebar/stories/Default.vue +153 -0
  347. package/src/components/Sidebar/stories/Legacy.vue +36 -0
  348. package/src/components/Sidebar/types.ts +105 -20
  349. package/src/components/Skeleton/Skeleton.cy.ts +21 -0
  350. package/src/components/Skeleton/Skeleton.md +21 -0
  351. package/src/components/Skeleton/Skeleton.vue +6 -0
  352. package/src/components/Skeleton/index.ts +1 -0
  353. package/src/components/Skeleton/stories/Card.vue +12 -0
  354. package/src/components/Skeleton/stories/List.vue +15 -0
  355. package/src/components/Skeleton/stories/Text.vue +11 -0
  356. package/src/components/Slider/Slider.api.md +1 -1
  357. package/src/components/Slider/Slider.cy.ts +29 -0
  358. package/src/components/Slider/Slider.md +10 -0
  359. package/src/components/Slider/Slider.vue +37 -9
  360. package/src/components/Slider/stories/NegativeValues.vue +12 -0
  361. package/src/components/Slider/types.ts +1 -1
  362. package/src/components/Spinner/Spinner.api.md +32 -0
  363. package/src/components/Spinner/Spinner.cy.ts +87 -0
  364. package/src/components/Spinner/Spinner.md +21 -0
  365. package/src/components/Spinner/Spinner.vue +168 -0
  366. package/src/components/Spinner/index.ts +2 -0
  367. package/src/components/Spinner/stories/InContext.vue +49 -0
  368. package/src/components/Spinner/stories/Sizes.vue +12 -0
  369. package/src/components/Spinner/stories/Themes.vue +10 -0
  370. package/src/components/Spinner/stories/Track.vue +12 -0
  371. package/src/components/Spinner/types.ts +14 -0
  372. package/src/components/Switch/Switch.md +4 -0
  373. package/src/components/Switch/Switch.vue +6 -23
  374. package/src/components/TabButtons/Pill.vue +161 -0
  375. package/src/components/TabButtons/TabButtons.api.md +52 -2
  376. package/src/components/TabButtons/TabButtons.cy.ts +18 -5
  377. package/src/components/TabButtons/TabButtons.md +49 -0
  378. package/src/components/TabButtons/TabButtons.vue +207 -109
  379. package/src/components/TabButtons/index.ts +11 -1
  380. package/src/components/TabButtons/pillTypes.ts +43 -0
  381. package/src/components/TabButtons/stories/PrefixSuffix.vue +65 -0
  382. package/src/components/TabButtons/stories/Sizes.vue +26 -0
  383. package/src/components/TabButtons/stories/Variants.vue +40 -0
  384. package/src/components/TabButtons/stories/Vertical.vue +64 -0
  385. package/src/components/TabButtons/types.ts +49 -0
  386. package/src/components/Tabs/Tabs.md +4 -0
  387. package/src/components/Tabs/Tabs.vue +1 -1
  388. package/src/components/TextEditor/TextEditor.cy.ts +1 -1
  389. package/src/components/TextEditor/TextEditor.md +3 -0
  390. package/src/components/TextEditor/TextEditor.vue +7 -4
  391. package/src/components/TextEditor/components/CodeBlockComponent.vue +4 -194
  392. package/src/components/TextEditor/components/FontColor.vue +1 -1
  393. package/src/components/TextEditor/components/LinkPopup.vue +1 -1
  394. package/src/components/TextEditor/components/MediaNodeView.vue +17 -17
  395. package/src/components/TextEditor/components/MentionList.vue +1 -1
  396. package/src/components/TextEditor/components/TextEditorBubbleMenu.vue +14 -5
  397. package/src/components/TextEditor/components/TextEditorFixedMenu.vue +3 -3
  398. package/src/components/TextEditor/components/{Menu.vue → TextEditorMenu.vue} +3 -3
  399. package/src/components/TextEditor/extensions/iframe/InsertIframe.vue +2 -2
  400. package/src/components/TextEditor/extensions/iframe/iframe-extension.ts +62 -19
  401. package/src/components/TextEditor/extensions/image-group/ImageGroupNodeView.vue +1 -1
  402. package/src/components/TextEditor/extensions/image-group/ImageGroupUploadDialog.vue +4 -4
  403. package/src/components/TextEditor/extensions/suggestion/SuggestionList.vue +1 -1
  404. package/src/components/TextEditor/extensions/toc-node/TocNodeView.vue +1 -1
  405. package/src/components/TextEditor/hljs-github.css +197 -0
  406. package/src/components/TextEditor/index.ts +13 -0
  407. package/src/components/TextInput/TextInput.cy.ts +8 -3
  408. package/src/components/TextInput/TextInput.md +4 -0
  409. package/src/components/TextInput/TextInput.vue +11 -15
  410. package/src/components/TextInput/stories/Slots.vue +1 -1
  411. package/src/components/Textarea/Textarea.cy.ts +1 -1
  412. package/src/components/Textarea/Textarea.md +4 -0
  413. package/src/components/Textarea/Textarea.vue +11 -15
  414. package/src/components/ThemeSwitcher/ThemePreview.vue +74 -0
  415. package/src/components/ThemeSwitcher/ThemeSwitcher.api.md +82 -0
  416. package/src/components/ThemeSwitcher/ThemeSwitcher.cy.ts +101 -0
  417. package/src/components/ThemeSwitcher/ThemeSwitcher.md +70 -0
  418. package/src/components/ThemeSwitcher/ThemeSwitcher.vue +145 -0
  419. package/src/components/ThemeSwitcher/index.ts +2 -0
  420. package/src/components/ThemeSwitcher/previews/PreviewWindow.vue +74 -0
  421. package/src/components/ThemeSwitcher/stories/Branded.vue +12 -0
  422. package/src/components/ThemeSwitcher/stories/Default.vue +7 -0
  423. package/src/components/ThemeSwitcher/stories/Menu.vue +53 -0
  424. package/src/components/ThemeSwitcher/stories/Toggle.vue +25 -0
  425. package/src/components/ThemeSwitcher/types.ts +35 -0
  426. package/src/components/TimePicker/TimePicker.api.md +67 -15
  427. package/src/components/TimePicker/TimePicker.cy.ts +130 -14
  428. package/src/components/TimePicker/TimePicker.md +6 -0
  429. package/src/components/TimePicker/TimePicker.vue +74 -19
  430. package/src/components/TimePicker/stories/Labeling.vue +21 -0
  431. package/src/components/TimePicker/stories/Range.vue +1 -1
  432. package/src/components/TimePicker/stories/SizesAndVariants.vue +23 -0
  433. package/src/components/TimePicker/stories/TwentyFour.vue +1 -1
  434. package/src/components/TimePicker/types.ts +15 -3
  435. package/src/components/TimePicker/utils.ts +82 -21
  436. package/src/components/Toast/Toast.md +1 -1
  437. package/src/components/Toast/Toast.sanitize.test.ts +50 -0
  438. package/src/components/Toast/Toast.test.ts +5 -0
  439. package/src/components/Toast/Toast.vue +7 -7
  440. package/src/components/Toast/ToastProvider.vue +18 -9
  441. package/src/components/Toast/stories/CustomIcon.vue +1 -1
  442. package/src/components/Toast/toast.ts +32 -8
  443. package/src/components/Tooltip/Tooltip.api.md +43 -5
  444. package/src/components/Tooltip/Tooltip.cy.ts +48 -0
  445. package/src/components/Tooltip/Tooltip.md +10 -0
  446. package/src/components/Tooltip/Tooltip.vue +20 -5
  447. package/src/components/Tooltip/TooltipBubble.vue +2 -2
  448. package/src/components/Tooltip/TooltipProvider.vue +53 -0
  449. package/src/components/Tooltip/index.ts +1 -0
  450. package/src/components/Tooltip/stories/Group.vue +22 -0
  451. package/src/components/Tooltip/stories/Slots.vue +2 -2
  452. package/src/components/Tooltip/types.ts +1 -1
  453. package/src/components/Tree/Tree.api.md +76 -18
  454. package/src/components/Tree/Tree.md +144 -2
  455. package/src/components/Tree/Tree.vue +276 -97
  456. package/src/components/Tree/TreeItem.vue +263 -0
  457. package/src/components/Tree/index.ts +9 -1
  458. package/src/components/Tree/stories/DragDrop.vue +94 -0
  459. package/src/components/Tree/stories/Example.vue +11 -34
  460. package/src/components/Tree/stories/ExpandAll.vue +48 -0
  461. package/src/components/Tree/stories/Guides.vue +49 -0
  462. package/src/components/Tree/stories/ListView.vue +74 -0
  463. package/src/components/Tree/tree.cy.ts +218 -90
  464. package/src/components/Tree/types.ts +114 -24
  465. package/src/components/Tree/useTreeDragDrop.ts +203 -0
  466. package/src/components/Tree/useTreeKeyboard.ts +109 -0
  467. package/src/components/VueGridLayout/Layout.vue +1 -1
  468. package/src/components/shared/picker/PickerShell.vue +20 -15
  469. package/src/components/shared/popover/PopoverPanel.vue +67 -0
  470. package/src/components/shared/popover/popoverPanel.css +102 -0
  471. package/src/components/shared/selection/utils.ts +6 -6
  472. package/src/composables/useAutofocusOnOpen.ts +2 -0
  473. package/src/composables/useScreenSize.ts +46 -0
  474. package/src/composables/useScrollContainer.ts +108 -0
  475. package/src/composables/useShortcut.ts +3 -0
  476. package/src/data-fetching/docStore.test.ts +74 -0
  477. package/src/data-fetching/docStore.ts +18 -7
  478. package/src/data-fetching/useCall/types.ts +1 -0
  479. package/src/data-fetching/useCall/useCall.test.ts +43 -0
  480. package/src/data-fetching/useCall/useCall.ts +17 -4
  481. package/src/data-fetching/useDoc/useDoc.test.ts +61 -2
  482. package/src/data-fetching/useDoc/useDoc.ts +35 -15
  483. package/src/data-fetching/useDoctype/useDoctype.ts +6 -5
  484. package/src/data-fetching/useFrappeFetch.ts +17 -4
  485. package/src/data-fetching/useList/types.ts +1 -0
  486. package/src/data-fetching/useList/useList.test.ts +40 -0
  487. package/src/data-fetching/useList/useList.ts +20 -13
  488. package/src/data-fetching/useNewDoc/useNewDoc.ts +9 -5
  489. package/src/directives/focus.ts +3 -3
  490. package/src/index.ts +105 -74
  491. package/src/mocks/handlers.ts +8 -0
  492. package/src/molecules/editor/Editor.cy.ts +6 -1
  493. package/src/molecules/editor/EditorBubbleMenu.vue +1 -1
  494. package/src/molecules/editor/EditorContent.vue +50 -9
  495. package/src/molecules/editor/EditorFixedMenu.vue +2 -1
  496. package/src/molecules/editor/EditorFloatingMenu.vue +1 -1
  497. package/src/molecules/editor/EditorTableMenu.vue +303 -0
  498. package/src/molecules/editor/MenuItems.vue +81 -69
  499. package/src/molecules/editor/commands.ts +10 -2
  500. package/src/molecules/editor/components/AttachmentNodeView.vue +115 -0
  501. package/src/molecules/editor/components/EditorDropZone.vue +105 -0
  502. package/src/molecules/editor/components/EditorPopover.vue +89 -0
  503. package/src/molecules/editor/components/MediaNodeView.vue +156 -49
  504. package/src/molecules/editor/components/MediaResizeHandles.vue +38 -0
  505. package/src/molecules/editor/components/MediaToolbar.vue +108 -54
  506. package/src/molecules/editor/components/TableContextMenu.vue +144 -0
  507. package/src/molecules/editor/components/UploadProgressIndicator.vue +33 -0
  508. package/src/molecules/editor/components/VideoControls.vue +208 -0
  509. package/src/molecules/editor/components/font-color/ColorSwatchGrid.vue +3 -5
  510. package/src/molecules/editor/components/font-color/fontColorController.ts +28 -23
  511. package/src/molecules/editor/components/font-color/swatches.ts +1 -1
  512. package/src/molecules/editor/components/media-node-view-controller.ts +4 -4
  513. package/src/molecules/editor/components/media-node-view-utils.test.ts +0 -13
  514. package/src/molecules/editor/components/media-node-view-utils.ts +0 -10
  515. package/src/molecules/editor/components/table-color/tableCellColorController.ts +80 -0
  516. package/src/molecules/editor/components/table-size-picker/TableSizePicker.vue +92 -0
  517. package/src/molecules/editor/components/table-size-picker/tableSizePickerController.ts +40 -0
  518. package/src/molecules/editor/composables/useEditorFileDrop.ts +117 -0
  519. package/src/molecules/editor/composables/useFloatingPopup.ts +46 -2
  520. package/src/molecules/editor/composables/useNodeViewResize.test.ts +60 -11
  521. package/src/molecules/editor/composables/useNodeViewResize.ts +80 -21
  522. package/src/molecules/editor/composables/useTableCellColorState.ts +78 -0
  523. package/src/molecules/editor/composables/useWindowFileDragging.ts +68 -0
  524. package/src/molecules/editor/extensions/attachment/attachment-engine.ts +250 -0
  525. package/src/molecules/editor/extensions/attachment/attachment-extension.ts +248 -0
  526. package/src/molecules/editor/extensions/attachment/attachment.flow.test.ts +80 -0
  527. package/src/molecules/editor/extensions/attachment/attachment.roundtrip.test.ts +50 -0
  528. package/src/molecules/editor/extensions/attachment/index.ts +5 -0
  529. package/src/molecules/editor/extensions/code-block/CodeBlockComponent.css +16 -26
  530. package/src/molecules/editor/extensions/code-block/CodeBlockComponent.vue +107 -22
  531. package/src/molecules/editor/extensions/content-paste/content-paste-extension.ts +5 -3
  532. package/src/molecules/editor/extensions/iframe/IframeInsertDialog.vue +34 -7
  533. package/src/molecules/editor/extensions/iframe/IframeNodeView.vue +54 -48
  534. package/src/molecules/editor/extensions/iframe/iframe-allowlist.ts +33 -4
  535. package/src/molecules/editor/extensions/iframe/iframe-commands.ts +49 -5
  536. package/src/molecules/editor/extensions/iframe/iframe-embed-utils.ts +30 -0
  537. package/src/molecules/editor/extensions/iframe/iframe-extension.ts +4 -4
  538. package/src/molecules/editor/extensions/iframe/iframeInsertDialogController.ts +12 -1
  539. package/src/molecules/editor/extensions/iframe/index.ts +4 -4
  540. package/src/molecules/editor/extensions/iframe/useIframeDialog.ts +25 -13
  541. package/src/molecules/editor/extensions/image/image-extension.ts +29 -11
  542. package/src/molecules/editor/extensions/image-group/ImageGroupGrid.vue +27 -11
  543. package/src/molecules/editor/extensions/image-group/ImageGroupGridCell.vue +55 -11
  544. package/src/molecules/editor/extensions/image-group/ImageGroupNodeView.vue +64 -31
  545. package/src/molecules/editor/extensions/image-group/ImageGroupUploadDialog.vue +84 -40
  546. package/src/molecules/editor/extensions/image-group/image-group-extension.ts +4 -3
  547. package/src/molecules/editor/extensions/image-group/useImageGroupDialog.ts +116 -17
  548. package/src/molecules/editor/extensions/link/LinkEditorPopup.vue +214 -71
  549. package/src/molecules/editor/extensions/link/link-click-plugin.ts +10 -15
  550. package/src/molecules/editor/extensions/link/link-commands.ts +24 -3
  551. package/src/molecules/editor/extensions/link/link-extension.ts +11 -2
  552. package/src/molecules/editor/extensions/link/link-popup-controller.test.ts +49 -0
  553. package/src/molecules/editor/extensions/link/link-popup-controller.ts +67 -2
  554. package/src/molecules/editor/extensions/link/link-shortcut-plugin.ts +7 -2
  555. package/src/molecules/editor/extensions/media-drop/media-drop-extension.ts +177 -0
  556. package/src/molecules/editor/extensions/shared/media-dimensions.ts +36 -3
  557. package/src/molecules/editor/extensions/shared/media-node-ops.ts +17 -0
  558. package/src/molecules/editor/extensions/shared/media-plugin.test.ts +60 -0
  559. package/src/molecules/editor/extensions/shared/media-plugin.ts +7 -37
  560. package/src/molecules/editor/extensions/shared/media-upload-engine.test.ts +39 -2
  561. package/src/molecules/editor/extensions/shared/media-upload-engine.ts +104 -10
  562. package/src/molecules/editor/extensions/shared/media-upload-state.ts +55 -0
  563. package/src/molecules/editor/extensions/shared/media-upload-types.ts +52 -1
  564. package/src/molecules/editor/extensions/shared/suggestion-helpers.ts +20 -0
  565. package/src/molecules/editor/extensions/shared/suggestion-types.ts +7 -0
  566. package/src/molecules/editor/extensions/shared/upload-types.ts +1 -0
  567. package/src/molecules/editor/extensions/slash-commands/slash-commands-extension.test.ts +38 -0
  568. package/src/molecules/editor/extensions/slash-commands/slash-commands-extension.ts +119 -55
  569. package/src/molecules/editor/extensions/suggestion/SuggestionList.vue +62 -22
  570. package/src/molecules/editor/extensions/suggestion/SuggestionListItem.vue +1 -1
  571. package/src/molecules/editor/extensions/suggestion/createSuggestionExtension.ts +4 -0
  572. package/src/molecules/editor/extensions/table/drag-scroll.ts +154 -0
  573. package/src/molecules/editor/extensions/table/table-cell-color.ts +188 -0
  574. package/src/molecules/editor/extensions/table/table-navigation.ts +560 -0
  575. package/src/molecules/editor/extensions/table/table-selection-overlay.ts +137 -0
  576. package/src/molecules/editor/extensions/toc-node/TocNodeView.vue +1 -1
  577. package/src/molecules/editor/extensions/toc-node/toc-render.ts +7 -3
  578. package/src/molecules/editor/extensions/video/video-extension.ts +72 -5
  579. package/src/molecules/editor/extensions.ts +176 -8
  580. package/src/molecules/editor/index.ts +9 -4
  581. package/src/molecules/editor/kits.test.ts +21 -1
  582. package/src/molecules/editor/kits.ts +56 -33
  583. package/src/molecules/editor/menu.test.ts +3 -1
  584. package/src/molecules/editor/menu.ts +180 -18
  585. package/src/molecules/editor/stories/Comment.vue +4 -4
  586. package/src/molecules/editor/stories/Inline.vue +1 -1
  587. package/src/molecules/editor/stories/Primitives.vue +1 -1
  588. package/src/molecules/editor/stories/RichText.vue +1 -1
  589. package/src/molecules/editor/style.css +80 -3
  590. package/src/molecules/editor/useEditor.test.ts +4 -0
  591. package/src/molecules/editor/useEditor.ts +7 -3
  592. package/src/molecules/list/List.cy.ts +626 -0
  593. package/src/molecules/list/List.vue +93 -0
  594. package/src/molecules/list/ListCell.vue +15 -0
  595. package/src/molecules/list/ListGroup.vue +40 -0
  596. package/src/molecules/list/ListHeader.vue +62 -0
  597. package/src/molecules/list/ListHeaderCell.vue +26 -0
  598. package/src/molecules/list/ListHeaderCellSort.vue +106 -0
  599. package/src/molecules/list/ListRow.vue +55 -0
  600. package/src/molecules/list/ListRowBase.vue +103 -0
  601. package/src/molecules/list/ListRows.vue +120 -0
  602. package/src/molecules/list/index.ts +24 -0
  603. package/src/molecules/list/list-context.ts +44 -0
  604. package/src/molecules/list/list.api.md +276 -0
  605. package/src/molecules/list/list.md +119 -0
  606. package/src/molecules/list/stories/Columns.vue +103 -0
  607. package/src/molecules/list/stories/Feed.vue +105 -0
  608. package/src/molecules/list/stories/Virtual.vue +31 -0
  609. package/src/molecules/list/style.css +173 -0
  610. package/src/molecules/list/types.ts +82 -0
  611. package/src/molecules/list/useVirtualRows.ts +80 -0
  612. package/src/resources/documentResource.d.ts +28 -0
  613. package/src/resources/documentResource.js +32 -4
  614. package/src/resources/documentResource.test.ts +111 -0
  615. package/src/resources/listResource.d.ts +33 -0
  616. package/src/resources/plugin.d.ts +7 -0
  617. package/src/resources/resources.d.ts +35 -0
  618. package/src/utils/{call.js → call.ts} +50 -9
  619. package/src/utils/config.ts +16 -1
  620. package/src/utils/confirmDialog.d.ts +17 -0
  621. package/src/utils/debounce.ts +6 -7
  622. package/src/utils/dialog.cy.ts +9 -9
  623. package/src/utils/fileSize.ts +36 -0
  624. package/src/utils/fileUploadHandler.ts +46 -6
  625. package/src/utils/frappeRequest.test.ts +79 -0
  626. package/src/utils/{frappeRequest.js → frappeRequest.ts} +76 -13
  627. package/src/utils/pageMeta.ts +1 -1
  628. package/src/utils/plugin.ts +58 -0
  629. package/src/utils/{request.js → request.ts} +28 -3
  630. package/src/utils/{socketio.js → socketio.ts} +11 -1
  631. package/src/utils/theme.ts +48 -57
  632. package/src/utils/useFileUpload.ts +80 -23
  633. package/tailwind/audit-token-drift.cjs +176 -0
  634. package/tailwind/colorPalette.js +69 -8
  635. package/tailwind/colors.json +1115 -397
  636. package/tailwind/figma-tokens-to-theme.js +364 -0
  637. package/tailwind/generated/colors.json +1217 -0
  638. package/tailwind/generated/effects.json +41 -0
  639. package/tailwind/generated/radius.json +20 -0
  640. package/tailwind/generated/typography.json +479 -0
  641. package/tailwind/migrate-tokens-v2.js +453 -0
  642. package/tailwind/migrate-tokens-v2.test.js +55 -0
  643. package/tailwind/plugin.js +220 -15
  644. package/tailwind/preset.js +15 -0
  645. package/tailwind/tokens.js +35 -37
  646. package/tsconfig.base.json +2 -2
  647. package/vitepress/components/Docs/CommandPalette.vue +214 -0
  648. package/vitepress/components/Docs/Demo.vue +60 -0
  649. package/vitepress/components/Docs/EmitsTable.vue +99 -0
  650. package/vitepress/components/Docs/MobileNavSheet.vue +148 -0
  651. package/vitepress/components/Docs/OnThisPage.vue +74 -0
  652. package/vitepress/components/Docs/PrevNextBtns.vue +58 -0
  653. package/vitepress/components/Docs/PropsTable.vue +185 -0
  654. package/vitepress/components/Docs/Search.vue +34 -0
  655. package/vitepress/components/Docs/Sidebar.vue +91 -0
  656. package/vitepress/components/Docs/SlotsTable.vue +99 -0
  657. package/vitepress/components/Docs/index.ts +13 -0
  658. package/vitepress/components/Docs/sidebarList.ts +33 -0
  659. package/vitepress/components/Layout.vue +58 -0
  660. package/vitepress/components/Navbar.vue +126 -0
  661. package/vitepress/components/index.ts +3 -0
  662. package/vitepress/composables/index.ts +3 -0
  663. package/vitepress/composables/useTheme.ts +39 -0
  664. package/vitepress/css/fonts/Inter-Italic.var.woff2 +0 -0
  665. package/vitepress/css/fonts/Inter.var.woff2 +0 -0
  666. package/vitepress/css/style.css +198 -0
  667. package/vitepress/index.d.ts +23 -0
  668. package/vitepress/index.node.ts +175 -0
  669. package/vitepress/index.ts +17 -0
  670. package/vitepress/plugins/colocatedComponentDocs.ts +164 -0
  671. package/vitepress/plugins/componentTransformer.ts +286 -0
  672. package/vitepress/plugins/index.ts +12 -0
  673. package/vitepress/state.ts +10 -0
  674. package/vitepress/theme/index.ts +21 -0
  675. package/frappe/telemetry/utils.ts +0 -15
  676. package/src/components/Badge/stories/Themes.vue +0 -10
  677. package/src/components/Badge/stories/Variants.vue +0 -10
  678. package/src/components/Button/stories/Icons.vue +0 -27
  679. package/src/components/Button/stories/Sizes.vue +0 -11
  680. package/src/components/Button/stories/Themes.vue +0 -10
  681. package/src/components/Button/stories/Variants.vue +0 -10
  682. package/src/components/Popover/stories/Hover.vue +0 -14
  683. package/src/components/Resource.vue +0 -21
  684. package/src/components/Sidebar/stories/Example.vue +0 -76
  685. package/src/components/Spinner.vue +0 -3
  686. package/src/components/TabButtons/TabButtons.story.vue +0 -22
  687. package/src/utils/plugin.js +0 -24
  688. /package/src/components/Dropdown/stories/{02_Shortcuts.vue → Shortcuts.vue} +0 -0
  689. /package/src/components/Dropdown/stories/{01_Simple.vue → Simple.vue} +0 -0
  690. /package/src/components/Dropdown/stories/{03_Submenus.vue → Submenus.vue} +0 -0
  691. /package/src/components/Dropdown/stories/{04_Switches.vue → Switches.vue} +0 -0
  692. /package/src/components/{Dropdown/DropdownRenderContentAsChild.vue → Menu/MenuRenderContentAsChild.vue} +0 -0
@@ -1,22 +1,22 @@
1
1
  import type {
2
- DropdownGroupOption,
3
- DropdownItem,
4
- DropdownOption,
5
- DropdownOptions,
6
- DropdownTheme,
2
+ MenuGroupOption,
3
+ MenuItem,
4
+ MenuOption,
5
+ MenuOptions,
6
+ MenuTheme,
7
7
  } from './types'
8
8
 
9
9
  /**
10
10
  * Group object after normalization. `options` is guaranteed to be present
11
11
  * (the deprecated `items` alias has been resolved into it).
12
12
  */
13
- export type NormalizedDropdownGroup = DropdownGroupOption & {
14
- options: DropdownOption[]
13
+ export type NormalizedMenuGroup = MenuGroupOption & {
14
+ options: MenuOption[]
15
15
  }
16
16
 
17
- export const dropdownClasses = {
17
+ export const menuClasses = {
18
18
  content:
19
- 'dropdown-content min-w-40 divide-y divide-outline-gray-modals rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none',
19
+ 'menu-content min-w-40 divide-y divide-outline-elevation-2 rounded-lg bg-surface-elevation-2 shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none',
20
20
  group: 'p-1.5',
21
21
  groupLabel: 'flex h-7 items-center px-2 text-sm font-medium text-ink-gray-4',
22
22
  itemIcon: 'size-4 shrink-0',
@@ -26,45 +26,41 @@ export const dropdownClasses = {
26
26
  'cursor-pointer rounded outline-none data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed',
27
27
  } as const
28
28
 
29
- export function isDropdownGroupOption(
30
- item: DropdownItem,
31
- ): item is DropdownGroupOption {
29
+ export function isMenuGroupOption(item: MenuItem): item is MenuGroupOption {
32
30
  return 'group' in item && ('options' in item || 'items' in item)
33
31
  }
34
32
 
35
- function resolveGroupChildren(group: DropdownGroupOption): DropdownOption[] {
33
+ function resolveGroupChildren(group: MenuGroupOption): MenuOption[] {
36
34
  if (import.meta.env.DEV && group.options && group.items) {
37
35
  console.warn(
38
- '[Dropdown] grouped entry has both `options` and `items`. `options` wins; `items` is the deprecated alias.',
36
+ '[Menu] grouped entry has both `options` and `items`. `options` wins; `items` is the deprecated alias.',
39
37
  )
40
38
  }
41
39
 
42
40
  return group.options ?? group.items ?? []
43
41
  }
44
42
 
45
- export function isDropdownSwitchOption(item: DropdownOption) {
43
+ export function isMenuSwitchOption(item: MenuOption) {
46
44
  return item.switch === true
47
45
  }
48
46
 
49
- export function isDropdownSubmenuOption(item: DropdownOption) {
47
+ export function isMenuSubmenuOption(item: MenuOption) {
50
48
  return Array.isArray(item.submenu)
51
49
  }
52
50
 
53
- export function isDropdownComponentOption(item: DropdownOption) {
51
+ export function isMenuComponentOption(item: MenuOption) {
54
52
  return 'component' in item && Boolean(item.component)
55
53
  }
56
54
 
57
- function shouldRenderOption(option: DropdownOption) {
55
+ function shouldRenderOption(option: MenuOption) {
58
56
  return option.condition ? option.condition() : true
59
57
  }
60
58
 
61
- function normalizeTheme(theme?: DropdownTheme): DropdownTheme {
59
+ function normalizeTheme(theme?: MenuTheme): MenuTheme {
62
60
  return theme ?? 'gray'
63
61
  }
64
62
 
65
- export function normalizeDropdownOption(
66
- option: DropdownOption,
67
- ): DropdownOption {
63
+ export function normalizeMenuOption(option: MenuOption): MenuOption {
68
64
  return {
69
65
  ...option,
70
66
  theme: normalizeTheme(option.theme),
@@ -72,18 +68,18 @@ export function normalizeDropdownOption(
72
68
  }
73
69
  }
74
70
 
75
- function normalizeGroupItems(items: DropdownOption[]) {
71
+ function normalizeGroupItems(items: MenuOption[]) {
76
72
  return (items || [])
77
73
  .filter(Boolean)
78
74
  .filter(shouldRenderOption)
79
- .map(normalizeDropdownOption)
75
+ .map(normalizeMenuOption)
80
76
  }
81
77
 
82
- export function normalizeDropdownOptions(
83
- options: DropdownOptions = [],
84
- ): NormalizedDropdownGroup[] {
85
- const groups: NormalizedDropdownGroup[] = []
86
- let currentGroup: NormalizedDropdownGroup | null = null
78
+ export function normalizeMenuOptions(
79
+ options: MenuOptions = [],
80
+ ): NormalizedMenuGroup[] {
81
+ const groups: NormalizedMenuGroup[] = []
82
+ let currentGroup: NormalizedMenuGroup | null = null
87
83
  let implicitGroupIndex = 0
88
84
 
89
85
  function flushCurrentGroup() {
@@ -99,7 +95,7 @@ export function normalizeDropdownOptions(
99
95
  for (const [index, item] of options.entries()) {
100
96
  if (!item) continue
101
97
 
102
- if (isDropdownGroupOption(item)) {
98
+ if (isMenuGroupOption(item)) {
103
99
  flushCurrentGroup()
104
100
 
105
101
  const visibleItems = normalizeGroupItems(resolveGroupChildren(item))
@@ -129,7 +125,7 @@ export function normalizeDropdownOptions(
129
125
  }
130
126
  }
131
127
 
132
- currentGroup.options.push(normalizeDropdownOption(item))
128
+ currentGroup.options.push(normalizeMenuOption(item))
133
129
  }
134
130
 
135
131
  flushCurrentGroup()
@@ -137,33 +133,33 @@ export function normalizeDropdownOptions(
137
133
  return groups
138
134
  }
139
135
 
140
- export function groupHasIcons(group: NormalizedDropdownGroup) {
136
+ export function groupHasIcons(group: NormalizedMenuGroup) {
141
137
  return group.options.some((item) => Boolean(item.icon))
142
138
  }
143
139
 
144
- export function getDropdownIconColor(item: {
140
+ export function getMenuIconColor(item: {
145
141
  disabled?: boolean
146
- theme?: DropdownTheme
142
+ theme?: MenuTheme
147
143
  }) {
148
144
  if (item.disabled) return 'text-ink-gray-4'
149
- return item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-6'
145
+ return item.theme === 'red' ? 'text-ink-red-6' : 'text-ink-gray-6'
150
146
  }
151
147
 
152
- export function getDropdownTextColor(item: {
148
+ export function getMenuTextColor(item: {
153
149
  disabled?: boolean
154
- theme?: DropdownTheme
150
+ theme?: MenuTheme
155
151
  }) {
156
152
  if (item.disabled) return 'text-ink-gray-4'
157
- return item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-7'
153
+ return item.theme === 'red' ? 'text-ink-red-6' : 'text-ink-gray-7'
158
154
  }
159
155
 
160
- export function getDropdownBackgroundColor(item: { theme?: DropdownTheme }) {
156
+ export function getMenuBackgroundColor(item: { theme?: MenuTheme }) {
161
157
  if (item.theme === 'red') {
162
158
  return 'focus:bg-surface-red-3 data-[highlighted]:bg-surface-red-3 data-[state=open]:bg-surface-red-3'
163
159
  }
164
160
 
165
161
  return [
166
- 'focus:bg-surface-gray-2 data-[highlighted]:bg-surface-gray-2 data-[state=open]:bg-surface-gray-2',
162
+ 'focus:bg-surface-gray-2 data-[highlighted]:bg-surface-alpha-gray-2 data-[state=open]:bg-surface-gray-2',
167
163
  'data-[state=checked]:bg-surface-gray-3',
168
164
  'data-[highlighted]:data-[state=checked]:bg-surface-gray-4',
169
165
  ].join(' ')
@@ -0,0 +1,70 @@
1
+ <!-- Auto Generated by scripts/propsgen.ts -->
2
+ <script setup>
3
+ import PropsTable from '@/components/Docs/PropsTable.vue'
4
+ import SlotsTable from '@/components/Docs/SlotsTable.vue'
5
+ import EmitsTable from '@/components/Docs/EmitsTable.vue'
6
+
7
+ const mobileNavSlots = [
8
+ {
9
+ name: 'default',
10
+ description: '',
11
+ type: '{}'
12
+ }
13
+ ]
14
+
15
+ const mobileNavItemProps = [
16
+ {
17
+ name: 'label',
18
+ description: 'Label under the icon; also the accessible name.',
19
+ required: true,
20
+ type: 'string'
21
+ },
22
+ {
23
+ name: 'icon',
24
+ description: 'Icon CSS class, e.g. `lucide-home`, or a component. Ignored when the\ndefault slot is used (for a custom glyph or an avatar).',
25
+ required: false,
26
+ type: 'string | Component'
27
+ },
28
+ {
29
+ name: 'to',
30
+ description: 'Navigation target. Renders a router link. Tapping the item while it is\nalready the current route scrolls the shell to the top instead of\nre-navigating.',
31
+ required: false,
32
+ type: 'string | kt | Tt'
33
+ },
34
+ {
35
+ name: 'active',
36
+ description: 'Highlight this item. Independent of the current route so one tab can stay\nlit across a whole section (e.g. Home across community routes). Defaults to\nwhether `to` resolves to the current route.',
37
+ required: false,
38
+ type: 'boolean'
39
+ }
40
+ ]
41
+
42
+ const mobileNavItemSlots = [
43
+ {
44
+ name: 'default',
45
+ description: '',
46
+ type: '{ active: boolean; }'
47
+ }
48
+ ]
49
+
50
+ const mobileNavItemEmits = [
51
+ {
52
+ name: 'click',
53
+ description: '',
54
+ type: '[event: MouseEvent]'
55
+ }
56
+ ]
57
+ </script>
58
+ ## API Reference
59
+
60
+ ### MobileNav
61
+
62
+ <SlotsTable :data="mobileNavSlots"/>
63
+
64
+ ### MobileNavItem
65
+
66
+ <PropsTable folder="MobileNav" name="MobileNavItem" :data="mobileNavItemProps"/>
67
+
68
+ <SlotsTable :data="mobileNavItemSlots"/>
69
+
70
+ <EmitsTable :data="mobileNavItemEmits"/>
@@ -0,0 +1,89 @@
1
+ import { h } from 'vue'
2
+ import { createMemoryHistory, createRouter } from 'vue-router'
3
+ import MobileNav from './MobileNav.vue'
4
+ import MobileNavItem from './MobileNavItem.vue'
5
+ import {
6
+ registerScrollContainer,
7
+ unregisterScrollContainer,
8
+ } from '../../composables/useScrollContainer'
9
+
10
+ function routerAt(path: string) {
11
+ const router = createRouter({
12
+ history: createMemoryHistory(),
13
+ routes: [
14
+ { path: '/', name: 'home', component: { template: '<div />' } },
15
+ { path: '/search', name: 'search', component: { template: '<div />' } },
16
+ ],
17
+ })
18
+ router.push(path)
19
+ return router
20
+ }
21
+
22
+ describe('<MobileNav />', () => {
23
+ it('lays its items out as an equal-width grid', () => {
24
+ cy.mount(MobileNav, {
25
+ slots: {
26
+ default: () => [
27
+ h(MobileNavItem, { label: 'Home', icon: 'lucide-house' }),
28
+ h(MobileNavItem, { label: 'Search', icon: 'lucide-search' }),
29
+ ],
30
+ },
31
+ })
32
+ cy.get('[data-slot=mobile-nav]').should('have.class', 'grid')
33
+ cy.get('[data-slot=mobile-nav-item]').should('have.length', 2)
34
+ })
35
+ })
36
+
37
+ describe('<MobileNavItem />', () => {
38
+ it('renders a button and emits click when there is no `to`', () => {
39
+ const onClick = cy.stub().as('click')
40
+ cy.mount(MobileNavItem, { props: { label: 'Home', icon: 'lucide-house', onClick } })
41
+ cy.get('button[data-slot=mobile-nav-item]').should('exist')
42
+ cy.get('button').click()
43
+ cy.get('@click').should('have.been.calledOnce')
44
+ })
45
+
46
+ it('renders a router link to a different route', () => {
47
+ cy.mount(MobileNavItem, {
48
+ props: { label: 'Search', icon: 'lucide-search', to: '/search' },
49
+ global: { plugins: [routerAt('/')] },
50
+ })
51
+ cy.get('a[data-slot=mobile-nav-item]').should('have.attr', 'href', '/search')
52
+ })
53
+
54
+ it('is a button (not a link) when `to` is already the current route', () => {
55
+ cy.mount(MobileNavItem, {
56
+ props: { label: 'Home', icon: 'lucide-house', to: '/' },
57
+ global: { plugins: [routerAt('/')] },
58
+ })
59
+ cy.get('button[data-slot=mobile-nav-item]').should('exist')
60
+ cy.get('a[data-slot=mobile-nav-item]').should('not.exist')
61
+ cy.get('[data-slot=mobile-nav-item]').should('have.attr', 'aria-current', 'page')
62
+ })
63
+
64
+ it('scrolls the registered container to the top when the current tab is tapped', () => {
65
+ const scroller = document.createElement('div')
66
+ Object.defineProperty(scroller, 'scrollHeight', { value: 2000 })
67
+ const scrollTo = cy.stub().as('scrollTo')
68
+ scroller.scrollTo = scrollTo
69
+ registerScrollContainer(scroller)
70
+
71
+ cy.mount(MobileNavItem, {
72
+ props: { label: 'Home', icon: 'lucide-house', to: '/' },
73
+ global: { plugins: [routerAt('/')] },
74
+ })
75
+ cy.get('button[data-slot=mobile-nav-item]').click()
76
+ cy.get('@scrollTo')
77
+ .should('have.been.calledOnce')
78
+ .then(() => unregisterScrollContainer(scroller))
79
+ })
80
+
81
+ it('reflects `active` in data-state and exposes it to the default slot', () => {
82
+ cy.mount(MobileNavItem, {
83
+ props: { label: 'You', active: true },
84
+ slots: { default: (props: { active: boolean }) => h('span', `active:${props.active}`) },
85
+ })
86
+ cy.get('[data-slot=mobile-nav-item][data-state=active]').should('exist')
87
+ cy.get('[data-slot=mobile-nav-item]').should('contain.text', 'active:true')
88
+ })
89
+ })
@@ -0,0 +1,34 @@
1
+ # MobileNav
2
+
3
+ The bottom tab bar for a [`MobileShell`](/docs/components/mobileshell).
4
+ `MobileNav` is a grid frame; each `MobileNavItem` becomes one equal-width tab, so
5
+ the bar adapts to any number of items.
6
+
7
+ <ComponentPreview name="MobileNav-Default" />
8
+
9
+ ## MobileNavItem
10
+
11
+ Each item takes a `label`, an `icon` (or a default slot for custom content like
12
+ an avatar), and a `to` target. It renders a router link when navigating
13
+ somewhere new, and — when it's already the current route — a button that scrolls
14
+ the shell's scroll container to the top instead of re-navigating.
15
+
16
+ `active` controls the highlight and is independent of the current route, so one
17
+ tab can stay lit across a whole section (e.g. Home across every community route)
18
+ while tapping it still navigates home. When `active` is omitted it defaults to
19
+ whether `to` matches the current route. The default slot receives `{ active }`
20
+ so custom content — an avatar, a badge — can react to the highlight:
21
+
22
+ ```vue
23
+ <MobileNavItem label="You" :to="{ name: 'More' }" :active="isMoreRoute">
24
+ <template #default="{ active }">
25
+ <UserAvatar :user="me" :class="{ 'ring-2 ring-outline-gray-4': active }" />
26
+ </template>
27
+ </MobileNavItem>
28
+ ```
29
+
30
+ Like `SidebarItem`, `MobileNavItem` is router-optional: mounted without
31
+ vue-router it degrades to a plain `<a>`/`<button>` with no warnings, so it works
32
+ in docs, tests, and embedded use.
33
+
34
+ <!-- @include: ./MobileNav.api.md -->
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <nav
3
+ data-slot="mobile-nav"
4
+ class="grid shrink-0 auto-cols-fr grid-flow-col border-t border-outline-gray-2 bg-surface-elevation-2 [@media(display-mode:standalone)]:pb-4"
5
+ >
6
+ <slot />
7
+ </nav>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ // A bare grid frame: each MobileNavItem becomes one equal-width column
12
+ // (auto-cols-fr + grid-flow-col), so the bar adapts to any item count without
13
+ // hardcoding a column class. Bottom padding clears the home indicator in an
14
+ // installed PWA (display-mode: standalone).
15
+ </script>
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <!--
3
+ A real link when navigating somewhere new; a plain button when this item is
4
+ already the current route (tap = scroll to top) or has no target. Switching
5
+ the element on `isCurrent` — rather than preventing RouterLink's default —
6
+ keeps the scroll-vs-navigate decision unambiguous. The 'button' string can't
7
+ go through <component :is> (it collides with the global <Button>), so the
8
+ button stays a literal v-else; the inner content is shared.
9
+ -->
10
+ <component
11
+ :is="linkComponent"
12
+ v-if="to && !isCurrent"
13
+ v-bind="linkAttrs"
14
+ data-slot="mobile-nav-item"
15
+ :data-state="resolvedActive ? 'active' : 'inactive'"
16
+ :aria-label="label"
17
+ :aria-current="isCurrent ? 'page' : undefined"
18
+ class="flex min-h-14 flex-col items-center justify-center gap-1 py-2 transition active:scale-95"
19
+ @click="emit('click', $event)"
20
+ >
21
+ <slot :active="resolvedActive">
22
+ <span
23
+ v-if="typeof icon === 'string'"
24
+ :class="[icon, resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5']"
25
+ class="size-6"
26
+ aria-hidden="true"
27
+ />
28
+ <component
29
+ v-else-if="icon"
30
+ :is="icon"
31
+ :class="resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5'"
32
+ class="size-6"
33
+ aria-hidden="true"
34
+ />
35
+ </slot>
36
+ <span
37
+ class="text-xs-medium"
38
+ :class="resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5'"
39
+ >
40
+ {{ label }}
41
+ </span>
42
+ </component>
43
+
44
+ <button
45
+ v-else
46
+ type="button"
47
+ data-slot="mobile-nav-item"
48
+ :data-state="resolvedActive ? 'active' : 'inactive'"
49
+ :aria-label="label"
50
+ :aria-current="isCurrent ? 'page' : undefined"
51
+ class="flex min-h-14 flex-col items-center justify-center gap-1 py-2 transition active:scale-95"
52
+ @click="onButtonClick"
53
+ >
54
+ <slot :active="resolvedActive">
55
+ <span
56
+ v-if="typeof icon === 'string'"
57
+ :class="[icon, resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5']"
58
+ class="size-6"
59
+ aria-hidden="true"
60
+ />
61
+ <component
62
+ v-else-if="icon"
63
+ :is="icon"
64
+ :class="resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5'"
65
+ class="size-6"
66
+ aria-hidden="true"
67
+ />
68
+ </slot>
69
+ <span
70
+ class="text-xs-medium"
71
+ :class="resolvedActive ? 'text-ink-gray-8' : 'text-ink-gray-5'"
72
+ >
73
+ {{ label }}
74
+ </span>
75
+ </button>
76
+ </template>
77
+
78
+ <script setup lang="ts">
79
+ import { computed, getCurrentInstance } from 'vue'
80
+ import { RouterLink } from 'vue-router'
81
+ import { scrollToTop } from '../../composables/useScrollContainer'
82
+ import type { MobileNavItemProps } from './types'
83
+
84
+ const props = defineProps<MobileNavItemProps>()
85
+ const emit = defineEmits<{ click: [event: MouseEvent] }>()
86
+
87
+ // Read router/route off global properties (not useRouter/useRoute) so the item
88
+ // works without warnings when mounted outside a vue-router app — docs, tests,
89
+ // embedded use. Same approach as SidebarItem.
90
+ const globals = getCurrentInstance()?.appContext.config.globalProperties
91
+ const hasRouter = computed(() => Boolean(globals?.$router))
92
+
93
+ const linkComponent = computed(() => (hasRouter.value ? RouterLink : 'a'))
94
+ const linkAttrs = computed(() =>
95
+ hasRouter.value
96
+ ? { to: props.to }
97
+ : { href: typeof props.to === 'string' ? props.to : undefined },
98
+ )
99
+
100
+ const resolvedRoute = computed(() =>
101
+ props.to && globals?.$router ? globals.$router.resolve(props.to) : null,
102
+ )
103
+
104
+ // Is this item's target the exact current route? Drives scroll-vs-navigate and
105
+ // aria-current — distinct from `active`, which may span a whole section.
106
+ const isCurrent = computed(() => {
107
+ const target = resolvedRoute.value
108
+ const current = globals?.$route
109
+ if (!target || !current) return false
110
+ return target.name
111
+ ? current.name === target.name
112
+ : current.path === target.path
113
+ })
114
+
115
+ // Explicit `active` wins (broad section highlight); otherwise fall back to the
116
+ // current-route match so simple navs light up the current item automatically.
117
+ const resolvedActive = computed(() => props.active ?? isCurrent.value)
118
+
119
+ function onButtonClick(event: MouseEvent) {
120
+ // Reached only when this item is already current (or has no target): a tap
121
+ // scrolls the shell's scroll container to the top.
122
+ if (isCurrent.value) scrollToTop()
123
+ emit('click', event)
124
+ }
125
+ </script>
@@ -0,0 +1,4 @@
1
+ export { default as MobileNav } from './MobileNav.vue'
2
+ export { default as MobileNavItem } from './MobileNavItem.vue'
3
+
4
+ export type { MobileNavProps, MobileNavItemProps } from './types'
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { MobileNav, MobileNavItem, Avatar } from 'frappe-ui'
4
+
5
+ const tab = ref('home')
6
+ </script>
7
+
8
+ <template>
9
+ <div class="mx-auto w-[360px] overflow-hidden rounded-xl border bg-surface-white">
10
+ <MobileNav>
11
+ <MobileNavItem
12
+ label="Home"
13
+ icon="lucide-house"
14
+ :active="tab === 'home'"
15
+ @click="tab = 'home'"
16
+ />
17
+ <MobileNavItem
18
+ label="Notifications"
19
+ icon="lucide-bell"
20
+ :active="tab === 'notifications'"
21
+ @click="tab = 'notifications'"
22
+ />
23
+ <MobileNavItem
24
+ label="Search"
25
+ icon="lucide-search"
26
+ :active="tab === 'search'"
27
+ @click="tab = 'search'"
28
+ />
29
+ <MobileNavItem label="You" :active="tab === 'you'" @click="tab = 'you'">
30
+ <template #default="{ active }">
31
+ <Avatar
32
+ label="Jane Doe"
33
+ size="md"
34
+ :class="active ? 'ring-2 ring-outline-gray-4' : ''"
35
+ />
36
+ </template>
37
+ </MobileNavItem>
38
+ </MobileNav>
39
+ </div>
40
+ </template>
@@ -0,0 +1,33 @@
1
+ import type { Component } from 'vue'
2
+ import type { RouteLocationRaw } from 'vue-router'
3
+
4
+ /**
5
+ * `MobileNav` (the bar) has no props — it's a grid frame for `MobileNavItem`s.
6
+ */
7
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
8
+ export interface MobileNavProps {}
9
+
10
+ export interface MobileNavItemProps {
11
+ /** Label under the icon; also the accessible name. */
12
+ label: string
13
+
14
+ /**
15
+ * Icon CSS class, e.g. `lucide-home`, or a component. Ignored when the
16
+ * default slot is used (for a custom glyph or an avatar).
17
+ */
18
+ icon?: string | Component
19
+
20
+ /**
21
+ * Navigation target. Renders a router link. Tapping the item while it is
22
+ * already the current route scrolls the shell to the top instead of
23
+ * re-navigating.
24
+ */
25
+ to?: RouteLocationRaw
26
+
27
+ /**
28
+ * Highlight this item. Independent of the current route so one tab can stay
29
+ * lit across a whole section (e.g. Home across community routes). Defaults to
30
+ * whether `to` resolves to the current route.
31
+ */
32
+ active?: boolean
33
+ }
@@ -0,0 +1,23 @@
1
+ <!-- Auto Generated by scripts/propsgen.ts -->
2
+ <script setup>
3
+ import PropsTable from '@/components/Docs/PropsTable.vue'
4
+ import SlotsTable from '@/components/Docs/SlotsTable.vue'
5
+ import EmitsTable from '@/components/Docs/EmitsTable.vue'
6
+
7
+ const slotsData = [
8
+ {
9
+ name: 'default',
10
+ description: '',
11
+ type: '{}'
12
+ },
13
+ {
14
+ name: 'nav',
15
+ description: '',
16
+ type: '{}'
17
+ }
18
+ ]
19
+ </script>
20
+ ## API Reference
21
+
22
+ <SlotsTable :data="slotsData"/>
23
+
@@ -0,0 +1,25 @@
1
+ import { h } from 'vue'
2
+ import MobileShell from './MobileShell.vue'
3
+ import { getScrollContainer } from '../../composables/useScrollContainer'
4
+
5
+ describe('<MobileShell />', () => {
6
+ it('renders the default content and #nav slots', () => {
7
+ cy.mount(MobileShell, {
8
+ slots: {
9
+ default: () => h('div', { 'data-test': 'page' }, 'page body'),
10
+ nav: () => h('div', { 'data-test': 'nav' }, 'tab bar'),
11
+ },
12
+ })
13
+ cy.get('[data-slot=mobile-shell]').should('exist')
14
+ cy.get('[data-slot=mobile-shell-scroll]').should('contain.text', 'page body')
15
+ cy.get('[data-test=nav]').should('contain.text', 'tab bar')
16
+ })
17
+
18
+ it('registers its scroll region so getScrollContainer() resolves', () => {
19
+ cy.mount(MobileShell, { slots: { default: () => h('div', 'content') } })
20
+ cy.get('[data-slot=mobile-shell-scroll]').should('exist')
21
+ cy.then(() => {
22
+ expect(getScrollContainer()).to.not.be.null
23
+ })
24
+ })
25
+ })
@@ -0,0 +1,24 @@
1
+ # MobileShell
2
+
3
+ The mobile app frame. `MobileShell` is a fixed, full-height column: a pinned
4
+ `PageHeaderTarget` on top (with safe-area padding for installed PWAs), a
5
+ native-scrolling content area, and a `#nav` slot for a bottom
6
+ [`MobileNav`](/docs/components/mobilenav). It's a separate family from
7
+ [`DesktopShell`](/docs/components/desktopshell) — mobile and desktop are
8
+ different navigation models, so the app chooses which to render for the viewport
9
+ rather than toggling one responsive component.
10
+
11
+ <ComponentPreview name="MobileShell-Default" />
12
+
13
+ Put the routed page in the default slot and the tab bar in `#nav`. The content
14
+ area scrolls with the platform's own momentum and overscroll; the header and nav
15
+ stay fixed to the edges.
16
+
17
+ ## Scroll container
18
+
19
+ Like `DesktopShell`, the content area registers into the scroll-container
20
+ registry, so [`useScrollContainer()`](/docs/other/utilities) and
21
+ `getScrollContainer()` resolve it — a tapped-active tab or a router
22
+ `scrollBehavior` can drive it with no app-owned global.
23
+
24
+ <!-- @include: ./MobileShell.api.md -->