@overdoser/react-toolkit 0.0.15 → 0.1.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/AGENTS.md +27 -0
- package/CHANGELOG.md +75 -0
- package/README.md +59 -2
- package/components/Form/Form.d.ts +16 -1
- package/components/Form/FormField.d.ts +17 -2
- package/components/Form/formFieldDefaults.d.ts +9 -0
- package/components/Link/Link.d.ts +10 -0
- package/components/Popover/Popover.d.ts +7 -0
- package/components/inputs/Checkbox/CheckboxGroup.d.ts +83 -0
- package/components/inputs/Checkbox/index.d.ts +2 -0
- package/index.css +1 -1
- package/index.d.ts +2 -2
- package/index.js +2185 -1980
- package/index.layered.css +5 -0
- package/llms.txt +56 -4
- package/manifest.json +1511 -290
- package/package.json +3 -2
package/AGENTS.md
CHANGED
|
@@ -19,6 +19,11 @@ For exhaustive component reference (every prop, every variant, every signature),
|
|
|
19
19
|
import '@overdoser/react-toolkit/theme.css';
|
|
20
20
|
```
|
|
21
21
|
Without this, components render unstyled.
|
|
22
|
+
- **Want `className` / `classes.*` overrides to always win regardless of bundler order?** Import the layered twin instead:
|
|
23
|
+
```ts
|
|
24
|
+
import '@overdoser/react-toolkit/theme.layered.css';
|
|
25
|
+
```
|
|
26
|
+
It wraps all toolkit CSS in a `crk` cascade layer, so any of your own *unlayered* rules beat it deterministically. See "Customizing styles" below.
|
|
22
27
|
|
|
23
28
|
## Import rules
|
|
24
29
|
|
|
@@ -44,6 +49,8 @@ For exhaustive component reference (every prop, every variant, every signature),
|
|
|
44
49
|
- Multi-pick with chips → `<Select multiple options={...} onValuesChange={...} />`.
|
|
45
50
|
- You want it to look like a "menu trigger" instead of a form input → `<Dropdown options={...} value={...} onChange={...} />` (select-mode dropdown).
|
|
46
51
|
|
|
52
|
+
- **Need to pick several values from a small fixed set?** → `<CheckboxGroup options={...} value={...} onChange={...} />` (a checkbox list, or `variant="chips"` for toggle chips). For a large/searchable set, prefer `<Select multiple>` instead.
|
|
53
|
+
|
|
47
54
|
- **Need a menu (Edit / Delete / Archive)?** → `<Dropdown trigger={...}>` with `<DropdownItem>` children.
|
|
48
55
|
|
|
49
56
|
- **Need a tooltip / hover card / contextual panel?** → `<Popover trigger={...} content={...} />`.
|
|
@@ -96,6 +103,26 @@ For exhaustive component reference (every prop, every variant, every signature),
|
|
|
96
103
|
</FormField>
|
|
97
104
|
```
|
|
98
105
|
|
|
106
|
+
### Wire a CheckboxGroup (multi-value) inside a Form
|
|
107
|
+
```tsx
|
|
108
|
+
<FormField name="interests" label="Interests" rules={{ validate: (v) => v.length > 0 || 'Pick at least one' }}>
|
|
109
|
+
<CheckboxGroup
|
|
110
|
+
variant="chips" // or omit for a checkbox list
|
|
111
|
+
options={[
|
|
112
|
+
{ value: 'design', label: 'Design' },
|
|
113
|
+
{ value: 'eng', label: 'Engineering' },
|
|
114
|
+
]}
|
|
115
|
+
/>
|
|
116
|
+
</FormField>
|
|
117
|
+
```
|
|
118
|
+
`CheckboxGroup` binds `value: string[]` / `onChange(values)` directly — no bridge needed.
|
|
119
|
+
|
|
120
|
+
## Customizing styles
|
|
121
|
+
|
|
122
|
+
- **Theme tokens:** override `--crk-*` custom properties on `:root` (colors, fonts, spacing, radii). This is the primary, stable customization surface.
|
|
123
|
+
- **Per-element overrides:** use each component's `classes` prop (and `className`) — internal class names are hashed and unstable, so never target them directly.
|
|
124
|
+
- **Make overrides deterministic:** `className` / `classes.*` are plain CSS classes; they only beat the toolkit's built-in class if your stylesheet is inserted *after* it, which the bundler controls. To guarantee precedence, import `@overdoser/react-toolkit/theme.layered.css` (everything ships in a `crk` cascade layer, so your unlayered rules always win), **or** add `@import '@overdoser/react-toolkit/theme.css' layer(crk);` as the first line of your global CSS. Caveat: an aggressive global reset that is itself unlayered will then also override the toolkit's base styles — put your reset in its own earlier layer if so. `theme.css` and `theme.layered.css` are identical except the layer wrapper — import exactly one, and token (`--crk-*`) theming works the same in either.
|
|
125
|
+
|
|
99
126
|
## Recipes
|
|
100
127
|
|
|
101
128
|
Full copy-paste-able files live alongside this doc. Each is one self-contained file that you can drop into a project. Adjust types/imports for your codebase.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@overdoser/react-toolkit` are documented here.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
|
5
|
+
project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0]
|
|
8
|
+
|
|
9
|
+
This release adds a `CheckboxGroup` component, a cascade-layered stylesheet for
|
|
10
|
+
deterministic style overrides, and viewport-aware popovers — plus a round of
|
|
11
|
+
`Form` ergonomics. A few **defaults changed** (forms, popovers, links); they are
|
|
12
|
+
all opt-out (see ⚠️ below).
|
|
13
|
+
|
|
14
|
+
### ⚠️ Notable default changes (visual)
|
|
15
|
+
|
|
16
|
+
No API was removed or renamed, but some components now **render differently by
|
|
17
|
+
default**. To restore the previous behavior:
|
|
18
|
+
|
|
19
|
+
- **Forms reserve space for validation messages** so an error no longer shifts
|
|
20
|
+
the layout, the error now appears *between the input and the description*
|
|
21
|
+
(instead of replacing the description), inter-field/element gaps are tighter,
|
|
22
|
+
and labels are bolder (weight 700). Opt out per field or form-wide with
|
|
23
|
+
`reserveErrorSpace={false}`.
|
|
24
|
+
- **Popovers reposition to stay in the viewport** (flip to the opposite side /
|
|
25
|
+
shift near a screen edge). Opt out with `<Popover autoPosition={false} />`.
|
|
26
|
+
- **Links that open in a new tab show an inline ↗ icon** (`external` or a manual
|
|
27
|
+
`target="_blank"`). Opt out with `<Link hideExternalIcon />`.
|
|
28
|
+
- `theme.css` is **unchanged** — the new cascade layer is opt-in via
|
|
29
|
+
`theme.layered.css`, so existing stylesheet imports are unaffected.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`CheckboxGroup` component** — multi-value selection from a fixed option set,
|
|
34
|
+
rendered as a checkbox list (`variant="checkbox"`, default) or toggleable chips
|
|
35
|
+
(`variant="chips"`). Supports `chipShape` (`pill | rounded | square`),
|
|
36
|
+
`chipCheckmark` (with constant chip width — padding compensates for the mark),
|
|
37
|
+
`orientation`, `disabled`, `error`, `name`, `required`, and a `classes`
|
|
38
|
+
override (`{ group, option, chip, chipSelected }`). Binds directly inside
|
|
39
|
+
`FormField` (`value: string[]` / `onChange(values)`), no bridge needed.
|
|
40
|
+
- **`theme.layered.css` stylesheet export** — identical to `theme.css` but
|
|
41
|
+
wrapped in a `@layer crk` cascade layer, so consumer `className` / `classes.*`
|
|
42
|
+
overrides win deterministically regardless of bundler import order. Import
|
|
43
|
+
exactly one of the two.
|
|
44
|
+
- **`Form` props** `reserveErrorSpace` (form-wide default for all fields) and
|
|
45
|
+
`fieldClasses` (form-wide `classes` default, merged with each field's own).
|
|
46
|
+
- **`FormField` prop** `reserveErrorSpace` (`boolean | number | string`) and a
|
|
47
|
+
`--crk-field-error-min-height` token to size the reserved space.
|
|
48
|
+
- **`Popover` prop** `autoPosition` (default `true`) for viewport-aware flipping
|
|
49
|
+
and edge shifting.
|
|
50
|
+
- **`Link` prop** `hideExternalIcon` to suppress the new-tab icon.
|
|
51
|
+
- `FormFieldClasses` gained a `message` key (the validation/reserve slot).
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- `FormField` validation layout reworked so the field's outer height stays
|
|
56
|
+
constant when a one-line error toggles (the reserved spacer sits after the
|
|
57
|
+
description and swaps 1:1 with the error). Multi-line errors grow past it.
|
|
58
|
+
- Form-wide reservation off (`<Form reserveErrorSpace={false}>`) uses a slightly
|
|
59
|
+
larger inter-field gap to compensate for the absent reserved line.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **Searchable single-select** dropdown was mispositioned / rendered as a ~1px
|
|
64
|
+
sliver in portal mode because it anchored to the trigger button (hidden while
|
|
65
|
+
open); it now anchors to the always-visible wrapper.
|
|
66
|
+
- **Native `Select`** silently dropped `onValueChange` and could trip React's
|
|
67
|
+
controlled-field warning when given `value` + `onValueChange`; it now wires
|
|
68
|
+
both `onChange` and `onValueChange`.
|
|
69
|
+
|
|
70
|
+
### Docs
|
|
71
|
+
|
|
72
|
+
- `README`, `llms.txt`, `manifest.json`, and `AGENTS.md` updated for all of the
|
|
73
|
+
above, including a `theme.css` vs `theme.layered.css` comparison and the
|
|
74
|
+
cascade-layer caveat (an unlayered global reset also beats layered toolkit
|
|
75
|
+
styles — put resets in an earlier layer).
|
package/README.md
CHANGED
|
@@ -28,22 +28,79 @@ Override `--crk-*` CSS custom properties to customize the theme:
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
For per-element tweaks, every component accepts `className` and a `classes` prop
|
|
32
|
+
(internal class names are hashed — never target them directly).
|
|
33
|
+
|
|
34
|
+
### `theme.css` vs `theme.layered.css`
|
|
35
|
+
|
|
36
|
+
The package ships two stylesheets with **identical content** — same rules, same
|
|
37
|
+
hashed class names, same `--crk-*` tokens. The only difference is that
|
|
38
|
+
`theme.layered.css` wraps everything in a CSS cascade layer:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
@layer crk {
|
|
42
|
+
/* ...the entire stylesheet... */
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
That wrapper changes how your overrides compete with the toolkit's styles.
|
|
47
|
+
Import **exactly one** of the two (never both).
|
|
48
|
+
|
|
49
|
+
**The problem with plain `theme.css`.** The overrides you pass via `className` /
|
|
50
|
+
`classes.*` are plain CSS classes, so they tie with the toolkit's own class on
|
|
51
|
+
specificity — the winner is decided by **stylesheet source order**, which your
|
|
52
|
+
bundler controls. In many setups the toolkit CSS is injected *after* your app
|
|
53
|
+
CSS, so your overrides silently lose.
|
|
54
|
+
|
|
55
|
+
**What the layer fixes.** A core rule of cascade layers: **any unlayered style
|
|
56
|
+
beats any layered style, regardless of specificity or import order.** Since
|
|
57
|
+
`theme.layered.css` puts the whole toolkit in the `crk` layer, your own
|
|
58
|
+
(unlayered) rules — including every `className` / `classes.*` override — always
|
|
59
|
+
win, deterministically:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import '@overdoser/react-toolkit/theme.layered.css'; // instead of theme.css
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
(If you import CSS from a `.css` entry instead of JS, the equivalent is
|
|
66
|
+
`@import '@overdoser/react-toolkit/theme.css' layer(crk);` as the first line.)
|
|
67
|
+
|
|
68
|
+
| | `theme.css` | `theme.layered.css` |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| Override wins by | specificity, then import order (bundler-dependent) | **always** (unlayered beats layered) |
|
|
71
|
+
| `--crk-*` token theming | ✅ | ✅ (identical) |
|
|
72
|
+
| Affected by a global CSS reset | only via normal specificity/order | ⚠️ an *unlayered* reset also beats the toolkit's base styles |
|
|
73
|
+
|
|
74
|
+
**The one caveat.** Because layered styles lose to *all* unlayered styles, an
|
|
75
|
+
aggressive global reset (e.g. `button { font: inherit }`) would also override the
|
|
76
|
+
toolkit's base styles under `theme.layered.css`. If you ship a heavy reset, put
|
|
77
|
+
it in its own earlier layer so the order is explicit:
|
|
78
|
+
|
|
79
|
+
```css
|
|
80
|
+
@layer reset, crk;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Rule of thumb:** if you heavily customize component internals via
|
|
84
|
+
`classes` / `className`, use `theme.layered.css`. Otherwise `theme.css` is fine.
|
|
85
|
+
Theme-token (`--crk-*`) overrides work the same in both.
|
|
86
|
+
|
|
31
87
|
## Components
|
|
32
88
|
|
|
33
89
|
| Component | Description |
|
|
34
90
|
| --- | --- |
|
|
35
91
|
| **Button** | Variants: `primary`, `secondary`, `danger`, `ghost`. Multiple sizes. Loading states with `dots`, `shimmer`, and `border` animations. |
|
|
36
|
-
| **Link** | Styled link with variants and external link support. |
|
|
92
|
+
| **Link** | Styled link with variants and external link support (inline new-tab icon, toggleable). |
|
|
37
93
|
| **Typography** | Renders `h1`-`h6`, `p`, `span`, `label`. Supports `weight`, `color`, `align`, and `truncate`. |
|
|
38
94
|
| **List / ListItem** | Ordered and unordered lists with configurable spacing. |
|
|
39
95
|
| **Table** | Sortable columns, multi-sort with Ctrl+click, pagination, and server-side sort support. |
|
|
40
96
|
| **Dropdown** | Menu dropdown with chevron indicator. Also works as a selectable form input with `options`, `value`, and `onChange`. |
|
|
41
|
-
| **Popover** | Positioned popover anchored to a trigger element. |
|
|
97
|
+
| **Popover** | Positioned popover anchored to a trigger element, with viewport-aware auto-flip. |
|
|
42
98
|
| **Modal** | Portal-based modal with `Header`, `Body`, and `Footer` compound components. Includes focus trap and escape/backdrop close. |
|
|
43
99
|
| **Form / FormField** | Form wrapper with react-hook-form integration. |
|
|
44
100
|
| **Input** | Text input with sizes, error state, and prefix/suffix slots. |
|
|
45
101
|
| **Select** | Native `<select>` with a custom arrow indicator. |
|
|
46
102
|
| **Checkbox** | Checkbox with label and indeterminate state support. |
|
|
103
|
+
| **CheckboxGroup** | Multi-value selection as a checkbox list or toggleable chips. |
|
|
47
104
|
| **Radio / RadioGroup** | Context-based radio group. |
|
|
48
105
|
| **Textarea** | Textarea with resize control. |
|
|
49
106
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UseFormReturn, FieldValues, SubmitHandler } from 'react-hook-form';
|
|
2
|
+
import { FormFieldClasses } from './FormField';
|
|
2
3
|
export interface FormProps<T extends FieldValues> {
|
|
3
4
|
/** The result of `useForm()`. */
|
|
4
5
|
form: UseFormReturn<T>;
|
|
@@ -6,6 +7,20 @@ export interface FormProps<T extends FieldValues> {
|
|
|
6
7
|
onSubmit: SubmitHandler<T>;
|
|
7
8
|
/** Top-of-form error messages. Rendered above children with `role="alert"`. */
|
|
8
9
|
errors?: React.ReactNode[];
|
|
10
|
+
/**
|
|
11
|
+
* Default `reserveErrorSpace` applied to every `FormField` inside this form
|
|
12
|
+
* (each field can still override it via its own `reserveErrorSpace` prop).
|
|
13
|
+
* Same accepted values as `FormField`: `boolean | number | string`.
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
reserveErrorSpace?: boolean | number | string;
|
|
17
|
+
/**
|
|
18
|
+
* Default `classes` applied to every `FormField` inside this form. These are
|
|
19
|
+
* *merged* with each field's own `classes` (both class names are applied), so
|
|
20
|
+
* a field can add to — not just replace — the form-wide defaults. Keys:
|
|
21
|
+
* `{ field, label, message, error, helperText }`.
|
|
22
|
+
*/
|
|
23
|
+
fieldClasses?: Partial<FormFieldClasses>;
|
|
9
24
|
className?: string;
|
|
10
25
|
style?: React.CSSProperties;
|
|
11
26
|
children: React.ReactNode;
|
|
@@ -23,4 +38,4 @@ export interface FormProps<T extends FieldValues> {
|
|
|
23
38
|
* <Button type="submit">Save</Button>
|
|
24
39
|
* </Form>
|
|
25
40
|
*/
|
|
26
|
-
export declare function Form<T extends FieldValues>({ form, onSubmit, errors, className, style, children, }: FormProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
export declare function Form<T extends FieldValues>({ form, onSubmit, errors, reserveErrorSpace, fieldClasses, className, style, children, }: FormProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,6 +2,7 @@ import { ReactElement, CSSProperties, ReactNode } from 'react';
|
|
|
2
2
|
export interface FormFieldClasses {
|
|
3
3
|
field: string;
|
|
4
4
|
label: string;
|
|
5
|
+
message: string;
|
|
5
6
|
error: string;
|
|
6
7
|
helperText: string;
|
|
7
8
|
}
|
|
@@ -10,12 +11,26 @@ export interface FormFieldProps {
|
|
|
10
11
|
name: string;
|
|
11
12
|
/** Field label rendered above the input. */
|
|
12
13
|
label?: ReactNode;
|
|
13
|
-
/** Helper text rendered below the input
|
|
14
|
+
/** Helper/description text rendered below the input. Stays visible when invalid — the error message appears above it, between the input and this text. */
|
|
14
15
|
helperText?: ReactNode;
|
|
15
16
|
/** Renders a `*` indicator next to the label. Does NOT add validation rules — pass those in `rules`. */
|
|
16
17
|
required?: boolean;
|
|
17
18
|
/** react-hook-form `useController` rules (e.g., `{ required: 'msg', minLength: { value: 8, message: '…' } }`). */
|
|
18
19
|
rules?: Record<string, unknown>;
|
|
20
|
+
/**
|
|
21
|
+
* Reserve vertical space (after the description) for the validation message so
|
|
22
|
+
* the field's outer height does not change when an error appears/disappears.
|
|
23
|
+
* - `true`: reserve one line via the `--crk-field-error-min-height` token.
|
|
24
|
+
* - `false`: no reservation — an error pushes content down (legacy behaviour).
|
|
25
|
+
* - `number`: reserved height in pixels.
|
|
26
|
+
* - `string`: any CSS length (e.g. `'2.5em'` to fit two lines).
|
|
27
|
+
*
|
|
28
|
+
* Multi-line messages are allowed to grow past the reserved height. When unset,
|
|
29
|
+
* inherits the `reserveErrorSpace` set on the enclosing `<Form>`, falling back
|
|
30
|
+
* to `true`.
|
|
31
|
+
* @default inherited from `<Form>`, else `true`
|
|
32
|
+
*/
|
|
33
|
+
reserveErrorSpace?: boolean | number | string;
|
|
19
34
|
/** Override class names on internal elements. */
|
|
20
35
|
classes?: Partial<FormFieldClasses>;
|
|
21
36
|
className?: string;
|
|
@@ -41,4 +56,4 @@ export interface FormFieldProps {
|
|
|
41
56
|
* <Input type="email" />
|
|
42
57
|
* </FormField>
|
|
43
58
|
*/
|
|
44
|
-
export declare function FormField({ name, label, helperText, required, rules, classes, className, style, children, }: FormFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
59
|
+
export declare function FormField({ name, label, helperText, required, rules, reserveErrorSpace, classes, className, style, children, }: FormFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FormFieldClasses } from './FormField';
|
|
2
|
+
/** Field-level defaults supplied by `<Form>` and inherited by every `<FormField>`. */
|
|
3
|
+
export interface FormFieldDefaults {
|
|
4
|
+
/** Default `reserveErrorSpace` for fields that don't set their own. */
|
|
5
|
+
reserveErrorSpace?: boolean | number | string;
|
|
6
|
+
/** Default `classes` merged into every field (each field's own `classes` are also applied). */
|
|
7
|
+
classes?: Partial<FormFieldClasses>;
|
|
8
|
+
}
|
|
9
|
+
export declare const FormFieldDefaultsContext: import('react').Context<FormFieldDefaults | null>;
|
|
@@ -9,10 +9,20 @@ export interface LinkProps extends ComponentPropsWithRef<'a'> {
|
|
|
9
9
|
* @default false
|
|
10
10
|
*/
|
|
11
11
|
external?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Hide the inline "opens in a new tab" icon that is shown by default whenever
|
|
14
|
+
* the link opens in a new tab (`external` or `target="_blank"`). The
|
|
15
|
+
* screen-reader suffix is kept regardless. @default false
|
|
16
|
+
*/
|
|
17
|
+
hideExternalIcon?: boolean;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* Styled `<a>` with variants and safe external-link defaults.
|
|
15
21
|
*
|
|
22
|
+
* When the link opens in a new tab (via `external`, or a manual
|
|
23
|
+
* `target="_blank"`), a small inline ↗ icon is appended to the right so users
|
|
24
|
+
* know the link leaves the current tab. Pass `hideExternalIcon` to suppress it.
|
|
25
|
+
*
|
|
16
26
|
* @example <Link href="https://example.com" external>Docs</Link>
|
|
17
27
|
*/
|
|
18
28
|
export declare const Link: import('react').ForwardRefExoticComponent<Omit<LinkProps, "ref"> & import('react').RefAttributes<HTMLAnchorElement>>;
|
|
@@ -26,6 +26,13 @@ export interface PopoverProps {
|
|
|
26
26
|
content: React.ReactNode;
|
|
27
27
|
/** Side of the trigger to anchor the panel to. @default 'bottom' */
|
|
28
28
|
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
29
|
+
/**
|
|
30
|
+
* Keep the panel inside the viewport: flip to the opposite side when the
|
|
31
|
+
* requested one would overflow, and shift along the cross-axis so the panel
|
|
32
|
+
* stays fully visible near a screen edge. The requested `position` is honored
|
|
33
|
+
* whenever it fits. @default true
|
|
34
|
+
*/
|
|
35
|
+
autoPosition?: boolean;
|
|
29
36
|
/** Controlled open state. */
|
|
30
37
|
open?: boolean;
|
|
31
38
|
/** Called when the open state changes. */
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
export interface CheckboxGroupOption {
|
|
3
|
+
/** Value added to / removed from the selected array. */
|
|
4
|
+
value: string;
|
|
5
|
+
/** Visible label (checkbox row label, or chip body). */
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
/** Non-interactive when true. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface CheckboxGroupClasses {
|
|
11
|
+
group: string;
|
|
12
|
+
/** Each rendered option (a `Checkbox` row, or a chip button). */
|
|
13
|
+
option: string;
|
|
14
|
+
/** The chip button (only in `variant="chips"`). */
|
|
15
|
+
chip: string;
|
|
16
|
+
/** Applied to a chip when its value is selected. */
|
|
17
|
+
chipSelected: string;
|
|
18
|
+
}
|
|
19
|
+
export interface CheckboxGroupProps {
|
|
20
|
+
/** Selectable options. */
|
|
21
|
+
options: CheckboxGroupOption[];
|
|
22
|
+
/** Controlled array of selected values. @default [] */
|
|
23
|
+
value?: string[];
|
|
24
|
+
/** Fires with the next selected array whenever an option is toggled. */
|
|
25
|
+
onChange?: (values: string[]) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Rendering style:
|
|
28
|
+
* - `'checkbox'` (default): a list of themed checkboxes.
|
|
29
|
+
* - `'chips'`: toggleable chips laid out one after another.
|
|
30
|
+
* @default 'checkbox'
|
|
31
|
+
*/
|
|
32
|
+
variant?: 'checkbox' | 'chips';
|
|
33
|
+
/**
|
|
34
|
+
* Chip corner style (`variant="chips"` only):
|
|
35
|
+
* - `'pill'`: fully rounded (default).
|
|
36
|
+
* - `'rounded'`: medium radius.
|
|
37
|
+
* - `'square'`: small radius — more rectangular.
|
|
38
|
+
* @default 'pill'
|
|
39
|
+
*/
|
|
40
|
+
chipShape?: 'pill' | 'rounded' | 'square';
|
|
41
|
+
/**
|
|
42
|
+
* Show a leading checkmark on selected chips (`variant="chips"` only). The
|
|
43
|
+
* chip's total width stays constant: when checked, the horizontal padding
|
|
44
|
+
* shrinks on both sides by exactly half the mark+gap width, so the freed
|
|
45
|
+
* space fits the mark and the centered content does not jump. @default true
|
|
46
|
+
*/
|
|
47
|
+
chipCheckmark?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Layout direction. `'horizontal'` wraps options onto multiple lines.
|
|
50
|
+
* Defaults to `'vertical'` for `checkbox` and `'horizontal'` for `chips`.
|
|
51
|
+
*/
|
|
52
|
+
orientation?: 'vertical' | 'horizontal';
|
|
53
|
+
/** Disables every option. */
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
/** Apply error styling (e.g. when a required group is empty). @default false */
|
|
56
|
+
error?: boolean;
|
|
57
|
+
/** Shared `name` for the underlying checkboxes (checkbox variant). */
|
|
58
|
+
name?: string;
|
|
59
|
+
/** Override class names on internal elements. */
|
|
60
|
+
classes?: Partial<CheckboxGroupClasses>;
|
|
61
|
+
className?: string;
|
|
62
|
+
style?: CSSProperties;
|
|
63
|
+
id?: string;
|
|
64
|
+
/** Accessible label. Use this OR `aria-labelledby`. */
|
|
65
|
+
'aria-label'?: string;
|
|
66
|
+
'aria-labelledby'?: string;
|
|
67
|
+
'aria-describedby'?: string;
|
|
68
|
+
'aria-invalid'?: boolean | 'true' | 'false';
|
|
69
|
+
/** Marks the group as required (`aria-required`). */
|
|
70
|
+
required?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Multi-value selection from a fixed set of options. Renders either a list of
|
|
74
|
+
* checkboxes (default) or a row of toggleable chips. Works standalone or inside
|
|
75
|
+
* a `<FormField>` (its `value: string[]` / `onChange(values)` bridge directly).
|
|
76
|
+
*
|
|
77
|
+
* @example Checkboxes:
|
|
78
|
+
* <CheckboxGroup options={topics} value={picked} onChange={setPicked} aria-label="Topics" />
|
|
79
|
+
*
|
|
80
|
+
* @example Chips:
|
|
81
|
+
* <CheckboxGroup variant="chips" options={tags} value={picked} onChange={setPicked} aria-label="Tags" />
|
|
82
|
+
*/
|
|
83
|
+
export declare const CheckboxGroup: import('react').ForwardRefExoticComponent<CheckboxGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|