@liorian/sdk 0.28.0-alpha.56010ca

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 (362) hide show
  1. package/README.md +483 -0
  2. package/package.json +94 -0
  3. package/schemas/module.schema.json +818 -0
  4. package/src/application/index.ts +3 -0
  5. package/src/application/module-instance.ts +36 -0
  6. package/src/application/service/auth-api-service.ts +291 -0
  7. package/src/application/service/auth-user.service.ts +108 -0
  8. package/src/application/service/index.ts +12 -0
  9. package/src/application/service/module-activation-api.service.ts +105 -0
  10. package/src/application/service/notifications-api-service.ts +38 -0
  11. package/src/application/service/notifications-push.service.ts +299 -0
  12. package/src/application/service/notifications-socket-service.ts +76 -0
  13. package/src/application/service/organizations-api-service.ts +104 -0
  14. package/src/application/service/otp-api-service.ts +11 -0
  15. package/src/application/service/storage-api-service.ts +77 -0
  16. package/src/application/service/storefront-api.service.ts +72 -0
  17. package/src/application/service/user-preferences-api.service.ts +57 -0
  18. package/src/domain/config/app.config.ts +35 -0
  19. package/src/domain/config/auth.config.ts +30 -0
  20. package/src/domain/config/index.ts +4 -0
  21. package/src/domain/config/logo.config.ts +17 -0
  22. package/src/domain/entities/activities.interface.ts +18 -0
  23. package/src/domain/entities/catalog.interface.ts +96 -0
  24. package/src/domain/entities/index.ts +13 -0
  25. package/src/domain/entities/media.ts +22 -0
  26. package/src/domain/entities/module-activation.interface.ts +173 -0
  27. package/src/domain/entities/module.interface.ts +101 -0
  28. package/src/domain/entities/notification.interface.ts +23 -0
  29. package/src/domain/entities/objectable.type.ts +3 -0
  30. package/src/domain/entities/organization.interface.ts +81 -0
  31. package/src/domain/entities/user-auth.interface.ts +17 -0
  32. package/src/domain/entities/user-phone.interface.ts +11 -0
  33. package/src/domain/entities/user-profile.interface.ts +23 -0
  34. package/src/domain/entities/user.interface.ts +79 -0
  35. package/src/domain/enums/coloring.enum.ts +6 -0
  36. package/src/domain/enums/domains.enum.ts +282 -0
  37. package/src/domain/enums/index.ts +8 -0
  38. package/src/domain/enums/module-category.enum.ts +57 -0
  39. package/src/domain/enums/module.enum.ts +97 -0
  40. package/src/domain/enums/routine.enum.ts +12 -0
  41. package/src/domain/enums/user-profile.enum.ts +25 -0
  42. package/src/domain/enums/user-status.enum.ts +7 -0
  43. package/src/domain/index.ts +6 -0
  44. package/src/domain/typing/auth-caches.ts +12 -0
  45. package/src/domain/typing/auth-oauth.types.ts +172 -0
  46. package/src/domain/typing/devise.ts +2 -0
  47. package/src/domain/typing/index.ts +10 -0
  48. package/src/domain/typing/response.ts +30 -0
  49. package/src/domain/typing/routine.types.ts +113 -0
  50. package/src/domain/typing/session.interface.ts +28 -0
  51. package/src/domain/typing/statisticals.ts +11 -0
  52. package/src/domain/typing/user-media-upload.ts +9 -0
  53. package/src/domain/typing/values.ts +6 -0
  54. package/src/index.tsx +168 -0
  55. package/src/infrastructure/capabilities/cache-storage/capability.ts +129 -0
  56. package/src/infrastructure/capabilities/cache-storage/enum.ts +5 -0
  57. package/src/infrastructure/capabilities/cache-storage/index.ts +4 -0
  58. package/src/infrastructure/capabilities/cache-storage/types.ts +13 -0
  59. package/src/infrastructure/capabilities/index.ts +3 -0
  60. package/src/infrastructure/capabilities/stackable/capability.ts +55 -0
  61. package/src/infrastructure/capabilities/stackable/index.ts +3 -0
  62. package/src/infrastructure/capabilities/stackable/types.ts +24 -0
  63. package/src/infrastructure/common-classname.constant.ts +4 -0
  64. package/src/infrastructure/data/countries.ts +208 -0
  65. package/src/infrastructure/data/gender.ts +5 -0
  66. package/src/infrastructure/data/index.ts +3 -0
  67. package/src/infrastructure/dataset/index.ts +3 -0
  68. package/src/infrastructure/dataset/sign-in.dataset.ts +21 -0
  69. package/src/infrastructure/dataset/sign-up.dataset.ts +64 -0
  70. package/src/infrastructure/hooks/index.ts +10 -0
  71. package/src/infrastructure/hooks/use-activity-lock-draft.ts +69 -0
  72. package/src/infrastructure/hooks/use-auth.ts +24 -0
  73. package/src/infrastructure/hooks/use-elastic-interaction.ts +180 -0
  74. package/src/infrastructure/hooks/use-is-desktop.ts +25 -0
  75. package/src/infrastructure/hooks/use-is-tauri.ts +17 -0
  76. package/src/infrastructure/hooks/use-mobile.ts +19 -0
  77. package/src/infrastructure/hooks/use-notifications.ts +128 -0
  78. package/src/infrastructure/hooks/use-recent-colors.ts +113 -0
  79. package/src/infrastructure/hooks/use-recent-modules.ts +76 -0
  80. package/src/infrastructure/index.tsx +11 -0
  81. package/src/infrastructure/library/design-system.ts +95 -0
  82. package/src/infrastructure/library/index.tsx +5 -0
  83. package/src/infrastructure/library/motion-utils.ts +77 -0
  84. package/src/infrastructure/library/motion.tsx +31 -0
  85. package/src/infrastructure/library/scroll-progress.tsx +93 -0
  86. package/src/infrastructure/providers/auth-guard.provider.tsx +47 -0
  87. package/src/infrastructure/providers/auth.provider.tsx +168 -0
  88. package/src/infrastructure/providers/index.tsx +8 -0
  89. package/src/infrastructure/providers/module-usage.provider.tsx +95 -0
  90. package/src/infrastructure/providers/modules-guard.provider.tsx +64 -0
  91. package/src/infrastructure/providers/modules-routines.provider.tsx +33 -0
  92. package/src/infrastructure/providers/modules-switcher.provider.tsx +25 -0
  93. package/src/infrastructure/providers/query.provider.tsx +27 -0
  94. package/src/infrastructure/routines/__tests__/routine.test.ts +368 -0
  95. package/src/infrastructure/routines/index.tsx +3 -0
  96. package/src/infrastructure/routines/routine.hook.ts +121 -0
  97. package/src/infrastructure/routines/routine.ts +283 -0
  98. package/src/infrastructure/routines/routine.tsx +283 -0
  99. package/src/infrastructure/stores/activity-lock.store.ts +22 -0
  100. package/src/infrastructure/stores/auth-user-connected.store.ts +24 -0
  101. package/src/infrastructure/stores/dataset.store.ts +106 -0
  102. package/src/infrastructure/stores/index.ts +6 -0
  103. package/src/infrastructure/stores/module.store.ts +266 -0
  104. package/src/infrastructure/stores/upload.store.ts +198 -0
  105. package/src/infrastructure/utilities/access-label.util.ts +158 -0
  106. package/src/infrastructure/utilities/activities.util.tsx +54 -0
  107. package/src/infrastructure/utilities/activity-lock.service.ts +263 -0
  108. package/src/infrastructure/utilities/activity-tracker.service.ts +205 -0
  109. package/src/infrastructure/utilities/api-service.ts +237 -0
  110. package/src/infrastructure/utilities/auth-logout.util.ts +23 -0
  111. package/src/infrastructure/utilities/classname.util.ts +7 -0
  112. package/src/infrastructure/utilities/encryption.service.ts +125 -0
  113. package/src/infrastructure/utilities/form-snapshot.service.ts +304 -0
  114. package/src/infrastructure/utilities/format.util.ts +40 -0
  115. package/src/infrastructure/utilities/index.tsx +23 -0
  116. package/src/infrastructure/utilities/media-label.service.ts +47 -0
  117. package/src/infrastructure/utilities/modules.ts +11 -0
  118. package/src/infrastructure/utilities/permission.util.ts +22 -0
  119. package/src/infrastructure/utilities/push-permission.util.ts +43 -0
  120. package/src/infrastructure/utilities/route-access.ts +38 -0
  121. package/src/infrastructure/utilities/socket-service.ts +123 -0
  122. package/src/infrastructure/utilities/sso-auth.util.ts +188 -0
  123. package/src/infrastructure/utilities/stringable.util.ts +16 -0
  124. package/src/infrastructure/utilities/strings.util.ts +18 -0
  125. package/src/infrastructure/utilities/tauri.util.ts +15 -0
  126. package/src/infrastructure/utilities/utils.ts +6 -0
  127. package/src/infrastructure/utilities/values.ts +5 -0
  128. package/src/presentation/8starlabs-ui/button.tsx +94 -0
  129. package/src/presentation/8starlabs-ui/flip-clock.tsx +368 -0
  130. package/src/presentation/8starlabs-ui/heatmap.tsx +430 -0
  131. package/src/presentation/8starlabs-ui/hooks/index.tsx +2 -0
  132. package/src/presentation/8starlabs-ui/hooks/use-mobile.ts +21 -0
  133. package/src/presentation/8starlabs-ui/index.tsx +20 -0
  134. package/src/presentation/8starlabs-ui/json-viewer.tsx +972 -0
  135. package/src/presentation/8starlabs-ui/marquee.tsx +134 -0
  136. package/src/presentation/8starlabs-ui/partition-bar.tsx +198 -0
  137. package/src/presentation/8starlabs-ui/scroll-fade.tsx +158 -0
  138. package/src/presentation/8starlabs-ui/status-indicator.tsx +86 -0
  139. package/src/presentation/8starlabs-ui/system-banner.tsx +50 -0
  140. package/src/presentation/8starlabs-ui/timeline.tsx +576 -0
  141. package/src/presentation/8starlabs-ui/transport-badge.tsx +249 -0
  142. package/src/presentation/8starlabs-ui/ui/copy-button.tsx +60 -0
  143. package/src/presentation/8starlabs-ui/ui/index.tsx +2 -0
  144. package/src/presentation/analytics-section.tsx +85 -0
  145. package/src/presentation/app-sidebar.tsx +234 -0
  146. package/src/presentation/charts/area-widget.chart-skeleton.tsx +61 -0
  147. package/src/presentation/charts/area-widget.chart.tsx +128 -0
  148. package/src/presentation/charts/chart-widgets.types.ts +81 -0
  149. package/src/presentation/charts/index.tsx +16 -0
  150. package/src/presentation/charts/line-widget.chart-skeleton.tsx +64 -0
  151. package/src/presentation/charts/line-widget.chart.tsx +105 -0
  152. package/src/presentation/charts/pie-widget.chart-skeleton.tsx +56 -0
  153. package/src/presentation/charts/pie-widget.chart.tsx +168 -0
  154. package/src/presentation/charts/radar-widget.chart-skeleton.tsx +67 -0
  155. package/src/presentation/charts/radar-widget.chart.tsx +80 -0
  156. package/src/presentation/charts/radial-stacked-widget.chart-skeleton.tsx +66 -0
  157. package/src/presentation/charts/radial-stacked-widget.chart.tsx +120 -0
  158. package/src/presentation/charts/radial-widget.chart-skeleton.tsx +61 -0
  159. package/src/presentation/charts/radial-widget.chart.tsx +87 -0
  160. package/src/presentation/charts/tooltip-widget.chart-skeleton.tsx +64 -0
  161. package/src/presentation/charts/tooltip-widget.chart.tsx +89 -0
  162. package/src/presentation/components/activity-actions.tsx +20 -0
  163. package/src/presentation/components/activity-container.tsx +55 -0
  164. package/src/presentation/components/activity-content.tsx +20 -0
  165. package/src/presentation/components/activity-descriptor-parser.tsx +37 -0
  166. package/src/presentation/components/activity-header.tsx +20 -0
  167. package/src/presentation/components/activity-loader.tsx +19 -0
  168. package/src/presentation/components/activity-title.tsx +32 -0
  169. package/src/presentation/components/activity.tsx +22 -0
  170. package/src/presentation/components/auth/index.tsx +4 -0
  171. package/src/presentation/components/auth/sso-callback.view.tsx +44 -0
  172. package/src/presentation/components/auth/sso-disconnect.view.tsx +41 -0
  173. package/src/presentation/components/auth/sso-sign-in.view.tsx +29 -0
  174. package/src/presentation/components/auth-lock-screen.tsx +309 -0
  175. package/src/presentation/components/auth-session.view.tsx +17 -0
  176. package/src/presentation/components/data-table.tsx +814 -0
  177. package/src/presentation/components/dynamic-icon.tsx +16 -0
  178. package/src/presentation/components/floating-upload.tsx +291 -0
  179. package/src/presentation/components/index.tsx +40 -0
  180. package/src/presentation/components/local-time.tsx +170 -0
  181. package/src/presentation/components/markdown-parser.tsx +201 -0
  182. package/src/presentation/components/message-scroller.tsx +131 -0
  183. package/src/presentation/components/module-first-access-config.view.tsx +181 -0
  184. package/src/presentation/components/module-first-access-pending.view.tsx +38 -0
  185. package/src/presentation/components/module-guard.tsx +34 -0
  186. package/src/presentation/components/modules-first-access.guard.tsx +88 -0
  187. package/src/presentation/components/modules-guard-forbidden.tsx +46 -0
  188. package/src/presentation/components/notification-details.modal.tsx +145 -0
  189. package/src/presentation/components/notification-item.tsx +127 -0
  190. package/src/presentation/components/notifications-popover.tsx +128 -0
  191. package/src/presentation/components/push-notifications.provider.tsx +65 -0
  192. package/src/presentation/components/upload-progress-dialog.tsx +140 -0
  193. package/src/presentation/components/waiting-bar.tsx +22 -0
  194. package/src/presentation/components/waiting-section.tsx +15 -0
  195. package/src/presentation/components/waiting.tsx +14 -0
  196. package/src/presentation/data-grid/data-grid-empty.tsx +24 -0
  197. package/src/presentation/data-grid/data-grid-search-engine.tsx +32 -0
  198. package/src/presentation/data-grid/data-grid.tsx +892 -0
  199. package/src/presentation/data-grid/index.tsx +4 -0
  200. package/src/presentation/form-screen.tsx +95 -0
  201. package/src/presentation/icons/custom.tsx +20 -0
  202. package/src/presentation/icons/glyphIcons.tsx +53 -0
  203. package/src/presentation/icons/icons.enum.ts +4 -0
  204. package/src/presentation/icons/icons.util.ts +6 -0
  205. package/src/presentation/icons/index.tsx +8 -0
  206. package/src/presentation/icons/lucide.tsx +17 -0
  207. package/src/presentation/icons/remix.tsx +33 -0
  208. package/src/presentation/icons/types.ts +27 -0
  209. package/src/presentation/index.tsx +45 -0
  210. package/src/presentation/modals/components/ModalBox.tsx +74 -0
  211. package/src/presentation/modals/components/ModalPortal.tsx +31 -0
  212. package/src/presentation/modals/components/ModalStepper.tsx +319 -0
  213. package/src/presentation/modals/components/ModalWrapper.tsx +65 -0
  214. package/src/presentation/modals/components/index.tsx +5 -0
  215. package/src/presentation/modals/hooks/index.ts +2 -0
  216. package/src/presentation/modals/hooks/useModal.ts +38 -0
  217. package/src/presentation/modals/index.tsx +5 -0
  218. package/src/presentation/modals/stores/index.ts +2 -0
  219. package/src/presentation/modals/stores/useModalStore.ts +90 -0
  220. package/src/presentation/modals/types/index.ts +2 -0
  221. package/src/presentation/modals/types/modal.type.ts +33 -0
  222. package/src/presentation/module-menubar.tsx +300 -0
  223. package/src/presentation/module-widget.tsx +233 -0
  224. package/src/presentation/nav-documents.tsx +89 -0
  225. package/src/presentation/nav-main.tsx +62 -0
  226. package/src/presentation/nav-secondary.tsx +41 -0
  227. package/src/presentation/nav-user.tsx +109 -0
  228. package/src/presentation/permission-action-badge.tsx +35 -0
  229. package/src/presentation/reui/index.tsx +3 -0
  230. package/src/presentation/reui/stepper.tsx +508 -0
  231. package/src/presentation/reui/timeline.tsx +226 -0
  232. package/src/presentation/sheets/index.tsx +2 -0
  233. package/src/presentation/sheets/legacy-sheet-header.tsx +0 -0
  234. package/src/presentation/sheets/legacy-sheet.tsx +37 -0
  235. package/src/presentation/size.enum.ts +19 -0
  236. package/src/presentation/system/index.tsx +3 -0
  237. package/src/presentation/system/logo.theme.tsx +21 -0
  238. package/src/presentation/system/types.ts +10 -0
  239. package/src/presentation/theme/index.tsx +6 -0
  240. package/src/presentation/theme/prefer-color-scheme.tsx +50 -0
  241. package/src/presentation/theme/switch-color-scheme.tsx +16 -0
  242. package/src/presentation/theme/theme-switcher-button.tsx +20 -0
  243. package/src/presentation/theme/theme.enum.ts +4 -0
  244. package/src/presentation/theme/theme.store.ts +87 -0
  245. package/src/presentation/themes/index.tsx +2 -0
  246. package/src/presentation/themes/katon/dashboard-layout.tsx +1080 -0
  247. package/src/presentation/themes/katon/edge-section.tsx +19 -0
  248. package/src/presentation/themes/katon/header-menubar.tsx +270 -0
  249. package/src/presentation/themes/katon/header-modules-available.tsx +44 -0
  250. package/src/presentation/themes/katon/header-modules-recents.tsx +52 -0
  251. package/src/presentation/themes/katon/header-modules-store.tsx +25 -0
  252. package/src/presentation/themes/katon/header-options.tsx +13 -0
  253. package/src/presentation/themes/katon/header-organization-select.tsx +146 -0
  254. package/src/presentation/themes/katon/header-routines.tsx +74 -0
  255. package/src/presentation/themes/katon/header-tasks-connected-user.tsx +150 -0
  256. package/src/presentation/themes/katon/index.tsx +16 -0
  257. package/src/presentation/themes/katon/main-wrapper.tsx +34 -0
  258. package/src/presentation/themes/katon/module-item-link.tsx +32 -0
  259. package/src/presentation/themes/katon/view-frame.tsx +25 -0
  260. package/src/presentation/themes/katon/view-helmet.tsx +53 -0
  261. package/src/presentation/themes/katon/view-status.tsx +32 -0
  262. package/src/presentation/themes/katon/view-wrapper.tsx +15 -0
  263. package/src/presentation/themes/katon/view.tsx +42 -0
  264. package/src/presentation/ui/accordion-multiselect.tsx +206 -0
  265. package/src/presentation/ui/accordion.tsx +81 -0
  266. package/src/presentation/ui/alert-dialog.tsx +199 -0
  267. package/src/presentation/ui/alert.tsx +76 -0
  268. package/src/presentation/ui/aspect-ratio.tsx +11 -0
  269. package/src/presentation/ui/attachment.tsx +204 -0
  270. package/src/presentation/ui/avatar.tsx +112 -0
  271. package/src/presentation/ui/badge.tsx +49 -0
  272. package/src/presentation/ui/breadcrumb.tsx +122 -0
  273. package/src/presentation/ui/bubble.tsx +125 -0
  274. package/src/presentation/ui/button-group.tsx +83 -0
  275. package/src/presentation/ui/button.tsx +87 -0
  276. package/src/presentation/ui/calendar.tsx +222 -0
  277. package/src/presentation/ui/card.tsx +106 -0
  278. package/src/presentation/ui/carousel.tsx +242 -0
  279. package/src/presentation/ui/chart.tsx +373 -0
  280. package/src/presentation/ui/checkbox.tsx +33 -0
  281. package/src/presentation/ui/clickable.tsx +58 -0
  282. package/src/presentation/ui/collapsible.tsx +33 -0
  283. package/src/presentation/ui/color-swatch-selector.tsx +81 -0
  284. package/src/presentation/ui/combobox.tsx +299 -0
  285. package/src/presentation/ui/command.tsx +195 -0
  286. package/src/presentation/ui/context-menu.tsx +263 -0
  287. package/src/presentation/ui/dialog.tsx +168 -0
  288. package/src/presentation/ui/direction.tsx +22 -0
  289. package/src/presentation/ui/drawer.tsx +134 -0
  290. package/src/presentation/ui/dropdown-menu.tsx +269 -0
  291. package/src/presentation/ui/empty.tsx +104 -0
  292. package/src/presentation/ui/field.tsx +238 -0
  293. package/src/presentation/ui/granularity-selector.tsx +58 -0
  294. package/src/presentation/ui/hover-card.tsx +44 -0
  295. package/src/presentation/ui/index.tsx +74 -0
  296. package/src/presentation/ui/input-group.tsx +156 -0
  297. package/src/presentation/ui/input-otp.tsx +87 -0
  298. package/src/presentation/ui/input.tsx +19 -0
  299. package/src/presentation/ui/item.tsx +196 -0
  300. package/src/presentation/ui/kpi-card.tsx +203 -0
  301. package/src/presentation/ui/label-selector.tsx +100 -0
  302. package/src/presentation/ui/label.tsx +24 -0
  303. package/src/presentation/ui/legacy-birth-date-input.tsx +43 -0
  304. package/src/presentation/ui/legacy-color-picker/index.tsx +42 -0
  305. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.content.tsx +37 -0
  306. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.context.tsx +42 -0
  307. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.hex-input.tsx +97 -0
  308. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.picker.tsx +266 -0
  309. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.presets.ts +22 -0
  310. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.quick-list.tsx +49 -0
  311. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.recent.tsx +43 -0
  312. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.swatches.tsx +111 -0
  313. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.trigger.tsx +128 -0
  314. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.tsx +110 -0
  315. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.types.ts +1 -0
  316. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.utils.ts +114 -0
  317. package/src/presentation/ui/legacy-country-input.tsx +171 -0
  318. package/src/presentation/ui/legacy-gender-input.tsx +22 -0
  319. package/src/presentation/ui/legacy-input.tsx +106 -0
  320. package/src/presentation/ui/legacy-phone-input.tsx +213 -0
  321. package/src/presentation/ui/legacy-select-input.tsx +114 -0
  322. package/src/presentation/ui/legacy-text-area.tsx +111 -0
  323. package/src/presentation/ui/list-items.tsx +59 -0
  324. package/src/presentation/ui/marker.tsx +69 -0
  325. package/src/presentation/ui/media-player/index.tsx +12 -0
  326. package/src/presentation/ui/media-player/media-player.context.tsx +36 -0
  327. package/src/presentation/ui/media-player/media-player.tsx +167 -0
  328. package/src/presentation/ui/media-player/player-controls.tsx +207 -0
  329. package/src/presentation/ui/media-player/players/audio-player.tsx +78 -0
  330. package/src/presentation/ui/media-player/players/index.tsx +4 -0
  331. package/src/presentation/ui/media-player/players/video-player.tsx +193 -0
  332. package/src/presentation/ui/media-player/players/voice-note-player.tsx +108 -0
  333. package/src/presentation/ui/media-player/use-media-player.hook.ts +263 -0
  334. package/src/presentation/ui/menubar.tsx +281 -0
  335. package/src/presentation/ui/message.tsx +92 -0
  336. package/src/presentation/ui/navigation-menu.tsx +172 -0
  337. package/src/presentation/ui/pagination.tsx +129 -0
  338. package/src/presentation/ui/popover.tsx +89 -0
  339. package/src/presentation/ui/progress.tsx +31 -0
  340. package/src/presentation/ui/resizable.tsx +50 -0
  341. package/src/presentation/ui/select.tsx +192 -0
  342. package/src/presentation/ui/separator.tsx +28 -0
  343. package/src/presentation/ui/sheet.tsx +147 -0
  344. package/src/presentation/ui/sidebar.tsx +702 -0
  345. package/src/presentation/ui/skeleton.tsx +13 -0
  346. package/src/presentation/ui/slide-to-confirm.tsx +129 -0
  347. package/src/presentation/ui/slider.tsx +59 -0
  348. package/src/presentation/ui/sonner.tsx +58 -0
  349. package/src/presentation/ui/switch.tsx +33 -0
  350. package/src/presentation/ui/table.tsx +116 -0
  351. package/src/presentation/ui/tabs.tsx +90 -0
  352. package/src/presentation/ui/text-gradient.tsx +84 -0
  353. package/src/presentation/ui/textarea.tsx +18 -0
  354. package/src/presentation/ui/timeline-steps.tsx +235 -0
  355. package/src/presentation/ui/toggle-group.tsx +89 -0
  356. package/src/presentation/ui/toggle.tsx +47 -0
  357. package/src/presentation/ui/tooltip.tsx +57 -0
  358. package/src/presentation/uploading/index.tsx +3 -0
  359. package/src/presentation/uploading/media-upload-field.tsx +152 -0
  360. package/src/presentation/uploading/storage-media.tsx +210 -0
  361. package/src/styles.css +403 -0
  362. package/src/themes.css +1038 -0
