@jig-ui/react 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/LICENSE +52 -0
- package/README.md +193 -0
- package/dist/adorn/adorn.d.ts +38 -0
- package/dist/adorn/index.d.ts +2 -0
- package/dist/box/box.d.ts +32 -0
- package/dist/box/index.d.ts +2 -0
- package/dist/breakpoints.d.ts +35 -0
- package/dist/button/button.d.ts +37 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/codeblock/codeblock.d.ts +28 -0
- package/dist/codeblock/index.d.ts +2 -0
- package/dist/collapsible/collapsible.d.ts +116 -0
- package/dist/collapsible/index.d.ts +2 -0
- package/dist/combobox/combobox.d.ts +119 -0
- package/dist/combobox/index.d.ts +2 -0
- package/dist/dev.d.ts +14 -0
- package/dist/dialog/dialog.d.ts +80 -0
- package/dist/dialog/index.d.ts +2 -0
- package/dist/focus-ring.d.ts +15 -0
- package/dist/grid/grid.d.ts +54 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/icon/generated/arrow-down.d.ts +4 -0
- package/dist/icon/generated/arrow-left.d.ts +4 -0
- package/dist/icon/generated/arrow-right.d.ts +4 -0
- package/dist/icon/generated/arrow-square-out.d.ts +4 -0
- package/dist/icon/generated/arrow-up.d.ts +4 -0
- package/dist/icon/generated/bell.d.ts +4 -0
- package/dist/icon/generated/calendar.d.ts +4 -0
- package/dist/icon/generated/caret-down.d.ts +4 -0
- package/dist/icon/generated/caret-left.d.ts +4 -0
- package/dist/icon/generated/caret-right.d.ts +4 -0
- package/dist/icon/generated/caret-up.d.ts +4 -0
- package/dist/icon/generated/check-circle.d.ts +4 -0
- package/dist/icon/generated/check.d.ts +4 -0
- package/dist/icon/generated/clock.d.ts +4 -0
- package/dist/icon/generated/copy.d.ts +4 -0
- package/dist/icon/generated/dots-nine.d.ts +4 -0
- package/dist/icon/generated/dots-three.d.ts +4 -0
- package/dist/icon/generated/eye-slash.d.ts +4 -0
- package/dist/icon/generated/eye.d.ts +4 -0
- package/dist/icon/generated/gear.d.ts +4 -0
- package/dist/icon/generated/github-logo.d.ts +4 -0
- package/dist/icon/generated/heart.d.ts +4 -0
- package/dist/icon/generated/index.d.ts +151 -0
- package/dist/icon/generated/info.d.ts +4 -0
- package/dist/icon/generated/list.d.ts +4 -0
- package/dist/icon/generated/magnifying-glass.d.ts +4 -0
- package/dist/icon/generated/minus.d.ts +4 -0
- package/dist/icon/generated/moon.d.ts +4 -0
- package/dist/icon/generated/pencil-simple.d.ts +4 -0
- package/dist/icon/generated/plus.d.ts +4 -0
- package/dist/icon/generated/question.d.ts +4 -0
- package/dist/icon/generated/star.d.ts +4 -0
- package/dist/icon/generated/sun.d.ts +4 -0
- package/dist/icon/generated/trash.d.ts +4 -0
- package/dist/icon/generated/user.d.ts +4 -0
- package/dist/icon/generated/warning-circle.d.ts +4 -0
- package/dist/icon/generated/warning.d.ts +4 -0
- package/dist/icon/generated/x.d.ts +4 -0
- package/dist/icon/icon.d.ts +46 -0
- package/dist/icon/index.d.ts +2 -0
- package/dist/icon-BRHwInc5.js +165 -0
- package/dist/icon-B_NrwKaL.js +173 -0
- package/dist/iconbutton/iconbutton.d.ts +35 -0
- package/dist/iconbutton/index.d.ts +2 -0
- package/dist/icons.d.ts +17 -0
- package/dist/icons.js +2 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +3061 -0
- package/dist/input/index.d.ts +2 -0
- package/dist/input/input.d.ts +63 -0
- package/dist/layout.d.ts +87 -0
- package/dist/link/index.d.ts +2 -0
- package/dist/link/link.d.ts +125 -0
- package/dist/listitem/index.d.ts +2 -0
- package/dist/listitem/listitem.d.ts +92 -0
- package/dist/polymorphic.d.ts +31 -0
- package/dist/reset.css +4 -0
- package/dist/responsive.d.ts +10 -0
- package/dist/scrollarea/index.d.ts +2 -0
- package/dist/scrollarea/scrollarea.d.ts +26 -0
- package/dist/separator/index.d.ts +2 -0
- package/dist/separator/separator.d.ts +48 -0
- package/dist/sidenav/index.d.ts +2 -0
- package/dist/sidenav/sidenav.d.ts +35 -0
- package/dist/sidenavsection/index.d.ts +2 -0
- package/dist/sidenavsection/sidenavsection.d.ts +44 -0
- package/dist/slider/index.d.ts +2 -0
- package/dist/slider/slider.d.ts +73 -0
- package/dist/spacing.d.ts +35 -0
- package/dist/stack/index.d.ts +2 -0
- package/dist/stack/stack.d.ts +52 -0
- package/dist/structuredlist/index.d.ts +2 -0
- package/dist/structuredlist/structuredlist.d.ts +104 -0
- package/dist/styles.css +911 -0
- package/dist/togglebutton/index.d.ts +2 -0
- package/dist/togglebutton/togglebutton.d.ts +93 -0
- package/dist/togglebuttongroup/index.d.ts +2 -0
- package/dist/togglebuttongroup/togglebuttongroup.d.ts +72 -0
- package/dist/token/index.d.ts +2 -0
- package/dist/token/token.d.ts +82 -0
- package/dist/tokens-vars.d.ts +579 -0
- package/dist/tokens.d.ts +24 -0
- package/dist/tokens.js +577 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/tooltip.d.ts +52 -0
- package/dist/typography/index.d.ts +2 -0
- package/dist/typography/typography.d.ts +71 -0
- package/package.json +81 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CSSProperties, InputHTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
export type InputSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
4
|
+
/**
|
|
5
|
+
* The field's label. Rendered as a real `<label>` bound to the control, so
|
|
6
|
+
* this is how the input gets its accessible name — an input without one is
|
|
7
|
+
* announced as unlabelled.
|
|
8
|
+
*/
|
|
9
|
+
label?: ReactNode;
|
|
10
|
+
/** Hint text below the control, associated via `aria-describedby`. */
|
|
11
|
+
description?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* An error message from outside the component — a server response, or a form
|
|
14
|
+
* library. Passing it marks the field invalid and shows the message
|
|
15
|
+
* unconditionally. Leave it undefined to let the browser's own constraint
|
|
16
|
+
* validation (`required`, `type="email"`, `pattern`) drive the invalid state
|
|
17
|
+
* instead.
|
|
18
|
+
*/
|
|
19
|
+
error?: ReactNode;
|
|
20
|
+
size?: InputSize;
|
|
21
|
+
/**
|
|
22
|
+
* Applied to the field wrapper, not the control.
|
|
23
|
+
*
|
|
24
|
+
* The wrapper is the element the surrounding layout sees — it is the flex or
|
|
25
|
+
* grid child, and it is what holds the label and the description as well as
|
|
26
|
+
* the input. Styling the control instead meant a `flexGrow` or a `gridColumn`
|
|
27
|
+
* landed on an element the parent layout never touches, and silently did
|
|
28
|
+
* nothing. `Slider` has always worked this way; Input was the outlier.
|
|
29
|
+
*
|
|
30
|
+
* Everything else spreads onto the control, so `placeholder`, `onChange`,
|
|
31
|
+
* `id` and the rest reach the `<input>` as they read.
|
|
32
|
+
*/
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Applied to the field wrapper, for the same reason as `className`. */
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
/** The control — the element you would focus, select or measure. */
|
|
37
|
+
ref?: Ref<HTMLInputElement>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A single-line text field.
|
|
41
|
+
*
|
|
42
|
+
* `label` is the accessible name and should always be set; it renders a real
|
|
43
|
+
* `<label>` bound to the control. `description` and `error` are wired to it
|
|
44
|
+
* with `aria-describedby` for you.
|
|
45
|
+
*
|
|
46
|
+
* Passing `error` marks the field invalid and shows the message
|
|
47
|
+
* unconditionally — use it for a server response or a form library. Leave it
|
|
48
|
+
* undefined to let native constraint validation (`required`, `type="email"`,
|
|
49
|
+
* `pattern`) drive the invalid state instead.
|
|
50
|
+
*
|
|
51
|
+
* `className` and `style` land on the field wrapper, which is the element the
|
|
52
|
+
* surrounding layout sees; every other prop reaches the `<input>`.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* <Input
|
|
56
|
+
* label="Email"
|
|
57
|
+
* type="email"
|
|
58
|
+
* required
|
|
59
|
+
* description="We'll only use this to sign you in."
|
|
60
|
+
* error={serverError}
|
|
61
|
+
* />
|
|
62
|
+
*/
|
|
63
|
+
export declare function Input({ label, description, error, size, disabled, name, className, style, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Responsive } from './responsive';
|
|
2
|
+
/**
|
|
3
|
+
* Twenty-four is the whole grid, and it is fixed — a Grid always lays out on
|
|
4
|
+
* the same 24 tracks, so two grids of the same width share column positions
|
|
5
|
+
* without a shared template. Children say how much of it they occupy.
|
|
6
|
+
*
|
|
7
|
+
* Decided in apps/docs/decisions/0003-layout-children.html.
|
|
8
|
+
*/
|
|
9
|
+
export type GridSpan = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24;
|
|
10
|
+
/**
|
|
11
|
+
* The column counts a Grid can distribute its children across — the divisors
|
|
12
|
+
* of 24, and nothing else. `columns={5}` would need tracks of 4.8, so it is a
|
|
13
|
+
* type error rather than a silent rounding.
|
|
14
|
+
*/
|
|
15
|
+
export type GridColumns = 1 | 2 | 3 | 4 | 6 | 8 | 12 | 24;
|
|
16
|
+
/** The number of tracks in the grid. */
|
|
17
|
+
export declare const GRID_COLUMNS = 24;
|
|
18
|
+
export type LayoutAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
19
|
+
export type LayoutJustify = 'start' | 'center' | 'end' | 'between' | 'around';
|
|
20
|
+
export type LayoutDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse';
|
|
21
|
+
export type LayoutSpacing = '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
|
|
22
|
+
/**
|
|
23
|
+
* The props that describe how a component sits inside its parent, rather than
|
|
24
|
+
* how it arranges its own children.
|
|
25
|
+
*
|
|
26
|
+
* Every layout primitive carries all three, because every layout primitive can
|
|
27
|
+
* be a child of any other — a Grid nested in a Grid, a Stack inside a Stack, a
|
|
28
|
+
* Box in either. Which of them does anything depends on the parent: `span`
|
|
29
|
+
* applies inside a Grid, `grow` inside a Stack, `alignSelf` in either. A prop
|
|
30
|
+
* that does not apply is inert rather than an error, which is the same
|
|
31
|
+
* contract `Box` has had since 0003.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately not on content components. Button and Input still get their
|
|
34
|
+
* position from a layout wrapper; this is the line 0003 drew and it has not
|
|
35
|
+
* moved — what changed is that the containers are on the child side of it too.
|
|
36
|
+
*/
|
|
37
|
+
export interface LayoutChildProps {
|
|
38
|
+
/**
|
|
39
|
+
* How many of a parent Grid's 24 columns to occupy. Overrides the
|
|
40
|
+
* distribution the Grid set with `columns`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* <Grid columns={3}>
|
|
44
|
+
* <Stack span={16}>...</Stack>
|
|
45
|
+
* <Box span={8}>...</Box>
|
|
46
|
+
* </Grid>
|
|
47
|
+
*/
|
|
48
|
+
span?: Responsive<GridSpan>;
|
|
49
|
+
/** Take the space left over by siblings. Only meaningful inside a Stack. */
|
|
50
|
+
grow?: Responsive<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Override the parent's `align` for this child alone. Works in both Stack
|
|
53
|
+
* and Grid.
|
|
54
|
+
*
|
|
55
|
+
* Stack's `align` defaults to `start`, so this is how a single child says it
|
|
56
|
+
* should fill the cross axis without changing the whole row. Note the pair
|
|
57
|
+
* on a container: `align` is what it does to its children, `alignSelf` is
|
|
58
|
+
* what it does to itself.
|
|
59
|
+
*/
|
|
60
|
+
alignSelf?: Responsive<LayoutAlign>;
|
|
61
|
+
}
|
|
62
|
+
/** Sprinkles keys its span values by string; the prop reads better as a number. */
|
|
63
|
+
export declare const toSpanKey: (value: Responsive<GridSpan>) => Responsive<`${GridSpan}`>;
|
|
64
|
+
/** Sprinkles keys its values by string; `grow` reads better as a boolean. */
|
|
65
|
+
export declare const toGrowKey: (value: Responsive<boolean>) => Responsive<"0" | "1">;
|
|
66
|
+
/**
|
|
67
|
+
* `LayoutChildProps` with every key present and possibly undefined, which is
|
|
68
|
+
* what the props look like once a component has destructured them. The
|
|
69
|
+
* optional form would be rejected under `exactOptionalPropertyTypes`.
|
|
70
|
+
*/
|
|
71
|
+
type ChildLayoutValues = {
|
|
72
|
+
[K in keyof LayoutChildProps]-?: LayoutChildProps[K] | undefined;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The child-side props as arguments for `layoutSprinkles`, so each primitive
|
|
76
|
+
* folds them into the single sprinkles call it already makes rather than
|
|
77
|
+
* emitting a second class string.
|
|
78
|
+
*
|
|
79
|
+
* Returned as an argument fragment rather than a class name to keep this
|
|
80
|
+
* module free of a dependency on `layout.css.ts`.
|
|
81
|
+
*/
|
|
82
|
+
export declare const childLayout: ({ span, grow, alignSelf }: ChildLayoutValues) => {
|
|
83
|
+
alignSelf?: Responsive<LayoutAlign>;
|
|
84
|
+
flexGrow?: Responsive<"0" | "1">;
|
|
85
|
+
gridColumn?: Responsive<"1" | "2" | "3" | "14" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24">;
|
|
86
|
+
};
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { AnchorHTMLAttributes, Ref } from 'react';
|
|
3
|
+
import { IconName } from '../icon';
|
|
4
|
+
import { ButtonSize, ButtonVariant } from '../button';
|
|
5
|
+
import { TypeStyles } from '../typography';
|
|
6
|
+
/**
|
|
7
|
+
* How loud the link is.
|
|
8
|
+
*
|
|
9
|
+
* `text` is the ordinary underlined link in a sentence; the other five are
|
|
10
|
+
* Button's, and mean exactly what they mean there. One axis rather than two
|
|
11
|
+
* components, decided in apps/docs/decisions/0009-link.html (D1) — a caller
|
|
12
|
+
* who starts with a text link and later wants it to look like a button changes
|
|
13
|
+
* a prop, not a component.
|
|
14
|
+
*/
|
|
15
|
+
export type LinkVariant = 'text' | ButtonVariant;
|
|
16
|
+
/** What Link owns, whichever variant is in play. */
|
|
17
|
+
interface LinkOwnProps {
|
|
18
|
+
/**
|
|
19
|
+
* Required. A Link without a target is not a link — it is text, or a Button.
|
|
20
|
+
* There is deliberately no `disabled`: `:disabled` never matches an anchor,
|
|
21
|
+
* and an anchor without `href` is not focusable or activatable, so a
|
|
22
|
+
* "disabled link" can only be announced, never reached (0009, settled list).
|
|
23
|
+
*/
|
|
24
|
+
href: string;
|
|
25
|
+
variant?: LinkVariant;
|
|
26
|
+
/**
|
|
27
|
+
* Sizes the five box variants. No effect on `variant="text"`, whose type
|
|
28
|
+
* comes from the parent or from `with` rather than from this ramp (0009 D3).
|
|
29
|
+
*/
|
|
30
|
+
size?: ButtonSize;
|
|
31
|
+
/**
|
|
32
|
+
* Names a Typography preset, for a text link with no typographic parent to
|
|
33
|
+
* inherit from. When passed it beats the inherited type — an explicit prop
|
|
34
|
+
* at the call site outranks an ambient value the caller did not set (0009
|
|
35
|
+
* D3's outcome). Ignored by the box variants, which take Button's sizing.
|
|
36
|
+
*/
|
|
37
|
+
with?: TypeStyles;
|
|
38
|
+
/**
|
|
39
|
+
* Underlines the text variant. On by default: with an inherited colour the
|
|
40
|
+
* underline is the only thing distinguishing a link from the words around
|
|
41
|
+
* it, so colour alone would be carrying the meaning (WCAG 1.4.1).
|
|
42
|
+
*
|
|
43
|
+
* `false` means never — there is no hover underline behind it. That makes it
|
|
44
|
+
* right for somewhere the link is already obviously a link (a nav row, a
|
|
45
|
+
* breadcrumb) and wrong in running text, which 0009 D5 accepted knowingly.
|
|
46
|
+
*/
|
|
47
|
+
underline?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Marks a link that leaves the app: the `arrow-square-out` glyph after the
|
|
50
|
+
* label, `target="_blank"`, `rel="noopener noreferrer"`, and a visually
|
|
51
|
+
* hidden "(opens in a new tab)" so the announcement matches what happens.
|
|
52
|
+
*
|
|
53
|
+
* The new tab is the component's opinion here, not the call site's — 0009 D6
|
|
54
|
+
* chose the whole convention over a marker alone, which means a caller who
|
|
55
|
+
* wants the glyph *without* a new tab wants `icon="arrow-square-out"` and
|
|
56
|
+
* `iconPosition="end"` instead.
|
|
57
|
+
*/
|
|
58
|
+
external?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* An icon from the curated set, sized and spaced by the component rather
|
|
61
|
+
* than by the caller. Decorative — the label names the link.
|
|
62
|
+
*/
|
|
63
|
+
icon?: IconName;
|
|
64
|
+
/** Which side of the label the icon sits on. */
|
|
65
|
+
iconPosition?: 'start' | 'end';
|
|
66
|
+
/**
|
|
67
|
+
* An element to render instead of the bare anchor — a router's link, so that
|
|
68
|
+
* client-side navigation works without Jig depending on a router.
|
|
69
|
+
*
|
|
70
|
+
* Not an `as` prop wearing a different hat. `as` asks a component to *be*
|
|
71
|
+
* another element and to take that element's prop types; this hands Link's
|
|
72
|
+
* own props and classes to an element the caller already constructed, and
|
|
73
|
+
* merges rather than overwrites, so Jig's `className` and the router's
|
|
74
|
+
* `onClick` both survive. Link is an anchor either way. Decided in 0009 D4.
|
|
75
|
+
*/
|
|
76
|
+
render?: useRender.RenderProp;
|
|
77
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
78
|
+
}
|
|
79
|
+
/** Attributes React declares that Link decides for itself. */
|
|
80
|
+
type Reserved = keyof LinkOwnProps | 'color';
|
|
81
|
+
/**
|
|
82
|
+
* `iconPosition="end"` is a type error alongside `external`, which owns that
|
|
83
|
+
* slot. A glyph at each end is legitimate, so `icon` at the default `start`
|
|
84
|
+
* still works — it is only the collision that is refused. Carried from 0009
|
|
85
|
+
* D6's outcome.
|
|
86
|
+
*/
|
|
87
|
+
type ExternalProps = {
|
|
88
|
+
external: true;
|
|
89
|
+
iconPosition?: 'start' | undefined;
|
|
90
|
+
};
|
|
91
|
+
type LocalProps = {
|
|
92
|
+
external?: false | undefined;
|
|
93
|
+
iconPosition?: 'start' | 'end' | undefined;
|
|
94
|
+
};
|
|
95
|
+
export type LinkProps = LinkOwnProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, Reserved | 'iconPosition'> & (ExternalProps | LocalProps);
|
|
96
|
+
/**
|
|
97
|
+
* A link.
|
|
98
|
+
*
|
|
99
|
+
* `href` is required. Defaults to `variant="text"` — an underlined link that
|
|
100
|
+
* takes the colour and size of the text around it, so it fits whatever it is
|
|
101
|
+
* dropped into. Set `with` to name a type preset when there is no surrounding
|
|
102
|
+
* text to inherit from, or `underline={false}` where the link is already
|
|
103
|
+
* obviously one, such as a nav row.
|
|
104
|
+
*
|
|
105
|
+
* The other variants are Button's, for a call to action that navigates. It is
|
|
106
|
+
* still a link: announced as one, activated with Enter, and openable in a new
|
|
107
|
+
* tab.
|
|
108
|
+
*
|
|
109
|
+
* `external` marks a link that leaves the app — it adds a trailing icon, opens
|
|
110
|
+
* a new tab, and tells assistive technology that it will.
|
|
111
|
+
*
|
|
112
|
+
* Pass `render` to hand the markup to a router's own link component so
|
|
113
|
+
* client-side navigation works.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* <Typography as="p">
|
|
117
|
+
* Released under the <Link href="https://opensource.org/license/mit" external>MIT licence</Link>.
|
|
118
|
+
* </Typography>
|
|
119
|
+
*
|
|
120
|
+
* <Link href="/dashboard" variant="primary" render={<NextLink href="/dashboard" />}>
|
|
121
|
+
* Open dashboard
|
|
122
|
+
* </Link>
|
|
123
|
+
*/
|
|
124
|
+
export declare function Link({ href, variant, size, with: typeStyle, underline, external, icon, iconPosition, render, className, children, ref, ...props }: LinkProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { MouseEventHandler, ReactNode } from 'react';
|
|
2
|
+
import { IconName } from '../icon';
|
|
3
|
+
import { PolymorphicProps } from '../polymorphic';
|
|
4
|
+
/**
|
|
5
|
+
* The elements a ListItem is willing to render as.
|
|
6
|
+
*
|
|
7
|
+
* Two, and only two. `li` is the default because a nav list is the case that
|
|
8
|
+
* needs the semantics: a real `li` inside a list gets its position and count
|
|
9
|
+
* computed by the browser, which is what produces "3 of 8". `div` is the
|
|
10
|
+
* escape hatch for a row that is not in a list — a settings row, a card body —
|
|
11
|
+
* and a caller who takes it owns `aria-setsize` and `aria-posinset` from then
|
|
12
|
+
* on.
|
|
13
|
+
*
|
|
14
|
+
* This union is why `ListItem` has an `as` prop at all when the rule is that
|
|
15
|
+
* polymorphism stays on layout and typography components. Decided in
|
|
16
|
+
* apps/docs/decisions/0014-sidebar-navigation.html (D2), which amends that
|
|
17
|
+
* rule to "layout and typography components, plus ListItem".
|
|
18
|
+
*/
|
|
19
|
+
export type ListItemElement = 'li' | 'div';
|
|
20
|
+
export type ListItemSize = 'sm' | 'md' | 'lg';
|
|
21
|
+
/** ListItem's own props. The element's own attributes are added by PolymorphicProps. */
|
|
22
|
+
export interface ListItemOwnProps {
|
|
23
|
+
/** The row's text. Truncates rather than wrapping. */
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Content before the label — an icon, an avatar, an image, a swatch.
|
|
27
|
+
*
|
|
28
|
+
* **Non-interactive only.** It renders inside the row's anchor or button, so
|
|
29
|
+
* a checkbox or a button here would be an interactive descendant of one,
|
|
30
|
+
* which HTML forbids and browsers handle by making one of the two
|
|
31
|
+
* unreachable. Put interactive content in `end`, which is a sibling.
|
|
32
|
+
* Decided in 0014 D1.
|
|
33
|
+
*/
|
|
34
|
+
start?: ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Content after the label, outside the row's control — a count, a Token, an
|
|
37
|
+
* IconButton, an overflow menu. The only slot that may hold something
|
|
38
|
+
* interactive.
|
|
39
|
+
*/
|
|
40
|
+
end?: ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Makes the row a link. The anchor covers the indicator, `start`, the label
|
|
43
|
+
* and the row's padding — everything except `end`.
|
|
44
|
+
*/
|
|
45
|
+
href?: string;
|
|
46
|
+
/** Makes the row a button. Ignored when `href` is set. */
|
|
47
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
48
|
+
size?: ListItemSize;
|
|
49
|
+
/**
|
|
50
|
+
* Marks the row as the current one: the ghost active fill, plus
|
|
51
|
+
* `aria-current="page"` on the link when there is one.
|
|
52
|
+
*/
|
|
53
|
+
selected?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* An icon shown only while the row is selected, in a gutter at the leading
|
|
56
|
+
* edge that every row reserves whether selected or not — so the labels form
|
|
57
|
+
* one column instead of shifting as the selection moves.
|
|
58
|
+
*
|
|
59
|
+
* **Set it consistently across a list.** The gutter is reserved per row, so
|
|
60
|
+
* a list where only some rows pass it will not line up. Nothing in the type
|
|
61
|
+
* can enforce that. Decided in 0014 D3.
|
|
62
|
+
*/
|
|
63
|
+
selectedIcon?: IconName | false;
|
|
64
|
+
/** Disables a button row. Has no effect on a link — see Link's note (0009). */
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export type ListItemProps<E extends ListItemElement = 'li'> = PolymorphicProps<E, ListItemOwnProps>;
|
|
68
|
+
/**
|
|
69
|
+
* A row: `start`, a label, and `end`.
|
|
70
|
+
*
|
|
71
|
+
* The whole row is the link when `href` is set — everything except the `end`
|
|
72
|
+
* slot, which sits outside it so it can hold a button. That split is the
|
|
73
|
+
* component's central rule: **`start` takes non-interactive content, `end` is
|
|
74
|
+
* the interactive one.** Nesting a button inside a link is invalid HTML and
|
|
75
|
+
* leaves one of the two unreachable.
|
|
76
|
+
*
|
|
77
|
+
* `selected` marks the current row. Pair it with `selectedIcon` for a tick in
|
|
78
|
+
* a reserved leading gutter, set consistently across the list so the labels
|
|
79
|
+
* line up.
|
|
80
|
+
*
|
|
81
|
+
* Renders an `<li>`, for a list. Pass `as="div"` for a row that is not in one.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <ListItem href="/docs/tokens" start={<Icon icon="star" />} selected selectedIcon="check">
|
|
85
|
+
* Tokens
|
|
86
|
+
* </ListItem>
|
|
87
|
+
*
|
|
88
|
+
* <ListItem start={<Icon icon="bell" />} end={<IconButton icon="x" label="Dismiss" />}>
|
|
89
|
+
* Notifications
|
|
90
|
+
* </ListItem>
|
|
91
|
+
*/
|
|
92
|
+
export declare function ListItem<E extends ListItemElement = 'li'>({ as, children, start, end, href, onClick, size, selected, selectedIcon, disabled, className, ...props }: ListItemProps<E>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ComponentRef, ElementType, Ref } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for a component that renders as one of a *restricted* set of elements.
|
|
4
|
+
*
|
|
5
|
+
* `E` is deliberately constrained by each component to its own union of
|
|
6
|
+
* legitimate tags rather than left open as `ElementType`. Arbitrary
|
|
7
|
+
* polymorphism would let a Stack render as a `<span>` or Adorn as a `<div>`,
|
|
8
|
+
* and would promise a flexibility the implementation never had.
|
|
9
|
+
*
|
|
10
|
+
* What this adds over declaring `as`, `HTMLAttributes<HTMLElement>` and `ref`
|
|
11
|
+
* by hand is *correlation*: the props and the ref follow the chosen element.
|
|
12
|
+
* `Typography as="label"` accepts `htmlFor`, `as="blockquote"` accepts `cite`,
|
|
13
|
+
* `Stack as="ol"` accepts `start` and `reversed`, and each gets a precise ref
|
|
14
|
+
* (`HTMLLabelElement`, `HTMLQuoteElement`, `HTMLOListElement`) instead of a
|
|
15
|
+
* blanket `HTMLElement`. All of those were type errors under the previous
|
|
16
|
+
* hand-declared pattern.
|
|
17
|
+
*
|
|
18
|
+
* `Own` wins on collision — `Omit`ting it from the element's attributes is
|
|
19
|
+
* what lets Stack define its own `spacing` without `HTMLAttributes` fighting
|
|
20
|
+
* it. `as` is omitted from the same side so it cannot be doubly declared.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* export type StackProps<E extends StackElement = 'div'> =
|
|
24
|
+
* PolymorphicProps<E, StackOwnProps>;
|
|
25
|
+
*
|
|
26
|
+
* export function Stack<E extends StackElement = 'div'>(props: StackProps<E>) {}
|
|
27
|
+
*/
|
|
28
|
+
export type PolymorphicProps<E extends ElementType, Own> = Own & Omit<ComponentPropsWithoutRef<E>, keyof Own | 'as'> & {
|
|
29
|
+
as?: E;
|
|
30
|
+
ref?: Ref<ComponentRef<E>>;
|
|
31
|
+
};
|
package/dist/reset.css
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Breakpoint } from './breakpoints';
|
|
2
|
+
/**
|
|
3
|
+
* A responsive prop value — either a plain value applied at all breakpoints,
|
|
4
|
+
* or an object mapping breakpoints to values (mobile-first, min-width).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* direction="column"
|
|
8
|
+
* direction={{ xs: 'column', lg: 'row' }}
|
|
9
|
+
*/
|
|
10
|
+
export type Responsive<T> = T | Partial<Record<Breakpoint, T>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
export interface ScrollAreaProps extends Omit<HTMLAttributes<HTMLDivElement>, 'className'> {
|
|
3
|
+
/** The scrolling content. */
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Applied to the root — the element whose height constrains the scroll. */
|
|
6
|
+
className?: string;
|
|
7
|
+
ref?: Ref<HTMLDivElement>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A region that scrolls, with a styled scrollbar in place of the platform's.
|
|
11
|
+
*
|
|
12
|
+
* The height is yours to set: it only scrolls once something constrains it, so
|
|
13
|
+
* give it a `maxHeight`, or put it in a flex or grid parent that bounds it
|
|
14
|
+
* (remembering `min-height: 0` on the flex child above it).
|
|
15
|
+
*
|
|
16
|
+
* No chrome at rest. The scrollbar appears on hover, on focus within, and
|
|
17
|
+
* while scrolling; a gradient mask at the cropped edges shows there is more in
|
|
18
|
+
* the meantime. Space for the scrollbar is always reserved, so content does not
|
|
19
|
+
* shift when it appears.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <ScrollArea style={{ maxHeight: '20rem' }}>
|
|
23
|
+
* {messages.map((m) => <Message key={m.id} {...m} />)}
|
|
24
|
+
* </ScrollArea>
|
|
25
|
+
*/
|
|
26
|
+
export declare function ScrollArea({ className, children, ref, ...props }: ScrollAreaProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { CSSProperties, Ref } from 'react';
|
|
2
|
+
export type SeparatorOrientation = 'horizontal' | 'vertical';
|
|
3
|
+
export interface SeparatorProps {
|
|
4
|
+
/**
|
|
5
|
+
* Which way the rule runs. A vertical separator takes its length from the
|
|
6
|
+
* flex or grid row it sits in, so it renders as nothing outside one.
|
|
7
|
+
*/
|
|
8
|
+
orientation?: SeparatorOrientation;
|
|
9
|
+
/**
|
|
10
|
+
* Hides the rule from assistive technology, for a divider that is decoration
|
|
11
|
+
* rather than a boundary.
|
|
12
|
+
*
|
|
13
|
+
* Reach for it wherever the structure already exists in the markup — between
|
|
14
|
+
* buttons in a labelled toolbar, or between items in a list. Leave it off
|
|
15
|
+
* where the rule itself is the only thing marking a boundary, which is when
|
|
16
|
+
* a screen reader user needs to hear about it.
|
|
17
|
+
*/
|
|
18
|
+
decorative?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
style?: CSSProperties;
|
|
21
|
+
ref?: Ref<HTMLDivElement>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A rule that divides content.
|
|
25
|
+
*
|
|
26
|
+
* `orientation="vertical"` takes its length from the flex or grid row it sits
|
|
27
|
+
* in — it has no height of its own, so give it a parent that has one.
|
|
28
|
+
*
|
|
29
|
+
* By default it is announced as a separator. Pass `decorative` where the rule
|
|
30
|
+
* is only visual and the structure is already carried by a labelled group, a
|
|
31
|
+
* list or a heading, so it is not read out as noise.
|
|
32
|
+
*
|
|
33
|
+
* Spacing around it comes from the parent, like every other component.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* <Stack spacing="500">
|
|
37
|
+
* <Typography as="h2" with="heading04">Ingredients</Typography>
|
|
38
|
+
* <Separator />
|
|
39
|
+
* <Typography as="h2" with="heading04">Method</Typography>
|
|
40
|
+
* </Stack>
|
|
41
|
+
*
|
|
42
|
+
* <Stack direction="row" spacing="300" align="center">
|
|
43
|
+
* <ToggleButton value="bold" isIconOnly icon="star" label="Bold" />
|
|
44
|
+
* <Separator orientation="vertical" decorative />
|
|
45
|
+
* <ToggleButton value="italic" isIconOnly icon="heart" label="Italic" />
|
|
46
|
+
* </Stack>
|
|
47
|
+
*/
|
|
48
|
+
export declare function Separator({ orientation, decorative, className, style, ref, }: SeparatorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
export interface SideNavProps extends Omit<HTMLAttributes<HTMLElement>, 'children' | 'title'> {
|
|
3
|
+
/** The sections and rows. Normally `SideNavSection`s. */
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Pinned above the scrolling area — a product mark, a search field. */
|
|
6
|
+
header?: ReactNode;
|
|
7
|
+
/** Pinned below it — an account row, a theme switch. */
|
|
8
|
+
footer?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* The accessible name. Required in practice: a page with two navigation
|
|
11
|
+
* landmarks and no names leaves a screen reader user choosing between
|
|
12
|
+
* "navigation" and "navigation". A missing one logs a development warning.
|
|
13
|
+
*/
|
|
14
|
+
'aria-label'?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
ref?: Ref<HTMLElement>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A sidebar navigation region.
|
|
20
|
+
*
|
|
21
|
+
* Renders a `<nav>` and takes its accessible name from `aria-label`. `header`
|
|
22
|
+
* and `footer` are pinned; whatever is between them scrolls in a `ScrollArea`
|
|
23
|
+
* when it overflows.
|
|
24
|
+
*
|
|
25
|
+
* It has no width of its own — that belongs to the layout around it, so give
|
|
26
|
+
* it one with `style` or a parent grid column.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* <SideNav aria-label="Docs" header={<Search />} footer={<AccountRow />} style={{ width: '16rem' }}>
|
|
30
|
+
* <SideNavSection label="Getting started" collapsible defaultOpen>
|
|
31
|
+
* <ListItem href="/docs/install">Installation</ListItem>
|
|
32
|
+
* </SideNavSection>
|
|
33
|
+
* </SideNav>
|
|
34
|
+
*/
|
|
35
|
+
export declare function SideNav({ children, header, footer, className, ref, ...props }: SideNavProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CSSProperties, HTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
export interface SideNavSectionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'className' | 'style' | 'children'> {
|
|
3
|
+
/**
|
|
4
|
+
* The section's heading. Optional — a section with no label is just a
|
|
5
|
+
* grouped list, which is how ungrouped items get their list semantics.
|
|
6
|
+
*/
|
|
7
|
+
label?: ReactNode;
|
|
8
|
+
/** The rows. Normally `ListItem`s. */
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Lets the section be folded away. Requires `label`, which becomes the
|
|
12
|
+
* disclosure trigger — there is nothing else to press.
|
|
13
|
+
*
|
|
14
|
+
* Uses `Collapsible` rather than a disclosure of its own (0014 D4), so it
|
|
15
|
+
* inherits the measured-height animation, the reduced-motion guard and the
|
|
16
|
+
* `plus`/`minus` indicator 0013 D3 chose.
|
|
17
|
+
*/
|
|
18
|
+
collapsible?: boolean;
|
|
19
|
+
/** Open state for a collapsing section. Omit to let it manage its own. */
|
|
20
|
+
open?: boolean;
|
|
21
|
+
defaultOpen?: boolean;
|
|
22
|
+
onOpenChange?: (open: boolean) => void;
|
|
23
|
+
className?: string;
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
ref?: Ref<HTMLDivElement>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A labelled group of rows inside a `SideNav`.
|
|
29
|
+
*
|
|
30
|
+
* `label` is optional; without one the section is a bare list, which is how a
|
|
31
|
+
* run of ungrouped items still gets its list semantics. With `collapsible` the
|
|
32
|
+
* label becomes a disclosure trigger and the rows fold away.
|
|
33
|
+
*
|
|
34
|
+
* The rows are wrapped in a `<ul role="list">` — the role as well as the
|
|
35
|
+
* element, because WebKit drops list semantics from a `ul` styled with
|
|
36
|
+
* `list-style: none`.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <SideNavSection label="Components" collapsible defaultOpen>
|
|
40
|
+
* <ListItem href="/docs/button">Button</ListItem>
|
|
41
|
+
* <ListItem href="/docs/combobox">Combobox</ListItem>
|
|
42
|
+
* </SideNavSection>
|
|
43
|
+
*/
|
|
44
|
+
export declare function SideNavSection({ label, children, collapsible, open, defaultOpen, onOpenChange, className, style, ref, ...props }: SideNavSectionProps): import("react/jsx-runtime").JSX.Element;
|