@entifix/next-shell 0.1.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +19 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/back-office/account-menu.d.ts +29 -0
  8. package/dist/lib/back-office/account-menu.d.ts.map +1 -0
  9. package/dist/lib/back-office/account-menu.js +70 -0
  10. package/dist/lib/back-office/account-menu.js.map +1 -0
  11. package/dist/lib/back-office/back-office-shell.d.ts +50 -0
  12. package/dist/lib/back-office/back-office-shell.d.ts.map +1 -0
  13. package/dist/lib/back-office/back-office-shell.js +128 -0
  14. package/dist/lib/back-office/back-office-shell.js.map +1 -0
  15. package/dist/lib/back-office/breadcrumbs.d.ts +16 -0
  16. package/dist/lib/back-office/breadcrumbs.d.ts.map +1 -0
  17. package/dist/lib/back-office/breadcrumbs.js +53 -0
  18. package/dist/lib/back-office/breadcrumbs.js.map +1 -0
  19. package/dist/lib/back-office/group-by-screen-type.d.ts +21 -0
  20. package/dist/lib/back-office/group-by-screen-type.d.ts.map +1 -0
  21. package/dist/lib/back-office/group-by-screen-type.js +39 -0
  22. package/dist/lib/back-office/group-by-screen-type.js.map +1 -0
  23. package/dist/lib/back-office/index.d.ts +6 -0
  24. package/dist/lib/back-office/index.d.ts.map +1 -0
  25. package/dist/lib/back-office/index.js +7 -0
  26. package/dist/lib/back-office/index.js.map +1 -0
  27. package/dist/lib/back-office/nav.d.ts +39 -0
  28. package/dist/lib/back-office/nav.d.ts.map +1 -0
  29. package/dist/lib/back-office/nav.js +3 -0
  30. package/dist/lib/back-office/nav.js.map +1 -0
  31. package/dist/lib/back-office/sidebar-nav.d.ts +26 -0
  32. package/dist/lib/back-office/sidebar-nav.d.ts.map +1 -0
  33. package/dist/lib/back-office/sidebar-nav.js +181 -0
  34. package/dist/lib/back-office/sidebar-nav.js.map +1 -0
  35. package/dist/lib/command-palette/command-palette-host.d.ts +41 -0
  36. package/dist/lib/command-palette/command-palette-host.d.ts.map +1 -0
  37. package/dist/lib/command-palette/command-palette-host.js +196 -0
  38. package/dist/lib/command-palette/command-palette-host.js.map +1 -0
  39. package/dist/lib/command-palette/index.d.ts +9 -0
  40. package/dist/lib/command-palette/index.d.ts.map +1 -0
  41. package/dist/lib/command-palette/index.js +10 -0
  42. package/dist/lib/command-palette/index.js.map +1 -0
  43. package/dist/lib/command-palette/palette-command.d.ts +32 -0
  44. package/dist/lib/command-palette/palette-command.d.ts.map +1 -0
  45. package/dist/lib/command-palette/palette-command.js +19 -0
  46. package/dist/lib/command-palette/palette-command.js.map +1 -0
  47. package/dist/lib/command-palette/use-command-recency.d.ts +28 -0
  48. package/dist/lib/command-palette/use-command-recency.d.ts.map +1 -0
  49. package/dist/lib/command-palette/use-command-recency.js +67 -0
  50. package/dist/lib/command-palette/use-command-recency.js.map +1 -0
  51. package/dist/lib/command-palette/use-command-source.d.ts +17 -0
  52. package/dist/lib/command-palette/use-command-source.d.ts.map +1 -0
  53. package/dist/lib/command-palette/use-command-source.js +70 -0
  54. package/dist/lib/command-palette/use-command-source.js.map +1 -0
  55. package/dist/lib/command-palette/use-nav-source.d.ts +21 -0
  56. package/dist/lib/command-palette/use-nav-source.d.ts.map +1 -0
  57. package/dist/lib/command-palette/use-nav-source.js +78 -0
  58. package/dist/lib/command-palette/use-nav-source.js.map +1 -0
  59. package/dist/lib/command-palette/use-records-source.d.ts +23 -0
  60. package/dist/lib/command-palette/use-records-source.d.ts.map +1 -0
  61. package/dist/lib/command-palette/use-records-source.js +199 -0
  62. package/dist/lib/command-palette/use-records-source.js.map +1 -0
  63. package/dist/lib/command-palette/use-tabs-source.d.ts +20 -0
  64. package/dist/lib/command-palette/use-tabs-source.d.ts.map +1 -0
  65. package/dist/lib/command-palette/use-tabs-source.js +52 -0
  66. package/dist/lib/command-palette/use-tabs-source.js.map +1 -0
  67. package/dist/lib/command-palette/use-use-cases-source.d.ts +22 -0
  68. package/dist/lib/command-palette/use-use-cases-source.d.ts.map +1 -0
  69. package/dist/lib/command-palette/use-use-cases-source.js +93 -0
  70. package/dist/lib/command-palette/use-use-cases-source.js.map +1 -0
  71. package/dist/lib/config/config-route.d.ts +51 -0
  72. package/dist/lib/config/config-route.d.ts.map +1 -0
  73. package/dist/lib/config/config-route.js +65 -0
  74. package/dist/lib/config/config-route.js.map +1 -0
  75. package/dist/lib/config/service-proxy-route.d.ts +28 -0
  76. package/dist/lib/config/service-proxy-route.d.ts.map +1 -0
  77. package/dist/lib/config/service-proxy-route.js +125 -0
  78. package/dist/lib/config/service-proxy-route.js.map +1 -0
  79. package/dist/lib/config/service-token.d.ts +5 -0
  80. package/dist/lib/config/service-token.d.ts.map +1 -0
  81. package/dist/lib/config/service-token.js +18 -0
  82. package/dist/lib/config/service-token.js.map +1 -0
  83. package/dist/lib/crud/entity-crud-form.d.ts +49 -0
  84. package/dist/lib/crud/entity-crud-form.d.ts.map +1 -0
  85. package/dist/lib/crud/entity-crud-form.js +133 -0
  86. package/dist/lib/crud/entity-crud-form.js.map +1 -0
  87. package/dist/lib/crud/hand-off-write.d.ts +35 -0
  88. package/dist/lib/crud/hand-off-write.d.ts.map +1 -0
  89. package/dist/lib/crud/hand-off-write.js +27 -0
  90. package/dist/lib/crud/hand-off-write.js.map +1 -0
  91. package/dist/lib/crud/index.d.ts +9 -0
  92. package/dist/lib/crud/index.d.ts.map +1 -0
  93. package/dist/lib/crud/index.js +10 -0
  94. package/dist/lib/crud/index.js.map +1 -0
  95. package/dist/lib/crud/make-entity-crud.d.ts +28 -0
  96. package/dist/lib/crud/make-entity-crud.d.ts.map +1 -0
  97. package/dist/lib/crud/make-entity-crud.js +318 -0
  98. package/dist/lib/crud/make-entity-crud.js.map +1 -0
  99. package/dist/lib/crud/make-entity-crud.types.d.ts +237 -0
  100. package/dist/lib/crud/make-entity-crud.types.d.ts.map +1 -0
  101. package/dist/lib/crud/make-entity-crud.types.js +6 -0
  102. package/dist/lib/crud/make-entity-crud.types.js.map +1 -0
  103. package/dist/lib/crud/pending-notice.d.ts +31 -0
  104. package/dist/lib/crud/pending-notice.d.ts.map +1 -0
  105. package/dist/lib/crud/pending-notice.js +72 -0
  106. package/dist/lib/crud/pending-notice.js.map +1 -0
  107. package/dist/lib/crud/slug.d.ts +13 -0
  108. package/dist/lib/crud/slug.d.ts.map +1 -0
  109. package/dist/lib/crud/slug.js +13 -0
  110. package/dist/lib/crud/slug.js.map +1 -0
  111. package/dist/lib/crud/use-entity-affordances.d.ts +20 -0
  112. package/dist/lib/crud/use-entity-affordances.d.ts.map +1 -0
  113. package/dist/lib/crud/use-entity-affordances.js +22 -0
  114. package/dist/lib/crud/use-entity-affordances.js.map +1 -0
  115. package/dist/lib/crud/use-entity-bulk.d.ts +43 -0
  116. package/dist/lib/crud/use-entity-bulk.d.ts.map +1 -0
  117. package/dist/lib/crud/use-entity-bulk.js +106 -0
  118. package/dist/lib/crud/use-entity-bulk.js.map +1 -0
  119. package/dist/lib/crud/use-entity-link-sources.d.ts +25 -0
  120. package/dist/lib/crud/use-entity-link-sources.d.ts.map +1 -0
  121. package/dist/lib/crud/use-entity-link-sources.js +37 -0
  122. package/dist/lib/crud/use-entity-link-sources.js.map +1 -0
  123. package/dist/lib/health/health-routes.d.ts +37 -0
  124. package/dist/lib/health/health-routes.d.ts.map +1 -0
  125. package/dist/lib/health/health-routes.js +90 -0
  126. package/dist/lib/health/health-routes.js.map +1 -0
  127. package/dist/lib/i18n/catalog/en.d.ts +4 -0
  128. package/dist/lib/i18n/catalog/en.d.ts.map +1 -0
  129. package/dist/lib/i18n/catalog/en.js +347 -0
  130. package/dist/lib/i18n/catalog/en.js.map +1 -0
  131. package/dist/lib/i18n/catalog/es.d.ts +397 -0
  132. package/dist/lib/i18n/catalog/es.d.ts.map +1 -0
  133. package/dist/lib/i18n/catalog/es.js +407 -0
  134. package/dist/lib/i18n/catalog/es.js.map +1 -0
  135. package/dist/lib/i18n/catalog/index.d.ts +671 -0
  136. package/dist/lib/i18n/catalog/index.d.ts.map +1 -0
  137. package/dist/lib/i18n/catalog/index.js +28 -0
  138. package/dist/lib/i18n/catalog/index.js.map +1 -0
  139. package/dist/lib/i18n/index.d.ts +2 -0
  140. package/dist/lib/i18n/index.d.ts.map +1 -0
  141. package/dist/lib/i18n/index.js +3 -0
  142. package/dist/lib/i18n/index.js.map +1 -0
  143. package/dist/lib/i18n/locale-link.d.ts +23 -0
  144. package/dist/lib/i18n/locale-link.d.ts.map +1 -0
  145. package/dist/lib/i18n/locale-link.js +43 -0
  146. package/dist/lib/i18n/locale-link.js.map +1 -0
  147. package/dist/lib/i18n/spec-catalog.d.ts +2 -0
  148. package/dist/lib/i18n/spec-catalog.d.ts.map +1 -0
  149. package/dist/lib/i18n/spec-catalog.js +84 -0
  150. package/dist/lib/i18n/spec-catalog.js.map +1 -0
  151. package/dist/lib/search/record-search-route.d.ts +44 -0
  152. package/dist/lib/search/record-search-route.d.ts.map +1 -0
  153. package/dist/lib/search/record-search-route.js +158 -0
  154. package/dist/lib/search/record-search-route.js.map +1 -0
  155. package/dist/lib/search/record-search-source.d.ts +59 -0
  156. package/dist/lib/search/record-search-source.d.ts.map +1 -0
  157. package/dist/lib/search/record-search-source.js +118 -0
  158. package/dist/lib/search/record-search-source.js.map +1 -0
  159. package/dist/lib/search/record-search.types.d.ts +85 -0
  160. package/dist/lib/search/record-search.types.d.ts.map +1 -0
  161. package/dist/lib/search/record-search.types.js +29 -0
  162. package/dist/lib/search/record-search.types.js.map +1 -0
  163. package/dist/lib/search/search-records.d.ts +25 -0
  164. package/dist/lib/search/search-records.d.ts.map +1 -0
  165. package/dist/lib/search/search-records.js +36 -0
  166. package/dist/lib/search/search-records.js.map +1 -0
  167. package/dist/lib/session/account-links.d.ts +46 -0
  168. package/dist/lib/session/account-links.d.ts.map +1 -0
  169. package/dist/lib/session/account-links.js +41 -0
  170. package/dist/lib/session/account-links.js.map +1 -0
  171. package/dist/lib/session/bearer.d.ts +25 -0
  172. package/dist/lib/session/bearer.d.ts.map +1 -0
  173. package/dist/lib/session/bearer.js +31 -0
  174. package/dist/lib/session/bearer.js.map +1 -0
  175. package/dist/lib/session/cookies.d.ts +14 -0
  176. package/dist/lib/session/cookies.d.ts.map +1 -0
  177. package/dist/lib/session/cookies.js +33 -0
  178. package/dist/lib/session/cookies.js.map +1 -0
  179. package/dist/lib/session/device.d.ts +31 -0
  180. package/dist/lib/session/device.d.ts.map +1 -0
  181. package/dist/lib/session/device.js +80 -0
  182. package/dist/lib/session/device.js.map +1 -0
  183. package/dist/lib/session/index.d.ts +3 -0
  184. package/dist/lib/session/index.d.ts.map +1 -0
  185. package/dist/lib/session/index.js +12 -0
  186. package/dist/lib/session/index.js.map +1 -0
  187. package/dist/lib/session/refresh-route.d.ts +19 -0
  188. package/dist/lib/session/refresh-route.d.ts.map +1 -0
  189. package/dist/lib/session/refresh-route.js +85 -0
  190. package/dist/lib/session/refresh-route.js.map +1 -0
  191. package/dist/lib/session/session-keepalive.d.ts +52 -0
  192. package/dist/lib/session/session-keepalive.d.ts.map +1 -0
  193. package/dist/lib/session/session-keepalive.js +72 -0
  194. package/dist/lib/session/session-keepalive.js.map +1 -0
  195. package/dist/lib/session/use-session-refresh.d.ts +43 -0
  196. package/dist/lib/session/use-session-refresh.d.ts.map +1 -0
  197. package/dist/lib/session/use-session-refresh.js +120 -0
  198. package/dist/lib/session/use-session-refresh.js.map +1 -0
  199. package/dist/lib/wizard/index.d.ts +4 -0
  200. package/dist/lib/wizard/index.d.ts.map +1 -0
  201. package/dist/lib/wizard/index.js +5 -0
  202. package/dist/lib/wizard/index.js.map +1 -0
  203. package/dist/lib/wizard/use-wizard-draft.d.ts +22 -0
  204. package/dist/lib/wizard/use-wizard-draft.d.ts.map +1 -0
  205. package/dist/lib/wizard/use-wizard-draft.js +39 -0
  206. package/dist/lib/wizard/use-wizard-draft.js.map +1 -0
  207. package/dist/lib/wizard/use-wizard-step-param.d.ts +60 -0
  208. package/dist/lib/wizard/use-wizard-step-param.d.ts.map +1 -0
  209. package/dist/lib/wizard/use-wizard-step-param.js +94 -0
  210. package/dist/lib/wizard/use-wizard-step-param.js.map +1 -0
  211. package/dist/lib/wizard/wizard-tab-kind.d.ts +31 -0
  212. package/dist/lib/wizard/wizard-tab-kind.d.ts.map +1 -0
  213. package/dist/lib/wizard/wizard-tab-kind.js +33 -0
  214. package/dist/lib/wizard/wizard-tab-kind.js.map +1 -0
  215. package/dist/lib/workspace/drafts-state.d.ts +88 -0
  216. package/dist/lib/workspace/drafts-state.d.ts.map +1 -0
  217. package/dist/lib/workspace/drafts-state.js +128 -0
  218. package/dist/lib/workspace/drafts-state.js.map +1 -0
  219. package/dist/lib/workspace/entity-nav.d.ts +26 -0
  220. package/dist/lib/workspace/entity-nav.d.ts.map +1 -0
  221. package/dist/lib/workspace/entity-nav.js +56 -0
  222. package/dist/lib/workspace/entity-nav.js.map +1 -0
  223. package/dist/lib/workspace/entity-tab-kind.d.ts +51 -0
  224. package/dist/lib/workspace/entity-tab-kind.d.ts.map +1 -0
  225. package/dist/lib/workspace/entity-tab-kind.js +47 -0
  226. package/dist/lib/workspace/entity-tab-kind.js.map +1 -0
  227. package/dist/lib/workspace/idb-state-storage.d.ts +9 -0
  228. package/dist/lib/workspace/idb-state-storage.d.ts.map +1 -0
  229. package/dist/lib/workspace/idb-state-storage.js +32 -0
  230. package/dist/lib/workspace/idb-state-storage.js.map +1 -0
  231. package/dist/lib/workspace/index.d.ts +13 -0
  232. package/dist/lib/workspace/index.d.ts.map +1 -0
  233. package/dist/lib/workspace/index.js +14 -0
  234. package/dist/lib/workspace/index.js.map +1 -0
  235. package/dist/lib/workspace/pending-state.d.ts +84 -0
  236. package/dist/lib/workspace/pending-state.d.ts.map +1 -0
  237. package/dist/lib/workspace/pending-state.js +155 -0
  238. package/dist/lib/workspace/pending-state.js.map +1 -0
  239. package/dist/lib/workspace/pending-transactions.d.ts +44 -0
  240. package/dist/lib/workspace/pending-transactions.d.ts.map +1 -0
  241. package/dist/lib/workspace/pending-transactions.js +114 -0
  242. package/dist/lib/workspace/pending-transactions.js.map +1 -0
  243. package/dist/lib/workspace/tab-kind.d.ts +48 -0
  244. package/dist/lib/workspace/tab-kind.d.ts.map +1 -0
  245. package/dist/lib/workspace/tab-kind.js +47 -0
  246. package/dist/lib/workspace/tab-kind.js.map +1 -0
  247. package/dist/lib/workspace/tab-state.d.ts +36 -0
  248. package/dist/lib/workspace/tab-state.d.ts.map +1 -0
  249. package/dist/lib/workspace/tab-state.js +81 -0
  250. package/dist/lib/workspace/tab-state.js.map +1 -0
  251. package/dist/lib/workspace/tabs-state.d.ts +46 -0
  252. package/dist/lib/workspace/tabs-state.d.ts.map +1 -0
  253. package/dist/lib/workspace/tabs-state.js +56 -0
  254. package/dist/lib/workspace/tabs-state.js.map +1 -0
  255. package/dist/lib/workspace/use-entity-draft.d.ts +25 -0
  256. package/dist/lib/workspace/use-entity-draft.d.ts.map +1 -0
  257. package/dist/lib/workspace/use-entity-draft.js +38 -0
  258. package/dist/lib/workspace/use-entity-draft.js.map +1 -0
  259. package/dist/lib/workspace/workspace-scope.d.ts +51 -0
  260. package/dist/lib/workspace/workspace-scope.d.ts.map +1 -0
  261. package/dist/lib/workspace/workspace-scope.js +42 -0
  262. package/dist/lib/workspace/workspace-scope.js.map +1 -0
  263. package/dist/lib/workspace/workspace-shell.d.ts +33 -0
  264. package/dist/lib/workspace/workspace-shell.d.ts.map +1 -0
  265. package/dist/lib/workspace/workspace-shell.js +206 -0
  266. package/dist/lib/workspace/workspace-shell.js.map +1 -0
  267. package/dist/server.d.ts +13 -0
  268. package/dist/server.d.ts.map +1 -0
  269. package/dist/server.js +41 -0
  270. package/dist/server.js.map +1 -0
  271. package/package.json +95 -0
