@inkorange/space-ui 1.10.0 → 1.12.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 +112 -0
- package/README.md +34 -0
- package/dist/components/Autocomplete.d.ts +11 -0
- package/dist/components/Badge.d.ts +3 -3
- package/dist/components/Button.d.ts +7 -3
- package/dist/components/Dialog.d.ts +16 -0
- package/dist/components/DropdownMenu.d.ts +16 -0
- package/dist/components/IconToggle.d.ts +9 -7
- package/dist/components/Loader.d.ts +8 -4
- package/dist/components/RadioGroup.d.ts +15 -0
- package/dist/components/Select.d.ts +17 -0
- package/dist/components/Slider.d.ts +10 -0
- package/dist/components/Tabs.d.ts +15 -0
- package/dist/components/TextField.d.ts +12 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +38 -0
- package/dist/index.js +911 -858
- package/dist/index.js.map +1 -1
- package/dist/space-ui.css +1 -1
- package/package.json +17 -5
package/AGENTS.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions for AI coding agents. Two audiences, in order: writing an
|
|
4
|
+
application that uses SpaceUI, then working inside this repository.
|
|
5
|
+
|
|
6
|
+
The complete, generated API reference lives at
|
|
7
|
+
<https://space-components.vercel.app/llms.txt> (and `llms-full.txt` for every
|
|
8
|
+
prop, data shape and token). It is derived from this source on every deploy, so
|
|
9
|
+
it describes the published version exactly. Prefer it over anything you
|
|
10
|
+
remember about this library.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Using SpaceUI in an application
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @inkorange/space-ui
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import "@inkorange/space-ui/styles.css";
|
|
22
|
+
import { Card, Heading, Text, Button } from "@inkorange/space-ui";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Three entry points, and no others: the package itself, `./styles.css` (the one
|
|
26
|
+
required stylesheet) and `./tokens.css` (the token layer alone, for a project
|
|
27
|
+
that wants the palette and the scales without the components).
|
|
28
|
+
|
|
29
|
+
1. **Import the stylesheet once, at the application root.** All component CSS
|
|
30
|
+
ships precompiled in one file. There is no per-component import, and no Sass
|
|
31
|
+
for consumers.
|
|
32
|
+
2. **Do not add a provider, context or theme wrapper.** Components read tokens
|
|
33
|
+
straight from CSS custom properties on the document.
|
|
34
|
+
3. **The library is dark-only, by design.** The tokens can be re-pointed, but
|
|
35
|
+
the components are drawn as lit glass over a dark ground, so a light
|
|
36
|
+
palette misrepresents every surface. There is no supported light theme; do
|
|
37
|
+
not build one.
|
|
38
|
+
4. **Style with tokens, never raw lengths or colours.** `var(--spacing-md)`,
|
|
39
|
+
not `16px`. Spacing is an 8pt grid — every step is a multiple of
|
|
40
|
+
`--sp-grid-base-size`. Control heights come from `--sp-control-height`
|
|
41
|
+
(40px, with `-sm` 36 and `-lg` 48), so a Button and the Select beside it
|
|
42
|
+
match. Colour is a named role: `primary` for emphasis, `success`,
|
|
43
|
+
`warning`, `danger` and `accent` for status, with `-solid`, `-text`,
|
|
44
|
+
`-soft`, `-border`, `-glow` and `-deep` saying which job within the role.
|
|
45
|
+
5. **Override a component token on a class, not with an inline style.** An
|
|
46
|
+
inline style wins over every media and container query the consumer will
|
|
47
|
+
later write.
|
|
48
|
+
|
|
49
|
+
```css
|
|
50
|
+
.featured { --sp-carousel-view-count: 2.5; }
|
|
51
|
+
```
|
|
52
|
+
6. **Boolean props default to false**, so `<Button fullWidth />` is the idiom,
|
|
53
|
+
not `fullWidth={true}`. The one exception is `animated`, which defaults to
|
|
54
|
+
true.
|
|
55
|
+
7. **Selection components are controlled through `onValueChange`** — Select,
|
|
56
|
+
Slider, RadioGroup, CheckboxGroup, Tabs. Native text inputs (TextField,
|
|
57
|
+
TextArea) keep React's own `value` and `onChange`.
|
|
58
|
+
8. **Keyboard support and ARIA are already inside each component.** Roving
|
|
59
|
+
tabindex, arrow-key navigation, Escape handling, `aria-checked`,
|
|
60
|
+
`aria-expanded` and `aria-current` are implemented; do not re-declare them
|
|
61
|
+
from outside. Do pass `aria-label` where a control has no visible label.
|
|
62
|
+
9. **Nothing touches the DOM at import time.** Components that measure do it in
|
|
63
|
+
effects, so the entry point imports cleanly in a server build. Components
|
|
64
|
+
needing the top layer use the platform popover API, so no portal target has
|
|
65
|
+
to be provided.
|
|
66
|
+
|
|
67
|
+
Peer dependencies are `react >= 19` and `react-dom >= 19`. There are no other
|
|
68
|
+
runtime dependencies.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Working in this repository
|
|
73
|
+
|
|
74
|
+
A pnpm monorepo: the library in `packages/space-ui`, a Ladle gallery in
|
|
75
|
+
`apps/docs`.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pnpm test # vitest: a happy-dom unit project and a real-Chromium browser project
|
|
79
|
+
pnpm build # build the library
|
|
80
|
+
pnpm docs # the gallery at localhost:61000
|
|
81
|
+
pnpm changeset # required for any change under packages/space-ui/src
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- **Styling a component follows a fixed pattern**, documented in
|
|
85
|
+
[CLAUDE.md](CLAUDE.md) and as a skill in
|
|
86
|
+
`.claude/skills/space-ui-styling/`. Read one of them before writing a
|
|
87
|
+
`*.module.scss`. The short version: spacing names a step, type is `rem()`
|
|
88
|
+
written in px, control heights come from the ladder, colour is a token, and
|
|
89
|
+
the only exceptions are hairlines and optical nudges — which go in the
|
|
90
|
+
`EXCEPTIONS` map in `src/components/grid.test.ts` with a reason.
|
|
91
|
+
- **Several invariants are tests, not conventions**, and they fail CI rather
|
|
92
|
+
than review: the spacing grid and rem type (`grid.test.ts`), the token
|
|
93
|
+
surface (`tokens.test.ts`), the ban on the component library this one
|
|
94
|
+
replaced, and the documentation a component publishes
|
|
95
|
+
(`published-docs.test.ts` — every component needs a description, and no doc
|
|
96
|
+
comment may name anything internal, because doc comments ship in the `.d.ts`
|
|
97
|
+
and in `llms.txt`).
|
|
98
|
+
- **A component's JSDoc is public copy.** It is published into the shipped
|
|
99
|
+
types, the gallery's prop tables, and the generated agent documentation.
|
|
100
|
+
Write it for someone who installed this from npm: what the component is,
|
|
101
|
+
when to reach for it, and what to use instead when it is the wrong choice.
|
|
102
|
+
- **Every PR touching `packages/space-ui/src` needs a changeset.** CI enforces
|
|
103
|
+
it. Prefer a minor bump over a major one.
|
|
104
|
+
- **Visual changes wait for the owner's sign-off in the gallery** before being
|
|
105
|
+
committed.
|
|
106
|
+
- **Commits are authored solely by Chris West.** Never add `Co-Authored-By` or
|
|
107
|
+
any AI-attribution trailer.
|
|
108
|
+
- Agent-facing files — `llms.txt`, `llms-full.txt`, `reference.html`,
|
|
109
|
+
`robots.txt`, `sitemap.xml` — are generated at docs build time by
|
|
110
|
+
`apps/docs/vite-plugin-agent-docs.ts` from the same TypeScript AST pass that
|
|
111
|
+
builds the gallery's prop tables. Never hand-write them, and never commit
|
|
112
|
+
them: they are build output, and a committed copy goes stale.
|
package/README.md
CHANGED
|
@@ -205,6 +205,40 @@ their edge cases already found rather than imagined.
|
|
|
205
205
|
**Requires** React 19 and a dark surface. There is deliberately no light theme;
|
|
206
206
|
these components assume the dark they were drawn for.
|
|
207
207
|
|
|
208
|
+
## For AI agents
|
|
209
|
+
|
|
210
|
+
The full API — every component, prop, data shape and design token — is
|
|
211
|
+
published in machine-readable form, generated from this source on every deploy
|
|
212
|
+
so it describes the published version exactly:
|
|
213
|
+
|
|
214
|
+
- [`llms.txt`](https://space-components.vercel.app/llms.txt) — the index:
|
|
215
|
+
install, the rules below, the scales, and one line per component.
|
|
216
|
+
- [`llms-full.txt`](https://space-components.vercel.app/llms-full.txt) — the
|
|
217
|
+
whole reference, as one file.
|
|
218
|
+
- [`reference.html`](https://space-components.vercel.app/reference.html) — the
|
|
219
|
+
same, as a page that needs no JavaScript.
|
|
220
|
+
- [`AGENTS.md`](https://github.com/inkorange/space-ui/blob/main/AGENTS.md) —
|
|
221
|
+
the short version, and it ships inside the package, so an agent working in a
|
|
222
|
+
project that depends on SpaceUI finds it without fetching anything.
|
|
223
|
+
|
|
224
|
+
The things that are easy to get wrong because no type signature says them:
|
|
225
|
+
|
|
226
|
+
- **One stylesheet import, at the root.** No per-component CSS, no provider, no
|
|
227
|
+
context, no theme wrapper, no build plugin.
|
|
228
|
+
- **Dark only.** The tokens can be re-pointed, but there is no supported light
|
|
229
|
+
theme — these components are drawn as lit glass over a dark ground.
|
|
230
|
+
- **Tokens, not lengths.** `var(--spacing-md)` over `16px`; spacing is an 8pt
|
|
231
|
+
grid and control heights come from a three-step ladder, so controls placed
|
|
232
|
+
side by side line up without arithmetic.
|
|
233
|
+
- **Set a component token on a class, never in an inline `style`** — inline
|
|
234
|
+
beats every media query a consumer will write afterwards.
|
|
235
|
+
- **Booleans default to false**, so `<Button fullWidth />` is the idiom.
|
|
236
|
+
`animated` is the one exception, defaulting to true.
|
|
237
|
+
- **Selection is controlled through `onValueChange`.** Native text inputs keep
|
|
238
|
+
React's `value` and `onChange`.
|
|
239
|
+
- **Keyboard behaviour and ARIA are already inside the components.** Add
|
|
240
|
+
`aria-label` where there is no visible label; do not re-declare the rest.
|
|
241
|
+
|
|
208
242
|
## License
|
|
209
243
|
|
|
210
244
|
MIT
|
|
@@ -59,4 +59,15 @@ export interface AutocompleteProps extends Omit<React.InputHTMLAttributes<HTMLIn
|
|
|
59
59
|
/** Applied to the wrapper — set width here. */
|
|
60
60
|
style?: React.CSSProperties;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* A text field that offers matching rows as you type.
|
|
64
|
+
*
|
|
65
|
+
* It holds no data of its own. Give it `options` and it renders them,
|
|
66
|
+
* highlights one, moves that highlight with the arrow keys, and calls
|
|
67
|
+
* `onSelect` when a row is chosen — however those options were produced.
|
|
68
|
+
*
|
|
69
|
+
* The list is a popover rather than a block in the flow: results that appear
|
|
70
|
+
* mid-keystroke and push the page down under the cursor are disorienting, and
|
|
71
|
+
* whatever is being searched usually sits directly below the field.
|
|
72
|
+
*/
|
|
62
73
|
export declare function Autocomplete({ value, onValueChange, options, onSelect, icon, caseSensitive, preFiltered, loading, loadingMessage, emptyMessage, footer, animated, className, style, ...inputProps }: AutocompleteProps): React.JSX.Element;
|
|
@@ -24,9 +24,9 @@ export interface BadgeProps extends SpacingProps, Omit<React.HTMLAttributes<HTML
|
|
|
24
24
|
variant?: "soft" | "solid";
|
|
25
25
|
/** 1 is the default chip; 2 is for standalone use away from body text. */
|
|
26
26
|
size?: "1" | "2";
|
|
27
|
-
/** Badges are single-line by default
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
/** Badges are single-line by default: one that wraps stops reading as a
|
|
28
|
+
* badge. Opt into wrapping for free text you do not control — anything a
|
|
29
|
+
* reader named rather than you — so it cannot overflow what contains it. */
|
|
30
30
|
wrap?: boolean;
|
|
31
31
|
/** Label text. Keep it short — a badge that wraps stops reading as one. */
|
|
32
32
|
children?: ReactNode;
|
|
@@ -13,8 +13,12 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
13
13
|
animated?: boolean;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* sunlit
|
|
18
|
-
*
|
|
16
|
+
* The thing a reader presses to make something happen. A glass capsule whose
|
|
17
|
+
* rim glows like a planet's sunlit limb, with stars twinkling inside it and a
|
|
18
|
+
* glint that sweeps across it now and then.
|
|
19
|
+
*
|
|
20
|
+
* It renders a plain `<button>` and forwards its ref, so it drops into
|
|
21
|
+
* anything that needs to borrow a trigger — a dialog, a menu, a router link's
|
|
22
|
+
* render prop — without a wrapper in between.
|
|
19
23
|
*/
|
|
20
24
|
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -72,6 +72,22 @@ export declare function Title({ className, ...rest }: HeadingProps): React.JSX.E
|
|
|
72
72
|
* description. Optional, and only announced when present.
|
|
73
73
|
*/
|
|
74
74
|
export declare function Description(props: TextProps): React.JSX.Element;
|
|
75
|
+
/**
|
|
76
|
+
* A modal window over the page, for a task that has to finish or be abandoned
|
|
77
|
+
* before anything else happens.
|
|
78
|
+
*
|
|
79
|
+
* It rides the platform's own `<dialog>`, so the backdrop, the top layer, the
|
|
80
|
+
* Escape key and the focus trap are the browser's rather than an
|
|
81
|
+
* approximation of them. Opening moves focus inside; closing returns it to
|
|
82
|
+
* whatever opened it.
|
|
83
|
+
*
|
|
84
|
+
* For a decision with consequences — deleting, discarding, overwriting —
|
|
85
|
+
* reach for `AlertDialog`, which refuses to close by a click outside, so a
|
|
86
|
+
* misplaced click cannot answer the question for the reader.
|
|
87
|
+
*
|
|
88
|
+
* Compose it from the parts hanging off this name: `Dialog.Trigger`,
|
|
89
|
+
* `Dialog.Content`, `Dialog.Title`, `Dialog.Description` and `Dialog.Close`.
|
|
90
|
+
*/
|
|
75
91
|
export declare const Dialog: (({ open, onOpenChange, children }: DialogProps) => React.JSX.Element) & {
|
|
76
92
|
Trigger: typeof Trigger;
|
|
77
93
|
Close: typeof Close;
|
|
@@ -56,6 +56,22 @@ declare function Item({ asChild, color, onSelect, children }: DropdownMenuItemPr
|
|
|
56
56
|
* routine ones, so the two are not adjacent to a moving cursor.
|
|
57
57
|
*/
|
|
58
58
|
declare function Separator(): React.JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* A button that opens a list of actions.
|
|
61
|
+
*
|
|
62
|
+
* Actions, not choices: every item does something when picked, and nothing in
|
|
63
|
+
* the menu holds a value. For choosing one of a set of values, that is
|
|
64
|
+
* `Select`, which looks similar and means something entirely different to a
|
|
65
|
+
* screen reader.
|
|
66
|
+
*
|
|
67
|
+
* Arrow keys move through the items, Home and End jump to the ends, Escape
|
|
68
|
+
* closes and returns focus to the button, and typing a letter jumps to the
|
|
69
|
+
* next item starting with it. The panel uses the browser's popover layer, so
|
|
70
|
+
* it stacks above the page without a z-index to maintain.
|
|
71
|
+
*
|
|
72
|
+
* Compose it from `DropdownMenu.Item`, `DropdownMenu.Label` and
|
|
73
|
+
* `DropdownMenu.Separator`.
|
|
74
|
+
*/
|
|
59
75
|
export declare const DropdownMenu: typeof DropdownMenuRoot & {
|
|
60
76
|
Item: typeof Item;
|
|
61
77
|
Separator: typeof Separator;
|
|
@@ -6,13 +6,15 @@ export interface IconToggleOption<V extends string> {
|
|
|
6
6
|
label: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* A segmented icon toggle: every option
|
|
10
|
-
* selected one
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
9
|
+
* A segmented icon toggle: every option visible at once in a single pill, the
|
|
10
|
+
* selected one reading as active, and a click on any of them selecting it.
|
|
11
|
+
*
|
|
12
|
+
* Reach for it to switch between modes or views of the same thing, where the
|
|
13
|
+
* options are few and each has an obvious glyph. The alternative pattern — one
|
|
14
|
+
* button that shows the mode you are NOT in and swaps its own icon on click —
|
|
15
|
+
* is deliberately not what this does: the control's meaning changes under the
|
|
16
|
+
* cursor, and nobody can tell whether the icon means "you are here" or "go
|
|
17
|
+
* here". Generic over the option set, so the values stay your own union type.
|
|
16
18
|
*/
|
|
17
19
|
export declare function IconToggle<V extends string>({ options, value, onValueChange, orientation, className, }: {
|
|
18
20
|
/** The segments, in display order. Every option is always visible —
|
|
@@ -7,9 +7,13 @@ export interface LoaderProps {
|
|
|
7
7
|
className?: string;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* ring, with a
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* An orbital spinner, for work whose length you cannot measure: a small
|
|
11
|
+
* pulsing planet at the centre of a static ring, with a moon travelling it.
|
|
12
|
+
* Where you CAN measure the work, use `Progress` instead — a spinner that
|
|
13
|
+
* could have been a bar tells the reader less than it knows.
|
|
14
|
+
*
|
|
15
|
+
* The motion is pure CSS and runs on the compositor, so it keeps turning
|
|
16
|
+
* smoothly while the main thread is busy doing the thing it is waiting on —
|
|
17
|
+
* which is exactly when a loader is on screen.
|
|
14
18
|
*/
|
|
15
19
|
export declare function Loader({ size, label, className }: LoaderProps): import("react").JSX.Element;
|
|
@@ -34,6 +34,21 @@ export interface RadioGroupItemProps {
|
|
|
34
34
|
* nesting one label inside another is invalid HTML.
|
|
35
35
|
*/
|
|
36
36
|
declare function Item({ value, disabled, children }: RadioGroupItemProps): React.JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* Exactly one choice from a set you can see all of at once.
|
|
39
|
+
*
|
|
40
|
+
* Use it where the options matter enough to be read side by side and there are
|
|
41
|
+
* few enough to show — up to about seven. Past that a `Select` keeps the page
|
|
42
|
+
* calm. Where several answers can be true at the same time, that is
|
|
43
|
+
* `CheckboxGroup`.
|
|
44
|
+
*
|
|
45
|
+
* Hold the chosen value and pass `onValueChange`. Each orb ignites when it is
|
|
46
|
+
* chosen, arrow keys move between the options the way a native radio group
|
|
47
|
+
* does, and a label that wraps to two lines keeps its orb beside the first
|
|
48
|
+
* line rather than drifting to the middle.
|
|
49
|
+
*
|
|
50
|
+
* Compose it from `RadioGroup.Item`.
|
|
51
|
+
*/
|
|
37
52
|
export declare const RadioGroup: typeof RadioGroupRoot & {
|
|
38
53
|
Item: typeof Item;
|
|
39
54
|
};
|
|
@@ -47,6 +47,23 @@ export interface SelectItemProps {
|
|
|
47
47
|
* selected, so anything rendered here has to read correctly in both places.
|
|
48
48
|
*/
|
|
49
49
|
declare function Item({ value, disabled, children }: SelectItemProps): React.JSX.Element;
|
|
50
|
+
/**
|
|
51
|
+
* Choosing one value from a list, with the list kept out of the way until it
|
|
52
|
+
* is wanted.
|
|
53
|
+
*
|
|
54
|
+
* The right control when the options are many, or dull, or both — a country, a
|
|
55
|
+
* size, a sort order. Where there are few options and each one deserves to be
|
|
56
|
+
* read, `RadioGroup` shows them all without a click. Where the items are
|
|
57
|
+
* actions rather than values, that is `DropdownMenu`.
|
|
58
|
+
*
|
|
59
|
+
* The panel opens on the browser's popover layer, which is what lets it escape
|
|
60
|
+
* a dialog, a transformed ancestor or a clipping overflow and sit above the
|
|
61
|
+
* page at its full height. It flips above the trigger when there is no room
|
|
62
|
+
* below, follows the trigger if the page scrolls, and closes on Escape with
|
|
63
|
+
* focus handed back. Typing jumps to a matching option.
|
|
64
|
+
*
|
|
65
|
+
* Compose it from `Select.Item`.
|
|
66
|
+
*/
|
|
50
67
|
export declare const Select: typeof SelectRoot & {
|
|
51
68
|
Item: typeof Item;
|
|
52
69
|
};
|
|
@@ -46,5 +46,15 @@ export interface SliderProps {
|
|
|
46
46
|
* With two thumbs they cannot cross: each is clamped to the other, so the
|
|
47
47
|
* array stays in order and a range can never read back inverted. `minDistance`
|
|
48
48
|
* keeps a gap between them where a zero-width range would be meaningless.
|
|
49
|
+
*
|
|
50
|
+
* The pointer is the component's own business, and the inputs take none of it.
|
|
51
|
+
* Two inputs each covering the whole track cannot decide between them which
|
|
52
|
+
* thumb a press meant: the browser hit-tests before any of this code runs, so
|
|
53
|
+
* the answer came down to which input was later in the DOM. Whenever the
|
|
54
|
+
* thumbs were within a thumb's width of each other — constant over a wide
|
|
55
|
+
* range, where a few units are a fraction of a pixel — a press on the lower
|
|
56
|
+
* one was handed to the upper one, which then refused to travel. So a press
|
|
57
|
+
* anywhere on the control is measured here, against where the thumbs actually
|
|
58
|
+
* are, and the nearest one is dragged until the pointer is released.
|
|
49
59
|
*/
|
|
50
60
|
export declare const Slider: React.ForwardRefExoticComponent<SliderProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -60,6 +60,21 @@ declare function Content({ value, children, }: {
|
|
|
60
60
|
/** Panel contents. Unmounted while another tab is selected. */
|
|
61
61
|
children?: ReactNode;
|
|
62
62
|
}): React.JSX.Element | null;
|
|
63
|
+
/**
|
|
64
|
+
* Several panels sharing one piece of the page, one visible at a time.
|
|
65
|
+
*
|
|
66
|
+
* Right for views of the same subject that a reader moves between and
|
|
67
|
+
* compares — overview, history, settings for one record. Wrong for steps in a
|
|
68
|
+
* sequence, where the reader needs to know how far along they are, and wrong
|
|
69
|
+
* for content that should be findable by search or linkable on its own: a
|
|
70
|
+
* hidden panel is invisible to both.
|
|
71
|
+
*
|
|
72
|
+
* Arrow keys move between the tabs, Home and End jump to the ends, and only
|
|
73
|
+
* the selected tab is in the tab order, so one press of Tab leaves the strip
|
|
74
|
+
* for the panel instead of walking every tab in it.
|
|
75
|
+
*
|
|
76
|
+
* Compose it from `Tabs.List`, `Tabs.Trigger` and `Tabs.Content`.
|
|
77
|
+
*/
|
|
63
78
|
export declare const Tabs: typeof TabsRoot & {
|
|
64
79
|
List: typeof List;
|
|
65
80
|
Trigger: typeof Trigger;
|
|
@@ -20,6 +20,18 @@ declare function Slot({ children, }: {
|
|
|
20
20
|
/** The slot's contents — an icon, a unit, a short affordance. */
|
|
21
21
|
children?: ReactNode;
|
|
22
22
|
}): React.JSX.Element;
|
|
23
|
+
/**
|
|
24
|
+
* A single line of text the reader types.
|
|
25
|
+
*
|
|
26
|
+
* A real `<input>` underneath, so `value`, `onChange`, `type`, `required`,
|
|
27
|
+
* `autoComplete` and the rest of the native attributes all work as they
|
|
28
|
+
* already do, and the browser's own autofill and validation come along with
|
|
29
|
+
* them. For more than a line, use `TextArea`.
|
|
30
|
+
*
|
|
31
|
+
* Put an icon, a unit or a small button beside the text with `TextField.Slot`.
|
|
32
|
+
* It sits inside the field's rim and keeps its own padding, so the text never
|
|
33
|
+
* runs underneath it.
|
|
34
|
+
*/
|
|
23
35
|
export declare const TextField: React.ForwardRefExoticComponent<TextFieldProps & React.RefAttributes<HTMLInputElement>> & {
|
|
24
36
|
Slot: typeof Slot;
|
|
25
37
|
};
|