@kb.ui/react 0.10.3 → 0.11.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/README.md +130 -708
- package/dist/components/Accordion/Accordion.d.ts +33 -0
- package/dist/components/Avatar/Avatar.d.ts +19 -0
- package/dist/components/Code/Code.d.ts +26 -3
- package/dist/components/Code/tokenize.d.ts +5 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +10 -0
- package/dist/components/Collection/Collection.d.ts +99 -0
- package/dist/components/Collection/useCollection.d.ts +66 -0
- package/dist/components/CollectionList/CollectionList.d.ts +12 -0
- package/dist/components/CollectionRow/CollectionRow.d.ts +17 -0
- package/dist/components/Combobox/Combobox.d.ts +14 -2
- package/dist/components/CopyableText/CopyableText.d.ts +38 -0
- package/dist/components/CopyableText/content.d.ts +14 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +20 -0
- package/dist/components/Dialog/Dialog.d.ts +3 -1
- package/dist/components/Disclosure/Disclosure.d.ts +21 -0
- package/dist/components/EmptyState/EmptyState.d.ts +30 -0
- package/dist/components/Grid/Grid.d.ts +17 -6
- package/dist/components/Image/Image.d.ts +20 -0
- package/dist/components/Link/Link.d.ts +15 -2
- package/dist/components/Popover/Popover.d.ts +55 -0
- package/dist/components/Skeleton/Skeleton.d.ts +32 -0
- package/dist/components/Spinner/Spinner.d.ts +26 -0
- package/dist/components/Table/Table.d.ts +65 -0
- package/dist/components/Tabs/Tabs.d.ts +69 -0
- package/dist/components/Tabs/index.d.ts +1 -0
- package/dist/components/Thumbnail/Thumbnail.d.ts +14 -0
- package/dist/components/Toast/Toast.d.ts +72 -0
- package/dist/index.d.ts +29 -4
- package/dist/index.js +3510 -1232
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/CollapsiblePanel.d.ts +10 -0
- package/dist/utils/useClipboard.d.ts +28 -0
- package/docs/components/Accordion.md +66 -0
- package/docs/components/Avatar.md +80 -0
- package/docs/components/Badge.md +37 -0
- package/docs/components/Button.md +46 -0
- package/docs/components/Callout.md +41 -0
- package/docs/components/Card.md +41 -0
- package/docs/components/Checkbox.md +60 -0
- package/docs/components/Code.md +77 -0
- package/docs/components/CodeBlock.md +77 -0
- package/docs/components/Collection.md +183 -0
- package/docs/components/CollectionList.md +44 -0
- package/docs/components/CollectionRow.md +62 -0
- package/docs/components/Combobox.md +88 -0
- package/docs/components/Container.md +41 -0
- package/docs/components/CopyableText.md +93 -0
- package/docs/components/DescriptionList.md +61 -0
- package/docs/components/Dialog.md +84 -0
- package/docs/components/Disclosure.md +53 -0
- package/docs/components/EmptyState.md +50 -0
- package/docs/components/ErrorSummary.md +46 -0
- package/docs/components/Fieldset.md +42 -0
- package/docs/components/FileInput.md +74 -0
- package/docs/components/FormActions.md +45 -0
- package/docs/components/Grid.md +66 -0
- package/docs/components/Heading.md +40 -0
- package/docs/components/Image.md +62 -0
- package/docs/components/Inline.md +42 -0
- package/docs/components/Input.md +82 -0
- package/docs/components/Link.md +52 -0
- package/docs/components/Menu.md +44 -0
- package/docs/components/MultiSelect.md +59 -0
- package/docs/components/NumberField.md +65 -0
- package/docs/components/Panel.md +145 -0
- package/docs/components/Popover.md +89 -0
- package/docs/components/Progress.md +37 -0
- package/docs/components/RadioGroup.md +69 -0
- package/docs/components/ScrollArea.md +40 -0
- package/docs/components/Select.md +71 -0
- package/docs/components/Separator.md +40 -0
- package/docs/components/Skeleton.md +46 -0
- package/docs/components/Spinner.md +40 -0
- package/docs/components/Split.md +47 -0
- package/docs/components/Stat.md +34 -0
- package/docs/components/Status.md +47 -0
- package/docs/components/Switch.md +73 -0
- package/docs/components/Table.md +105 -0
- package/docs/components/Tabs.md +89 -0
- package/docs/components/Text.md +36 -0
- package/docs/components/Textarea.md +47 -0
- package/docs/components/Thumbnail.md +66 -0
- package/docs/components/Toast.md +130 -0
- package/docs/components/Toolbar.md +39 -0
- package/docs/components/Tooltip.md +42 -0
- package/package.json +3 -2
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
Use Input for text entry. It keeps the label, help text, and error message together, and has space for icons or actions at either end.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-input--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Input } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return <Input label="Email" type="email" name="email" autoComplete="email" />;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## More examples
|
|
19
|
+
|
|
20
|
+
- [Search and clear](https://kbui.kcb.pro/storybook/?path=/story/components-input--with-icons-and-actions): Keep the input stable while editing actions change.
|
|
21
|
+
- [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-input--with-error): Associate an error with the field.
|
|
22
|
+
- [A visually hidden label](https://kbui.kcb.pro/storybook/?path=/story/components-input--hidden-label): Retain the accessible name when hiding the visual label.
|
|
23
|
+
|
|
24
|
+
## Reference
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Notes |
|
|
27
|
+
| ----------------------------- | ---------------------- | -------- | ------------------------------------------------------------- |
|
|
28
|
+
| `startContent` / `endContent` | `ReactNode` | | Icons or actions at either end; give actions accessible names |
|
|
29
|
+
| `label` | `string` | required | Visible label and accessible name |
|
|
30
|
+
| `visuallyHidden` | `boolean` | | Hides the label visually but keeps it for screen readers |
|
|
31
|
+
| `description` | `string` | | Help text below the field |
|
|
32
|
+
| `error` | `string` | | Shows an error message and marks the field invalid |
|
|
33
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Field height. Replaces the native `size` attribute |
|
|
34
|
+
| `className` | `string` | | Applied to the wrapper, not the input element |
|
|
35
|
+
|
|
36
|
+
Other native input props, including `value` and `defaultValue`, pass through to the input. Base UI's `onValueChange` is also supported.
|
|
37
|
+
|
|
38
|
+
## Search composition
|
|
39
|
+
|
|
40
|
+
Use `Input type="search"` with content slots and a `Button` when search needs a visible clear action. Your app handles filtering, submission, debounce, reset, and result announcements.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { useRef, useState } from "react";
|
|
44
|
+
import { Button, Input } from "@kb.ui/react";
|
|
45
|
+
|
|
46
|
+
export function SearchExample() {
|
|
47
|
+
const [query, setQuery] = useState("");
|
|
48
|
+
const control = useRef<HTMLInputElement>(null);
|
|
49
|
+
return (
|
|
50
|
+
<Input
|
|
51
|
+
ref={control}
|
|
52
|
+
label="Search components"
|
|
53
|
+
type="search"
|
|
54
|
+
name="q"
|
|
55
|
+
value={query}
|
|
56
|
+
onValueChange={setQuery}
|
|
57
|
+
endContent={
|
|
58
|
+
query ? (
|
|
59
|
+
<Button
|
|
60
|
+
type="button"
|
|
61
|
+
size="sm"
|
|
62
|
+
variant="ghost"
|
|
63
|
+
aria-label="Clear search"
|
|
64
|
+
onClick={() => {
|
|
65
|
+
setQuery("");
|
|
66
|
+
control.current?.focus();
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<span aria-hidden="true">×</span>
|
|
70
|
+
</Button>
|
|
71
|
+
) : undefined
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The field label names the input. Give each action its own accessible name, and hide decorative icons with `aria-hidden`. Use `type="button"` on the clear action so it does not submit the form, then return focus to the input. Hide editing actions when the field is disabled or read-only. Adding or removing content at either end keeps the same input node, value, and focus. See the **Icons and actions** story for a working search example.
|
|
79
|
+
|
|
80
|
+
## Related components
|
|
81
|
+
|
|
82
|
+
Use [Textarea](Textarea.md) for multiline answers, [NumberField](NumberField.md) for numeric stepping, and [Combobox](Combobox.md) for a searchable choice from existing values.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Link
|
|
2
|
+
|
|
3
|
+
Native anchor for navigation, with persistent underline and visible keyboard focus.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-link--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Link } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return <Link href="/projects">Browse projects</Link>;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## More examples
|
|
19
|
+
|
|
20
|
+
- [Navigation within prose](https://kbui.kcb.pro/storybook/?path=/story/components-link--in-text): Inspect link treatment inside surrounding text.
|
|
21
|
+
- [Router adapter](https://kbui.kcb.pro/storybook/?path=/story/components-link--with-router): Client-side navigation through `Link.Provider`.
|
|
22
|
+
|
|
23
|
+
## Reference
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Notes |
|
|
26
|
+
| ------------------------------------------- | ------------------- | -------- | -------------------------------- |
|
|
27
|
+
| `href` | `string` | required | Navigation destination |
|
|
28
|
+
| `target`, `rel`, `download`, `aria-current` | Native anchor props | unset | Passed through without rewriting |
|
|
29
|
+
| `className`, `ref` | Native anchor props | unset | Ref targets anchor |
|
|
30
|
+
|
|
31
|
+
Use descriptive link text. Use Button for an action. Links inherit surrounding type size; Tab focuses, Enter follows, and Space retains native behavior. Callers own new-tab wording and target/rel policy. No disabled link is provided. Color, underline and focus must remain visible.
|
|
32
|
+
|
|
33
|
+
### Router links
|
|
34
|
+
|
|
35
|
+
kbui never imports a router. Wrap your app once in `Link.Provider` with a component that renders an anchor: it receives `href` plus native anchor props, and must pass them and `ref` through. `Link` then renders through it and keeps `kb-link`; nested providers override outer ones, and without a provider it renders a plain `<a>`. A React Router adapter:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { Link, type LinkProps } from "@kb.ui/react";
|
|
39
|
+
import { Link as RouterLink } from "react-router";
|
|
40
|
+
|
|
41
|
+
const AppLink = ({ href, ...props }: LinkProps) => <RouterLink to={href} {...props} />;
|
|
42
|
+
|
|
43
|
+
<Link.Provider component={AppLink}>
|
|
44
|
+
<App />
|
|
45
|
+
</Link.Provider>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`useLinkComponent()` returns the current component for your own anchors.
|
|
49
|
+
|
|
50
|
+
## Related components
|
|
51
|
+
|
|
52
|
+
Use [Button](Button.md) for an action and [Card](Card.md) to group content around a destination.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
Offer a short list of actions without leaving the current context. Use a Select when people are choosing a saved field value.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-menu--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Menu } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Menu>
|
|
16
|
+
<Menu.Trigger render={<Button />}>Page actions</Menu.Trigger>
|
|
17
|
+
<Menu.Content>
|
|
18
|
+
<Menu.Item onClick={() => window.print()}>Print page</Menu.Item>
|
|
19
|
+
</Menu.Content>
|
|
20
|
+
</Menu>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## More examples
|
|
26
|
+
|
|
27
|
+
- [Keyboard interaction](https://kbui.kcb.pro/storybook/?path=/story/components-menu--default): Try the trigger, arrow keys, and dismissal.
|
|
28
|
+
- [A themed popup](https://kbui.kcb.pro/storybook/?path=/story/components-menu--nested-theme): Keep a portaled popup within its intended theme.
|
|
29
|
+
|
|
30
|
+
## Reference
|
|
31
|
+
|
|
32
|
+
| Part | Props and responsibility |
|
|
33
|
+
| ---------------- | ---------------------------------------------------------------------------------------- |
|
|
34
|
+
| `Menu` | Root; use open/defaultOpen and onOpenChange when your app controls visibility |
|
|
35
|
+
| `Menu.Trigger` | Named trigger; render a Button for shared styling |
|
|
36
|
+
| `Menu.Content` | Popup; side defaults to bottom, align to start; container chooses the themed portal host |
|
|
37
|
+
| `Menu.Item` | Action text and click handler; disabled prevents selection |
|
|
38
|
+
| `Menu.Separator` | Divides related groups without adding a focus stop |
|
|
39
|
+
|
|
40
|
+
Name the trigger, keep action labels specific, and retain the default arrow-key and Escape behavior. A menu item should perform an action rather than contain another button.
|
|
41
|
+
|
|
42
|
+
## Related components
|
|
43
|
+
|
|
44
|
+
Use [Select](Select.md) for a saved field value and [Dialog](Dialog.md) for a focused task with content or fields.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# MultiSelect
|
|
2
|
+
|
|
3
|
+
Use MultiSelect when people need to search a longer list and keep multiple selections visible as removable chips. Selected values render inside a named chip toolbar with keyboard arrow/Backspace/Delete support and per-chip remove buttons. Choosing or deselecting an option keeps the popup open and preserves the filter. Escape, an outside click, or the toggle closes it.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-multiselect--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
import { MultiSelect } from "@kb.ui/react";
|
|
13
|
+
|
|
14
|
+
const scopes = [
|
|
15
|
+
{ value: "payments:read", label: "Payments read" },
|
|
16
|
+
{ value: "webhooks:manage", label: "Webhooks" },
|
|
17
|
+
{ value: "reporting:export", label: "Reporting export" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
export function ScopeMultiSelect() {
|
|
21
|
+
const [selected, setSelected] = useState<string[]>(["payments:read"]);
|
|
22
|
+
return (
|
|
23
|
+
<MultiSelect
|
|
24
|
+
label="API scopes"
|
|
25
|
+
options={scopes}
|
|
26
|
+
value={selected}
|
|
27
|
+
onValueChange={setSelected}
|
|
28
|
+
placeholder="Filter scopes..."
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## More examples
|
|
35
|
+
|
|
36
|
+
- [Several retained choices](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--many-selections): Inspect removable chips and their keyboard model.
|
|
37
|
+
- [No matching options](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--empty): Inspect the empty filtering state.
|
|
38
|
+
- [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--invalid): Explain a selection that needs correction.
|
|
39
|
+
|
|
40
|
+
## Reference
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Default | Notes |
|
|
43
|
+
| ----------------------- | --------------------------------------- | ------------------------- | ----------------------------------------------------- |
|
|
44
|
+
| `label` | `string` | required | Visible field label and accessible combobox name |
|
|
45
|
+
| `options` | `readonly MultiSelectOption[]` | required | Selectable options filtered by label |
|
|
46
|
+
| `value` | `readonly string[]` | required | Controlled array of selected option values |
|
|
47
|
+
| `onValueChange` | `(value: string[]) => void` | required | Called when selections are added, removed, or cleared |
|
|
48
|
+
| `placeholder` | `string` | unset | Input placeholder |
|
|
49
|
+
| `emptyMessage` | `ReactNode` | `"No matching options"` | Polite status text when no options match |
|
|
50
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Control height and text scale |
|
|
51
|
+
| `description` / `error` | `ReactNode` | unset | Associated help and invalid-state text |
|
|
52
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Prevent edits and chip removal |
|
|
53
|
+
| `removeLabel` | `(option: MultiSelectOption) => string` | `"Remove {option.label}"` | Accessible name for each chip remove button |
|
|
54
|
+
| `container` | `Combobox.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
|
|
55
|
+
| `classNames` | `ClassNames<MultiSelectSlot>` | unset | Extra classes for inner parts |
|
|
56
|
+
|
|
57
|
+
## Related components
|
|
58
|
+
|
|
59
|
+
Use [Combobox](Combobox.md) for one searchable choice and [Checkbox](Checkbox.md) for independent choices that should remain visible.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# NumberField
|
|
2
|
+
|
|
3
|
+
Use NumberField for quantities people can type or adjust with step buttons. Your app sets the range and validates the value. See [Numeric fields](https://github.com/KhallilB/kbui/blob/main/docs/guides/number-fields.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-numberfield--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { NumberField } from "@kb.ui/react";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
|
|
14
|
+
export function Example() {
|
|
15
|
+
const [value, setValue] = useState<number | null>(1);
|
|
16
|
+
const error =
|
|
17
|
+
value === null || !Number.isInteger(value) || value < 0 || value > 99
|
|
18
|
+
? "Enter a whole number from 0 to 99."
|
|
19
|
+
: "";
|
|
20
|
+
return (
|
|
21
|
+
<NumberField
|
|
22
|
+
label="Quantity"
|
|
23
|
+
value={value}
|
|
24
|
+
onValueChange={setValue}
|
|
25
|
+
min={0}
|
|
26
|
+
max={99}
|
|
27
|
+
step={1}
|
|
28
|
+
error={error}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The field can be empty (`null`), and directly typed values remain available for your app to validate. The example validates a whole-number quantity; `min`, `max`, and `step` govern stepping. See [numeric-field state and interaction](https://github.com/KhallilB/kbui/blob/main/docs/guides/number-fields.md#state-and-interaction) for locale and draft behavior.
|
|
35
|
+
|
|
36
|
+
## More examples
|
|
37
|
+
|
|
38
|
+
- [An unanswered quantity](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--empty): Represent an empty field with null.
|
|
39
|
+
- [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--invalid): Explain a value that needs correction.
|
|
40
|
+
- [Fractional steps](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--fractional): Compare non-integer increments.
|
|
41
|
+
|
|
42
|
+
## Reference
|
|
43
|
+
|
|
44
|
+
| Prop | Type | Default | Notes |
|
|
45
|
+
| ----------------------------------------------- | --------------------------------- | ------------------------- | ----------------------------------------------------------------------- |
|
|
46
|
+
| `label` | `string` | required | Visible field name; include the quantity or unit |
|
|
47
|
+
| `value` | `number` or `null` | required | Controlled number; null means no answer |
|
|
48
|
+
| `onValueChange` | `(value: number \| null) => void` | required | Update your stored value after an edit |
|
|
49
|
+
| `min`, `max` | `number` | unbounded | Bounds for stepping; your app validates direct drafts |
|
|
50
|
+
| `step` | `number` | `1` | Positive increment and alignment |
|
|
51
|
+
| `locale` | `Intl.LocalesArgument` | runtime locale | Number formatting and editing locale |
|
|
52
|
+
| `size` | `sm` / `md` / `lg` | `md` | Control size; lg suits touch-heavy tasks |
|
|
53
|
+
| `description`, `error` | `string` | unset | Associated help or a specific correction; error marks the field invalid |
|
|
54
|
+
| `disabled`, `readOnly` | `boolean` | `false` | Prevent changes; disabled also prevents submission |
|
|
55
|
+
| `name`, `form`, `required` | native form props | unset / false | Form ownership and validation |
|
|
56
|
+
| `visuallyHidden` | `boolean` | `false` | Hide the visual label while keeping its accessible name |
|
|
57
|
+
| `decrementLabel`, `incrementLabel` | `string` | Decrease/Increase + label | Localized names for the step actions |
|
|
58
|
+
| `inputRef`, `inputProps` | input ref / native props | unset | Visible input access and supported native event or ARIA extensions |
|
|
59
|
+
| `className`, `groupClassName`, `inputClassName` | `string` | unset | Classes for root, step group, and input |
|
|
60
|
+
|
|
61
|
+
Native div props and the root ref pass through to the wrapper. Any `aria-describedby` values from the root and `inputProps` are added after the help and error IDs. Use the explicit NumberField props for the input’s value, type, disabled/read-only state, name, required state, and ref; `inputProps` cannot override those. Custom event handlers can prevent defaults, so take care to preserve keyboard behavior.
|
|
62
|
+
|
|
63
|
+
## Related components
|
|
64
|
+
|
|
65
|
+
Use [Input](Input.md) for text or identifiers whose leading zeroes and exact characters must be preserved.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Panel
|
|
2
|
+
|
|
3
|
+
Use Panel for a section that needs a header, body, and actions. Its parts help keep those areas aligned. Give the section an accessible name with `aria-labelledby`, pointing to the heading in `Panel.Header`.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-panel--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Panel } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Panel aria-labelledby="queue-title">
|
|
16
|
+
<Panel.Header>
|
|
17
|
+
<h2 id="queue-title">Review queue</h2>
|
|
18
|
+
</Panel.Header>
|
|
19
|
+
<Panel.Body>Three items need review.</Panel.Body>
|
|
20
|
+
<Panel.Footer>
|
|
21
|
+
<Button>Open queue</Button>
|
|
22
|
+
</Panel.Footer>
|
|
23
|
+
</Panel>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## More examples
|
|
29
|
+
|
|
30
|
+
- [Optional details](https://kbui.kcb.pro/storybook/?path=/story/components-panel--collapsible): Expand and collapse a section from its toggle.
|
|
31
|
+
- [Section actions](https://kbui.kcb.pro/storybook/?path=/story/components-panel--toolbar): Group actions alongside the section heading.
|
|
32
|
+
- [Nested sections](https://kbui.kcb.pro/storybook/?path=/story/components-panel--nested): Inspect depth and grouping inside a parent panel.
|
|
33
|
+
|
|
34
|
+
## Reference
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Panel tone="active" rail="status" aria-labelledby="queue-title">
|
|
38
|
+
<Panel.Header>
|
|
39
|
+
<h2 id="queue-title">Queue</h2>
|
|
40
|
+
<Panel.Toolbar>
|
|
41
|
+
<Button size="sm">Retry</Button>
|
|
42
|
+
</Panel.Toolbar>
|
|
43
|
+
</Panel.Header>
|
|
44
|
+
<Panel.Body>
|
|
45
|
+
<Panel.Well>…</Panel.Well>
|
|
46
|
+
</Panel.Body>
|
|
47
|
+
<Panel.Footer>…</Panel.Footer>
|
|
48
|
+
</Panel>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Prop | Values | Default | Notes |
|
|
52
|
+
| -------------- | ------------------------------------------------------ | ------------ | --------------------------------------------------------------------- |
|
|
53
|
+
| `tone` | `quiet` / `default` / `sunken` / `active` / `critical` | `default` | Changes the surface emphasis; pair state colors with explanatory text |
|
|
54
|
+
| `rail` | `none` / `accent` / `status` | `none` | Accent stays the accent color; status follows the current tone |
|
|
55
|
+
| `density` | `compact` / `standard` | `standard` | Changes padding without changing semantics |
|
|
56
|
+
| `collapsible` | `boolean` | `false` | Enables Panel.Toggle and collapsible body behavior |
|
|
57
|
+
| `open` | `boolean` | uncontrolled | Current body visibility when collapsible is enabled |
|
|
58
|
+
| `defaultOpen` | `boolean` | `false` | Initial visibility for an uncontrolled collapsible panel |
|
|
59
|
+
| `onOpenChange` | `(open: boolean) => void` | unset | Update open here when your app controls visibility |
|
|
60
|
+
|
|
61
|
+
`quiet` removes the panel background; `sunken` gives it a recessed surface. Use `Panel.Well` for logs or other output that should sit inside the panel. Customize the shape with `--kb-panel-radius`, the rim with `--kb-panel-rim-top`, `--kb-panel-border`, and `--kb-panel-rim-bottom`, and the depth with `--kb-panel-shadow` or `--kb-panel-shadow-active`.
|
|
62
|
+
|
|
63
|
+
For additional lighting, use `--kb-panel-sheen`, `--kb-panel-backdrop`, `--kb-panel-glow`, `--kb-panel-glow-active`, and `--kb-panel-glow-critical`. These effects stay off by default. Active and critical tones change the upper rim and glow colors. The rail follows the panel’s rounded corners.
|
|
64
|
+
|
|
65
|
+
## Resizable panels
|
|
66
|
+
|
|
67
|
+
Put `Panel.Handle` between two panels in a `Panel.Group` to let people resize them. The handle sizes the panel before it, as a percentage of the group; the panel after it takes the remaining space. Name each handle with `aria-label` or `aria-labelledby`. A column group needs a height.
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
<Panel.Group direction="row">
|
|
71
|
+
<Panel aria-labelledby="code-title">…</Panel>
|
|
72
|
+
<Panel.Handle aria-label="Resize code" defaultSize={50} min={25} max={75} />
|
|
73
|
+
<Panel aria-labelledby="view-title">…</Panel>
|
|
74
|
+
</Panel.Group>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`size` (controlled) or `defaultSize` (default `50`) sets the size of the panel before the handle in percent. `min` and `max` limit it (defaults `10` and `90`), `step` sets the arrow-key change (default `5`), and `onSizeChange` receives the next size after a key press or drag.
|
|
78
|
+
|
|
79
|
+
The handle follows the window splitter pattern. Arrow keys along the group's direction resize the panel, `Home` and `End` jump to the limits, and `Enter` collapses the panel to `min` and restores the previous size. Pointer drags work in both directions. Arrow keys do not flip in right-to-left layouts. Style the handle with `--kb-panel-handle-size`, `--kb-panel-handle-hit`, `--kb-panel-handle-grip`, `--kb-panel-handle-line` and `--kb-panel-handle-line-active`.
|
|
80
|
+
|
|
81
|
+
## Related components
|
|
82
|
+
|
|
83
|
+
Use [Card](Card.md) for a self-contained item and [Grid](Grid.md) or [Split](Split.md) to arrange sections.
|
|
84
|
+
|
|
85
|
+
## Resizing without dragging
|
|
86
|
+
|
|
87
|
+
The handle’s keyboard model supports keyboard access. For users who operate a pointer without dragging, provide controls for the same resizing task. This composition uses the existing controlled size API; the surrounding application supplies named click/tap buttons and feedback after button actions. Assess the chosen range and increments against the task’s required functionality.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import "@kb.ui/react/styles.css";
|
|
91
|
+
import { Button, Inline, Panel, Status } from "@kb.ui/react";
|
|
92
|
+
import { useId, useState } from "react";
|
|
93
|
+
|
|
94
|
+
export function ResizableWorkspace() {
|
|
95
|
+
const titleId = useId();
|
|
96
|
+
const [size, setSize] = useState(50);
|
|
97
|
+
const [message, setMessage] = useState("");
|
|
98
|
+
function resizeBy(amount: number) {
|
|
99
|
+
const next = Math.max(25, Math.min(75, size + amount));
|
|
100
|
+
setSize(next);
|
|
101
|
+
setMessage(`Code panel width ${next} percent.`);
|
|
102
|
+
}
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
<Inline>
|
|
106
|
+
<Button
|
|
107
|
+
type="button"
|
|
108
|
+
disabled={size <= 25}
|
|
109
|
+
onClick={() => resizeBy(-5)}
|
|
110
|
+
>
|
|
111
|
+
Make code narrower
|
|
112
|
+
</Button>
|
|
113
|
+
<Button type="button" disabled={size >= 75} onClick={() => resizeBy(5)}>
|
|
114
|
+
Make code wider
|
|
115
|
+
</Button>
|
|
116
|
+
<Status live>{message}</Status>
|
|
117
|
+
</Inline>
|
|
118
|
+
<Panel.Group direction="row" style={{ width: "100%", minHeight: 240 }}>
|
|
119
|
+
<Panel aria-labelledby={titleId}>
|
|
120
|
+
<Panel.Header>
|
|
121
|
+
<h2 id={titleId}>Code</h2>
|
|
122
|
+
</Panel.Header>
|
|
123
|
+
<Panel.Body>Editable source content.</Panel.Body>
|
|
124
|
+
</Panel>
|
|
125
|
+
<Panel.Handle
|
|
126
|
+
aria-labelledby={titleId}
|
|
127
|
+
size={size}
|
|
128
|
+
onSizeChange={(next) => {
|
|
129
|
+
setSize(next);
|
|
130
|
+
setMessage("");
|
|
131
|
+
}}
|
|
132
|
+
min={25}
|
|
133
|
+
max={75}
|
|
134
|
+
step={5}
|
|
135
|
+
/>
|
|
136
|
+
<Panel aria-label="Preview">
|
|
137
|
+
<Panel.Body>Resulting preview.</Panel.Body>
|
|
138
|
+
</Panel>
|
|
139
|
+
</Panel.Group>
|
|
140
|
+
</>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Click each resize button, then focus the handle and use its arrow keys, Home/End, and Enter. Check that pane width, separator value, disabled limits, focus visibility, and feedback stay correct. Test the actual composition at zoom and with supported assistive technology. See the shared [accessibility verification guide](https://github.com/KhallilB/kbui/blob/main/docs/guides/accessibility.md#keyboard-focus-and-pointer-input) for WCAG 2.5.7 and target-size requirements.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
Reveal supporting controls or details in an anchored popup while retaining page context. Base UI owns positioning, focus management and dismissal. Non-modal interaction is the default.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-popover--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Input, Popover } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function ViewOptions() {
|
|
14
|
+
return (
|
|
15
|
+
<Popover>
|
|
16
|
+
<Popover.Trigger render={<Button variant="secondary" />}>View options</Popover.Trigger>
|
|
17
|
+
<Popover.Content title="View options">
|
|
18
|
+
<Popover.Body><Input label="Contains text" /></Popover.Body>
|
|
19
|
+
<Popover.Footer>
|
|
20
|
+
<Popover.Close render={<Button />}>Done</Popover.Close>
|
|
21
|
+
</Popover.Footer>
|
|
22
|
+
</Popover.Content>
|
|
23
|
+
</Popover>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## More examples
|
|
29
|
+
|
|
30
|
+
- [Display preferences](https://kbui.kcb.pro/storybook/?path=/story/components-popover--default): immediate, reversible changes to the activity list, with Reset and Done.
|
|
31
|
+
- [Controlled editing](https://kbui.kcb.pro/storybook/?path=/story/components-popover--controlled): drafts, Cancel, validation and native Enter submission; only Save commits the new name.
|
|
32
|
+
- [Nested theme](https://kbui.kcb.pro/storybook/?path=/story/components-popover--scoped-portal): portal inside a local theme host.
|
|
33
|
+
- [Inside Dialog](https://kbui.kcb.pro/storybook/?path=/story/components-popover--inside-dialog): nested Escape dismissal and focus recovery.
|
|
34
|
+
- [Scrolling workspace](https://kbui.kcb.pro/storybook/?path=/story/components-popover--scrolling): keep a compact form and its Done action visible while the surrounding workspace scrolls.
|
|
35
|
+
|
|
36
|
+
## Reference
|
|
37
|
+
|
|
38
|
+
| Part / prop | Type | Default | Purpose |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| `Popover` | Base UI Popover root props | — | Groups parts without adding a DOM element. |
|
|
41
|
+
| `open` / `defaultOpen` | `boolean` | `false` | Controlled or initial open state. |
|
|
42
|
+
| `onOpenChange` | `(open, details) => void` | — | Requests opening/dismissal; supports `details.cancel()`. |
|
|
43
|
+
| `modal` | `boolean` or `"trap-focus"` | `false` | Configures interaction containment. Include Close for modal focus containment and touch-screen-reader escape. |
|
|
44
|
+
| `Popover.Trigger` | Base UI Popover trigger props | `button` | Supports Button composition, refs and native disabled. |
|
|
45
|
+
| `Popover.Content` | Base UI Popover popup props | `div` | Portaled interactive popup with ref and native attributes. |
|
|
46
|
+
| `Content.title` / `description` | `ReactNode` | — | Adds associated Title and Description inside Header; omit when composing those parts. |
|
|
47
|
+
| `Content.container` | Base UI portal container | `document.body` | Targets a stable theme host, including refs. |
|
|
48
|
+
| `Content.side` / `align` | Base UI positioner values | `bottom` / `start` | Preferred placement; collision handling may adjust it. |
|
|
49
|
+
| `Content.sideOffset` | Base UI side offset | `6` | Gap from trigger in CSS pixels. |
|
|
50
|
+
| `Content.positionerProps` | Base UI positioner props | — | Advanced collision boundary/padding, offsets, custom anchor, styles and ref; excludes children, className, side, align and sideOffset. |
|
|
51
|
+
| `Content.initialFocus` / `finalFocus` | Base UI focus target | Primitive defaults | Customize entry and return focus; supports refs and callbacks. |
|
|
52
|
+
| `Content.className` | `string` | — | Additional popup class. |
|
|
53
|
+
| `Content.classNames` | `{ positioner?: string }` | — | Additional class on positioning wrapper. |
|
|
54
|
+
| `Popover.Title` / `Description` | Base UI naming part props | — | Compose accessible names and descriptions; accepts string className and refs. |
|
|
55
|
+
| `Popover.Header` / `Body` / `Footer` | Native `div` props and refs | `div` | Header and Footer stay outside Body scrolling. Body must be a direct Content child; Footer holds visible actions. |
|
|
56
|
+
| `Popover.Close` | Base UI close props | `button` | Dismisses without performing an application action. |
|
|
57
|
+
|
|
58
|
+
Name every popup with title, Title or aria-label. Include a visible Close action, especially for touch and modal usage. Escape closes the popup and restores focus; a non-modal outside press dismisses while allowing outside interaction. Default keyboard opening focuses the first tabbable control or the popup; touch opening can focus the popup to avoid launching a virtual keyboard. Keep required instructions available outside temporary content.
|
|
59
|
+
|
|
60
|
+
Keep popovers short: show the relevant controls and a visible Done/Close action together. Avoid artificial height caps, large descriptions or long lists of secondary content. Use Dialog, Drawer or inline Disclosure when a task needs more room.
|
|
61
|
+
|
|
62
|
+
For constrained viewports, compose direct Header, Body and Footer children. Content title/description props create Header automatically. Only Body shrinks and scrolls; Footer actions and the heading stay visible. A long scrollable Body needs a name and `tabIndex={0}` for keyboard scrolling; keep essential instructions and actions outside it. The outer popup can still scroll as a fallback when enlarged header/footer content alone exceeds available space. The popup fits the positioning engine's available width/height. `positionerProps` retains Base UI collision and anchor configuration. Set `container` for nested themes and keep the host outside clipping/transformed ancestors when needed. See [theme hosts and portals](../../../../docs/guides/forms-and-overlays.md#theme-hosts-and-portals).
|
|
63
|
+
|
|
64
|
+
Style `--kb-popover-width`, `-padding`, `-background`, `-color`, `-border`, `-radius` and `-shadow`. `--kb-popover-motion-duration`, `-motion-easing`, `-enter-scale` and `-enter-offset` control anchored motion; reduced motion disables transitions and movement. Position changes track scrolling immediately. Change theme-dependent aliases on the appropriate portal host.
|
|
65
|
+
|
|
66
|
+
## Interaction patterns
|
|
67
|
+
|
|
68
|
+
Use an explicit button with a descriptive label. A decorative chevron can show that it reveals controls; preserve the trigger's expanded state and native Enter/Space handling. Open by click, tap or keyboard activation. Keep non-modal controls in normal Tab order and provide a visible dismissal action. Escape returns focus to the trigger; outside press dismisses without blocking the surrounding page. Base UI owns these behaviors and adapts touch focus to avoid opening a virtual keyboard unnecessarily.
|
|
69
|
+
|
|
70
|
+
Choose one update model and explain it:
|
|
71
|
+
|
|
72
|
+
| Task | Update model | Actions and dismissal |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| View preferences | Apply immediately; show the effect in surrounding content. | Reset restores defaults; Done, Escape and outside press retain the chosen settings. |
|
|
75
|
+
| Edit a value | Keep a separate draft until valid submission. | Save/Enter commits; Cancel, Escape and outside press discard the draft. Reopening starts from the saved value. |
|
|
76
|
+
|
|
77
|
+
The Default and Controlled stories implement these two models. Do not label a dismiss-only button Save, and do not silently commit a draft on outside dismissal. Keep asynchronous operations and error recovery application-owned.
|
|
78
|
+
|
|
79
|
+
Test the actual embedding viewport. A portal escapes DOM clipping but cannot escape an iframe's viewport. Leave space around the trigger for the complete panel and its actions; a tiny host must offer a larger preview or compose Dialog/Drawer. Do not accept a Body that collapses to zero height while a field technically remains in the accessibility tree. Catalog previews reserve the popup footprint and open the real panel at mobile/desktop widths, including paired themes.
|
|
80
|
+
|
|
81
|
+
Follow the [Base UI focus/positioning contract](https://base-ui.com/react/components/popover) and [WAI non-modal dialog guidance](https://www.w3.org/TR/wai-aria-1.2/#dialog). For complex tasks on compact screens, use an explicit sheet/dialog composition and preserve its modal semantics rather than changing modes during an open interaction.
|
|
82
|
+
|
|
83
|
+
## Verification limits
|
|
84
|
+
|
|
85
|
+
Run `bun run test:overlays` for Chromium, Firefox and WebKit checks in both themes and motion preferences. Scans exclude only Base UI’s implementation focus guards, following maintainer guidance; real controls retain naming checks. Native keyboard and scanner negative-control regressions protect that boundary. See [overlay verification](../../../../docs/guides/accessibility.md#overlay-compatibility) for the policy and manual screen-reader assessment limits.
|
|
86
|
+
|
|
87
|
+
## Related components
|
|
88
|
+
|
|
89
|
+
Use [Tooltip](Tooltip.md) for brief non-interactive hints, [Menu](Menu.md) for action lists, [Disclosure](Disclosure.md) for inline details, and [Dialog](Dialog.md) for modal tasks and the documented drawer/confirmation patterns.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Progress
|
|
2
|
+
|
|
3
|
+
Show how much of a known task is complete. Use a task label rather than a percentage as the accessible name.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-progress--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Progress } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return <Progress label="Upload progress" value={60} />;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## More examples
|
|
19
|
+
|
|
20
|
+
- [Counted work](https://kbui.kcb.pro/storybook/?path=/story/components-progress--steps): Present a readable completed/total value.
|
|
21
|
+
- [Completed work](https://kbui.kcb.pro/storybook/?path=/story/components-progress--complete): Inspect the final state.
|
|
22
|
+
|
|
23
|
+
## Reference
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Notes |
|
|
26
|
+
| ------------ | ------------- | -------------------- | ----------------------------------------------------------- |
|
|
27
|
+
| `label` | `ReactNode` | required | Visible task name and accessible progressbar label |
|
|
28
|
+
| `value` | `number` | required | Completed amount, from zero to max |
|
|
29
|
+
| `max` | `number` | `100` | Total amount; set it for counts such as three of five steps |
|
|
30
|
+
| `valueText` | `string` | formatted percentage | Visible and announced value, such as 3 of 5 files |
|
|
31
|
+
| `classNames` | keyed classes | unset | Style head, label, value, track, or indicator |
|
|
32
|
+
|
|
33
|
+
The current value stays available to assistive technology. Your app owns task completion and any separate completion announcement.
|
|
34
|
+
|
|
35
|
+
## Related components
|
|
36
|
+
|
|
37
|
+
Use [Status](Status.md) for a textual state and [Stat](Stat.md) for a headline measure without completion semantics.
|