@@ -0,0 +1,39 @@
1
+ import type { ScreenType } from '@entifix/authz';
2
+ import type { ReactNode } from 'react';
3
+ export interface NavItem {
4
+ label: string;
5
+ href: string;
6
+ /** Optional leading glyph, shown in both expanded and collapsed states. */
7
+ icon?: ReactNode;
8
+ /**
9
+ * When set, the item also offers "Open in workspace" — a link to
10
+ * `/workspace?tab=<workspace>` that opens this destination as a persisted tab
11
+ * instead of navigating the whole page.
12
+ */
13
+ workspace?: string;
14
+ }
15
+ export interface NavSection {
16
+ /** The domain group's heading, already translated. */
17
+ title?: string;
18
+ items: NavItem[];
19
+ /**
20
+ * What shape these screens are — the sidebar's **top tier**, above the domain
21
+ * ([ADR 0033](../../../../../../../docs/adr/0033-the-screen-taxonomy.md)).
22
+ *
23
+ * A `ScreenType` rather than a translated string, unlike `title`: the four
24
+ * names are one shipped vocabulary that `SCREEN_TYPE_LABEL_KEYS` maps into the
25
+ * `shell:` namespace, so this component resolves them itself. A host that
26
+ * translated them would be translating copy it does not own.
27
+ *
28
+ * **Optional, and narrowly so.** A section with no type is not a fifth
29
+ * category, it is a section that is not a screen group at all — the account
30
+ * surface is the one case. Untyped sections render below every typed one.
31
+ */
32
+ type?: ScreenType;
33
+ }
34
+ /** A tier of the sidebar: the sections sharing one {@link ScreenType}. */
35
+ export interface NavTier {
36
+ type?: ScreenType;
37
+ sections: NavSection[];
38
+ }
39
+ //# sourceMappingURL=nav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nav.d.ts","sourceRoot":"","sources":["../../../src/lib/back-office/nav.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ /** A tier of the sidebar: the sections sharing one {@link ScreenType}. */ export { };
2
+
3
+ //# sourceMappingURL=nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/back-office/nav.ts"],"sourcesContent":["import type { ScreenType } from '@entifix/authz';\nimport type { ReactNode } from 'react';\n\nexport interface NavItem {\n label: string;\n href: string;\n /** Optional leading glyph, shown in both expanded and collapsed states. */\n icon?: ReactNode;\n /**\n * When set, the item also offers \"Open in workspace\" — a link to\n * `/workspace?tab=<workspace>` that opens this destination as a persisted tab\n * instead of navigating the whole page.\n */\n workspace?: string;\n}\n\nexport interface NavSection {\n /** The domain group's heading, already translated. */\n title?: string;\n items: NavItem[];\n /**\n * What shape these screens are — the sidebar's **top tier**, above the domain\n * ([ADR 0033](../../../../../../../docs/adr/0033-the-screen-taxonomy.md)).\n *\n * A `ScreenType` rather than a translated string, unlike `title`: the four\n * names are one shipped vocabulary that `SCREEN_TYPE_LABEL_KEYS` maps into the\n * `shell:` namespace, so this component resolves them itself. A host that\n * translated them would be translating copy it does not own.\n *\n * **Optional, and narrowly so.** A section with no type is not a fifth\n * category, it is a section that is not a screen group at all — the account\n * surface is the one case. Untyped sections render below every typed one.\n */\n type?: ScreenType;\n}\n\n/** A tier of the sidebar: the sections sharing one {@link ScreenType}. */\nexport interface NavTier {\n type?: ScreenType;\n sections: NavSection[];\n}\n"],"names":[],"mappings":"AAoCA,wEAAwE,GACxE,WAGC"}
@@ -0,0 +1,26 @@
1
+ import type { NavSection } from './nav.js';
2
+ export interface SidebarNavProps {
3
+ sections: NavSection[];
4
+ /** When collapsed, labels and headings hide; only icons remain. */
5
+ collapsed?: boolean;
6
+ /** Which domain groups are collapsed, keyed by heading. */
7
+ collapsedGroups?: Record<string, boolean>;
8
+ onToggleGroup?: (title: string) => void;
9
+ }
10
+ /** A path is active when it equals the item href or is nested beneath it. */
11
+ export declare function isActive(pathname: string, href: string): boolean;
12
+ /**
13
+ * The back office's primary navigation: screen type › domain › destination.
14
+ *
15
+ * The top tier is the **type**, not the domain (ADR 0033). Four fixed entries
16
+ * against the eleven domains ADR 0022 fixes for v1, so a new operator has one
17
+ * place to look; the daily operator's speed is the command palette's job.
18
+ *
19
+ * **Collapsed mode deliberately does not nest.** The icon column stays flat and
20
+ * every group becomes a labelled separator, because a flyout submenu would cost
21
+ * an extra click per navigation to precisely the operator who chose the compact
22
+ * mode. What collapsing hides is labels, and the per-item tooltip already
23
+ * returns those. Group collapse is therefore an expanded-mode affordance.
24
+ */
25
+ export declare function SidebarNav({ sections, collapsed, collapsedGroups, onToggleGroup, }: SidebarNavProps): import("react").JSX.Element;
26
+ //# sourceMappingURL=sidebar-nav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../../src/lib/back-office/sidebar-nav.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,UAAU,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhE;AA+ED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,SAAiB,EACjB,eAAoB,EACpB,aAAa,GACd,EAAE,eAAe,+BA2GjB"}
@@ -0,0 +1,181 @@
1
+ 'use client';
2
+ import { _ as _extends } from "@swc/helpers/_/_extends";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
+ import { SCREEN_TYPE_LABEL_KEYS } from '@entifix/authz';
5
+ import { cn, useT, useTranslateKey } from '@entifix/react-controls';
6
+ import { usePathname } from 'next/navigation';
7
+ import { useMemo } from 'react';
8
+ import { LocaleLink, useLocaleHref } from '../i18n/index.js';
9
+ import { groupByScreenType } from './group-by-screen-type.js';
10
+ /** A path is active when it equals the item href or is nested beneath it. */ export function isActive(pathname, href) {
11
+ return pathname === href || pathname.startsWith(`${href}/`);
12
+ }
13
+ const workspaceHref = (workspace)=>`/workspace?tab=${encodeURIComponent(workspace)}`;
14
+ /**
15
+ * The two "open where" choices for one destination.
16
+ *
17
+ * Both used to be either absent or invisible. The workspace link existed but was
18
+ * `opacity-0` until `group-hover/nav` — undiscoverable on touch, where there is
19
+ * no hover — and was dropped entirely while collapsed, which is the mode a power
20
+ * operator lives in. There was no open-in-a-browser-tab control at all; middle
21
+ * click worked by accident, and only with a mouse.
22
+ *
23
+ * They are now always rendered and always focusable. `text-content-muted` plus a
24
+ * hover/focus lift is what keeps a permanently visible control from competing
25
+ * with the destination itself — the affordance is quiet, not hidden.
26
+ */ function ItemActions({ item, label }) {
27
+ const t = useT('shell');
28
+ const withLocale = useLocaleHref();
29
+ return /*#__PURE__*/ _jsxs(_Fragment, {
30
+ children: [
31
+ item.workspace !== undefined && /*#__PURE__*/ _jsx(LocaleLink, {
32
+ href: workspaceHref(item.workspace),
33
+ "aria-label": t('nav.openInWorkspace', {
34
+ label
35
+ }),
36
+ title: t('nav.openInWorkspaceShort'),
37
+ className: "rounded shrink-0 p-3xs text-content-muted focus-ring transition-colors hover:bg-surface hover:text-content",
38
+ children: /*#__PURE__*/ _jsx("span", {
39
+ "aria-hidden": "true",
40
+ children: "⧉"
41
+ })
42
+ }),
43
+ /*#__PURE__*/ _jsx("a", {
44
+ href: withLocale(item.href),
45
+ target: "_blank",
46
+ rel: "noopener noreferrer",
47
+ "aria-label": t('nav.openInNewTab', {
48
+ label
49
+ }),
50
+ title: t('nav.openInNewTabShort'),
51
+ className: "rounded shrink-0 p-3xs text-content-muted focus-ring transition-colors hover:bg-surface hover:text-content",
52
+ children: /*#__PURE__*/ _jsx("span", {
53
+ "aria-hidden": "true",
54
+ children: "↗"
55
+ })
56
+ })
57
+ ]
58
+ });
59
+ }
60
+ function ItemLink({ item, active, collapsed }) {
61
+ return /*#__PURE__*/ _jsxs(LocaleLink, {
62
+ href: item.href,
63
+ "aria-current": active ? 'page' : undefined,
64
+ title: collapsed ? item.label : undefined,
65
+ className: cn('flex flex-1 items-center gap-2xs rounded-md px-2xs py-3xs text-step-sm focus-ring transition-colors', active ? 'bg-primary text-primary-content' : 'text-content hover:bg-surface'),
66
+ children: [
67
+ item.icon !== undefined && /*#__PURE__*/ _jsx("span", {
68
+ "aria-hidden": "true",
69
+ className: "shrink-0",
70
+ children: item.icon
71
+ }),
72
+ !collapsed && /*#__PURE__*/ _jsx("span", {
73
+ className: "truncate",
74
+ children: item.label
75
+ })
76
+ ]
77
+ });
78
+ }
79
+ /**
80
+ * The back office's primary navigation: screen type › domain › destination.
81
+ *
82
+ * The top tier is the **type**, not the domain (ADR 0033). Four fixed entries
83
+ * against the eleven domains ADR 0022 fixes for v1, so a new operator has one
84
+ * place to look; the daily operator's speed is the command palette's job.
85
+ *
86
+ * **Collapsed mode deliberately does not nest.** The icon column stays flat and
87
+ * every group becomes a labelled separator, because a flyout submenu would cost
88
+ * an extra click per navigation to precisely the operator who chose the compact
89
+ * mode. What collapsing hides is labels, and the per-item tooltip already
90
+ * returns those. Group collapse is therefore an expanded-mode affordance.
91
+ */ export function SidebarNav({ sections, collapsed = false, collapsedGroups = {}, onToggleGroup }) {
92
+ var _usePathname;
93
+ const t = useT('shell');
94
+ // The four type names are `shell:` copy owned by `@entifix/authz`'s
95
+ // `SCREEN_TYPE_LABEL_KEYS`, so they arrive as fully-qualified keys rather than
96
+ // as names in this namespace — the documented escape hatch, not authored copy.
97
+ const translateKey = useTranslateKey();
98
+ const pathname = (_usePathname = usePathname()) != null ? _usePathname : '';
99
+ const tiers = useMemo(()=>groupByScreenType(sections), [
100
+ sections
101
+ ]);
102
+ return /*#__PURE__*/ _jsx("nav", {
103
+ "aria-label": t('nav.primary'),
104
+ className: "flex flex-col gap-m",
105
+ children: tiers.map((tier, tierIndex)=>{
106
+ var _tier_type;
107
+ return /*#__PURE__*/ _jsxs("div", {
108
+ className: "flex flex-col gap-2xs",
109
+ children: [
110
+ tier.type !== undefined && !collapsed && /*#__PURE__*/ _jsx("p", {
111
+ className: "tracking-wide px-2xs text-step-xs font-semibold text-content uppercase",
112
+ children: translateKey(SCREEN_TYPE_LABEL_KEYS[tier.type])
113
+ }),
114
+ collapsed && tierIndex > 0 && /*#__PURE__*/ _jsx("hr", {
115
+ className: "border-border",
116
+ "aria-hidden": "true"
117
+ }),
118
+ /*#__PURE__*/ _jsx("div", _extends({
119
+ className: "flex flex-col gap-2xs"
120
+ }, tier.type === undefined ? {} : {
121
+ role: 'group',
122
+ 'aria-label': translateKey(SCREEN_TYPE_LABEL_KEYS[tier.type])
123
+ }, {
124
+ children: tier.sections.map((section, sectionIndex)=>{
125
+ const title = section.title;
126
+ const groupCollapsed = title !== undefined && collapsedGroups[title] === true;
127
+ // A collapsed group holding the active route still shows where you
128
+ // are — otherwise collapsing a group hides the answer.
129
+ const hasActive = section.items.some((item)=>isActive(pathname, item.href));
130
+ return /*#__PURE__*/ _jsxs("div", {
131
+ className: "flex flex-col gap-3xs",
132
+ children: [
133
+ title !== undefined && !collapsed && (onToggleGroup === undefined ? /*#__PURE__*/ _jsx("p", {
134
+ className: "tracking-wide px-2xs text-step-xs text-content-muted uppercase",
135
+ children: title
136
+ }) : /*#__PURE__*/ _jsxs("button", {
137
+ type: "button",
138
+ onClick: ()=>onToggleGroup(title),
139
+ "aria-expanded": !groupCollapsed,
140
+ "aria-label": groupCollapsed ? t('sidebar.expandGroup', {
141
+ group: title
142
+ }) : t('sidebar.collapseGroup', {
143
+ group: title
144
+ }),
145
+ className: cn('rounded tracking-wide flex items-center gap-3xs px-2xs text-step-xs uppercase focus-ring transition-colors hover:text-content', groupCollapsed && hasActive ? 'text-content' : 'text-content-muted'),
146
+ children: [
147
+ /*#__PURE__*/ _jsx("span", {
148
+ "aria-hidden": "true",
149
+ children: groupCollapsed ? '▸' : '▾'
150
+ }),
151
+ /*#__PURE__*/ _jsx("span", {
152
+ className: "truncate",
153
+ children: title
154
+ })
155
+ ]
156
+ })),
157
+ !(groupCollapsed && !collapsed) && section.items.map((item)=>/*#__PURE__*/ _jsxs("div", {
158
+ className: "flex items-center gap-3xs",
159
+ children: [
160
+ /*#__PURE__*/ _jsx(ItemLink, {
161
+ item: item,
162
+ active: isActive(pathname, item.href),
163
+ collapsed: collapsed
164
+ }),
165
+ !collapsed && /*#__PURE__*/ _jsx(ItemActions, {
166
+ item: item,
167
+ label: item.label
168
+ })
169
+ ]
170
+ }, item.href))
171
+ ]
172
+ }, title != null ? title : `section-${sectionIndex}`);
173
+ })
174
+ }))
175
+ ]
176
+ }, (_tier_type = tier.type) != null ? _tier_type : `tier-${tierIndex}`);
177
+ })
178
+ });
179
+ }
180
+
181
+ //# sourceMappingURL=sidebar-nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/back-office/sidebar-nav.tsx"],"sourcesContent":["'use client';\n\nimport { SCREEN_TYPE_LABEL_KEYS } from '@entifix/authz';\nimport { cn, useT, useTranslateKey } from '@entifix/react-controls';\nimport { usePathname } from 'next/navigation';\nimport { useMemo } from 'react';\n\nimport { LocaleLink, useLocaleHref } from '../i18n/index.js';\nimport { groupByScreenType } from './group-by-screen-type.js';\nimport type { NavItem, NavSection } from './nav.js';\n\nexport interface SidebarNavProps {\n sections: NavSection[];\n /** When collapsed, labels and headings hide; only icons remain. */\n collapsed?: boolean;\n /** Which domain groups are collapsed, keyed by heading. */\n collapsedGroups?: Record<string, boolean>;\n onToggleGroup?: (title: string) => void;\n}\n\n/** A path is active when it equals the item href or is nested beneath it. */\nexport function isActive(pathname: string, href: string): boolean {\n return pathname === href || pathname.startsWith(`${href}/`);\n}\n\nconst workspaceHref = (workspace: string) =>\n `/workspace?tab=${encodeURIComponent(workspace)}`;\n\n/**\n * The two \"open where\" choices for one destination.\n *\n * Both used to be either absent or invisible. The workspace link existed but was\n * `opacity-0` until `group-hover/nav` — undiscoverable on touch, where there is\n * no hover — and was dropped entirely while collapsed, which is the mode a power\n * operator lives in. There was no open-in-a-browser-tab control at all; middle\n * click worked by accident, and only with a mouse.\n *\n * They are now always rendered and always focusable. `text-content-muted` plus a\n * hover/focus lift is what keeps a permanently visible control from competing\n * with the destination itself — the affordance is quiet, not hidden.\n */\nfunction ItemActions({ item, label }: { item: NavItem; label: string }) {\n const t = useT('shell');\n const withLocale = useLocaleHref();\n\n return (\n <>\n {item.workspace !== undefined && (\n <LocaleLink\n href={workspaceHref(item.workspace)}\n aria-label={t('nav.openInWorkspace', { label })}\n title={t('nav.openInWorkspaceShort')}\n className=\"rounded shrink-0 p-3xs text-content-muted focus-ring transition-colors hover:bg-surface hover:text-content\"\n >\n <span aria-hidden=\"true\">⧉</span>\n </LocaleLink>\n )}\n <a\n href={withLocale(item.href)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={t('nav.openInNewTab', { label })}\n title={t('nav.openInNewTabShort')}\n className=\"rounded shrink-0 p-3xs text-content-muted focus-ring transition-colors hover:bg-surface hover:text-content\"\n >\n <span aria-hidden=\"true\">↗</span>\n </a>\n </>\n );\n}\n\nfunction ItemLink({\n item,\n active,\n collapsed,\n}: {\n item: NavItem;\n active: boolean;\n collapsed: boolean;\n}) {\n return (\n <LocaleLink\n href={item.href}\n aria-current={active ? 'page' : undefined}\n title={collapsed ? item.label : undefined}\n className={cn(\n 'flex flex-1 items-center gap-2xs rounded-md px-2xs py-3xs text-step-sm focus-ring transition-colors',\n active\n ? 'bg-primary text-primary-content'\n : 'text-content hover:bg-surface',\n )}\n >\n {item.icon !== undefined && (\n <span aria-hidden=\"true\" className=\"shrink-0\">\n {item.icon}\n </span>\n )}\n {!collapsed && <span className=\"truncate\">{item.label}</span>}\n </LocaleLink>\n );\n}\n\n/**\n * The back office's primary navigation: screen type › domain › destination.\n *\n * The top tier is the **type**, not the domain (ADR 0033). Four fixed entries\n * against the eleven domains ADR 0022 fixes for v1, so a new operator has one\n * place to look; the daily operator's speed is the command palette's job.\n *\n * **Collapsed mode deliberately does not nest.** The icon column stays flat and\n * every group becomes a labelled separator, because a flyout submenu would cost\n * an extra click per navigation to precisely the operator who chose the compact\n * mode. What collapsing hides is labels, and the per-item tooltip already\n * returns those. Group collapse is therefore an expanded-mode affordance.\n */\nexport function SidebarNav({\n sections,\n collapsed = false,\n collapsedGroups = {},\n onToggleGroup,\n}: SidebarNavProps) {\n const t = useT('shell');\n // The four type names are `shell:` copy owned by `@entifix/authz`'s\n // `SCREEN_TYPE_LABEL_KEYS`, so they arrive as fully-qualified keys rather than\n // as names in this namespace — the documented escape hatch, not authored copy.\n const translateKey = useTranslateKey();\n const pathname = usePathname() ?? '';\n const tiers = useMemo(() => groupByScreenType(sections), [sections]);\n\n return (\n <nav aria-label={t('nav.primary')} className=\"flex flex-col gap-m\">\n {tiers.map((tier, tierIndex) => (\n <div\n key={tier.type ?? `tier-${tierIndex}`}\n className=\"flex flex-col gap-2xs\"\n >\n {tier.type !== undefined && !collapsed && (\n <p className=\"tracking-wide px-2xs text-step-xs font-semibold text-content uppercase\">\n {translateKey(SCREEN_TYPE_LABEL_KEYS[tier.type])}\n </p>\n )}\n {/* Collapsed, the heading is gone but the grouping is not: a rule plus\n an accessible name is what keeps the icon column from reading as\n one undifferentiated list. */}\n {collapsed && tierIndex > 0 && (\n <hr className=\"border-border\" aria-hidden=\"true\" />\n )}\n {/* `role=\"group\"` only where there is a name for it. An unnamed group\n is announced as an empty landmark, which is noise rather than\n structure — and the untyped section is not a screen group at all. */}\n <div\n className=\"flex flex-col gap-2xs\"\n {...(tier.type === undefined\n ? {}\n : {\n role: 'group',\n 'aria-label': translateKey(SCREEN_TYPE_LABEL_KEYS[tier.type]),\n })}\n >\n {tier.sections.map((section, sectionIndex) => {\n const title = section.title;\n const groupCollapsed =\n title !== undefined && collapsedGroups[title] === true;\n // A collapsed group holding the active route still shows where you\n // are — otherwise collapsing a group hides the answer.\n const hasActive = section.items.some(item =>\n isActive(pathname, item.href),\n );\n\n return (\n <div\n key={title ?? `section-${sectionIndex}`}\n className=\"flex flex-col gap-3xs\"\n >\n {title !== undefined &&\n !collapsed &&\n (onToggleGroup === undefined ? (\n <p className=\"tracking-wide px-2xs text-step-xs text-content-muted uppercase\">\n {title}\n </p>\n ) : (\n <button\n type=\"button\"\n onClick={() => onToggleGroup(title)}\n aria-expanded={!groupCollapsed}\n aria-label={\n groupCollapsed\n ? t('sidebar.expandGroup', { group: title })\n : t('sidebar.collapseGroup', { group: title })\n }\n className={cn(\n 'rounded tracking-wide flex items-center gap-3xs px-2xs text-step-xs uppercase focus-ring transition-colors hover:text-content',\n groupCollapsed && hasActive\n ? 'text-content'\n : 'text-content-muted',\n )}\n >\n <span aria-hidden=\"true\">\n {groupCollapsed ? '▸' : '▾'}\n </span>\n <span className=\"truncate\">{title}</span>\n </button>\n ))}\n {!(groupCollapsed && !collapsed) &&\n section.items.map(item => (\n <div\n key={item.href}\n className=\"flex items-center gap-3xs\"\n >\n <ItemLink\n item={item}\n active={isActive(pathname, item.href)}\n collapsed={collapsed}\n />\n {!collapsed && (\n <ItemActions item={item} label={item.label} />\n )}\n </div>\n ))}\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </nav>\n );\n}\n"],"names":["SCREEN_TYPE_LABEL_KEYS","cn","useT","useTranslateKey","usePathname","useMemo","LocaleLink","useLocaleHref","groupByScreenType","isActive","pathname","href","startsWith","workspaceHref","workspace","encodeURIComponent","ItemActions","item","label","t","withLocale","undefined","aria-label","title","className","span","aria-hidden","a","target","rel","ItemLink","active","collapsed","aria-current","icon","SidebarNav","sections","collapsedGroups","onToggleGroup","translateKey","tiers","nav","map","tier","tierIndex","div","type","p","hr","role","section","sectionIndex","groupCollapsed","hasActive","items","some","button","onClick","aria-expanded","group"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { NavSection } from '../back-office/nav.js';
2
+ import type { PaletteCommand } from './palette-command.js';
3
+ import { type UseCaseCommandEntity } from './use-use-cases-source.js';
4
+ export interface CommandPaletteHostProps {
5
+ /**
6
+ * Deterministic commands, already permission-filtered and translated by the
7
+ * server layout that has the principal.
8
+ */
9
+ readonly commands: readonly PaletteCommand[];
10
+ /** The same resolved nav tree the sidebar renders. */
11
+ readonly nav: readonly NavSection[];
12
+ /**
13
+ * Entities whose served `$metadata` contributes `unbound` verbs, with the
14
+ * handler for each.
15
+ *
16
+ * ⚠️ Must be a **module-scope constant**: the sources are produced by a hook
17
+ * per entity, so a fresh array each render changes the hook count. See
18
+ * `useUseCaseSources`.
19
+ */
20
+ readonly useCaseEntities?: readonly UseCaseCommandEntity[];
21
+ }
22
+ /**
23
+ * The back office's command palette: its trigger, its shortcuts, and everything
24
+ * it can reach.
25
+ *
26
+ * This is the composition point. The control in `@entifix/react-controls` is
27
+ * presentational and the sources are hooks; what lives here is the small set of
28
+ * decisions neither can make — which sources a typed prefix asks for, what
29
+ * selecting an option does, and when to ask first.
30
+ *
31
+ * **The grammar is for entry, the stack is for depth.** `>` narrows to commands
32
+ * and actions, `#` to records, and anything else searches everything. Descending
33
+ * into "Nuevo…" is a pushed page rather than a third prefix, because a prefix has
34
+ * to be remembered and a list can be read.
35
+ *
36
+ * The whole thing is mounted in the chrome, so it is reachable from every route
37
+ * the back office serves — including `/workspace`, which is where the open-tabs
38
+ * group has anything in it.
39
+ */
40
+ export declare function CommandPaletteHost({ commands, nav, useCaseEntities, }: CommandPaletteHostProps): import("react").JSX.Element;
41
+ //# sourceMappingURL=command-palette-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-palette-host.d.ts","sourceRoot":"","sources":["../../../src/lib/command-palette/command-palette-host.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAM3D,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;AAmBnC,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,SAAS,UAAU,EAAE,CAAC;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC5D;AAWD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,GAAG,EACH,eAA6B,GAC9B,EAAE,uBAAuB,+BA6JzB"}
@@ -0,0 +1,196 @@
1
+ 'use client';
2
+ import { _ as _extends } from "@swc/helpers/_/_extends";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
+ import { NEW_COMMAND_PAGE } from '@entifix/authz';
5
+ import { parseCommandTerm, ROOT_COMMAND_PAGE } from '@entifix/core';
6
+ import { Button, CommandPalette, ConfirmDialog, useHotkey, useT } from '@entifix/react-controls';
7
+ import { useRouter } from 'next/navigation';
8
+ import { useState } from 'react';
9
+ import { useCommandRecency } from './use-command-recency.js';
10
+ import { useCommandSource } from './use-command-source.js';
11
+ import { useNavSource } from './use-nav-source.js';
12
+ import { useRecordsSource } from './use-records-source.js';
13
+ import { useTabsSource } from './use-tabs-source.js';
14
+ import { useUseCaseSources } from './use-use-cases-source.js';
15
+ /**
16
+ * ⌘K **and** ⌘⇧P, and neither is load-bearing.
17
+ *
18
+ * #112 argued for ⌘⇧P alone because Chrome and Firefox claim ⌘K for address-bar
19
+ * search. That is half the picture: ⌘⇧P / Ctrl+Shift+P is Firefox's private
20
+ * window, so **both** candidates collide somewhere. ⌘K is also what Linear,
21
+ * GitHub, Slack and Vercel trained people on, so leaving it unbound costs a
22
+ * reflex.
23
+ *
24
+ * Binding both, plus a permanently visible trigger, is what makes the collision
25
+ * a non-issue: whichever a given browser swallows, two other ways in remain.
26
+ */ const HOTKEYS = [
27
+ {
28
+ key: 'k',
29
+ mod: true
30
+ },
31
+ {
32
+ key: 'p',
33
+ mod: true,
34
+ shift: true
35
+ }
36
+ ];
37
+ const NO_ENTITIES = [];
38
+ /**
39
+ * The back office's command palette: its trigger, its shortcuts, and everything
40
+ * it can reach.
41
+ *
42
+ * This is the composition point. The control in `@entifix/react-controls` is
43
+ * presentational and the sources are hooks; what lives here is the small set of
44
+ * decisions neither can make — which sources a typed prefix asks for, what
45
+ * selecting an option does, and when to ask first.
46
+ *
47
+ * **The grammar is for entry, the stack is for depth.** `>` narrows to commands
48
+ * and actions, `#` to records, and anything else searches everything. Descending
49
+ * into "Nuevo…" is a pushed page rather than a third prefix, because a prefix has
50
+ * to be remembered and a list can be read.
51
+ *
52
+ * The whole thing is mounted in the chrome, so it is reachable from every route
53
+ * the back office serves — including `/workspace`, which is where the open-tabs
54
+ * group has anything in it.
55
+ */ export function CommandPaletteHost({ commands, nav, useCaseEntities = NO_ENTITIES }) {
56
+ const t = useT('shell');
57
+ const router = useRouter();
58
+ const recency = useCommandRecency();
59
+ const [open, setOpen] = useState(false);
60
+ const [rawTerm, setRawTerm] = useState('');
61
+ const [stack, setStack] = useState([]);
62
+ const [pending, setPending] = useState(null);
63
+ const { scope, term } = parseCommandTerm(rawTerm);
64
+ // Every source runs on every render — the hook count may not depend on the
65
+ // page or the prefix. What those decide is which sources are *shown*, which is
66
+ // why each returns a whole `CommandSource` instead of being called
67
+ // conditionally. So the root's commands and the create page's are two sources
68
+ // rather than one that reads the stack.
69
+ const commandSource = useCommandSource(commands, term, undefined);
70
+ const createSource = useCommandSource(commands, term, NEW_COMMAND_PAGE);
71
+ const useCaseSources = useUseCaseSources(useCaseEntities, term);
72
+ const navSource = useNavSource(nav, term);
73
+ const tabsSource = useTabsSource(term);
74
+ const recordsSource = useRecordsSource(term, // A record fan-out is four authenticated requests per keystroke, so it is
75
+ // spent only where its answer is rendered: not while closed, not while the
76
+ // prefix says commands, and not on a pushed page, which shows its own
77
+ // sources and nothing else.
78
+ open && scope !== 'commands' && stack.length === 0);
79
+ const rank = (source)=>_extends({}, source, {
80
+ groups: source.groups.map(recency.rank)
81
+ });
82
+ const rootSources = scope === 'records' ? [
83
+ recordsSource
84
+ ] : scope === 'commands' ? [
85
+ commandSource,
86
+ ...useCaseSources
87
+ ] : [
88
+ commandSource,
89
+ ...useCaseSources,
90
+ navSource,
91
+ tabsSource,
92
+ recordsSource
93
+ ];
94
+ const pages = [
95
+ {
96
+ id: ROOT_COMMAND_PAGE,
97
+ placeholder: t('commandPalette.placeholder'),
98
+ sources: rootSources.map(rank)
99
+ },
100
+ {
101
+ id: NEW_COMMAND_PAGE,
102
+ title: t('commandPalette.newTitle'),
103
+ placeholder: t('commandPalette.newPlaceholder'),
104
+ sources: [
105
+ rank(createSource)
106
+ ]
107
+ }
108
+ ];
109
+ const labels = {
110
+ title: t('commandPalette.title'),
111
+ empty: t('commandPalette.empty'),
112
+ loading: t('commandPalette.loading'),
113
+ more: (remaining)=>t('commandPalette.more', {
114
+ count: remaining
115
+ }),
116
+ back: t('commandPalette.back')
117
+ };
118
+ const close = ()=>{
119
+ setOpen(false);
120
+ setPending(null);
121
+ };
122
+ // Opening resets the term and the stack in the same handler that opens it,
123
+ // rather than from an effect keyed on `open` — a fresh palette is a fact about
124
+ // this event, not something to react to afterwards.
125
+ const openPalette = ()=>{
126
+ setRawTerm('');
127
+ setStack([]);
128
+ setPending(null);
129
+ setOpen(true);
130
+ };
131
+ useHotkey(HOTKEYS, openPalette);
132
+ const perform = (option)=>{
133
+ recency.remember(option.id);
134
+ close();
135
+ if (option.href !== undefined) {
136
+ router.push(option.href);
137
+ return;
138
+ }
139
+ // A rejected command is the handler's to report — it owns the request and
140
+ // therefore the only context in which the failure means anything. Letting it
141
+ // reject unhandled here would surface as an unhandled rejection instead.
142
+ void (option.run == null ? void 0 : option.run.call(option));
143
+ };
144
+ const select = (option)=>{
145
+ if (option.confirm !== undefined) {
146
+ // The palette closes and the question stands alone. Leaving the list
147
+ // behind a modal invites a second selection against a dialog that is
148
+ // already about the first one.
149
+ setOpen(false);
150
+ setPending({
151
+ option,
152
+ message: option.confirm.message,
153
+ tone: option.confirm.tone
154
+ });
155
+ return;
156
+ }
157
+ perform(option);
158
+ };
159
+ return /*#__PURE__*/ _jsxs(_Fragment, {
160
+ children: [
161
+ /*#__PURE__*/ _jsx(Button, {
162
+ type: "button",
163
+ variant: "ghost",
164
+ size: "sm",
165
+ onClick: openPalette,
166
+ "data-testid": "command-palette-trigger",
167
+ children: t('commandPalette.open')
168
+ }),
169
+ /*#__PURE__*/ _jsx(CommandPalette, {
170
+ open: open,
171
+ onClose: close,
172
+ pages: pages,
173
+ stack: stack,
174
+ onStackChange: setStack,
175
+ term: rawTerm,
176
+ onTermChange: setRawTerm,
177
+ onSelect: select,
178
+ labels: labels
179
+ }),
180
+ pending !== null && /*#__PURE__*/ _jsx(ConfirmDialog, {
181
+ open: true,
182
+ title: pending.option.label,
183
+ message: pending.message,
184
+ tone: pending.tone,
185
+ onConfirm: ()=>{
186
+ const option = pending.option;
187
+ setPending(null);
188
+ perform(option);
189
+ },
190
+ onCancel: ()=>setPending(null)
191
+ })
192
+ ]
193
+ });
194
+ }
195
+
196
+ //# sourceMappingURL=command-palette-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/command-palette/command-palette-host.tsx"],"sourcesContent":["'use client';\n\nimport { NEW_COMMAND_PAGE } from '@entifix/authz';\nimport {\n type CommandOption,\n type CommandPage,\n type CommandSource,\n parseCommandTerm,\n ROOT_COMMAND_PAGE,\n} from '@entifix/core';\nimport {\n Button,\n CommandPalette,\n type CommandPaletteLabels,\n ConfirmDialog,\n useHotkey,\n useT,\n} from '@entifix/react-controls';\nimport { useRouter } from 'next/navigation';\nimport { useState } from 'react';\n\nimport type { NavSection } from '../back-office/nav.js';\nimport type { PaletteCommand } from './palette-command.js';\nimport { useCommandRecency } from './use-command-recency.js';\nimport { useCommandSource } from './use-command-source.js';\nimport { useNavSource } from './use-nav-source.js';\nimport { useRecordsSource } from './use-records-source.js';\nimport { useTabsSource } from './use-tabs-source.js';\nimport {\n type UseCaseCommandEntity,\n useUseCaseSources,\n} from './use-use-cases-source.js';\n\n/**\n * ⌘K **and** ⌘⇧P, and neither is load-bearing.\n *\n * #112 argued for ⌘⇧P alone because Chrome and Firefox claim ⌘K for address-bar\n * search. That is half the picture: ⌘⇧P / Ctrl+Shift+P is Firefox's private\n * window, so **both** candidates collide somewhere. ⌘K is also what Linear,\n * GitHub, Slack and Vercel trained people on, so leaving it unbound costs a\n * reflex.\n *\n * Binding both, plus a permanently visible trigger, is what makes the collision\n * a non-issue: whichever a given browser swallows, two other ways in remain.\n */\nconst HOTKEYS = [\n { key: 'k', mod: true },\n { key: 'p', mod: true, shift: true },\n] as const;\n\nexport interface CommandPaletteHostProps {\n /**\n * Deterministic commands, already permission-filtered and translated by the\n * server layout that has the principal.\n */\n readonly commands: readonly PaletteCommand[];\n /** The same resolved nav tree the sidebar renders. */\n readonly nav: readonly NavSection[];\n /**\n * Entities whose served `$metadata` contributes `unbound` verbs, with the\n * handler for each.\n *\n * ⚠️ Must be a **module-scope constant**: the sources are produced by a hook\n * per entity, so a fresh array each render changes the hook count. See\n * `useUseCaseSources`.\n */\n readonly useCaseEntities?: readonly UseCaseCommandEntity[];\n}\n\n/** A verb waiting on its confirmation. */\ninterface PendingConfirm {\n readonly option: CommandOption;\n readonly message: string;\n readonly tone: 'destructive' | 'neutral';\n}\n\nconst NO_ENTITIES: readonly UseCaseCommandEntity[] = [];\n\n/**\n * The back office's command palette: its trigger, its shortcuts, and everything\n * it can reach.\n *\n * This is the composition point. The control in `@entifix/react-controls` is\n * presentational and the sources are hooks; what lives here is the small set of\n * decisions neither can make — which sources a typed prefix asks for, what\n * selecting an option does, and when to ask first.\n *\n * **The grammar is for entry, the stack is for depth.** `>` narrows to commands\n * and actions, `#` to records, and anything else searches everything. Descending\n * into \"Nuevo…\" is a pushed page rather than a third prefix, because a prefix has\n * to be remembered and a list can be read.\n *\n * The whole thing is mounted in the chrome, so it is reachable from every route\n * the back office serves — including `/workspace`, which is where the open-tabs\n * group has anything in it.\n */\nexport function CommandPaletteHost({\n commands,\n nav,\n useCaseEntities = NO_ENTITIES,\n}: CommandPaletteHostProps) {\n const t = useT('shell');\n const router = useRouter();\n const recency = useCommandRecency();\n\n const [open, setOpen] = useState(false);\n const [rawTerm, setRawTerm] = useState('');\n const [stack, setStack] = useState<readonly string[]>([]);\n const [pending, setPending] = useState<PendingConfirm | null>(null);\n\n const { scope, term } = parseCommandTerm(rawTerm);\n\n // Every source runs on every render — the hook count may not depend on the\n // page or the prefix. What those decide is which sources are *shown*, which is\n // why each returns a whole `CommandSource` instead of being called\n // conditionally. So the root's commands and the create page's are two sources\n // rather than one that reads the stack.\n const commandSource = useCommandSource(commands, term, undefined);\n const createSource = useCommandSource(commands, term, NEW_COMMAND_PAGE);\n const useCaseSources = useUseCaseSources(useCaseEntities, term);\n const navSource = useNavSource(nav, term);\n const tabsSource = useTabsSource(term);\n const recordsSource = useRecordsSource(\n term,\n // A record fan-out is four authenticated requests per keystroke, so it is\n // spent only where its answer is rendered: not while closed, not while the\n // prefix says commands, and not on a pushed page, which shows its own\n // sources and nothing else.\n open && scope !== 'commands' && stack.length === 0,\n );\n\n const rank = (source: CommandSource): CommandSource => ({\n ...source,\n groups: source.groups.map(recency.rank),\n });\n\n const rootSources: CommandSource[] =\n scope === 'records'\n ? [recordsSource]\n : scope === 'commands'\n ? [commandSource, ...useCaseSources]\n : [\n commandSource,\n ...useCaseSources,\n navSource,\n tabsSource,\n recordsSource,\n ];\n\n const pages: CommandPage[] = [\n {\n id: ROOT_COMMAND_PAGE,\n placeholder: t('commandPalette.placeholder'),\n sources: rootSources.map(rank),\n },\n {\n id: NEW_COMMAND_PAGE,\n title: t('commandPalette.newTitle'),\n placeholder: t('commandPalette.newPlaceholder'),\n sources: [rank(createSource)],\n },\n ];\n\n const labels: CommandPaletteLabels = {\n title: t('commandPalette.title'),\n empty: t('commandPalette.empty'),\n loading: t('commandPalette.loading'),\n more: remaining => t('commandPalette.more', { count: remaining }),\n back: t('commandPalette.back'),\n };\n\n const close = () => {\n setOpen(false);\n setPending(null);\n };\n\n // Opening resets the term and the stack in the same handler that opens it,\n // rather than from an effect keyed on `open` — a fresh palette is a fact about\n // this event, not something to react to afterwards.\n const openPalette = () => {\n setRawTerm('');\n setStack([]);\n setPending(null);\n setOpen(true);\n };\n\n useHotkey(HOTKEYS, openPalette);\n\n const perform = (option: CommandOption) => {\n recency.remember(option.id);\n close();\n if (option.href !== undefined) {\n router.push(option.href);\n return;\n }\n // A rejected command is the handler's to report — it owns the request and\n // therefore the only context in which the failure means anything. Letting it\n // reject unhandled here would surface as an unhandled rejection instead.\n void option.run?.();\n };\n\n const select = (option: CommandOption) => {\n if (option.confirm !== undefined) {\n // The palette closes and the question stands alone. Leaving the list\n // behind a modal invites a second selection against a dialog that is\n // already about the first one.\n setOpen(false);\n setPending({\n option,\n message: option.confirm.message,\n tone: option.confirm.tone,\n });\n return;\n }\n perform(option);\n };\n\n return (\n <>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={openPalette}\n data-testid=\"command-palette-trigger\"\n >\n {t('commandPalette.open')}\n </Button>\n\n <CommandPalette\n open={open}\n onClose={close}\n pages={pages}\n stack={stack}\n onStackChange={setStack}\n term={rawTerm}\n onTermChange={setRawTerm}\n onSelect={select}\n labels={labels}\n />\n\n {pending !== null && (\n <ConfirmDialog\n open\n title={pending.option.label}\n message={pending.message}\n tone={pending.tone}\n onConfirm={() => {\n const option = pending.option;\n setPending(null);\n perform(option);\n }}\n onCancel={() => setPending(null)}\n />\n )}\n </>\n );\n}\n"],"names":["NEW_COMMAND_PAGE","parseCommandTerm","ROOT_COMMAND_PAGE","Button","CommandPalette","ConfirmDialog","useHotkey","useT","useRouter","useState","useCommandRecency","useCommandSource","useNavSource","useRecordsSource","useTabsSource","useUseCaseSources","HOTKEYS","key","mod","shift","NO_ENTITIES","CommandPaletteHost","commands","nav","useCaseEntities","t","router","recency","open","setOpen","rawTerm","setRawTerm","stack","setStack","pending","setPending","scope","term","commandSource","undefined","createSource","useCaseSources","navSource","tabsSource","recordsSource","length","rank","source","groups","map","rootSources","pages","id","placeholder","sources","title","labels","empty","loading","more","remaining","count","back","close","openPalette","perform","option","remember","href","push","run","select","confirm","message","tone","type","variant","size","onClick","data-testid","onClose","onStackChange","onTermChange","onSelect","label","onConfirm","onCancel"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from './command-palette-host.js';
2
+ export * from './palette-command.js';
3
+ export * from './use-command-recency.js';
4
+ export * from './use-command-source.js';
5
+ export * from './use-nav-source.js';
6
+ export * from './use-records-source.js';
7
+ export * from './use-tabs-source.js';
8
+ export * from './use-use-cases-source.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/command-palette/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from './command-palette-host.js';
2
+ export * from './palette-command.js';
3
+ export * from './use-command-recency.js';
4
+ export * from './use-command-source.js';
5
+ export * from './use-nav-source.js';
6
+ export * from './use-records-source.js';
7
+ export * from './use-tabs-source.js';
8
+ export * from './use-use-cases-source.js';
9
+
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/command-palette/index.ts"],"sourcesContent":["export * from './command-palette-host.js';\nexport * from './palette-command.js';\nexport * from './use-command-recency.js';\nexport * from './use-command-source.js';\nexport * from './use-nav-source.js';\nexport * from './use-records-source.js';\nexport * from './use-tabs-source.js';\nexport * from './use-use-cases-source.js';\n"],"names":[],"mappings":"AAAA,cAAc,4BAA4B;AAC1C,cAAc,uBAAuB;AACrC,cAAc,2BAA2B;AACzC,cAAc,0BAA0B;AACxC,cAAc,sBAAsB;AACpC,cAAc,0BAA0B;AACxC,cAAc,uBAAuB;AACrC,cAAc,4BAA4B"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A deterministic command, with its copy already resolved.
3
+ *
4
+ * The wire shape between a **server** layout — which is where `visibleNav`'s
5
+ * principal and the translate function live — and the client palette. So it is
6
+ * plain serializable data and nothing else: a `GuardedCommand` carries catalog
7
+ * keys and a `Permission`, neither of which a client component should have to
8
+ * deal with, and a function would not survive the crossing at all.
9
+ */
10
+ export interface PaletteCommand {
11
+ /** Stable across renders and hosts. Also the recency key. */
12
+ readonly key: string;
13
+ readonly label: string;
14
+ /** Already split from the catalog's comma list by the host. */
15
+ readonly keywords: readonly string[];
16
+ /** Locale-free; the palette prefixes it. */
17
+ readonly href: string;
18
+ /** The page this command sits on. Omitted means the root. */
19
+ readonly page?: string;
20
+ }
21
+ /**
22
+ * How many characters before records are queried at all.
23
+ *
24
+ * The same floor `/api/search` enforces, restated here so the palette can *say*
25
+ * why a record group is absent instead of silently showing nothing. Below it the
26
+ * route answers empty groups, which would otherwise read as "no matches" for a
27
+ * search that never ran.
28
+ */
29
+ export declare const RECORD_SEARCH_MIN_TERM = 2;
30
+ /** How long after the last keystroke the fan-out runs. */
31
+ export declare const RECORD_SEARCH_DEBOUNCE_MS = 250;
32
+ //# sourceMappingURL=palette-command.d.ts.map