@xsolla/xui-context-menu 0.174.3 → 0.175.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 (2) hide show
  1. package/README.md +51 -15
  2. package/package.json +10 -10
package/README.md CHANGED
@@ -1,20 +1,56 @@
1
1
  # Context Menu
2
2
 
3
- ## Overview
4
-
5
- `ContextMenu` is an anchored panel of selectable cells. The component is built around two primitives: a single `ContextMenuItem` whose `type` prop switches between cell variants (`option`, `search`, `heading`, `divider`), and a panel that supports a preset shorthand (`type="list" | "phone" | "checkbox" | "radio" | "status" | "brandLogo" | "avatar" | "loading"`) plus a fully custom composition path via `children`.
6
-
7
- ## When to use
8
-
9
- - A primary action menu attached to a trigger (e.g. a button's overflow actions).
10
- - A selection control with checkbox or radio cells (multi-select or single-select).
11
- - A lightweight picker for status, country, or brand-logo lists.
12
-
13
- ## When not to use
14
-
15
- - For form fields driven by validation — use `Select`, `Autocomplete` or a plain `Input` instead.
16
- - For navigational menus or app-level navigation use the appropriate navigation primitives.
17
- - For a single destructive confirmation — use a `Dialog`.
3
+ <!-- BEGIN:xui-mcp-instructions:context-menu -->
4
+ A floating panel containing a vertical list of ContextMenuCell rows. Serves as the shared dropdown layer for multiple input components — Select, Multiselect, Combobox, StatusDropdown, Phone input — as well as for contextual action menus triggered by right-click or an overflow button. Each instance is a preset configuration of cells — the Type prop selects a ready-made composition suited to a specific use case. All cells within one menu share the same Size.
5
+
6
+ ### When to use
7
+ - As the dropdown panel for Select — single-value picker from a predefined list
8
+ - As the dropdown panel for Multiselect — multiple-value picker; use Type=Checkbox so selections stay visible
9
+ - As the dropdown panel for Autocomplete use Type=Search + options
10
+ - As the dropdown panel for StatusDropdown inline status picker; use Type=Status
11
+ - As the dropdown panel for Phone input — country dial-code picker; use Type=Phone
12
+ - To surface contextual actions for a selected item or element (right-click menu, overflow *"⋯"* button)
13
+ - When the number of actions or options is too large for inline buttons but too small for a full page
14
+
15
+ ### When not to use
16
+ - As the primary navigation of a page and top-level site navigation
17
+ - When there are only 1–2 actions — use ToggleButtonGroup, Radio or Checkboxes
18
+ - When the selection requires multiple steps or complex input — use a Dialog or a dedicated panel
19
+
20
+ ### Content guidelines
21
+ - Option labels — concise imperative verbs for actions (*"Delete"*, *"Rename"*, *"Export"*); nouns for selections (*"English"*, *"Admin"*, *"Dark mode"*). Keep to 1–4 words.
22
+ - Heading labels — short noun phrases in title case or uppercase; describe the group below. Examples: *"Actions"*, *"Sort by"*, *"FILTERS"*.
23
+ - Destructive label colour — use the Alert/red colour token for the label text of destructive options. Do not use red for informational or reversible actions.
24
+ - Search placeholder — use *"Search…"* or a more specific variant: *"Search countries…"*, *"Search members…"*.
25
+ - Empty state message — be specific: *"No countries match"*, *"No team members found"*. Avoid generic *"No results"* when a more informative string is available.
26
+ - Menu length — aim for 7 or fewer options before considering grouping, search, or a different pattern. More than 12 options without search significantly degrades usability.
27
+
28
+ ### Behaviour guidelines
29
+ - Trigger — the menu opens from a trigger element: right-click on a target, click on an overflow button (⋯), or programmatic call. The trigger element should have aria-haspopup=*"menu"* and aria-expanded updated on open/close.
30
+ - Positioning — the panel is positioned relative to the trigger. Default placement is bottom-start; fallback to top-start, bottom-end, or top-end when the default position would clip the viewport. Never let the panel appear partially off-screen.
31
+ - Width — the panel width is set by Size × Type. Do not stretch it to fill the viewport or a parent container. If option labels are longer than the panel width, truncate with ellipsis and show a tooltip on hover.
32
+ - Single-select close — for Type=List, Phone, Avatar, BrandLogo, Status, and Radio, the menu closes automatically after the user selects an option. The trigger updates to reflect the new value.
33
+ - Multi-select stay open — for Type=Checkbox, the menu stays open after each selection. Close on: clicking outside, pressing Escape, or an explicit *"Apply"* / close action.
34
+ - Loading state — show Type=Loading immediately when the menu opens and the option list has not yet been fetched. The panel renders at its normal dimensions with a centered Loader spinner replacing all cell content. Switch to the real Type as soon as data arrives. Do not show an empty panel while loading.
35
+ - Empty state — if search filtering produces no results, show an empty state message inside the panel (e.g. *"No results found"*) rather than closing the menu or showing a blank panel.
36
+ - Search filtering — when a Type=Search cell is present, typing filters visible options in real time with ~200ms debounce. Heading cells and dividers that become empty after filtering should be hidden alongside their options to avoid orphaned labels.
37
+ - Sub-menus — an option with a chevron in its right slot opens a nested ContextMenu on hover (desktop) or tap (touch). The parent item remains in Hover/Active state while the sub-menu is open. ← / Escape closes the sub-menu and returns focus to the parent item.
38
+ - Destructive actions — place destructive options (delete, remove, revoke) at the bottom of the list, separated from safe actions by a Type=Divider cell. Render in the Alert/red colour token.
39
+ - Scroll — if the option list exceeds the viewport height, the panel body becomes scrollable. Pin the Type=Search cell to the top so it remains visible while the user scrolls through options. Pin a footer action row to the bottom if one is present.
40
+ - Focus management — when the menu opens, focus moves to the first interactive option (or to the Search input if present). When the menu closes, focus returns to the trigger element.
41
+
42
+ ### Accessibility
43
+ - The panel must have role=*"menu"* (for action menus) or role=*"listbox"* (for selection menus). Each Type=Option cell must have role=*"menuitem"*, role=*"menuitemcheckbox"*, or role=*"option"* accordingly.
44
+ - The trigger element must have aria-haspopup=*"menu"* and aria-expanded=*"true"* / *"false"* to reflect the open state.
45
+ - Type=Heading cells must either wrap their option group in role=*"group"* with aria-labelledby pointing to the heading, or carry role=*"presentation"* themselves.
46
+ - Type=Divider cells must have role=*"separator"*.
47
+ - Type=Search input must have role=*"searchbox"* and aria-label (e.g. aria-label=*"Search options"*).
48
+ - When the menu opens, move focus to the first focusable option (or the Search input if present).
49
+ - Keyboard navigation: ↑ / ↓ move between options (skipping Heading and Divider); Enter / Space activate the focused option; Escape closes the menu and returns focus to the trigger; Tab closes the menu and moves focus to the next element in the page.
50
+ - For sub-menus: → / Enter opens the sub-menu; ← / Escape closes it and returns focus to the parent item.
51
+ - When the menu closes, focus must return to the trigger element that opened it.
52
+ - For Type=Checkbox (multi-select), each option must have aria-checked=*"true"* / *"false"*. For Type=Radio and single-select list types, use aria-selected or aria-checked consistently with the chosen ARIA role.
53
+ <!-- END:xui-mcp-instructions:context-menu -->
18
54
 
19
55
  ## Installation
20
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-context-menu",
3
- "version": "0.174.3",
3
+ "version": "0.175.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,15 +13,15 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-checkbox": "0.174.3",
17
- "@xsolla/xui-core": "0.174.3",
18
- "@xsolla/xui-divider": "0.174.3",
19
- "@xsolla/xui-icons": "0.174.3",
20
- "@xsolla/xui-icons-base": "0.174.3",
21
- "@xsolla/xui-primitives-core": "0.174.3",
22
- "@xsolla/xui-radio": "0.174.3",
23
- "@xsolla/xui-spinner": "0.174.3",
24
- "@xsolla/xui-typography": "0.174.3"
16
+ "@xsolla/xui-checkbox": "0.175.0",
17
+ "@xsolla/xui-core": "0.175.0",
18
+ "@xsolla/xui-divider": "0.175.0",
19
+ "@xsolla/xui-icons": "0.175.0",
20
+ "@xsolla/xui-icons-base": "0.175.0",
21
+ "@xsolla/xui-primitives-core": "0.175.0",
22
+ "@xsolla/xui-radio": "0.175.0",
23
+ "@xsolla/xui-spinner": "0.175.0",
24
+ "@xsolla/xui-typography": "0.175.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": ">=16.8.0",