charcell 0.1.0
mode

ActionMenu

a list of actions that opens from a button, with separators between groups.

usage

example

code

import { ActionMenu, Button } from 'charcell/react';

export function ActionMenuExample() {
  return (
    <ActionMenu
      items={[
        { value: 'aim', label: 'aim' },
        { value: 'fire', label: 'fire' },
        { value: 'break', separator: true },
        { value: 'raise', label: 'raise', disabled: true },
        { value: 'lower', label: 'lower' },
      ]}
      trigger={({ triggerProps }) => (
        <Button {...triggerProps} label="turret" />
      )}
    />
  );
}

as text

at rest
┌────────┐
│ turret │
├────────┴╖
│❯aim     ║
│ fire    ║
│╶───────╴║
│ raise   ║
│ lower   ║
╘═════════╝
hover
┌────────┐
│ turret │
├────────┴╖
│❯aim     ║
│ fire    ║
│╶───────╴║
│ raise   ║
│ lower   ║
╘═════════╝
press
┌────────┐
│ turret │
├────────┴╖
│❯aim     ║
│ fire    ║
│╶───────╴║
│ raise   ║
│ lower   ║
╘═════════╝
focus
┌────────┐
│❯turret │
├────────┴╖
│❯aim     ║
│ fire    ║
│╶───────╴║
│ raise   ║
│ lower   ║
╘═════════╝

props

ActionMenu

direction'ltr' | 'rtl'
The reading direction its keys and placement follow ('rtl' mirrors the arrow keys); the page's, once mounted, when unset.
itemsActionMenuItem[]
The actions, in order: { value, label, disabled }, or { value, separator: true } for a break between groups.
onSelect(value: string) => void
Called with the chosen item's value.
labelstring
The list's accessible name, when its trigger does not say enough.
widthnumber
The menu's width in whole cells, its ring included; it fits its content when unset.
minWidthnumber
The menu's least width in whole cells, its ring included: it grows past it with its content.
attachedboolean= true
Whether the list grows out of a boxed trigger, sharing its last row of stroke; it does when it opens at a start placement ('bottom-start', 'top-start'), as placed once it fits the screen, and its left side, and the side it shares (its top below, its bottom above), are single or rounded, as a boxed Button's are. false holds it a row apart, for a trigger with no ring.
openboolean
Controlled open state; pair it with onOpenChange.
binds with v-model:open in vue, bind:open in svelte
defaultOpenboolean
Uncontrolled initial open state.
onOpenChange(open: boolean) => void
Called with the next open state whenever the menu opens or closes.
spaciousboolean
Gives each item two rows, its text in the first: a 32px target, which meets WCAG 2.5.8. One-row items miss it.
closeOnSelectboolean= true
Whether choosing an item closes the menu.
loopFocusboolean
Whether the highlight wraps from the last item to the first.
placementPlacement
Where the list opens against its trigger, as a Zag placement ('bottom-start' when unset).
border'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of every side of the list's ring: single, rounded, heavy, double or none.
borderX'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's start and end sides, over border.
borderY'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's top and bottom sides, over border.
borderTop'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's top side, over borderY and border.
borderEnd'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's end side, over borderX and border; double when none of them is set, raising the list.
borderBottom'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's bottom side, over borderY and border; double when none of them is set, raising the list.
borderStart'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the list's ring's start side, over borderX and border.

ActionMenuList

attachedboolean
Fuses the window to a boxed trigger: it moves one row onto it and shares its stroke.
spaciousboolean
Each item takes two rows, its text in the first: a 32px target, which meets WCAG 2.5.8.
aboveboolean
Opened above the trigger, so an attached window shares the trigger's top stroke.
widthnumber
The window's width in whole cells, its ring included; it fits its content when unset, and never outgrows the space it has.
minWidthnumber
The window's least width in whole cells, its ring included: it grows past it with its content.
border'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of every side of the ring: single, rounded, heavy, double or none.
borderX'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's start and end sides, over border.
borderY'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's top and bottom sides, over border.
borderTop'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's top side, over borderY and border.
borderEnd'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's end side, over borderX and border.
borderBottom'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's bottom side, over borderY and border.
borderStart'none' | 'single' | 'rounded' | 'heavy' | 'double'
The style of the ring's start side, over borderX and border.

it also takes any other attribute of its <div>.

slots

in react, the default slot is children and each named slot a prop of its name, a function where the slot hands values; in vue, a slot; in svelte, a snippet.

ActionMenu

trigger{ triggerProps: Record<string, unknown> }its values required
What opens the menu, typically a Button: spread triggerProps onto it.

ActionMenuList

default