@maxio-com/react-ui-components 9.16.0 → 9.16.1
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/dist/skills/maxio-react/SKILL.md +68 -0
- package/dist/skills/maxio-react/agents/openai.yaml +4 -0
- package/dist/skills/maxio-react/references/components-action-list.md +92 -0
- package/dist/skills/maxio-react/references/components-action-menu.md +162 -0
- package/dist/skills/maxio-react/references/components-avatar.md +66 -0
- package/dist/skills/maxio-react/references/components-breadcrumbs.md +86 -0
- package/dist/skills/maxio-react/references/components-buttons-button.md +170 -0
- package/dist/skills/maxio-react/references/components-buttons-iconbutton.md +102 -0
- package/dist/skills/maxio-react/references/components-card.md +175 -0
- package/dist/skills/maxio-react/references/components-chip.md +151 -0
- package/dist/skills/maxio-react/references/components-data-table.md +344 -0
- package/dist/skills/maxio-react/references/components-drawer.md +293 -0
- package/dist/skills/maxio-react/references/components-flex.md +185 -0
- package/dist/skills/maxio-react/references/components-forms-checkbox.md +257 -0
- package/dist/skills/maxio-react/references/components-forms-combobox.md +250 -0
- package/dist/skills/maxio-react/references/components-forms-radio-group.md +202 -0
- package/dist/skills/maxio-react/references/components-forms-select.md +295 -0
- package/dist/skills/maxio-react/references/components-forms-textfield.md +253 -0
- package/dist/skills/maxio-react/references/components-grid.md +140 -0
- package/dist/skills/maxio-react/references/components-icon.md +169 -0
- package/dist/skills/maxio-react/references/components-link.md +180 -0
- package/dist/skills/maxio-react/references/components-listbox.md +205 -0
- package/dist/skills/maxio-react/references/components-loading-spinner.md +123 -0
- package/dist/skills/maxio-react/references/components-logo.md +91 -0
- package/dist/skills/maxio-react/references/components-notifications-alert.md +103 -0
- package/dist/skills/maxio-react/references/components-notifications-banner.md +173 -0
- package/dist/skills/maxio-react/references/components-notifications-toast.md +155 -0
- package/dist/skills/maxio-react/references/components-pagination.md +115 -0
- package/dist/skills/maxio-react/references/components-popover.md +176 -0
- package/dist/skills/maxio-react/references/components-progressbar.md +98 -0
- package/dist/skills/maxio-react/references/components-segmentedcontrol.md +292 -0
- package/dist/skills/maxio-react/references/components-tabs.md +193 -0
- package/dist/skills/maxio-react/references/components-tag.md +117 -0
- package/dist/skills/maxio-react/references/components-tile.md +114 -0
- package/dist/skills/maxio-react/references/components-toggle.md +218 -0
- package/dist/skills/maxio-react/references/components-tooltip.md +178 -0
- package/dist/skills/maxio-react/references/components-typography-body.md +101 -0
- package/dist/skills/maxio-react/references/components-typography-code.md +72 -0
- package/dist/skills/maxio-react/references/components-typography-display.md +91 -0
- package/dist/skills/maxio-react/references/components-typography-heading.md +88 -0
- package/dist/skills/maxio-react/references/components-typography-label.md +82 -0
- package/dist/skills/maxio-react/references/deprecated-textinput.md +250 -0
- package/dist/skills/maxio-react/references/foundations-dark-mode.md +85 -0
- package/dist/skills/maxio-react/references/foundations-design-tokens-about.md +108 -0
- package/dist/skills/maxio-react/references/foundations-design-tokens-colors-primitive-colors.md +33 -0
- package/dist/skills/maxio-react/references/foundations-design-tokens-colors-semantic-colors.md +11 -0
- package/dist/skills/maxio-react/references/foundations-start-here.md +128 -0
- package/dist/skills/maxio-react/references/patterns-auth-layout.md +318 -0
- package/dist/skills/maxio-react/references/patterns-side-nav.md +182 -0
- package/dist/skills/maxio-react/references/patterns-top-bar.md +214 -0
- package/package.json +2 -2
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
## Usage Guidelines
|
|
4
|
+
|
|
5
|
+
### Overview
|
|
6
|
+
|
|
7
|
+
Popover positions dismissible overlay content next to a trigger.
|
|
8
|
+
|
|
9
|
+
#### When to Use
|
|
10
|
+
|
|
11
|
+
- Use Popover for dismissible rich content that is anchored to a trigger.
|
|
12
|
+
- Use when the content needs more structure than a Tooltip, such as text with actions, short forms, or contextual details.
|
|
13
|
+
- Use with DialogTrigger when the trigger opens a generic dialog-like overlay.
|
|
14
|
+
- Use as the shared overlay shell for components that already manage listbox, menu, or combobox behavior.
|
|
15
|
+
|
|
16
|
+
#### When Not to Use
|
|
17
|
+
|
|
18
|
+
- Do not use for brief explanatory text. Use Tooltip instead.
|
|
19
|
+
- Do not use for a simple list of contextual actions. Use ActionMenu instead.
|
|
20
|
+
- Do not use for page-level or blocking decisions. Use a modal dialog pattern instead.
|
|
21
|
+
- Do not use Popover by itself when you need trigger state, focus return, or dismissal behavior. Pair it with a React Aria trigger.
|
|
22
|
+
|
|
23
|
+
### Behavior
|
|
24
|
+
|
|
25
|
+
- **Mouse and touch**: activating the trigger opens the popover. Pressing outside the popover or selecting a closing action should dismiss it.
|
|
26
|
+
- **Keyboard**: Tab moves through focusable content in the trigger and popover. Escape dismisses the popover.
|
|
27
|
+
- **Focus management**: focus remains predictable through React Aria trigger components and returns to the trigger after dismissal.
|
|
28
|
+
- **Placement**: use `placement`, `offset`, and `shouldFlip` to keep the popover connected to the trigger without clipping the viewport.
|
|
29
|
+
- **Arrow**: keep the arrow for most standalone popovers. Hide it when the popover is visually anchored by another component, such as an input or menu surface.
|
|
30
|
+
|
|
31
|
+
### Accessibility
|
|
32
|
+
|
|
33
|
+
- Pair Popover with DialogTrigger or another React Aria trigger so `aria-expanded`, `aria-controls`, dismissal, and focus return stay synchronized.
|
|
34
|
+
- Give the trigger an accessible name that describes what opens, such as "Show billing details" or "Edit filters".
|
|
35
|
+
- Keep popover content concise and focused on the trigger context.
|
|
36
|
+
- Include a clear dismiss path when the content contains interactive controls or can stay open while users review information.
|
|
37
|
+
- Keep focus indicators visible inside the popover and preserve Escape dismissal.
|
|
38
|
+
- Do not rely on placement or arrow direction alone to communicate meaning.
|
|
39
|
+
|
|
40
|
+
### Content
|
|
41
|
+
|
|
42
|
+
- Use short, specific copy that extends the trigger context.
|
|
43
|
+
- Start action labels with verbs when the popover includes buttons or links.
|
|
44
|
+
- Avoid placing long workflows, dense tables, or unrelated navigation inside a popover.
|
|
45
|
+
|
|
46
|
+
### Related
|
|
47
|
+
|
|
48
|
+
- **[Tooltip](components-tooltip.md)**: use for short, noninteractive explanatory text.
|
|
49
|
+
- **[ActionMenu](components-action-menu.md)**: use for a menu of related actions behind a trigger.
|
|
50
|
+
- **[Button](components-buttons-button.md)**: use as the typical trigger for standalone popovers.
|
|
51
|
+
|
|
52
|
+
## React
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import {
|
|
56
|
+
Body,
|
|
57
|
+
Button,
|
|
58
|
+
Popover,
|
|
59
|
+
DialogTrigger,
|
|
60
|
+
} from '@maxio-com/react-ui-components';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### State Management
|
|
64
|
+
|
|
65
|
+
Use uncontrolled state for ordinary trigger-and-popover interactions. Use controlled state when product logic needs to open or close the popover from another control, route change, or validation result.
|
|
66
|
+
|
|
67
|
+
#### Controlled
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
const [isOpen, setOpen] = React.useState(false);
|
|
71
|
+
|
|
72
|
+
<DialogTrigger isOpen={isOpen} onOpenChange={setOpen}>
|
|
73
|
+
<Button variant="secondary" size="md">
|
|
74
|
+
Open popover
|
|
75
|
+
</Button>
|
|
76
|
+
<Popover placement="bottom start">
|
|
77
|
+
<Body size="sm">Review customer billing details.</Body>
|
|
78
|
+
</Popover>
|
|
79
|
+
</DialogTrigger>;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Uncontrolled
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
<DialogTrigger>
|
|
86
|
+
<Button variant="secondary" size="md">
|
|
87
|
+
Open popover
|
|
88
|
+
</Button>
|
|
89
|
+
<Popover placement="bottom start">
|
|
90
|
+
<Body size="sm">Review customer billing details.</Body>
|
|
91
|
+
</Popover>
|
|
92
|
+
</DialogTrigger>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Related Exports
|
|
96
|
+
|
|
97
|
+
`DialogTrigger` and `Pressable` are re-exported from
|
|
98
|
+
`react-aria-components` for convenience.
|
|
99
|
+
|
|
100
|
+
## Imports
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { Body, Button, DialogTrigger, Popover } from "@maxio-com/react-ui-components";
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Prop Types
|
|
107
|
+
|
|
108
|
+
### Popover
|
|
109
|
+
|
|
110
|
+
| Prop | Type | Required | Default | Description | Source |
|
|
111
|
+
| --- | --- | --- | --- | --- | --- |
|
|
112
|
+
| `hideArrow` | `boolean` | no | `false` | When true, hides the arrow aligned to the trigger. | PopoverProps |
|
|
113
|
+
|
|
114
|
+
## Stories
|
|
115
|
+
|
|
116
|
+
### Default
|
|
117
|
+
|
|
118
|
+
Use Popover for dismissible rich content that is tied to a trigger, such as compact details, contextual controls, or selection surfaces. Pair it with DialogTrigger so trigger state, focus return, and Escape dismissal are wired by React Aria.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const Default = () => <DialogTrigger>
|
|
122
|
+
<Button variant="secondary" size="md">Open popover
|
|
123
|
+
</Button>
|
|
124
|
+
<Popover hideArrow={false} placement="bottom start" shouldFlip>
|
|
125
|
+
<Body size="sm">Review customer billing details.</Body>
|
|
126
|
+
</Popover>
|
|
127
|
+
</DialogTrigger>;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Without arrow
|
|
131
|
+
|
|
132
|
+
Hide the arrow when the popover is visually anchored by another shape, such as an input, menu, or flush container. Keep the trigger relationship and dismissal behavior the same.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
const WithoutArrow = () => (
|
|
136
|
+
<DialogTrigger>
|
|
137
|
+
<Button variant="secondary" size="md">
|
|
138
|
+
Open popover
|
|
139
|
+
</Button>
|
|
140
|
+
<Popover hideArrow={true} placement="bottom start">
|
|
141
|
+
<Body size="sm">Review customer billing details.</Body>
|
|
142
|
+
</Popover>
|
|
143
|
+
</DialogTrigger>
|
|
144
|
+
);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### All placements
|
|
148
|
+
|
|
149
|
+
Use placement options to keep the popover visually connected to its trigger. Leave `shouldFlip` enabled in product code unless a fixed placement is required for visual QA or documentation.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
const AllPlacements = ({ ...args }) => (
|
|
153
|
+
<div
|
|
154
|
+
style={{
|
|
155
|
+
display: 'grid',
|
|
156
|
+
gridTemplateColumns: 'repeat(3, 1fr)',
|
|
157
|
+
gap: '1rem',
|
|
158
|
+
justifyItems: 'center',
|
|
159
|
+
maxWidth: '32rem',
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
{ALL_PLACEMENTS.map((placement) => (
|
|
163
|
+
<div key={placement}>
|
|
164
|
+
<DialogTrigger>
|
|
165
|
+
<Button variant="secondary" size="sm">
|
|
166
|
+
{placement}
|
|
167
|
+
</Button>
|
|
168
|
+
<Popover placement={placement} shouldFlip={false} {...args}>
|
|
169
|
+
<Body size="sm">Popover placement preview.</Body>
|
|
170
|
+
</Popover>
|
|
171
|
+
</DialogTrigger>
|
|
172
|
+
</div>
|
|
173
|
+
))}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ProgressBar
|
|
2
|
+
|
|
3
|
+
## Usage Guidelines
|
|
4
|
+
|
|
5
|
+
### Overview
|
|
6
|
+
|
|
7
|
+
ProgressBar communicates the completion state of a known or ongoing process.
|
|
8
|
+
|
|
9
|
+
#### When to Use
|
|
10
|
+
|
|
11
|
+
- Use ProgressBar for determinate work with a known value, such as imports, exports, file uploads, batch jobs, or onboarding progress.
|
|
12
|
+
- Use ProgressBar for indeterminate work when progress is active but the current value is unknown.
|
|
13
|
+
- Use helper text to clarify the current milestone, percentage, or completion result.
|
|
14
|
+
|
|
15
|
+
#### When Not to Use
|
|
16
|
+
|
|
17
|
+
- Do not use ProgressBar for short blocking page loads with no meaningful task context. Use LoadingSpinner instead.
|
|
18
|
+
- Do not use ProgressBar for success, error, or warning messages by themselves. Pair status with helper text or use Alert/Banner for standalone messages.
|
|
19
|
+
- Do not use ProgressBar as a step navigation control.
|
|
20
|
+
|
|
21
|
+
### Variants
|
|
22
|
+
|
|
23
|
+
Choose the variant based on how much surrounding context the progress message
|
|
24
|
+
needs.
|
|
25
|
+
|
|
26
|
+
| Variant | Purpose | Usage notes |
|
|
27
|
+
| :-------- | :-------------------------------------- | :----------------------------------------------------------------- |
|
|
28
|
+
| `default` | Stacks label, track, and helper text. | Use for most progress states and when helper text carries detail. |
|
|
29
|
+
| `inline` | Places label, track, and helper inline. | Use in dense layouts where the label and value are short. |
|
|
30
|
+
| `indent` | Indents label and helper text. | Use when the bar belongs to nested content or a grouped task list. |
|
|
31
|
+
|
|
32
|
+
### States
|
|
33
|
+
|
|
34
|
+
| State | Purpose | Usage notes |
|
|
35
|
+
| :-------------- | :----------------------------- | :-------------------------------------------------------------------------- |
|
|
36
|
+
| `value` set | Shows determinate progress. | Keep `value` within `0` and `maxValue` and update helper text as needed. |
|
|
37
|
+
| `value` omitted | Shows indeterminate progress. | Use when work is active but the percentage or completion value is unknown. |
|
|
38
|
+
| `success` | Reinforces completed progress. | Use with completion copy such as "Import complete". |
|
|
39
|
+
| `error` | Reinforces failed progress. | Use with actionable helper text that explains what failed or what to retry. |
|
|
40
|
+
|
|
41
|
+
### Accessibility
|
|
42
|
+
|
|
43
|
+
- Provide a concise visible label that names the task being tracked.
|
|
44
|
+
- Use determinate values when progress is measurable; omit `value` only when the amount completed is unknown.
|
|
45
|
+
- Keep helper text synchronized with the visual state when progress succeeds, fails, or reaches a meaningful milestone.
|
|
46
|
+
- Do not rely on the progress color alone to communicate success or error status.
|
|
47
|
+
- Avoid rapidly changing helper text in a way that would create noisy announcements.
|
|
48
|
+
|
|
49
|
+
### Content
|
|
50
|
+
|
|
51
|
+
- Name the task, such as "Importing customers" or "Uploading contract".
|
|
52
|
+
- Use helper text for user-relevant progress, such as "50% complete" or "Retry failed records".
|
|
53
|
+
- Keep status copy short and update it when the process completes or fails.
|
|
54
|
+
|
|
55
|
+
### Related
|
|
56
|
+
|
|
57
|
+
- **[LoadingSpinner](components-loading-spinner.md)**: Use for indeterminate loading with no useful percentage or milestone.
|
|
58
|
+
- **[Alert](components-notifications-alert.md)**: Use for standalone success, warning, or error feedback.
|
|
59
|
+
|
|
60
|
+
## React
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { ProgressBar } from '@maxio-com/react-ui-components';
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Imports
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { ProgressBar } from "@maxio-com/react-ui-components";
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Prop Types
|
|
73
|
+
|
|
74
|
+
### ProgressBar
|
|
75
|
+
|
|
76
|
+
| Prop | Type | Required | Default | Description | Source |
|
|
77
|
+
| --- | --- | --- | --- | --- | --- |
|
|
78
|
+
| `helperText` | `string` | no | - | Helper text for the progress bar | ProgressBarProps |
|
|
79
|
+
| `label` | `string` | yes | - | Label for the progress bar | ProgressBarProps |
|
|
80
|
+
| `maxValue` | `number` | no | `100` | Defines the maximum value of the progress bar | ProgressBarProps |
|
|
81
|
+
| `size` | `"md" \| "lg"` | no | `md` | Defines the size of the progress bar | ProgressBarProps |
|
|
82
|
+
| `status` | `"error" \| "success"` | no | - | Defines the status of the progress bar | ProgressBarProps |
|
|
83
|
+
| `value` | `number` | no | - | Defines the current value of the progress bar. If `undefined` the progress bar will be indeterminate. | ProgressBarProps |
|
|
84
|
+
| `variant` | `"inline" \| "indent" \| "default"` | no | `default` | Defines the position applied to the label and helper text | ProgressBarProps |
|
|
85
|
+
|
|
86
|
+
## Stories
|
|
87
|
+
|
|
88
|
+
### Default
|
|
89
|
+
|
|
90
|
+
Use ProgressBar when a user needs to understand how much of a process has completed. Keep the label specific to the task and use helper text for the current milestone, percentage, or outcome.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
const Default = () => <ProgressBar
|
|
94
|
+
helperText="50% complete"
|
|
95
|
+
label="Importing customers"
|
|
96
|
+
maxValue={100}
|
|
97
|
+
value={50} />;
|
|
98
|
+
```
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# SegmentedControl
|
|
2
|
+
|
|
3
|
+
## Usage Guidelines
|
|
4
|
+
|
|
5
|
+
### Overview
|
|
6
|
+
|
|
7
|
+
#### When to Use
|
|
8
|
+
|
|
9
|
+
- Use SegmentedControl when users choose one option from a small set of closely related views, modes, or filters.
|
|
10
|
+
- Use SegmentedControl when the selection should take effect immediately and stay visible in a compact control.
|
|
11
|
+
- Use SegmentedControl for chart type, billing period, report range, export format, or density settings that change the current view.
|
|
12
|
+
|
|
13
|
+
#### When Not to Use
|
|
14
|
+
|
|
15
|
+
- Do not use SegmentedControl for navigation between unrelated pages or major app areas. Use SideNav instead.
|
|
16
|
+
- Do not use SegmentedControl when each option reveals a separate content panel with its own heading hierarchy. Use Tabs instead.
|
|
17
|
+
- Do not use SegmentedControl for form submission with many options or helper text per choice. Use Radio or Select instead.
|
|
18
|
+
- Do not use SegmentedControl when users can choose more than one option. Use CheckboxGroup instead.
|
|
19
|
+
|
|
20
|
+
### Variants
|
|
21
|
+
|
|
22
|
+
Choose the size and layout that fit the surrounding surface.
|
|
23
|
+
|
|
24
|
+
| Variants | Purpose | Usage notes |
|
|
25
|
+
| :---------- | :------------------------------ | :--------------------------------------------------------------------- |
|
|
26
|
+
| `sm` | Compact inline selection. | Use in dense toolbars, table filters, or chart controls. |
|
|
27
|
+
| `md` | Default size for most surfaces. | Use for standard page-level mode switching. |
|
|
28
|
+
| `lg` | Larger touch and scan targets. | Use when segments include supporting metrics or secondary content. |
|
|
29
|
+
| `fullWidth` | Equal-width segments. | Use when the control spans a container and each option needs balance. |
|
|
30
|
+
| `vertical` | Stacked segment layout. | Use when horizontal space is limited or options read better as a list. |
|
|
31
|
+
|
|
32
|
+
### Behavior
|
|
33
|
+
|
|
34
|
+
- **Mouse and touch**: Selecting a segment updates the active choice and clears the previous selection.
|
|
35
|
+
- **Keyboard**: Tab moves focus into the group. Arrow keys move selection across enabled segments in the current orientation.
|
|
36
|
+
- **Focus management**: Focus stays on the selected segment after keyboard selection. Disabled segments are skipped.
|
|
37
|
+
- **Controlled state**: Use `selectedKeys` with `onSelectionChange` when route state, saved preferences, or another component owns the selection.
|
|
38
|
+
- **Uncontrolled state**: Use `defaultSelectedKeys` when the control can manage its own selection after the initial render.
|
|
39
|
+
- **Disabled state**: Disable individual segments with `isDisabled` on `SegmentedControl.Item`, or disable the entire group with `isDisabled` on `SegmentedControl`.
|
|
40
|
+
|
|
41
|
+
### Accessibility
|
|
42
|
+
|
|
43
|
+
- Provide an accessible group name with `aria-label` or `aria-labelledby` on `SegmentedControl`.
|
|
44
|
+
- Give each `SegmentedControl.Item` a concise visible label that describes the option.
|
|
45
|
+
- Provide `aria-label` on icon-only segments because the icon does not name the option by itself.
|
|
46
|
+
- Keep disabled segments out of keyboard selection and prevent activation.
|
|
47
|
+
- Do not rely on color alone to communicate the selected segment; the selection indicator provides an additional cue.
|
|
48
|
+
|
|
49
|
+
### Content
|
|
50
|
+
|
|
51
|
+
- Use short, parallel labels that describe the view or mode, such as "Monthly", "Annual", or "Custom".
|
|
52
|
+
- Keep labels specific to the current context instead of generic words such as "Option 1".
|
|
53
|
+
- Use icons as supporting context next to text labels; avoid icon-only segments unless the meaning is unmistakable.
|
|
54
|
+
- Consider truncation and localization when labels may grow in translated copy.
|
|
55
|
+
|
|
56
|
+
### Related
|
|
57
|
+
|
|
58
|
+
- **[Tabs](components-tabs.md)**: Use when each option reveals a separate panel with its own content area.
|
|
59
|
+
- **[Radio Group](components-forms-radio-group.md)**: Use when the choice belongs to a form and needs a visible group label, helper text, or validation.
|
|
60
|
+
- **[Select](components-forms-select.md)**: Use when only one option can be selected but the list should stay compact.
|
|
61
|
+
|
|
62
|
+
## React
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { SegmentedControl } from '@maxio-com/react-ui-components';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Composition
|
|
69
|
+
|
|
70
|
+
- `SegmentedControl` owns selection state and renders the toggle button group.
|
|
71
|
+
- `SegmentedControl.Item` renders one selectable segment. Each item needs a stable `id` that matches the keys used in `defaultSelectedKeys` or `selectedKeys`.
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<SegmentedControl aria-label="Billing period" defaultSelectedKeys={['monthly']}>
|
|
75
|
+
<SegmentedControl.Item id="monthly">Monthly</SegmentedControl.Item>
|
|
76
|
+
<SegmentedControl.Item id="annual">Annual</SegmentedControl.Item>
|
|
77
|
+
<SegmentedControl.Item id="custom">Custom</SegmentedControl.Item>
|
|
78
|
+
</SegmentedControl>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### State Management
|
|
82
|
+
|
|
83
|
+
Use uncontrolled SegmentedControl for local view state. Use controlled SegmentedControl when selection is driven by routing, persisted preferences, or another component.
|
|
84
|
+
|
|
85
|
+
#### Controlled
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const [selectedKeys, setSelectedKeys] = React.useState(new Set(['week']));
|
|
89
|
+
|
|
90
|
+
<SegmentedControl
|
|
91
|
+
aria-label="Report range"
|
|
92
|
+
selectedKeys={selectedKeys}
|
|
93
|
+
onSelectionChange={setSelectedKeys}
|
|
94
|
+
>
|
|
95
|
+
<SegmentedControl.Item id="day">Day</SegmentedControl.Item>
|
|
96
|
+
<SegmentedControl.Item id="week">Week</SegmentedControl.Item>
|
|
97
|
+
<SegmentedControl.Item id="month">Month</SegmentedControl.Item>
|
|
98
|
+
</SegmentedControl>;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Uncontrolled
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<SegmentedControl aria-label="Billing period" defaultSelectedKeys={['monthly']}>
|
|
105
|
+
<SegmentedControl.Item id="monthly">Monthly</SegmentedControl.Item>
|
|
106
|
+
<SegmentedControl.Item id="annual">Annual</SegmentedControl.Item>
|
|
107
|
+
<SegmentedControl.Item id="custom">Custom</SegmentedControl.Item>
|
|
108
|
+
</SegmentedControl>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Imports
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { Flex, Heading, Icon, Label, SegmentedControl } from "@maxio-com/react-ui-components";
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Stories
|
|
118
|
+
|
|
119
|
+
### Default
|
|
120
|
+
|
|
121
|
+
Use Default for switching between closely related views or modes with a compact control. Provide `aria-label` when no visible group label is present.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
const Default = () => <SegmentedControl aria-label="Billing period" defaultSelectedKeys={['monthly']}>
|
|
125
|
+
<SegmentedControl.Item id="monthly">Monthly</SegmentedControl.Item>
|
|
126
|
+
<SegmentedControl.Item id="annual">Annual</SegmentedControl.Item>
|
|
127
|
+
<SegmentedControl.Item id="custom">Custom</SegmentedControl.Item>
|
|
128
|
+
</SegmentedControl>;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Controlled
|
|
132
|
+
|
|
133
|
+
Use Controlled when application state owns the selected segment.
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
const Controlled = () => {
|
|
137
|
+
const [selectedKeys, setSelectedKeys] = React.useState<Set<Key>>(
|
|
138
|
+
() => new Set(['week'])
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<SegmentedControl
|
|
143
|
+
aria-label="Report range"
|
|
144
|
+
selectedKeys={selectedKeys}
|
|
145
|
+
onSelectionChange={setSelectedKeys}
|
|
146
|
+
>
|
|
147
|
+
<SegmentedControl.Item id="day">Day</SegmentedControl.Item>
|
|
148
|
+
<SegmentedControl.Item id="week">Week</SegmentedControl.Item>
|
|
149
|
+
<SegmentedControl.Item id="month">Month</SegmentedControl.Item>
|
|
150
|
+
</SegmentedControl>
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Disabled
|
|
156
|
+
|
|
157
|
+
Use Disabled when one or more segments are unavailable in the current context. Disable individual items before disabling the entire group.
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
const Disabled = () => (
|
|
161
|
+
<Flex flexDirection="col" gap={4}>
|
|
162
|
+
<SegmentedControl
|
|
163
|
+
aria-label="Calendar view"
|
|
164
|
+
defaultSelectedKeys={['month']}
|
|
165
|
+
>
|
|
166
|
+
<SegmentedControl.Item id="week">Week</SegmentedControl.Item>
|
|
167
|
+
<SegmentedControl.Item id="month">Month</SegmentedControl.Item>
|
|
168
|
+
<SegmentedControl.Item id="quarter" isDisabled>
|
|
169
|
+
Quarter
|
|
170
|
+
</SegmentedControl.Item>
|
|
171
|
+
</SegmentedControl>
|
|
172
|
+
<SegmentedControl aria-label="Calendar view" isDisabled>
|
|
173
|
+
<SegmentedControl.Item id="week">Week</SegmentedControl.Item>
|
|
174
|
+
<SegmentedControl.Item id="month">Month</SegmentedControl.Item>
|
|
175
|
+
<SegmentedControl.Item id="quarter" isDisabled>
|
|
176
|
+
Quarter
|
|
177
|
+
</SegmentedControl.Item>
|
|
178
|
+
</SegmentedControl>
|
|
179
|
+
</Flex>
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Full Width
|
|
184
|
+
|
|
185
|
+
Use Full Width when segments should share the available width equally.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
const FullWidth = () => (
|
|
189
|
+
<SegmentedControl
|
|
190
|
+
aria-label="Revenue type"
|
|
191
|
+
defaultSelectedKeys={['gross']}
|
|
192
|
+
fullWidth
|
|
193
|
+
>
|
|
194
|
+
<SegmentedControl.Item id="gross">Gross revenue</SegmentedControl.Item>
|
|
195
|
+
<SegmentedControl.Item id="net">Net revenue</SegmentedControl.Item>
|
|
196
|
+
<SegmentedControl.Item id="mrr">MRR</SegmentedControl.Item>
|
|
197
|
+
</SegmentedControl>
|
|
198
|
+
);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Small
|
|
202
|
+
|
|
203
|
+
Use Small in dense toolbars, table filters, or chart controls.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
const Small = () => (
|
|
207
|
+
<SegmentedControl
|
|
208
|
+
aria-label="Density"
|
|
209
|
+
defaultSelectedKeys={['compact']}
|
|
210
|
+
size="sm"
|
|
211
|
+
>
|
|
212
|
+
<SegmentedControl.Item id="compact">Compact</SegmentedControl.Item>
|
|
213
|
+
<SegmentedControl.Item id="comfortable">
|
|
214
|
+
Comfortable
|
|
215
|
+
</SegmentedControl.Item>
|
|
216
|
+
</SegmentedControl>
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Vertical
|
|
221
|
+
|
|
222
|
+
Use Vertical when horizontal space is limited or options read better as a stacked list.
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
const Vertical = () => (
|
|
226
|
+
<SegmentedControl
|
|
227
|
+
aria-label="Export format"
|
|
228
|
+
defaultSelectedKeys={['csv']}
|
|
229
|
+
orientation="vertical"
|
|
230
|
+
>
|
|
231
|
+
<SegmentedControl.Item id="csv">CSV</SegmentedControl.Item>
|
|
232
|
+
<SegmentedControl.Item id="xlsx">XLSX</SegmentedControl.Item>
|
|
233
|
+
<SegmentedControl.Item id="pdf">PDF</SegmentedControl.Item>
|
|
234
|
+
</SegmentedControl>
|
|
235
|
+
);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### With Icons
|
|
239
|
+
|
|
240
|
+
Use icons as supporting context next to labels, or provide `aria-label` for icon-only segments.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
const WithIcons = () => (
|
|
244
|
+
<Flex flexDirection="col" gap={4}>
|
|
245
|
+
<SegmentedControl aria-label="Chart type" defaultSelectedKeys={['bar']}>
|
|
246
|
+
<SegmentedControl.Item id="bar">
|
|
247
|
+
<Icon variant="bar-chart" />
|
|
248
|
+
Bar
|
|
249
|
+
</SegmentedControl.Item>
|
|
250
|
+
<SegmentedControl.Item id="list">
|
|
251
|
+
<Icon variant="list" />
|
|
252
|
+
List
|
|
253
|
+
</SegmentedControl.Item>
|
|
254
|
+
</SegmentedControl>
|
|
255
|
+
<SegmentedControl aria-label="Chart type" defaultSelectedKeys={['bar']}>
|
|
256
|
+
<SegmentedControl.Item id="bar" aria-label="Bar chart">
|
|
257
|
+
<Icon variant="bar-chart" />
|
|
258
|
+
</SegmentedControl.Item>
|
|
259
|
+
<SegmentedControl.Item id="list" aria-label="List view">
|
|
260
|
+
<Icon variant="list" />
|
|
261
|
+
</SegmentedControl.Item>
|
|
262
|
+
</SegmentedControl>
|
|
263
|
+
</Flex>
|
|
264
|
+
);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Custom
|
|
268
|
+
|
|
269
|
+
Use custom content sparingly when a segment needs supporting metrics or secondary text.
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
const Custom = () => <SegmentedControl aria-label="Status" defaultSelectedKeys={['active']} size="lg">
|
|
273
|
+
<SegmentedControl.Item id="active">
|
|
274
|
+
<Flex flexDirection="col" alignItems="start">
|
|
275
|
+
<Label size="sm">Active</Label>
|
|
276
|
+
<Heading size="md">96</Heading>
|
|
277
|
+
</Flex>
|
|
278
|
+
</SegmentedControl.Item>
|
|
279
|
+
<SegmentedControl.Item id="inactive">
|
|
280
|
+
<Flex flexDirection="col" alignItems="start">
|
|
281
|
+
<Label size="sm">Inactive</Label>
|
|
282
|
+
<Heading size="md">12</Heading>
|
|
283
|
+
</Flex>
|
|
284
|
+
</SegmentedControl.Item>
|
|
285
|
+
<SegmentedControl.Item id="pending">
|
|
286
|
+
<Flex flexDirection="col" alignItems="start">
|
|
287
|
+
<Label size="sm">Pending</Label>
|
|
288
|
+
<Heading size="md">3</Heading>
|
|
289
|
+
</Flex>
|
|
290
|
+
</SegmentedControl.Item>
|
|
291
|
+
</SegmentedControl>;
|
|
292
|
+
```
|