@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.
- package/LICENSE +201 -0
- package/README.md +138 -0
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +8 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/navigation.d.ts +39 -0
- package/dist/browser/navigation.d.ts.map +1 -0
- package/dist/browser/navigation.js +113 -0
- package/dist/browser/navigation.js.map +1 -0
- package/dist/core/gated/types.d.ts +87 -0
- package/dist/core/gated/types.d.ts.map +1 -0
- package/dist/core/gated/types.js +37 -0
- package/dist/core/gated/types.js.map +1 -0
- package/dist/core/index.d.ts +20 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +15 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/manifest/rules.d.ts +84 -0
- package/dist/core/manifest/rules.d.ts.map +1 -0
- package/dist/core/manifest/rules.js +130 -0
- package/dist/core/manifest/rules.js.map +1 -0
- package/dist/core/manifest/types.d.ts +154 -0
- package/dist/core/manifest/types.d.ts.map +1 -0
- package/dist/core/manifest/types.js +31 -0
- package/dist/core/manifest/types.js.map +1 -0
- package/dist/core/permissions/rules.d.ts +32 -0
- package/dist/core/permissions/rules.d.ts.map +1 -0
- package/dist/core/permissions/rules.js +34 -0
- package/dist/core/permissions/rules.js.map +1 -0
- package/dist/core/ports/analytics.d.ts +35 -0
- package/dist/core/ports/analytics.d.ts.map +1 -0
- package/dist/core/ports/analytics.js +14 -0
- package/dist/core/ports/analytics.js.map +1 -0
- package/dist/core/ports/auth.d.ts +49 -0
- package/dist/core/ports/auth.d.ts.map +1 -0
- package/dist/core/ports/auth.js +19 -0
- package/dist/core/ports/auth.js.map +1 -0
- package/dist/core/ports/comments.d.ts +90 -0
- package/dist/core/ports/comments.d.ts.map +1 -0
- package/dist/core/ports/comments.js +24 -0
- package/dist/core/ports/comments.js.map +1 -0
- package/dist/core/ports/database.d.ts +101 -0
- package/dist/core/ports/database.d.ts.map +1 -0
- package/dist/core/ports/database.js +2 -0
- package/dist/core/ports/database.js.map +1 -0
- package/dist/core/ports/forms.d.ts +130 -0
- package/dist/core/ports/forms.d.ts.map +1 -0
- package/dist/core/ports/forms.js +62 -0
- package/dist/core/ports/forms.js.map +1 -0
- package/dist/core/ports/identity.d.ts +114 -0
- package/dist/core/ports/identity.d.ts.map +1 -0
- package/dist/core/ports/identity.js +28 -0
- package/dist/core/ports/identity.js.map +1 -0
- package/dist/core/ports/index.d.ts +21 -0
- package/dist/core/ports/index.d.ts.map +1 -0
- package/dist/core/ports/index.js +6 -0
- package/dist/core/ports/index.js.map +1 -0
- package/dist/core/ports/integrations.d.ts +81 -0
- package/dist/core/ports/integrations.d.ts.map +1 -0
- package/dist/core/ports/integrations.js +21 -0
- package/dist/core/ports/integrations.js.map +1 -0
- package/dist/core/ports/media.d.ts +74 -0
- package/dist/core/ports/media.d.ts.map +1 -0
- package/dist/core/ports/media.js +28 -0
- package/dist/core/ports/media.js.map +1 -0
- package/dist/core/ports/members.d.ts +50 -0
- package/dist/core/ports/members.d.ts.map +1 -0
- package/dist/core/ports/members.js +17 -0
- package/dist/core/ports/members.js.map +1 -0
- package/dist/core/ports/menus.d.ts +179 -0
- package/dist/core/ports/menus.d.ts.map +1 -0
- package/dist/core/ports/menus.js +70 -0
- package/dist/core/ports/menus.js.map +1 -0
- package/dist/core/ports/plugins.d.ts +68 -0
- package/dist/core/ports/plugins.d.ts.map +1 -0
- package/dist/core/ports/plugins.js +27 -0
- package/dist/core/ports/plugins.js.map +1 -0
- package/dist/core/ports/recovery.d.ts +171 -0
- package/dist/core/ports/recovery.d.ts.map +1 -0
- package/dist/core/ports/recovery.js +2 -0
- package/dist/core/ports/recovery.js.map +1 -0
- package/dist/core/ports/redirects.d.ts +139 -0
- package/dist/core/ports/redirects.d.ts.map +1 -0
- package/dist/core/ports/redirects.js +55 -0
- package/dist/core/ports/redirects.js.map +1 -0
- package/dist/core/ports/seo.d.ts +147 -0
- package/dist/core/ports/seo.d.ts.map +1 -0
- package/dist/core/ports/seo.js +39 -0
- package/dist/core/ports/seo.js.map +1 -0
- package/dist/core/ports/settings.d.ts +87 -0
- package/dist/core/ports/settings.d.ts.map +1 -0
- package/dist/core/ports/settings.js +23 -0
- package/dist/core/ports/settings.js.map +1 -0
- package/dist/core/ports/workspace.d.ts +44 -0
- package/dist/core/ports/workspace.d.ts.map +1 -0
- package/dist/core/ports/workspace.js +29 -0
- package/dist/core/ports/workspace.js.map +1 -0
- package/dist/core/routing/rules.d.ts +54 -0
- package/dist/core/routing/rules.d.ts.map +1 -0
- package/dist/core/routing/rules.js +113 -0
- package/dist/core/routing/rules.js.map +1 -0
- package/dist/core/routing/types.d.ts +36 -0
- package/dist/core/routing/types.d.ts.map +1 -0
- package/dist/core/routing/types.js +17 -0
- package/dist/core/routing/types.js.map +1 -0
- package/dist/core/transport/errors.d.ts +53 -0
- package/dist/core/transport/errors.d.ts.map +1 -0
- package/dist/core/transport/errors.js +63 -0
- package/dist/core/transport/errors.js.map +1 -0
- package/dist/core/transport/http.d.ts +63 -0
- package/dist/core/transport/http.d.ts.map +1 -0
- package/dist/core/transport/http.js +63 -0
- package/dist/core/transport/http.js.map +1 -0
- package/dist/core/transport/index.d.ts +5 -0
- package/dist/core/transport/index.d.ts.map +1 -0
- package/dist/core/transport/index.js +3 -0
- package/dist/core/transport/index.js.map +1 -0
- package/dist/core/transport/types.d.ts +81 -0
- package/dist/core/transport/types.d.ts.map +1 -0
- package/dist/core/transport/types.js +43 -0
- package/dist/core/transport/types.js.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.d.ts +40 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +22 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +59 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.js +40 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.js.map +1 -0
- package/dist/react/components/ConfirmButton.d.ts +39 -0
- package/dist/react/components/ConfirmButton.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton.js +79 -0
- package/dist/react/components/ConfirmButton.js.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +90 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +49 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +81 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +92 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js.map +1 -0
- package/dist/react/components/ConfirmDialog.d.ts +57 -0
- package/dist/react/components/ConfirmDialog.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog.js +85 -0
- package/dist/react/components/ConfirmDialog.js.map +1 -0
- package/dist/react/components/DataTable.d.ts +97 -0
- package/dist/react/components/DataTable.d.ts.map +1 -0
- package/dist/react/components/DataTable.js +20 -0
- package/dist/react/components/DataTable.js.map +1 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +25 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts.map +1 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +148 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.d.ts +77 -0
- package/dist/react/components/RowMenu/RowMenu.d.ts.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +30 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.d.ts.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.js +154 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.js.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.js +46 -0
- package/dist/react/components/RowMenu/RowMenu.js.map +1 -0
- package/dist/react/components/RowMenu.d.ts +44 -0
- package/dist/react/components/RowMenu.d.ts.map +1 -0
- package/dist/react/components/RowMenu.js +149 -0
- package/dist/react/components/RowMenu.js.map +1 -0
- package/dist/react/components/Sidebar.d.ts +128 -0
- package/dist/react/components/Sidebar.d.ts.map +1 -0
- package/dist/react/components/Sidebar.js +168 -0
- package/dist/react/components/Sidebar.js.map +1 -0
- package/dist/react/hooks/use-nav-sections.d.ts +50 -0
- package/dist/react/hooks/use-nav-sections.d.ts.map +1 -0
- package/dist/react/hooks/use-nav-sections.js +112 -0
- package/dist/react/hooks/use-nav-sections.js.map +1 -0
- package/dist/react/hooks/use-sidebar-rail.d.ts +39 -0
- package/dist/react/hooks/use-sidebar-rail.d.ts.map +1 -0
- package/dist/react/hooks/use-sidebar-rail.js +93 -0
- package/dist/react/hooks/use-sidebar-rail.js.map +1 -0
- package/dist/react/index.d.ts +53 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +53 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/types.d.ts +28 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/react/types.js +23 -0
- package/dist/react/types.js.map +1 -0
- package/dist/server/composio/bounded-data.d.ts +36 -0
- package/dist/server/composio/bounded-data.d.ts.map +1 -0
- package/dist/server/composio/bounded-data.js +181 -0
- package/dist/server/composio/bounded-data.js.map +1 -0
- package/dist/server/composio/catalog.d.ts +147 -0
- package/dist/server/composio/catalog.d.ts.map +1 -0
- package/dist/server/composio/catalog.js +126 -0
- package/dist/server/composio/catalog.js.map +1 -0
- package/dist/server/composio/composio-config.d.ts +42 -0
- package/dist/server/composio/composio-config.d.ts.map +1 -0
- package/dist/server/composio/composio-config.js +145 -0
- package/dist/server/composio/composio-config.js.map +1 -0
- package/dist/server/composio/composio-descriptions.d.ts +16 -0
- package/dist/server/composio/composio-descriptions.d.ts.map +1 -0
- package/dist/server/composio/composio-descriptions.js +766 -0
- package/dist/server/composio/composio-descriptions.js.map +1 -0
- package/dist/server/composio/composio.d.ts +364 -0
- package/dist/server/composio/composio.d.ts.map +1 -0
- package/dist/server/composio/composio.js +1902 -0
- package/dist/server/composio/composio.js.map +1 -0
- package/dist/server/composio/errors.d.ts +15 -0
- package/dist/server/composio/errors.d.ts.map +1 -0
- package/dist/server/composio/errors.js +16 -0
- package/dist/server/composio/errors.js.map +1 -0
- package/dist/server/composio/file-lock.d.ts +13 -0
- package/dist/server/composio/file-lock.d.ts.map +1 -0
- package/dist/server/composio/file-lock.js +92 -0
- package/dist/server/composio/file-lock.js.map +1 -0
- package/dist/server/composio/index.d.ts +18 -0
- package/dist/server/composio/index.d.ts.map +1 -0
- package/dist/server/composio/index.js +7 -0
- package/dist/server/composio/index.js.map +1 -0
- package/dist/server/composio/json-schema.d.ts +93 -0
- package/dist/server/composio/json-schema.d.ts.map +1 -0
- package/dist/server/composio/json-schema.js +498 -0
- package/dist/server/composio/json-schema.js.map +1 -0
- package/dist/server/composio/output-protection.d.ts +32 -0
- package/dist/server/composio/output-protection.d.ts.map +1 -0
- package/dist/server/composio/output-protection.js +105 -0
- package/dist/server/composio/output-protection.js.map +1 -0
- package/dist/server/composio/service.d.ts +181 -0
- package/dist/server/composio/service.d.ts.map +1 -0
- package/dist/server/composio/service.js +758 -0
- package/dist/server/composio/service.js.map +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +15 -0
- package/dist/server/index.js.map +1 -0
- 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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"}
|