Bumbag UI Library

repository·main·Indexed 21 days ago

https://github.com/jxom/bumbag-ui

A UI library for building themeable applications across React and React Native platforms. It includes various packages and addons such as @bumbag/addon-highlighted-code, @bumbag/addon-markdown, @bumbag-native/bottom-sheet, @bumbag-native/haptic, bumbag-native-picker, and @bumbag/native-toast. Note: Bumbag is currently unmaintained.

Tokens
285.2K
Snippets
906
Records
1.3K
Agent score
76%

What's inside Bumbag

  1. Use OptionGroups for selectable items

    main

    The <DropdownMenu.OptionGroup> component allows you to include selectable items that behave like checkboxes or radio buttons within a menu.

    Uncontrolled Usage

    Use defaultValue to set the initial selection. For checkboxes, defaultValue is an array of values. For radio, it is a single value.

    Controlled Usage

    Use value to manage the state and onChange to handle selection changes.

    Props

    • type: Either 'radio' (single selection) or 'checkbox' (multiple selection).
    • title: The label for the group.
    • value: The current selected value(s) (for controlled components).
    • defaultValue: The initial selected value(s) (for uncontrolled components).
    • onChange: Callback function triggered when the selection changes.
    // Controlled Example
    function Example() {
      const [sortBy, setSortBy] = React.useState('asc');
      const [countries, setCountries] = React.useState(['australia', 'india']);
    
      return (
        <DropdownMenu
          menu={
            <React.Fragment>
              <DropdownMenu.OptionGroup
                onChange={setSortBy}
                value={sortBy}
                title="Sort by"
                type="radio"
              >
                <DropdownMenu.OptionItem value="asc">Ascending</DropdownMenu.OptionItem>
                <DropdownMenu.OptionItem value="desc">Descending</DropdownMenu.OptionItem>
              </DropdownMenu.OptionGroup>
    
              <DropdownMenu.OptionGroup
                onChange={setCountries}
                value={countries}
                title="Countries"
                type="checkbox"
              >
                <DropdownMenu.OptionItem value="australia">Australia</DropdownMenu.OptionItem>
                <DropdownMenu.OptionItem value="us">United States</DropdownMenu.OptionItem>
                <DropdownMenu.OptionItem value="india">India</DropdownMenu.OptionItem>
              </DropdownMenu.OptionGroup>
            </React.Fragment>
          }
        >
          <Button iconAfter="chevron-down">Filters</Button>
        </DropdownMenu>
      );
    }
  2. Handle touch responder capture phase

    main

    By default, responder handlers like onStartShouldSetResponder and onMoveShouldSetResponder use a bubbling pattern where the deepest node is called first. This ensures child controls (like buttons) are usable.

    If a parent component needs to intercept a touch before it reaches its children, use the capture phase handlers. Returning true from these handlers allows the parent to become the responder and prevent children from receiving the touch event.

    // To prevent children from becoming responders on touch start:
    onStartShouldSetResponderCapture: (event: GestureResponderEvent) => boolean;
    
    // To prevent children from becoming responders on move:
    onMoveShouldSetResponderCapture: (event: GestureResponderEvent) => boolean;
  3. Accessibility requirements for Switch

    main

    The <Switch> component follows the WAI ARIA Checkbox Pattern.

    Accessibility Rules

    • Labeling: The switch must have an accessible label. You should provide a label prop. If label is not provided, you must specify either aria-label or aria-labelledby.

    Interaction Patterns

    • Role: The component has a role of checkbox.
    • Keyboard: When the switch has focus, pressing the Space key changes its state.
  4. Ensure Input accessibility

    main

    To maintain accessibility, every input must have an accessible label. You can achieve this in three ways:

    1. Use the <InputField> component with a label prop.
    2. Use aria-label or aria-labelledby directly on the <Input>.
    3. Use a standard <Label> with htmlFor matching the <Input> id.

    Bumbag automatically sets aria-required="true" if an input is required and aria-invalid="true" if it is invalid.

    // Via InputField
    <InputField label="First name" />
    
    // Via aria-label
    <Input aria-label="First name" />
    
    // Via htmlFor/id
    <Label htmlFor="firstName">First name</Label>
    <Input id="firstName" />
  5. Use the Box primitive in Bumbag Native

    main

    The <Box> component is the fundamental building block of all Bumbag Native components. It serves as a primitive that renders React Native's <View> component at its core. You can use it to create layout containers and styled elements by passing layout and style props directly to it.

    <Box>
      <Box width="50px" height="50px" backgroundColor="primary" />
      <Box width="50px" height="50px" backgroundColor="secondary" />
    </Box>
  6. Group and set Tags

    main

    Tags are often used in collections. You can use <Set> for spacing between tags or <Group> to wrap them together.

    Using Set

    <Set spacing="minor-1">
      <Tag>Tag 1</Tag>
      <Tag>Tag 2</Tag>
    </Set>

    Using Group

    <Group>
      <Tag>Default</Tag>
      <Tag palette="textTint">Hello</Tag>
    </Group>
    <Set spacing="minor-1">
      <Tag>Hello</Tag>
      <Tag>World</Tag>
    </Set>
  7. Accessibility patterns for Rating

    main

    The <Rating> component is built with accessibility in mind using the following patterns:

    • It extends the accessibility features of the RadioGroup component.
    • Rating.Item has a role="radio".
    • The currently selected item has aria-checked="true".
    • Each item includes aria-posinset (its position in the set) and aria-setsize (the total number of items in the set).
  8. How Popover components work together

    main

    A Popover is a lightweight dialog that floats beside a disclosure trigger. To use it, you typically compose three parts:

    1. <Popover.State>: Manages the open/closed state. It can be used as a wrapper or via render props to provide utilities like hide.
    2. <Popover.Disclosure>: The trigger element (e.g., a button) that opens the popover. Use the use prop to specify which component should act as the trigger.
    3. <Popover>: The actual floating content container.

    For automatic state management, wrap them in <Popover.State>. For manual control, use the Popover.useState() hook or the render prop pattern.

    import { Popover } from 'bumbag';
    
    <Popover.State>
      <Popover.Disclosure use={Button}>Open Popover</Popover.Disclosure>
      <Popover hasArrow>
        Popover content goes here.
      </Popover>
    </Popover.State>
  9. Toggle the header visibility

    main

    You can control the visibility of the header in two ways:

    1. Using <PageWithHeader.Disclosure>: This component acts as a trigger (e.g., a button) to toggle the header. Use the use prop to specify which component should be used as the trigger.
    2. Using the usePage hook: For more manual control, use the usePage hook to access the header object, which contains a toggle method.

    Note: The usePage hook must be used within a component that is a child of <PageWithHeader>.

    // Option 1: Using Disclosure component
    <PageWithHeader.Disclosure use={Button}>
      Toggle header
    </PageWithHeader.Disclosure>
    
    // Option 2: Using usePage hook
    function Example() {
      const { header } = usePage();
      return (
        <Button onClick={header.toggle}>Toggle header</Button>
      )
    }