@jini-ai/admin 0.1.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 (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +138 -0
  3. package/dist/browser/index.d.ts +8 -0
  4. package/dist/browser/index.d.ts.map +1 -0
  5. package/dist/browser/index.js +8 -0
  6. package/dist/browser/index.js.map +1 -0
  7. package/dist/browser/navigation.d.ts +39 -0
  8. package/dist/browser/navigation.d.ts.map +1 -0
  9. package/dist/browser/navigation.js +113 -0
  10. package/dist/browser/navigation.js.map +1 -0
  11. package/dist/core/gated/types.d.ts +87 -0
  12. package/dist/core/gated/types.d.ts.map +1 -0
  13. package/dist/core/gated/types.js +37 -0
  14. package/dist/core/gated/types.js.map +1 -0
  15. package/dist/core/index.d.ts +20 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +15 -0
  18. package/dist/core/index.js.map +1 -0
  19. package/dist/core/manifest/rules.d.ts +84 -0
  20. package/dist/core/manifest/rules.d.ts.map +1 -0
  21. package/dist/core/manifest/rules.js +130 -0
  22. package/dist/core/manifest/rules.js.map +1 -0
  23. package/dist/core/manifest/types.d.ts +154 -0
  24. package/dist/core/manifest/types.d.ts.map +1 -0
  25. package/dist/core/manifest/types.js +31 -0
  26. package/dist/core/manifest/types.js.map +1 -0
  27. package/dist/core/permissions/rules.d.ts +32 -0
  28. package/dist/core/permissions/rules.d.ts.map +1 -0
  29. package/dist/core/permissions/rules.js +34 -0
  30. package/dist/core/permissions/rules.js.map +1 -0
  31. package/dist/core/ports/analytics.d.ts +35 -0
  32. package/dist/core/ports/analytics.d.ts.map +1 -0
  33. package/dist/core/ports/analytics.js +14 -0
  34. package/dist/core/ports/analytics.js.map +1 -0
  35. package/dist/core/ports/auth.d.ts +49 -0
  36. package/dist/core/ports/auth.d.ts.map +1 -0
  37. package/dist/core/ports/auth.js +19 -0
  38. package/dist/core/ports/auth.js.map +1 -0
  39. package/dist/core/ports/comments.d.ts +90 -0
  40. package/dist/core/ports/comments.d.ts.map +1 -0
  41. package/dist/core/ports/comments.js +24 -0
  42. package/dist/core/ports/comments.js.map +1 -0
  43. package/dist/core/ports/database.d.ts +101 -0
  44. package/dist/core/ports/database.d.ts.map +1 -0
  45. package/dist/core/ports/database.js +2 -0
  46. package/dist/core/ports/database.js.map +1 -0
  47. package/dist/core/ports/forms.d.ts +130 -0
  48. package/dist/core/ports/forms.d.ts.map +1 -0
  49. package/dist/core/ports/forms.js +62 -0
  50. package/dist/core/ports/forms.js.map +1 -0
  51. package/dist/core/ports/identity.d.ts +114 -0
  52. package/dist/core/ports/identity.d.ts.map +1 -0
  53. package/dist/core/ports/identity.js +28 -0
  54. package/dist/core/ports/identity.js.map +1 -0
  55. package/dist/core/ports/index.d.ts +21 -0
  56. package/dist/core/ports/index.d.ts.map +1 -0
  57. package/dist/core/ports/index.js +6 -0
  58. package/dist/core/ports/index.js.map +1 -0
  59. package/dist/core/ports/integrations.d.ts +81 -0
  60. package/dist/core/ports/integrations.d.ts.map +1 -0
  61. package/dist/core/ports/integrations.js +21 -0
  62. package/dist/core/ports/integrations.js.map +1 -0
  63. package/dist/core/ports/media.d.ts +74 -0
  64. package/dist/core/ports/media.d.ts.map +1 -0
  65. package/dist/core/ports/media.js +28 -0
  66. package/dist/core/ports/media.js.map +1 -0
  67. package/dist/core/ports/members.d.ts +50 -0
  68. package/dist/core/ports/members.d.ts.map +1 -0
  69. package/dist/core/ports/members.js +17 -0
  70. package/dist/core/ports/members.js.map +1 -0
  71. package/dist/core/ports/menus.d.ts +179 -0
  72. package/dist/core/ports/menus.d.ts.map +1 -0
  73. package/dist/core/ports/menus.js +70 -0
  74. package/dist/core/ports/menus.js.map +1 -0
  75. package/dist/core/ports/plugins.d.ts +68 -0
  76. package/dist/core/ports/plugins.d.ts.map +1 -0
  77. package/dist/core/ports/plugins.js +27 -0
  78. package/dist/core/ports/plugins.js.map +1 -0
  79. package/dist/core/ports/recovery.d.ts +171 -0
  80. package/dist/core/ports/recovery.d.ts.map +1 -0
  81. package/dist/core/ports/recovery.js +2 -0
  82. package/dist/core/ports/recovery.js.map +1 -0
  83. package/dist/core/ports/redirects.d.ts +139 -0
  84. package/dist/core/ports/redirects.d.ts.map +1 -0
  85. package/dist/core/ports/redirects.js +55 -0
  86. package/dist/core/ports/redirects.js.map +1 -0
  87. package/dist/core/ports/seo.d.ts +147 -0
  88. package/dist/core/ports/seo.d.ts.map +1 -0
  89. package/dist/core/ports/seo.js +39 -0
  90. package/dist/core/ports/seo.js.map +1 -0
  91. package/dist/core/ports/settings.d.ts +87 -0
  92. package/dist/core/ports/settings.d.ts.map +1 -0
  93. package/dist/core/ports/settings.js +23 -0
  94. package/dist/core/ports/settings.js.map +1 -0
  95. package/dist/core/ports/workspace.d.ts +44 -0
  96. package/dist/core/ports/workspace.d.ts.map +1 -0
  97. package/dist/core/ports/workspace.js +29 -0
  98. package/dist/core/ports/workspace.js.map +1 -0
  99. package/dist/core/routing/rules.d.ts +54 -0
  100. package/dist/core/routing/rules.d.ts.map +1 -0
  101. package/dist/core/routing/rules.js +113 -0
  102. package/dist/core/routing/rules.js.map +1 -0
  103. package/dist/core/routing/types.d.ts +36 -0
  104. package/dist/core/routing/types.d.ts.map +1 -0
  105. package/dist/core/routing/types.js +17 -0
  106. package/dist/core/routing/types.js.map +1 -0
  107. package/dist/core/transport/errors.d.ts +53 -0
  108. package/dist/core/transport/errors.d.ts.map +1 -0
  109. package/dist/core/transport/errors.js +63 -0
  110. package/dist/core/transport/errors.js.map +1 -0
  111. package/dist/core/transport/http.d.ts +63 -0
  112. package/dist/core/transport/http.d.ts.map +1 -0
  113. package/dist/core/transport/http.js +63 -0
  114. package/dist/core/transport/http.js.map +1 -0
  115. package/dist/core/transport/index.d.ts +5 -0
  116. package/dist/core/transport/index.d.ts.map +1 -0
  117. package/dist/core/transport/index.js +3 -0
  118. package/dist/core/transport/index.js.map +1 -0
  119. package/dist/core/transport/types.d.ts +81 -0
  120. package/dist/core/transport/types.d.ts.map +1 -0
  121. package/dist/core/transport/types.js +43 -0
  122. package/dist/core/transport/types.js.map +1 -0
  123. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts +40 -0
  124. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts.map +1 -0
  125. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +22 -0
  126. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts.map +1 -0
  127. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +59 -0
  128. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js.map +1 -0
  129. package/dist/react/components/ConfirmButton/ConfirmButton.js +40 -0
  130. package/dist/react/components/ConfirmButton/ConfirmButton.js.map +1 -0
  131. package/dist/react/components/ConfirmButton.d.ts +39 -0
  132. package/dist/react/components/ConfirmButton.d.ts.map +1 -0
  133. package/dist/react/components/ConfirmButton.js +79 -0
  134. package/dist/react/components/ConfirmButton.js.map +1 -0
  135. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +90 -0
  136. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
  137. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +49 -0
  138. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +1 -0
  139. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +81 -0
  140. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js.map +1 -0
  141. package/dist/react/components/ConfirmDialog/ConfirmDialog.js +92 -0
  142. package/dist/react/components/ConfirmDialog/ConfirmDialog.js.map +1 -0
  143. package/dist/react/components/ConfirmDialog.d.ts +57 -0
  144. package/dist/react/components/ConfirmDialog.d.ts.map +1 -0
  145. package/dist/react/components/ConfirmDialog.js +85 -0
  146. package/dist/react/components/ConfirmDialog.js.map +1 -0
  147. package/dist/react/components/DataTable.d.ts +97 -0
  148. package/dist/react/components/DataTable.d.ts.map +1 -0
  149. package/dist/react/components/DataTable.js +20 -0
  150. package/dist/react/components/DataTable.js.map +1 -0
  151. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +25 -0
  152. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts.map +1 -0
  153. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +148 -0
  154. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js.map +1 -0
  155. package/dist/react/components/RowMenu/RowMenu.d.ts +77 -0
  156. package/dist/react/components/RowMenu/RowMenu.d.ts.map +1 -0
  157. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +30 -0
  158. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts.map +1 -0
  159. package/dist/react/components/RowMenu/RowMenu.hooks.js +154 -0
  160. package/dist/react/components/RowMenu/RowMenu.hooks.js.map +1 -0
  161. package/dist/react/components/RowMenu/RowMenu.js +46 -0
  162. package/dist/react/components/RowMenu/RowMenu.js.map +1 -0
  163. package/dist/react/components/RowMenu.d.ts +44 -0
  164. package/dist/react/components/RowMenu.d.ts.map +1 -0
  165. package/dist/react/components/RowMenu.js +149 -0
  166. package/dist/react/components/RowMenu.js.map +1 -0
  167. package/dist/react/components/Sidebar.d.ts +128 -0
  168. package/dist/react/components/Sidebar.d.ts.map +1 -0
  169. package/dist/react/components/Sidebar.js +168 -0
  170. package/dist/react/components/Sidebar.js.map +1 -0
  171. package/dist/react/hooks/use-nav-sections.d.ts +50 -0
  172. package/dist/react/hooks/use-nav-sections.d.ts.map +1 -0
  173. package/dist/react/hooks/use-nav-sections.js +112 -0
  174. package/dist/react/hooks/use-nav-sections.js.map +1 -0
  175. package/dist/react/hooks/use-sidebar-rail.d.ts +39 -0
  176. package/dist/react/hooks/use-sidebar-rail.d.ts.map +1 -0
  177. package/dist/react/hooks/use-sidebar-rail.js +93 -0
  178. package/dist/react/hooks/use-sidebar-rail.js.map +1 -0
  179. package/dist/react/index.d.ts +53 -0
  180. package/dist/react/index.d.ts.map +1 -0
  181. package/dist/react/index.js +53 -0
  182. package/dist/react/index.js.map +1 -0
  183. package/dist/react/types.d.ts +28 -0
  184. package/dist/react/types.d.ts.map +1 -0
  185. package/dist/react/types.js +23 -0
  186. package/dist/react/types.js.map +1 -0
  187. package/dist/server/composio/bounded-data.d.ts +36 -0
  188. package/dist/server/composio/bounded-data.d.ts.map +1 -0
  189. package/dist/server/composio/bounded-data.js +181 -0
  190. package/dist/server/composio/bounded-data.js.map +1 -0
  191. package/dist/server/composio/catalog.d.ts +147 -0
  192. package/dist/server/composio/catalog.d.ts.map +1 -0
  193. package/dist/server/composio/catalog.js +126 -0
  194. package/dist/server/composio/catalog.js.map +1 -0
  195. package/dist/server/composio/composio-config.d.ts +42 -0
  196. package/dist/server/composio/composio-config.d.ts.map +1 -0
  197. package/dist/server/composio/composio-config.js +145 -0
  198. package/dist/server/composio/composio-config.js.map +1 -0
  199. package/dist/server/composio/composio-descriptions.d.ts +16 -0
  200. package/dist/server/composio/composio-descriptions.d.ts.map +1 -0
  201. package/dist/server/composio/composio-descriptions.js +766 -0
  202. package/dist/server/composio/composio-descriptions.js.map +1 -0
  203. package/dist/server/composio/composio.d.ts +364 -0
  204. package/dist/server/composio/composio.d.ts.map +1 -0
  205. package/dist/server/composio/composio.js +1902 -0
  206. package/dist/server/composio/composio.js.map +1 -0
  207. package/dist/server/composio/errors.d.ts +15 -0
  208. package/dist/server/composio/errors.d.ts.map +1 -0
  209. package/dist/server/composio/errors.js +16 -0
  210. package/dist/server/composio/errors.js.map +1 -0
  211. package/dist/server/composio/file-lock.d.ts +13 -0
  212. package/dist/server/composio/file-lock.d.ts.map +1 -0
  213. package/dist/server/composio/file-lock.js +92 -0
  214. package/dist/server/composio/file-lock.js.map +1 -0
  215. package/dist/server/composio/index.d.ts +18 -0
  216. package/dist/server/composio/index.d.ts.map +1 -0
  217. package/dist/server/composio/index.js +7 -0
  218. package/dist/server/composio/index.js.map +1 -0
  219. package/dist/server/composio/json-schema.d.ts +93 -0
  220. package/dist/server/composio/json-schema.d.ts.map +1 -0
  221. package/dist/server/composio/json-schema.js +498 -0
  222. package/dist/server/composio/json-schema.js.map +1 -0
  223. package/dist/server/composio/output-protection.d.ts +32 -0
  224. package/dist/server/composio/output-protection.d.ts.map +1 -0
  225. package/dist/server/composio/output-protection.js +105 -0
  226. package/dist/server/composio/output-protection.js.map +1 -0
  227. package/dist/server/composio/service.d.ts +181 -0
  228. package/dist/server/composio/service.d.ts.map +1 -0
  229. package/dist/server/composio/service.js +758 -0
  230. package/dist/server/composio/service.js.map +1 -0
  231. package/dist/server/index.d.ts +15 -0
  232. package/dist/server/index.d.ts.map +1 -0
  233. package/dist/server/index.js +15 -0
  234. package/dist/server/index.js.map +1 -0
  235. package/package.json +92 -0
@@ -0,0 +1,77 @@
1
+ import { type ConfirmTone } from '../../types.js';
2
+ import { useRowMenu } from './RowMenu.hooks.js';
3
+ /**
4
+ * @file Three-dot overflow menu for table rows — replaces the "one visible button per row" pattern
5
+ * so a row can grow more actions (Edit, Disable, Delete, …) without widening the table or producing
6
+ * the wall of buttons that pattern turns into.
7
+ *
8
+ * Portaled to `document.body` and positioned with `getBoundingClientRect()` rather than rendered as
9
+ * an in-flow absolutely-positioned child of the trigger — an admin table normally sits inside a
10
+ * horizontal scroller (`overflow-x: auto`), and per the CSS overflow spec, setting either axis to a
11
+ * non-`visible` value forces the *other* axis to compute as `auto` as well, so a menu positioned to
12
+ * escape the table's own box would be silently clipped by that same scroller. This is the identical
13
+ * problem `Sidebar.tsx`'s `RailTooltip` solves for `.cms-nav`'s `overflow-y: auto` (see that
14
+ * component's doc comment, where it was verified live via `getComputedStyle`) — same fix here: a
15
+ * DOM sibling of the app root, not a descendant of the clipping element. The measurement and
16
+ * repositioning itself lives in `RowMenu.hooks.tsx` — see that file's doc comment.
17
+ *
18
+ * Unstyled: `.row-menu-trigger`, `.row-menu-popup`, `.row-menu-popup-above`, and `.row-menu-item`
19
+ * are emitted for the host stylesheet to define. Only the positioning that has to be measured at
20
+ * runtime is set inline.
21
+ *
22
+ * ## Agent handles
23
+ *
24
+ * Given `agentHandle="post-42"` this publishes, whenever the menu is actually open:
25
+ *
26
+ * | element | handle | role |
27
+ * |---|---|---|
28
+ * | the trigger button | `post-42` | `button` |
29
+ * | one dropdown item, keyed by the caller's own `RowMenuItem.key` | `post-42-item-<slug of key>` | `button` |
30
+ *
31
+ * Items sit under their own `-item-` namespace, via `@jini-ai/agentic`'s `buildAgentListHandles`,
32
+ * rather than directly under `<base>` — a host is free to key an item `"edit"`, and nothing should
33
+ * stop that colliding with a hypothetical future `<base>-edit` action of this component's own, the
34
+ * same reasoning `source-config-list/agent-handles.ts` documents for its own `-field-`/`-item-`
35
+ * namespaces. `buildAgentListHandles` also absorbs two host realities this component cannot control:
36
+ * item keys are arbitrary strings, not pre-validated handle segments, and two different keys can
37
+ * slugify to the same thing (`"Edit"` and `"edit"`) — both are resolved there once rather than
38
+ * re-derived here. `agentHandle` itself is NOT sanitized: it is the caller's own explicit choice of
39
+ * name and a bad one should fail loudly at first render rather than silently answer to a handle the
40
+ * caller never wrote. Omit `agentHandle` and no `data-agent-*` markup is emitted at all.
41
+ *
42
+ * A table renders one `RowMenu` per row, so the caller is responsible for handing each row a
43
+ * DISTINCT base — two rows under the same base would publish duplicate handles and make every verb
44
+ * on them ambiguous.
45
+ */
46
+ export interface RowMenuItem {
47
+ key: string;
48
+ label: string;
49
+ onSelect: () => void;
50
+ /** Visual tone — `"warning"` for reversible-but-access-affecting actions (e.g. Disable),
51
+ * `"danger"` for genuinely destructive ones (e.g. Delete). Defaults to `"default"` (neutral).
52
+ * Shares `ConfirmDialog`'s three-tier vocabulary on purpose — a caller wiring up "Disable opens
53
+ * nothing, Delete opens a ConfirmDialog" from the same item list should not have to reconcile
54
+ * two different tone enums to keep the colors matching. Wins over `destructive` below when both
55
+ * are passed. */
56
+ tone?: ConfirmTone;
57
+ /** @deprecated Use `tone: "danger"` instead — this only ever expressed the danger tier, and the
58
+ * vocabulary has a second one (`"warning"`) this boolean cannot reach. Kept working (mapped to
59
+ * `tone: "danger"` when `tone` is not set) for existing callers rather than a breaking rename. */
60
+ destructive?: boolean;
61
+ }
62
+ export interface RowMenuProps {
63
+ items: RowMenuItem[];
64
+ /** Full accessible name for the trigger, e.g. `Actions for "My Post"` — the row's own title
65
+ * doesn't disambiguate a bare "⋯" for a screen-reader user navigating control-by-control rather
66
+ * than row-by-row, same reasoning as `ConfirmButton.ariaLabel`. */
67
+ triggerLabel: string;
68
+ /** Injectable seam for the menu's open/close, positioning, and keyboard/focus state. Defaults to
69
+ * the real {@link useRowMenu}; a test can pass a fake here to exercise `RowMenu`'s rendering
70
+ * without driving the real positioning math or DOM measurement. */
71
+ useRowMenu?: typeof useRowMenu;
72
+ /** This row's own agent handle — see this file's "Agent handles" doc comment for the full
73
+ * scheme. Omit and no `data-agent-*` markup is emitted at all. */
74
+ agentHandle?: string;
75
+ }
76
+ export declare function RowMenu({ useRowMenu: useRowMenuState, agentHandle: baseHandle, ...props }: RowMenuProps): import("react").JSX.Element;
77
+ //# sourceMappingURL=RowMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.d.ts","sourceRoot":"","sources":["../../../../src/react/components/RowMenu/RowMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;;;;sBAKkB;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;uGAEmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;;wEAEoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB;;wEAEoE;IACpE,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC;IAC/B;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD,wBAAgB,OAAO,CAAC,EACtB,UAAU,EAAE,eAA4B,EACxC,WAAW,EAAE,UAAU,EACvB,GAAG,KAAK,EACT,EAAE,YAAY,+BA0Fd"}
@@ -0,0 +1,30 @@
1
+ import { type KeyboardEvent } from 'react';
2
+ /**
3
+ * @file `RowMenu`'s open/close state, viewport-aware positioning, and keyboard/focus behavior,
4
+ * split out of the component so it can be swapped for a fake via the `useRowMenu` prop on
5
+ * `RowMenuProps` — see that prop's doc comment in `RowMenu.tsx`.
6
+ */
7
+ interface Position {
8
+ top: number;
9
+ left: number;
10
+ placement: 'below' | 'above';
11
+ }
12
+ /**
13
+ * Owns `RowMenu`'s open/close state, positioning, and keyboard/focus behavior.
14
+ *
15
+ * @param itemCount Length of the caller's item list — the only piece of `RowMenuProps` this state
16
+ * needs, for `ArrowUp`-to-last-item and wraparound navigation.
17
+ */
18
+ export declare function useRowMenu(itemCount: number): {
19
+ open: boolean;
20
+ position: Position | null;
21
+ triggerRef: import("react").RefObject<HTMLButtonElement | null>;
22
+ menuRef: import("react").RefObject<HTMLDivElement | null>;
23
+ itemRefs: import("react").RefObject<(HTMLButtonElement | null)[]>;
24
+ onTriggerClick: () => void;
25
+ onTriggerKeyDown: (e: KeyboardEvent<HTMLButtonElement>) => void;
26
+ onMenuKeyDown: (e: KeyboardEvent<HTMLDivElement>) => void;
27
+ selectItem: (onSelect: () => void) => void;
28
+ };
29
+ export {};
30
+ //# sourceMappingURL=RowMenu.hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.hooks.d.ts","sourceRoot":"","sources":["../../../../src/react/components/RowMenu/RowMenu.hooks.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAEzF;;;;GAIG;AAEH,UAAU,QAAQ;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC;CAC9B;AAKD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM;;;;;;;0BAsFb,aAAa,CAAC,iBAAiB,CAAC;uBAUnC,aAAa,CAAC,cAAc,CAAC;2BAoCzB,MAAM,IAAI;EAgBzC"}
@@ -0,0 +1,154 @@
1
+ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ /** 8px clearance kept between the menu and the viewport edge on every side it's tested against. */
3
+ const VIEWPORT_MARGIN = 8;
4
+ /**
5
+ * Owns `RowMenu`'s open/close state, positioning, and keyboard/focus behavior.
6
+ *
7
+ * @param itemCount Length of the caller's item list — the only piece of `RowMenuProps` this state
8
+ * needs, for `ArrowUp`-to-last-item and wraparound navigation.
9
+ */
10
+ export function useRowMenu(itemCount) {
11
+ const [open, setOpen] = useState(false);
12
+ const [position, setPosition] = useState(null);
13
+ const [activeIndex, setActiveIndex] = useState(0);
14
+ const triggerRef = useRef(null);
15
+ const menuRef = useRef(null);
16
+ const itemRefs = useRef([]);
17
+ itemRefs.current = itemRefs.current.slice(0, itemCount);
18
+ function close(returnFocus) {
19
+ setOpen(false);
20
+ setPosition(null);
21
+ if (returnFocus)
22
+ triggerRef.current?.focus();
23
+ }
24
+ function openAt(index) {
25
+ setActiveIndex(index);
26
+ setOpen(true);
27
+ }
28
+ // Measured after the (initially off-screen, `visibility: hidden`) menu has actually laid out, so
29
+ // `menuRef.current`'s real dimensions are known before deciding above-vs-below — a plain
30
+ // `useEffect` would run one paint too late and produce a visible jump. Recomputed on scroll and
31
+ // resize too: a portaled menu is a DOM sibling of its anchor, not a child, so it does not track
32
+ // the anchor's position on its own the way an in-flow popup would.
33
+ useLayoutEffect(() => {
34
+ if (!open)
35
+ return;
36
+ function reposition() {
37
+ const trigger = triggerRef.current;
38
+ if (!trigger)
39
+ return;
40
+ const rect = trigger.getBoundingClientRect();
41
+ const menuHeight = menuRef.current?.offsetHeight ?? 0;
42
+ const menuWidth = menuRef.current?.offsetWidth ?? 0;
43
+ const spaceBelow = window.innerHeight - rect.bottom;
44
+ const fitsBelow = spaceBelow >= menuHeight + VIEWPORT_MARGIN;
45
+ const placement = fitsBelow || rect.top < menuHeight + VIEWPORT_MARGIN ? 'below' : 'above';
46
+ // Right-aligned to the trigger by default (the trigger is the table's last column), clamped
47
+ // so it never overflows the viewport's left or right edge.
48
+ const left = Math.min(Math.max(VIEWPORT_MARGIN, rect.right - menuWidth), window.innerWidth - menuWidth - VIEWPORT_MARGIN);
49
+ setPosition({
50
+ top: placement === 'below' ? rect.bottom + 4 : rect.top - 4,
51
+ left,
52
+ placement,
53
+ });
54
+ }
55
+ reposition();
56
+ window.addEventListener('scroll', reposition, true);
57
+ window.addEventListener('resize', reposition);
58
+ return () => {
59
+ window.removeEventListener('scroll', reposition, true);
60
+ window.removeEventListener('resize', reposition);
61
+ };
62
+ }, [open]);
63
+ // Click-outside closes. Scoped to the open window only, same lifecycle discipline as
64
+ // `ConfirmButton`'s armed-only document listeners — a closed, idle `RowMenu` costs nothing beyond
65
+ // its trigger button even with many mounted per table.
66
+ useEffect(() => {
67
+ if (!open)
68
+ return;
69
+ function onDocMouseDown(e) {
70
+ const target = e.target;
71
+ if (menuRef.current?.contains(target) || triggerRef.current?.contains(target))
72
+ return;
73
+ close(false);
74
+ }
75
+ document.addEventListener('mousedown', onDocMouseDown);
76
+ return () => document.removeEventListener('mousedown', onDocMouseDown);
77
+ // eslint-disable-next-line react-hooks/exhaustive-deps
78
+ }, [open]);
79
+ // Keeps real DOM focus on the active item (roving focus via `tabIndex={-1}` on every item except
80
+ // the active one) rather than only tracking `activeIndex` in state — arrow-key navigation needs
81
+ // to move the browser's actual focus for a screen reader to announce it.
82
+ useEffect(() => {
83
+ if (!open)
84
+ return;
85
+ itemRefs.current[activeIndex]?.focus();
86
+ }, [open, activeIndex]);
87
+ function onTriggerClick() {
88
+ if (open)
89
+ close(false);
90
+ else
91
+ openAt(0);
92
+ }
93
+ function onTriggerKeyDown(e) {
94
+ if (e.key === 'ArrowDown') {
95
+ e.preventDefault();
96
+ openAt(0);
97
+ }
98
+ else if (e.key === 'ArrowUp') {
99
+ e.preventDefault();
100
+ openAt(itemCount - 1);
101
+ }
102
+ }
103
+ function onMenuKeyDown(e) {
104
+ switch (e.key) {
105
+ case 'ArrowDown':
106
+ e.preventDefault();
107
+ setActiveIndex((i) => (i + 1) % itemCount);
108
+ break;
109
+ case 'ArrowUp':
110
+ e.preventDefault();
111
+ setActiveIndex((i) => (i - 1 + itemCount) % itemCount);
112
+ break;
113
+ case 'Home':
114
+ e.preventDefault();
115
+ setActiveIndex(0);
116
+ break;
117
+ case 'End':
118
+ e.preventDefault();
119
+ setActiveIndex(itemCount - 1);
120
+ break;
121
+ case 'Escape':
122
+ e.preventDefault();
123
+ close(true);
124
+ break;
125
+ case 'Tab':
126
+ // Leaving via Tab closes the menu but does not steal focus back to the trigger — the
127
+ // browser's own tab order continues from wherever it lands, matching native menu behavior
128
+ // (and unlike Escape, which is an explicit "back out" gesture).
129
+ close(false);
130
+ break;
131
+ default:
132
+ break;
133
+ }
134
+ }
135
+ /** Closes (returning focus to the trigger, same as Escape) and then fires the selected item's own
136
+ * callback — takes the callback directly rather than a whole `RowMenuItem` so this hook stays
137
+ * free of any dependency on that component-level type. */
138
+ function selectItem(onSelect) {
139
+ close(true);
140
+ onSelect();
141
+ }
142
+ return {
143
+ open,
144
+ position,
145
+ triggerRef,
146
+ menuRef,
147
+ itemRefs,
148
+ onTriggerClick,
149
+ onTriggerKeyDown,
150
+ onMenuKeyDown,
151
+ selectItem,
152
+ };
153
+ }
154
+ //# sourceMappingURL=RowMenu.hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.hooks.js","sourceRoot":"","sources":["../../../../src/react/components/RowMenu/RowMenu.hooks.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { createPortal } from 'react-dom';
3
+ import { agentHandle, buildAgentListHandles } from '@jini-ai/agentic';
4
+ import { resolveTone, toneClassName } from '../../types.js';
5
+ import { useRowMenu } from './RowMenu.hooks.js';
6
+ /**
7
+ * Builds the `data-agent-*` attribute props for one of this row's sub-elements, or nothing at all
8
+ * when the row published no base handle — same shape as `source-config-list/agent-handles.ts`'s
9
+ * `sourceConfigAgentProps`, kept local and unexported here since only this one component needs it.
10
+ *
11
+ * @param handle - This sub-element's already-resolved handle, or `undefined` when the caller
12
+ * published no `agentHandle` for the row at all.
13
+ * @param options - Role and stable label for this sub-element.
14
+ * @returns Spreadable attribute props, or `{}` when `handle` is `undefined`.
15
+ * @complexity O(1).
16
+ */
17
+ function rowMenuAgentProps(handle, options) {
18
+ return handle === undefined ? {} : agentHandle(handle, options);
19
+ }
20
+ export function RowMenu({ useRowMenu: useRowMenuState = useRowMenu, agentHandle: baseHandle, ...props }) {
21
+ const { open, position, triggerRef, menuRef, itemRefs, onTriggerClick, onTriggerKeyDown, onMenuKeyDown, selectItem, } = useRowMenuState(props.items.length);
22
+ // One base handle per item, positionally aligned with `props.items` — undefined (rather than an
23
+ // empty array) when the caller published no `agentHandle` at all, so the render below can tell
24
+ // "opted out" apart from "an empty item list" without a second flag.
25
+ const itemHandles = baseHandle
26
+ ? buildAgentListHandles(`${baseHandle}-item`, props.items.map((item) => item.key))
27
+ : undefined;
28
+ return (_jsxs(_Fragment, { children: [_jsx("button", { ref: triggerRef, type: "button", className: "row-menu-trigger", "aria-label": props.triggerLabel, "aria-haspopup": "menu", "aria-expanded": open, onClick: onTriggerClick, onKeyDown: onTriggerKeyDown, ...rowMenuAgentProps(baseHandle, { role: 'button', label: props.triggerLabel }), children: _jsxs("svg", { viewBox: "0 0 18 18", fill: "currentColor", "aria-hidden": "true", children: [_jsx("circle", { cx: "9", cy: "4.5", r: "1.5" }), _jsx("circle", { cx: "9", cy: "9", r: "1.5" }), _jsx("circle", { cx: "9", cy: "13.5", r: "1.5" })] }) }), open
29
+ ? createPortal(_jsx("div", { ref: menuRef, role: "menu", "aria-label": props.triggerLabel, className: `row-menu-popup${position?.placement === 'above' ? ' row-menu-popup-above' : ''}`, style: {
30
+ position: 'fixed',
31
+ top: position ? position.top : -9999,
32
+ left: position ? position.left : -9999,
33
+ // Laid out but invisible until the first `reposition()` measurement lands (see
34
+ // `RowMenu.hooks.tsx`) — keeps `offsetHeight`/`offsetWidth` measurable without a
35
+ // visible flash at the wrong coordinates.
36
+ visibility: position ? 'visible' : 'hidden',
37
+ transform: position?.placement === 'above' ? 'translateY(-100%)' : undefined,
38
+ }, onKeyDown: onMenuKeyDown, children: props.items.map((item, index) => {
39
+ const toneClass = toneClassName(resolveTone(item));
40
+ return (_jsx("button", { ref: (el) => {
41
+ itemRefs.current[index] = el;
42
+ }, type: "button", role: "menuitem", tabIndex: -1, className: ['row-menu-item', toneClass].filter(Boolean).join(' '), onClick: () => selectItem(item.onSelect), ...rowMenuAgentProps(itemHandles?.[index], { role: 'button', label: item.label }), children: item.label }, item.key));
43
+ }) }), document.body)
44
+ : null] }));
45
+ }
46
+ //# sourceMappingURL=RowMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.js","sourceRoot":"","sources":["../../../../src/react/components/RowMenu/RowMenu.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { type ConfirmTone } from '../types.js';
2
+ /**
3
+ * @file Three-dot overflow menu for table rows — replaces the "one visible button per row" pattern
4
+ * so a row can grow more actions (Edit, Disable, Delete, …) without widening the table or producing
5
+ * the wall of buttons that pattern turns into.
6
+ *
7
+ * Portaled to `document.body` and positioned with `getBoundingClientRect()` rather than rendered as
8
+ * an in-flow absolutely-positioned child of the trigger — an admin table normally sits inside a
9
+ * horizontal scroller (`overflow-x: auto`), and per the CSS overflow spec, setting either axis to a
10
+ * non-`visible` value forces the *other* axis to compute as `auto` as well, so a menu positioned to
11
+ * escape the table's own box would be silently clipped by that same scroller. This is the identical
12
+ * problem `Sidebar.tsx`'s `RailTooltip` solves for `.cms-nav`'s `overflow-y: auto` (see that
13
+ * component's doc comment, where it was verified live via `getComputedStyle`) — same fix here: a
14
+ * DOM sibling of the app root, not a descendant of the clipping element.
15
+ *
16
+ * Unstyled: `.row-menu-trigger`, `.row-menu-popup`, `.row-menu-popup-above`, and `.row-menu-item`
17
+ * are emitted for the host stylesheet to define. Only the positioning that has to be measured at
18
+ * runtime is set inline.
19
+ */
20
+ export interface RowMenuItem {
21
+ key: string;
22
+ label: string;
23
+ onSelect: () => void;
24
+ /** Visual tone — `"warning"` for reversible-but-access-affecting actions (e.g. Disable),
25
+ * `"danger"` for genuinely destructive ones (e.g. Delete). Defaults to `"default"` (neutral).
26
+ * Shares `ConfirmDialog`'s three-tier vocabulary on purpose — a caller wiring up "Disable opens
27
+ * nothing, Delete opens a ConfirmDialog" from the same item list should not have to reconcile
28
+ * two different tone enums to keep the colors matching. Wins over `destructive` below when both
29
+ * are passed. */
30
+ tone?: ConfirmTone;
31
+ /** @deprecated Use `tone: "danger"` instead — this only ever expressed the danger tier, and the
32
+ * vocabulary has a second one (`"warning"`) this boolean cannot reach. Kept working (mapped to
33
+ * `tone: "danger"` when `tone` is not set) for existing callers rather than a breaking rename. */
34
+ destructive?: boolean;
35
+ }
36
+ export interface RowMenuProps {
37
+ items: RowMenuItem[];
38
+ /** Full accessible name for the trigger, e.g. `Actions for "My Post"` — the row's own title
39
+ * doesn't disambiguate a bare "⋯" for a screen-reader user navigating control-by-control rather
40
+ * than row-by-row, same reasoning as `ConfirmButton.ariaLabel`. */
41
+ triggerLabel: string;
42
+ }
43
+ export declare function RowMenu(props: RowMenuProps): import("react").JSX.Element;
44
+ //# sourceMappingURL=RowMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.d.ts","sourceRoot":"","sources":["../../../src/react/components/RowMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3E;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;;;;sBAKkB;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;uGAEmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;;wEAEoE;IACpE,YAAY,EAAE,MAAM,CAAC;CACtB;AAWD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,+BAsM1C"}
@@ -0,0 +1,149 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { resolveTone, toneClassName } from '../types.js';
5
+ /** 8px clearance kept between the menu and the viewport edge on every side it's tested against. */
6
+ const VIEWPORT_MARGIN = 8;
7
+ export function RowMenu(props) {
8
+ const [open, setOpen] = useState(false);
9
+ const [position, setPosition] = useState(null);
10
+ const [activeIndex, setActiveIndex] = useState(0);
11
+ const triggerRef = useRef(null);
12
+ const menuRef = useRef(null);
13
+ const itemRefs = useRef([]);
14
+ itemRefs.current = itemRefs.current.slice(0, props.items.length);
15
+ function close(returnFocus) {
16
+ setOpen(false);
17
+ setPosition(null);
18
+ if (returnFocus)
19
+ triggerRef.current?.focus();
20
+ }
21
+ function openAt(index) {
22
+ setActiveIndex(index);
23
+ setOpen(true);
24
+ }
25
+ // Measured after the (initially off-screen, `visibility: hidden`) menu has actually laid out, so
26
+ // `menuRef.current`'s real dimensions are known before deciding above-vs-below — a plain
27
+ // `useEffect` would run one paint too late and produce a visible jump. Recomputed on scroll and
28
+ // resize too: a portaled menu is a DOM sibling of its anchor, not a child, so it does not track
29
+ // the anchor's position on its own the way an in-flow popup would.
30
+ useLayoutEffect(() => {
31
+ if (!open)
32
+ return;
33
+ function reposition() {
34
+ const trigger = triggerRef.current;
35
+ if (!trigger)
36
+ return;
37
+ const rect = trigger.getBoundingClientRect();
38
+ const menuHeight = menuRef.current?.offsetHeight ?? 0;
39
+ const menuWidth = menuRef.current?.offsetWidth ?? 0;
40
+ const spaceBelow = window.innerHeight - rect.bottom;
41
+ const fitsBelow = spaceBelow >= menuHeight + VIEWPORT_MARGIN;
42
+ const placement = fitsBelow || rect.top < menuHeight + VIEWPORT_MARGIN ? 'below' : 'above';
43
+ // Right-aligned to the trigger by default (the trigger is the table's last column), clamped
44
+ // so it never overflows the viewport's left or right edge.
45
+ const left = Math.min(Math.max(VIEWPORT_MARGIN, rect.right - menuWidth), window.innerWidth - menuWidth - VIEWPORT_MARGIN);
46
+ setPosition({
47
+ top: placement === 'below' ? rect.bottom + 4 : rect.top - 4,
48
+ left,
49
+ placement,
50
+ });
51
+ }
52
+ reposition();
53
+ window.addEventListener('scroll', reposition, true);
54
+ window.addEventListener('resize', reposition);
55
+ return () => {
56
+ window.removeEventListener('scroll', reposition, true);
57
+ window.removeEventListener('resize', reposition);
58
+ };
59
+ }, [open]);
60
+ // Click-outside closes. Scoped to the open window only, same lifecycle discipline as
61
+ // `ConfirmButton`'s armed-only document listeners — a closed, idle `RowMenu` costs nothing beyond
62
+ // its trigger button even with many mounted per table.
63
+ useEffect(() => {
64
+ if (!open)
65
+ return;
66
+ function onDocMouseDown(e) {
67
+ const target = e.target;
68
+ if (menuRef.current?.contains(target) || triggerRef.current?.contains(target))
69
+ return;
70
+ close(false);
71
+ }
72
+ document.addEventListener('mousedown', onDocMouseDown);
73
+ return () => document.removeEventListener('mousedown', onDocMouseDown);
74
+ // eslint-disable-next-line react-hooks/exhaustive-deps
75
+ }, [open]);
76
+ // Keeps real DOM focus on the active item (roving focus via `tabIndex={-1}` on every item except
77
+ // the active one) rather than only tracking `activeIndex` in state — arrow-key navigation needs
78
+ // to move the browser's actual focus for a screen reader to announce it.
79
+ useEffect(() => {
80
+ if (!open)
81
+ return;
82
+ itemRefs.current[activeIndex]?.focus();
83
+ }, [open, activeIndex]);
84
+ function onTriggerKeyDown(e) {
85
+ if (e.key === 'ArrowDown') {
86
+ e.preventDefault();
87
+ openAt(0);
88
+ }
89
+ else if (e.key === 'ArrowUp') {
90
+ e.preventDefault();
91
+ openAt(props.items.length - 1);
92
+ }
93
+ }
94
+ function onMenuKeyDown(e) {
95
+ const count = props.items.length;
96
+ switch (e.key) {
97
+ case 'ArrowDown':
98
+ e.preventDefault();
99
+ setActiveIndex((i) => (i + 1) % count);
100
+ break;
101
+ case 'ArrowUp':
102
+ e.preventDefault();
103
+ setActiveIndex((i) => (i - 1 + count) % count);
104
+ break;
105
+ case 'Home':
106
+ e.preventDefault();
107
+ setActiveIndex(0);
108
+ break;
109
+ case 'End':
110
+ e.preventDefault();
111
+ setActiveIndex(count - 1);
112
+ break;
113
+ case 'Escape':
114
+ e.preventDefault();
115
+ close(true);
116
+ break;
117
+ case 'Tab':
118
+ // Leaving via Tab closes the menu but does not steal focus back to the trigger — the
119
+ // browser's own tab order continues from wherever it lands, matching native menu behavior
120
+ // (and unlike Escape, which is an explicit "back out" gesture).
121
+ close(false);
122
+ break;
123
+ default:
124
+ break;
125
+ }
126
+ }
127
+ function selectItem(item) {
128
+ close(true);
129
+ item.onSelect();
130
+ }
131
+ return (_jsxs(_Fragment, { children: [_jsx("button", { ref: triggerRef, type: "button", className: "row-menu-trigger", "aria-label": props.triggerLabel, "aria-haspopup": "menu", "aria-expanded": open, onClick: () => (open ? close(false) : openAt(0)), onKeyDown: onTriggerKeyDown, children: _jsxs("svg", { viewBox: "0 0 18 18", fill: "currentColor", "aria-hidden": "true", children: [_jsx("circle", { cx: "9", cy: "4.5", r: "1.5" }), _jsx("circle", { cx: "9", cy: "9", r: "1.5" }), _jsx("circle", { cx: "9", cy: "13.5", r: "1.5" })] }) }), open
132
+ ? createPortal(_jsx("div", { ref: menuRef, role: "menu", "aria-label": props.triggerLabel, className: `row-menu-popup${position?.placement === 'above' ? ' row-menu-popup-above' : ''}`, style: {
133
+ position: 'fixed',
134
+ top: position ? position.top : -9999,
135
+ left: position ? position.left : -9999,
136
+ // Laid out but invisible until the first `reposition()` measurement lands (see the
137
+ // layout effect above) — keeps `offsetHeight`/`offsetWidth` measurable without a
138
+ // visible flash at the wrong coordinates.
139
+ visibility: position ? 'visible' : 'hidden',
140
+ transform: position?.placement === 'above' ? 'translateY(-100%)' : undefined,
141
+ }, onKeyDown: onMenuKeyDown, children: props.items.map((item, index) => {
142
+ const toneClass = toneClassName(resolveTone(item));
143
+ return (_jsx("button", { ref: (el) => {
144
+ itemRefs.current[index] = el;
145
+ }, type: "button", role: "menuitem", tabIndex: -1, className: ['row-menu-item', toneClass].filter(Boolean).join(' '), onClick: () => selectItem(item), children: item.label }, item.key));
146
+ }) }), document.body)
147
+ : null] }));
148
+ }
149
+ //# sourceMappingURL=RowMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.js","sourceRoot":"","sources":["../../../src/react/components/RowMenu.tsx"],"names":[],"mappings":"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"}