@@ -0,0 +1,108 @@
1
+ "use client"
2
+
3
+ import * as React from "react";
4
+ import {MicIcon, PauseIcon, PlayIcon} from "lucide-react";
5
+
6
+ import {cn} from "../../../../infrastructure/utilities/utils";
7
+ import {usePlayer} from "../media-player.context";
8
+ import {formatMediaTime} from "../player-controls";
9
+ import {ButtonGhost} from "../player-controls";
10
+
11
+ /**
12
+ Apparence « note vocale » inspirée de WhatsApp : bulle arrondie avec bouton
13
+ de lecture, forme d'onde cliquable pour naviguer, temps restant décompté et
14
+ cycle de vitesse 1× → 1,5× → 2×.
15
+ */
16
+ export function VoiceNotePlayer() {
17
+ const {controller, accentClassName} = usePlayer();
18
+ const {isPlaying, currentTime, duration, rate, seekMin, seekMax} = controller.state;
19
+ const {togglePlay, seekTo, cycleRate} = controller.actions;
20
+ const barsRef = React.useRef<HTMLDivElement | null>(null);
21
+
22
+ // En lecture on affiche le restant (décompte WhatsApp), sinon la durée totale.
23
+ const total = Number.isFinite(duration) && duration > 0 ? duration : seekMax;
24
+ const remaining = Math.max(total - currentTime, 0);
25
+ const fraction = total > 0 ? Math.min(currentTime / total, 1) : 0;
26
+
27
+ const seekFromPointer = (clientX: number) => {
28
+ const bars = barsRef.current;
29
+ if (!bars) return;
30
+ const rect = bars.getBoundingClientRect();
31
+ const ratio = rect.width > 0 ? Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1) : 0;
32
+ seekTo(ratio * total);
33
+ };
34
+
35
+ return (
36
+ <div
37
+ data-slot="voice-note"
38
+ className="flex w-full max-w-xs items-center gap-2.5 rounded-full bg-secondary/80 py-2 pr-3 pl-2"
39
+ >
40
+ {/* Pastille micro à la place de l'avatar d'expéditeur */}
41
+ <span
42
+ aria-hidden
43
+ className="flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground"
44
+ >
45
+ <MicIcon className="size-4"/>
46
+ </span>
47
+
48
+ <ButtonGhost
49
+ label={isPlaying ? "Pause (Espace)" : "Lire la note vocale (Espace)"}
50
+ onClick={togglePlay}
51
+ className={cn("size-8 bg-primary/10 hover:bg-primary/20", accentClassName)}
52
+ >
53
+ {isPlaying ? <PauseIcon className="size-4 fill-current"/> : <PlayIcon className="size-4 fill-current"/>}
54
+ </ButtonGhost>
55
+
56
+ {/* Forme d'onde : hauteur pseudo-aléatoire déterministe (SSR-safe), remplie selon l'avancement */}
57
+ <div
58
+ ref={barsRef}
59
+ role="slider"
60
+ tabIndex={0}
61
+ aria-label="Position dans la note vocale"
62
+ aria-valuemin={0}
63
+ aria-valuemax={Math.round(total)}
64
+ aria-valuenow={Math.round(currentTime)}
65
+ aria-valuetext={`${formatMediaTime(currentTime)} sur ${formatMediaTime(total)}`}
66
+ className="group/wave relative flex h-8 min-w-0 flex-1 cursor-pointer touch-none items-center gap-[2px]"
67
+ onPointerDown={(event) => {
68
+ event.currentTarget.setPointerCapture(event.pointerId);
69
+ seekFromPointer(event.clientX);
70
+ }}
71
+ onPointerMove={(event) => {
72
+ if (event.buttons === 1) seekFromPointer(event.clientX);
73
+ }}
74
+ >
75
+ {Array.from({length: 30}, (_, index) => {
76
+ const seedFraction = Math.abs(Math.sin((index + 1) * 12.9898)) % 1;
77
+ const height = 18 + seedFraction * 82; // pourcentage de h-8
78
+ const active = index / 30 <= fraction;
79
+ return (
80
+ <span
81
+ key={index}
82
+ aria-hidden
83
+ className={cn(
84
+ "w-[3px] shrink-0 rounded-full transition-colors",
85
+ active ? cn("bg-primary", accentClassName) : "bg-muted-foreground/35",
86
+ )}
87
+ style={{height: `${height}%`}}
88
+ />
89
+ );
90
+ })}
91
+ </div>
92
+
93
+ <span className="shrink-0 text-xs tabular-nums text-muted-foreground select-none">
94
+ {formatMediaTime(isPlaying || currentTime > 0 ? remaining : total)}
95
+ </span>
96
+
97
+ <button
98
+ type="button"
99
+ onClick={cycleRate}
100
+ title="Vitesse de lecture"
101
+ aria-label={`Vitesse de lecture ${rate}×`}
102
+ className="shrink-0 cursor-pointer rounded px-1 text-[11px] font-semibold text-muted-foreground tabular-nums outline-hidden hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
103
+ >
104
+ {String(rate).replace(".", ",")}×
105
+ </button>
106
+ </div>
107
+ );
108
+ }
@@ -0,0 +1,263 @@
1
+ "use client"
2
+
3
+ import * as React from "react";
4
+
5
+ /** Vitesses de lecture proposées par le menu « vitesse » (style YouTube). */
6
+ export const DEFAULT_PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
7
+ /** Vitesses de la note vocale (cycle au clic, style WhatsApp). */
8
+ export const VOICE_NOTE_PLAYBACK_RATES = [1, 1.5, 2];
9
+
10
+ export interface UseMediaPlayerOptions {
11
+ /** URL du média : fichier (mp3, mp4, webm…) ou flux live HLS (.m3u8). */
12
+ src: string;
13
+ /** Force l'affichage « direct » même si la durée est finie. */
14
+ live?: boolean;
15
+ /** Démarrage automatique (ignoré si le navigateur le bloque). */
16
+ autoPlay?: boolean;
17
+ /** Vitesses de lecture disponibles dans le menu. */
18
+ rates?: number[];
19
+ }
20
+
21
+ /**
22
+ Cœur logique partagé par les trois apparences du lecteur : état de lecture,
23
+ progression + tampon, volume, vitesse, plein écran, Picture-in-Picture et
24
+ gestion des flux live (durée infinie / fenêtre DVR seekable).
25
+
26
+ Le flux HLS est pris en charge nativement (Safari/iOS) ou via hls.js chargé
27
+ dynamiquement pour les autres navigateurs — aucun coût tant qu'on ne diffuse
28
+ pas de .m3u8.
29
+ */
30
+ export function useMediaPlayer({src, live, autoPlay = false, rates = DEFAULT_PLAYBACK_RATES}: UseMediaPlayerOptions) {
31
+ const mediaRef = React.useRef<HTMLMediaElement | null>(null);
32
+ const containerRef = React.useRef<HTMLDivElement | null>(null);
33
+
34
+ const [isPlaying, setIsPlaying] = React.useState(false);
35
+ const [currentTime, setCurrentTime] = React.useState(0);
36
+ const [duration, setDuration] = React.useState(0);
37
+ const [bufferedEnd, setBufferedEnd] = React.useState(0);
38
+ const [volume, setVolumeState] = React.useState(1);
39
+ const [muted, setMutedState] = React.useState(false);
40
+ const [rate, setRateState] = React.useState(1);
41
+ const [isLoading, setIsLoading] = React.useState(false);
42
+ const [isFullscreen, setIsFullscreen] = React.useState(false);
43
+ const [error, setError] = React.useState<string | null>(null);
44
+
45
+ // ------------------------------------------------------------------
46
+ // Détection du direct
47
+ // ------------------------------------------------------------------
48
+
49
+ const [seekWindow, setSeekWindow] = React.useState<{start: number; end: number} | null>(null);
50
+
51
+ const isLive = React.useMemo(
52
+ () => Boolean(live) || duration === Infinity || (!Number.isFinite(duration) && duration > 0) || seekWindow !== null && duration === Infinity,
53
+ [live, duration, seekWindow],
54
+ );
55
+
56
+ /** Bornes de scrub : fenêtre DVR en direct, sinon [0, durée]. */
57
+ const seekMin = isLive ? seekWindow?.start ?? 0 : 0;
58
+ const seekMax = isLive ? seekWindow?.end ?? currentTime : duration || 0;
59
+
60
+ // ------------------------------------------------------------------
61
+ // Attachement de la source (HLS natif ou hls.js dynamique)
62
+ // ------------------------------------------------------------------
63
+
64
+ React.useEffect(() => {
65
+ const element = mediaRef.current;
66
+ if (!element || !src) return;
67
+
68
+ setError(null);
69
+ if (!/\.m3u8($|[?#])/i.test(src)) {
70
+ element.src = src;
71
+ return;
72
+ }
73
+
74
+ // Safari lit le HLS nativement ; les autres via hls.js importé à la demande.
75
+ if (element.canPlayType("application/vnd.apple.mpegurl")) {
76
+ element.src = src;
77
+ return;
78
+ }
79
+
80
+ let cancelled = false;
81
+ let destroy: (() => void) | null = null;
82
+
83
+ void import("hls.js")
84
+ .then(({default: Hls}) => {
85
+ const target = mediaRef.current;
86
+ if (cancelled || !target || !Hls.isSupported()) return;
87
+ const instance = new Hls({lowLatencyMode: true, backBufferLength: 90});
88
+ instance.loadSource(src);
89
+ instance.attachMedia(target);
90
+ instance.on(Hls.Events.ERROR, (_event, data) => {
91
+ if (data.fatal) setError("Flux indisponible");
92
+ });
93
+ destroy = () => instance.destroy();
94
+ })
95
+ .catch(() => setError("Lecteur HLS indisponible"));
96
+
97
+ return () => {
98
+ cancelled = true;
99
+ destroy?.();
100
+ };
101
+ }, [src]);
102
+
103
+ // ------------------------------------------------------------------
104
+ // Écouteurs d'événements média
105
+ // ------------------------------------------------------------------
106
+
107
+ React.useEffect(() => {
108
+ const element = mediaRef.current;
109
+ if (!element) return;
110
+
111
+ const syncTime = () => {
112
+ setCurrentTime(element.currentTime);
113
+ if (element.seekable.length > 0) {
114
+ setSeekWindow({start: element.seekable.start(0), end: element.seekable.end(element.seekable.length - 1)});
115
+ }
116
+ };
117
+ const syncBuffer = () => {
118
+ for (let index = 0; index < element.buffered.length; index += 1) {
119
+ if (element.buffered.start(index) <= element.currentTime && element.currentTime <= element.buffered.end(index)) {
120
+ setBufferedEnd(element.buffered.end(index));
121
+ break;
122
+ }
123
+ }
124
+ };
125
+
126
+ const onLoadedMetadata = () => {
127
+ setDuration(element.duration);
128
+ if (autoPlay) void element.play().catch(() => undefined);
129
+ };
130
+ const onPlay = () => setIsPlaying(true);
131
+ const onPause = () => setIsPlaying(false);
132
+ const onWaiting = () => setIsLoading(true);
133
+ const onPlaying = () => setIsLoading(false);
134
+ const onCanPlay = () => setIsLoading(false);
135
+ const onVolumeChange = () => {
136
+ setVolumeState(element.volume);
137
+ setMutedState(element.muted);
138
+ };
139
+ const onRateChange = () => setRateState(element.playbackRate);
140
+ const onError = () => setError("Lecture impossible");
141
+
142
+ element.addEventListener("loadedmetadata", onLoadedMetadata);
143
+ element.addEventListener("timeupdate", syncTime);
144
+ element.addEventListener("progress", syncBuffer);
145
+ element.addEventListener("play", onPlay);
146
+ element.addEventListener("pause", onPause);
147
+ element.addEventListener("waiting", onWaiting);
148
+ element.addEventListener("playing", onPlaying);
149
+ element.addEventListener("canplay", onCanPlay);
150
+ element.addEventListener("volumechange", onVolumeChange);
151
+ element.addEventListener("ratechange", onRateChange);
152
+ element.addEventListener("error", onError);
153
+ return () => {
154
+ element.removeEventListener("loadedmetadata", onLoadedMetadata);
155
+ element.removeEventListener("timeupdate", syncTime);
156
+ element.removeEventListener("progress", syncBuffer);
157
+ element.removeEventListener("play", onPlay);
158
+ element.removeEventListener("pause", onPause);
159
+ element.removeEventListener("waiting", onWaiting);
160
+ element.removeEventListener("playing", onPlaying);
161
+ element.removeEventListener("canplay", onCanPlay);
162
+ element.removeEventListener("volumechange", onVolumeChange);
163
+ element.removeEventListener("ratechange", onRateChange);
164
+ element.removeEventListener("error", onError);
165
+ };
166
+ }, [autoPlay]);
167
+
168
+ // Suivi du plein écran (échappement clavier, sortie via le navigateur…)
169
+ React.useEffect(() => {
170
+ const onFullscreenChange = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
171
+ document.addEventListener("fullscreenchange", onFullscreenChange);
172
+ return () => document.removeEventListener("fullscreenchange", onFullscreenChange);
173
+ }, []);
174
+
175
+ // ------------------------------------------------------------------
176
+ // Actions
177
+ // ------------------------------------------------------------------
178
+
179
+ const play = React.useCallback(async () => {
180
+ try {
181
+ await mediaRef.current?.play();
182
+ } catch { /* lecture refusée par le navigateur (autoplay policy) */ }
183
+ }, []);
184
+
185
+ const pause = React.useCallback(() => {
186
+ mediaRef.current?.pause();
187
+ }, []);
188
+
189
+ const togglePlay = React.useCallback(() => {
190
+ const element = mediaRef.current;
191
+ if (!element) return;
192
+ if (element.paused) void play();
193
+ else element.pause();
194
+ }, [play]);
195
+
196
+ const seekTo = React.useCallback((time: number) => {
197
+ const element = mediaRef.current;
198
+ if (!element) return;
199
+ const max = element.duration === Infinity ? (element.seekable.length ? element.seekable.end(element.seekable.length - 1) : element.currentTime) : element.duration;
200
+ element.currentTime = Math.max(0, Math.min(time, Number.isFinite(max) ? max : time));
201
+ setCurrentTime(element.currentTime);
202
+ }, []);
203
+
204
+ const seekBy = React.useCallback((delta: number) => {
205
+ const element = mediaRef.current;
206
+ if (!element) return;
207
+ seekTo(element.currentTime + delta);
208
+ }, [seekTo]);
209
+
210
+ const jumpToFraction = React.useCallback((fraction: number) => {
211
+ if (isLive) return;
212
+ seekTo(fraction * duration);
213
+ }, [duration, isLive, seekTo]);
214
+
215
+ const setVolume = React.useCallback((next: number) => {
216
+ const element = mediaRef.current;
217
+ if (!element) return;
218
+ element.volume = Math.max(0, Math.min(1, next));
219
+ if (next > 0 && element.muted) element.muted = false;
220
+ }, []);
221
+
222
+ const toggleMute = React.useCallback(() => {
223
+ const element = mediaRef.current;
224
+ if (!element) return;
225
+ element.muted = !element.muted;
226
+ }, []);
227
+
228
+ const setRate = React.useCallback((next: number) => {
229
+ if (mediaRef.current) mediaRef.current.playbackRate = next;
230
+ }, []);
231
+
232
+ const cycleRate = React.useCallback(() => {
233
+ const index = rates.indexOf(rate);
234
+ const next = rates[(index + 1) % rates.length] ?? rates[0] ?? 1;
235
+ setRate(next);
236
+ }, [rate, rates, setRate]);
237
+
238
+ const toggleFullscreen = React.useCallback(() => {
239
+ const container = containerRef.current;
240
+ if (!container) return;
241
+ if (document.fullscreenElement === container) void document.exitFullscreen().catch(() => undefined);
242
+ else void container.requestFullscreen?.().catch(() => undefined);
243
+ }, []);
244
+
245
+ const togglePictureInPicture = React.useCallback(async () => {
246
+ const element = mediaRef.current;
247
+ if (!element || !document.pictureInPictureEnabled || !(element instanceof HTMLVideoElement)) return;
248
+ try {
249
+ if (document.pictureInPictureElement === element) await document.exitPictureInPicture();
250
+ else await element.requestPictureInPicture();
251
+ } catch { /* PiP refusé (format non supporté, permissions…) */ }
252
+ }, []);
253
+
254
+ return {
255
+ mediaRef,
256
+ containerRef,
257
+ state: {isPlaying, currentTime, duration, bufferedEnd, volume, muted, rate, isLoading, isLive, isFullscreen, error, seekMin, seekMax},
258
+ actions: {play, pause, togglePlay, seekTo, seekBy, jumpToFraction, setVolume, toggleMute, setRate, cycleRate, toggleFullscreen, togglePictureInPicture},
259
+ options: {rates},
260
+ };
261
+ }
262
+
263
+ export type MediaPlayerController = ReturnType<typeof useMediaPlayer>;
@@ -0,0 +1,281 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Menubar as MenubarPrimitive } from "radix-ui"
5
+ import { CheckIcon, ChevronRightIcon } from "lucide-react"
6
+ import {cn} from "../../infrastructure/utilities/utils";
7
+
8
+ function Menubar({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof MenubarPrimitive.Root>) {
12
+ return (
13
+ <MenubarPrimitive.Root
14
+ data-slot="menubar"
15
+ className={cn(
16
+ "flex h-8 items-center gap-0.5 rounded-lg border p-[3px]",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ )
22
+ }
23
+
24
+ function MenubarMenu({
25
+ ...props
26
+ }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
27
+ return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />
28
+ }
29
+
30
+ function MenubarGroup({
31
+ ...props
32
+ }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
33
+ return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />
34
+ }
35
+
36
+ function MenubarPortal({
37
+ ...props
38
+ }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
39
+ return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />
40
+ }
41
+
42
+ function MenubarRadioGroup({
43
+ ...props
44
+ }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
45
+ return (
46
+ <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
47
+ )
48
+ }
49
+
50
+ function MenubarTrigger({
51
+ className,
52
+ ...props
53
+ }: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
54
+ return (
55
+ <MenubarPrimitive.Trigger
56
+ data-slot="menubar-trigger"
57
+ className={cn(
58
+ "flex items-center rounded-sm px-1.5 py-[2px] text-sm font-medium outline-hidden select-none hover:bg-muted aria-expanded:bg-muted",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ function MenubarContent({
67
+ className,
68
+ align = "start",
69
+ alignOffset = -4,
70
+ sideOffset = -4,
71
+ ...props
72
+ }: React.ComponentProps<typeof MenubarPrimitive.Content>) {
73
+ return (
74
+ <MenubarPortal>
75
+ <MenubarPrimitive.Content
76
+ data-slot="menubar-content"
77
+ align={align}
78
+ alignOffset={alignOffset}
79
+ sideOffset={sideOffset}
80
+ className={cn("z-50 min-w-36 origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95", className )}
81
+ {...props}
82
+ />
83
+ </MenubarPortal>
84
+ )
85
+ }
86
+
87
+ function MenubarItem({
88
+ className,
89
+ inset,
90
+ variant = "default",
91
+ ...props
92
+ }: React.ComponentProps<typeof MenubarPrimitive.Item> & {
93
+ inset?: boolean
94
+ variant?: "default" | "destructive"
95
+ }) {
96
+ return (
97
+ <MenubarPrimitive.Item
98
+ data-slot="menubar-item"
99
+ data-inset={inset}
100
+ data-variant={variant}
101
+ className={cn(
102
+ "group/menubar-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive!",
103
+ className
104
+ )}
105
+ {...props}
106
+ />
107
+ )
108
+ }
109
+
110
+ function MenubarCheckboxItem({
111
+ className,
112
+ children,
113
+ checked,
114
+ inset,
115
+ ...props
116
+ }: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem> & {
117
+ inset?: boolean
118
+ }) {
119
+ return (
120
+ <MenubarPrimitive.CheckboxItem
121
+ data-slot="menubar-checkbox-item"
122
+ data-inset={inset}
123
+ className={cn(
124
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
125
+ className
126
+ )}
127
+ checked={checked}
128
+ {...props}
129
+ >
130
+ <span className="pointer-events-none absolute left-1.5 flex size-4 items-center justify-center [&_svg:not([class*='size-'])]:size-4">
131
+ <MenubarPrimitive.ItemIndicator>
132
+ <CheckIcon
133
+ />
134
+ </MenubarPrimitive.ItemIndicator>
135
+ </span>
136
+ {children}
137
+ </MenubarPrimitive.CheckboxItem>
138
+ )
139
+ }
140
+
141
+ function MenubarRadioItem({
142
+ className,
143
+ children,
144
+ inset,
145
+ ...props
146
+ }: React.ComponentProps<typeof MenubarPrimitive.RadioItem> & {
147
+ inset?: boolean
148
+ }) {
149
+ return (
150
+ <MenubarPrimitive.RadioItem
151
+ data-slot="menubar-radio-item"
152
+ data-inset={inset}
153
+ className={cn(
154
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
155
+ className
156
+ )}
157
+ {...props}
158
+ >
159
+ <span className="pointer-events-none absolute left-1.5 flex size-4 items-center justify-center [&_svg:not([class*='size-'])]:size-4">
160
+ <MenubarPrimitive.ItemIndicator>
161
+ <CheckIcon
162
+ />
163
+ </MenubarPrimitive.ItemIndicator>
164
+ </span>
165
+ {children}
166
+ </MenubarPrimitive.RadioItem>
167
+ )
168
+ }
169
+
170
+ function MenubarLabel({
171
+ className,
172
+ inset,
173
+ ...props
174
+ }: React.ComponentProps<typeof MenubarPrimitive.Label> & {
175
+ inset?: boolean
176
+ }) {
177
+ return (
178
+ <MenubarPrimitive.Label
179
+ data-slot="menubar-label"
180
+ data-inset={inset}
181
+ className={cn(
182
+ "px-1.5 py-1 text-sm font-medium data-inset:pl-7",
183
+ className
184
+ )}
185
+ {...props}
186
+ />
187
+ )
188
+ }
189
+
190
+ function MenubarSeparator({
191
+ className,
192
+ ...props
193
+ }: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
194
+ return (
195
+ <MenubarPrimitive.Separator
196
+ data-slot="menubar-separator"
197
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
198
+ {...props}
199
+ />
200
+ )
201
+ }
202
+
203
+ function MenubarShortcut({
204
+ className,
205
+ ...props
206
+ }: React.ComponentProps<"span">) {
207
+ return (
208
+ <span
209
+ data-slot="menubar-shortcut"
210
+ className={cn(
211
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/menubar-item:text-accent-foreground",
212
+ className
213
+ )}
214
+ {...props}
215
+ />
216
+ )
217
+ }
218
+
219
+ function MenubarSub({
220
+ ...props
221
+ }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
222
+ return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />
223
+ }
224
+
225
+ function MenubarSubTrigger({
226
+ className,
227
+ inset,
228
+ children,
229
+ ...props
230
+ }: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
231
+ inset?: boolean
232
+ }) {
233
+ return (
234
+ <MenubarPrimitive.SubTrigger
235
+ data-slot="menubar-sub-trigger"
236
+ data-inset={inset}
237
+ className={cn(
238
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4",
239
+ className
240
+ )}
241
+ {...props}
242
+ >
243
+ {children}
244
+ <ChevronRightIcon className="ml-auto size-4" />
245
+ </MenubarPrimitive.SubTrigger>
246
+ )
247
+ }
248
+
249
+ function MenubarSubContent({
250
+ className,
251
+ sideOffset = -4,
252
+ ...props
253
+ }: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
254
+ return (
255
+ <MenubarPrimitive.SubContent
256
+ data-slot="menubar-sub-content"
257
+ sideOffset={sideOffset}
258
+ className={cn("z-50 min-w-32 origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
259
+ {...props}
260
+ />
261
+ )
262
+ }
263
+
264
+ export {
265
+ Menubar,
266
+ MenubarPortal,
267
+ MenubarMenu,
268
+ MenubarTrigger,
269
+ MenubarContent,
270
+ MenubarGroup,
271
+ MenubarSeparator,
272
+ MenubarLabel,
273
+ MenubarItem,
274
+ MenubarShortcut,
275
+ MenubarCheckboxItem,
276
+ MenubarRadioGroup,
277
+ MenubarRadioItem,
278
+ MenubarSub,
279
+ MenubarSubTrigger,
280
+ MenubarSubContent,
281
+ }