shelving 1.236.2 → 1.237.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/extract/IndexExtractor.js +9 -2
- package/extract/MergingExtractor.d.ts +3 -1
- package/extract/MergingExtractor.js +41 -3
- package/extract/TypescriptExtractor.d.ts +1 -0
- package/extract/TypescriptExtractor.js +12 -2
- package/package.json +1 -1
- package/ui/README.md +19 -274
- package/ui/app/App.d.ts +1 -0
- package/ui/app/App.js +1 -0
- package/ui/app/App.md +58 -0
- package/ui/app/App.tsx +1 -0
- package/ui/block/Card.d.ts +1 -0
- package/ui/block/Card.js +1 -0
- package/ui/block/Card.md +85 -0
- package/ui/block/Card.tsx +1 -0
- package/ui/block/Heading.d.ts +1 -0
- package/ui/block/Heading.js +1 -0
- package/ui/block/Heading.md +70 -0
- package/ui/block/Heading.tsx +1 -0
- package/ui/block/List.d.ts +1 -0
- package/ui/block/List.js +1 -0
- package/ui/block/List.md +51 -0
- package/ui/block/List.tsx +1 -0
- package/ui/block/Panel.d.ts +1 -0
- package/ui/block/Panel.js +1 -0
- package/ui/block/Panel.md +50 -0
- package/ui/block/Panel.tsx +1 -0
- package/ui/block/Paragraph.d.ts +1 -0
- package/ui/block/Paragraph.js +1 -0
- package/ui/block/Paragraph.md +48 -0
- package/ui/block/Paragraph.tsx +1 -0
- package/ui/block/Prose.d.ts +1 -0
- package/ui/block/Prose.js +1 -0
- package/ui/block/Prose.md +49 -0
- package/ui/block/Prose.tsx +1 -0
- package/ui/block/Section.d.ts +6 -0
- package/ui/block/Section.js +6 -0
- package/ui/block/Section.md +56 -0
- package/ui/block/Section.tsx +6 -0
- package/ui/block/Subheading.d.ts +1 -0
- package/ui/block/Subheading.js +1 -0
- package/ui/block/Subheading.md +58 -0
- package/ui/block/Subheading.tsx +1 -0
- package/ui/block/Table.d.ts +1 -0
- package/ui/block/Table.js +1 -0
- package/ui/block/Table.md +54 -0
- package/ui/block/Table.tsx +1 -0
- package/ui/block/Title.d.ts +1 -0
- package/ui/block/Title.js +1 -0
- package/ui/block/Title.md +57 -0
- package/ui/block/Title.tsx +1 -0
- package/ui/dialog/Dialog.d.ts +1 -0
- package/ui/dialog/Dialog.js +1 -0
- package/ui/dialog/Dialog.md +73 -0
- package/ui/dialog/Dialog.tsx +1 -0
- package/ui/dialog/Modal.d.ts +1 -0
- package/ui/dialog/Modal.js +1 -0
- package/ui/dialog/Modal.md +40 -0
- package/ui/dialog/Modal.tsx +1 -0
- package/ui/docs/DocumentationButtons.d.ts +2 -0
- package/ui/docs/DocumentationButtons.js +2 -0
- package/ui/docs/DocumentationButtons.md +38 -0
- package/ui/docs/DocumentationButtons.tsx +2 -0
- package/ui/docs/DocumentationCard.d.ts +1 -0
- package/ui/docs/DocumentationCard.js +1 -0
- package/ui/docs/DocumentationCard.md +35 -0
- package/ui/docs/DocumentationCard.tsx +1 -0
- package/ui/docs/DocumentationKind.d.ts +1 -1
- package/ui/docs/DocumentationKind.js +9 -4
- package/ui/docs/DocumentationKind.tsx +10 -5
- package/ui/docs/DocumentationPage.d.ts +1 -0
- package/ui/docs/DocumentationPage.js +2 -0
- package/ui/docs/DocumentationPage.md +46 -0
- package/ui/docs/DocumentationPage.tsx +2 -0
- package/ui/form/Button.d.ts +1 -0
- package/ui/form/Button.js +1 -0
- package/ui/form/Button.md +88 -0
- package/ui/form/Button.tsx +1 -0
- package/ui/form/Field.d.ts +6 -1
- package/ui/form/Field.js +6 -1
- package/ui/form/Field.md +59 -0
- package/ui/form/Field.tsx +6 -1
- package/ui/form/Form.d.ts +1 -0
- package/ui/form/Form.md +118 -0
- package/ui/form/Form.tsx +1 -0
- package/ui/form/FormStore.md +47 -0
- package/ui/form/SchemaInput.d.ts +1 -0
- package/ui/form/SchemaInput.md +64 -0
- package/ui/form/SchemaInput.tsx +1 -0
- package/ui/inline/Code.d.ts +1 -0
- package/ui/inline/Code.js +1 -0
- package/ui/inline/Code.md +58 -0
- package/ui/inline/Code.tsx +1 -0
- package/ui/inline/Link.d.ts +1 -0
- package/ui/inline/Link.js +1 -0
- package/ui/inline/Link.md +47 -0
- package/ui/inline/Link.tsx +1 -0
- package/ui/inline/Mark.d.ts +1 -0
- package/ui/inline/Mark.js +1 -0
- package/ui/inline/Mark.md +40 -0
- package/ui/inline/Mark.tsx +1 -0
- package/ui/inline/Strong.d.ts +1 -0
- package/ui/inline/Strong.js +1 -0
- package/ui/inline/Strong.md +34 -0
- package/ui/inline/Strong.tsx +1 -0
- package/ui/layout/CenteredLayout.d.ts +1 -0
- package/ui/layout/CenteredLayout.js +1 -0
- package/ui/layout/CenteredLayout.md +38 -0
- package/ui/layout/CenteredLayout.tsx +1 -0
- package/ui/layout/SidebarLayout.d.ts +1 -0
- package/ui/layout/SidebarLayout.js +1 -0
- package/ui/layout/SidebarLayout.md +65 -0
- package/ui/layout/SidebarLayout.tsx +1 -0
- package/ui/menu/Menu.d.ts +2 -0
- package/ui/menu/Menu.js +2 -0
- package/ui/menu/Menu.md +51 -0
- package/ui/menu/Menu.tsx +2 -0
- package/ui/menu/MenuItem.md +54 -0
- package/ui/misc/Catcher.d.ts +1 -0
- package/ui/misc/Catcher.js +1 -0
- package/ui/misc/Catcher.md +41 -0
- package/ui/misc/Catcher.tsx +1 -0
- package/ui/misc/Loading.d.ts +1 -0
- package/ui/misc/Loading.js +1 -0
- package/ui/misc/Loading.md +28 -0
- package/ui/misc/Loading.tsx +1 -0
- package/ui/misc/Mapper.md +40 -0
- package/ui/misc/Markup.d.ts +1 -0
- package/ui/misc/Markup.js +1 -0
- package/ui/misc/Markup.md +34 -0
- package/ui/misc/Markup.tsx +1 -0
- package/ui/misc/StatusIcon.d.ts +1 -0
- package/ui/misc/StatusIcon.js +1 -0
- package/ui/misc/StatusIcon.md +25 -0
- package/ui/misc/StatusIcon.tsx +1 -0
- package/ui/misc/Tag.d.ts +1 -0
- package/ui/misc/Tag.js +1 -0
- package/ui/misc/Tag.md +47 -0
- package/ui/misc/Tag.tsx +1 -0
- package/ui/notice/Notice.d.ts +1 -0
- package/ui/notice/Notice.js +1 -0
- package/ui/notice/Notice.md +53 -0
- package/ui/notice/Notice.tsx +1 -0
- package/ui/notice/Notices.d.ts +1 -0
- package/ui/notice/Notices.js +1 -0
- package/ui/notice/Notices.md +59 -0
- package/ui/notice/Notices.tsx +1 -0
- package/ui/page/HTML.d.ts +1 -0
- package/ui/page/HTML.js +1 -0
- package/ui/page/HTML.md +36 -0
- package/ui/page/HTML.tsx +1 -0
- package/ui/page/Head.d.ts +1 -0
- package/ui/page/Head.js +1 -0
- package/ui/page/Head.md +26 -0
- package/ui/page/Head.tsx +1 -0
- package/ui/page/Page.d.ts +1 -0
- package/ui/page/Page.js +1 -0
- package/ui/page/Page.md +42 -0
- package/ui/page/Page.tsx +1 -0
- package/ui/router/Navigation.d.ts +1 -0
- package/ui/router/Navigation.js +1 -0
- package/ui/router/Navigation.md +41 -0
- package/ui/router/Navigation.tsx +1 -0
- package/ui/router/NavigationStore.md +34 -0
- package/ui/router/Router.d.ts +1 -0
- package/ui/router/Router.js +1 -0
- package/ui/router/Router.md +143 -0
- package/ui/router/Router.tsx +1 -0
- package/ui/style/TINT_CLASS.md +55 -0
- package/ui/transition/CollapseTransition.d.ts +1 -0
- package/ui/transition/CollapseTransition.js +1 -0
- package/ui/transition/CollapseTransition.md +34 -0
- package/ui/transition/CollapseTransition.tsx +1 -0
- package/ui/transition/FadeTransition.d.ts +1 -0
- package/ui/transition/FadeTransition.js +1 -0
- package/ui/transition/FadeTransition.md +36 -0
- package/ui/transition/FadeTransition.tsx +1 -0
- package/ui/transition/HorizontalTransition.d.ts +1 -0
- package/ui/transition/HorizontalTransition.js +1 -0
- package/ui/transition/HorizontalTransition.md +44 -0
- package/ui/transition/HorizontalTransition.tsx +1 -0
- package/ui/transition/Transition.d.ts +1 -0
- package/ui/transition/Transition.js +1 -0
- package/ui/transition/Transition.md +70 -0
- package/ui/transition/Transition.tsx +1 -0
- package/ui/transition/VerticalTransition.d.ts +1 -0
- package/ui/transition/VerticalTransition.js +1 -0
- package/ui/transition/VerticalTransition.md +34 -0
- package/ui/transition/VerticalTransition.tsx +1 -0
- package/ui/tree/TreeApp.d.ts +1 -0
- package/ui/tree/TreeApp.js +1 -0
- package/ui/tree/TreeApp.md +59 -0
- package/ui/tree/TreeApp.tsx +1 -0
- package/ui/tree/TreeMenu.d.ts +1 -0
- package/ui/tree/TreeMenu.js +1 -0
- package/ui/tree/TreeMenu.md +35 -0
- package/ui/tree/TreeMenu.tsx +1 -0
- package/ui/tree/TreeSidebar.d.ts +1 -0
- package/ui/tree/TreeSidebar.js +1 -0
- package/ui/tree/TreeSidebar.md +24 -0
- package/ui/tree/TreeSidebar.tsx +1 -0
- package/ui/util/getClass.md +55 -0
- package/ui/util/notify.md +50 -0
- package/ui/util/requireContext.md +24 -0
- package/ui/app/README.md +0 -32
- package/ui/block/README.md +0 -144
- package/ui/dialog/README.md +0 -80
- package/ui/docs/README.md +0 -71
- package/ui/form/README.md +0 -165
- package/ui/inline/README.md +0 -86
- package/ui/layout/README.md +0 -71
- package/ui/menu/README.md +0 -33
- package/ui/misc/README.md +0 -121
- package/ui/notice/README.md +0 -94
- package/ui/page/README.md +0 -56
- package/ui/router/README.md +0 -186
- package/ui/transition/README.md +0 -80
- package/ui/tree/README.md +0 -78
- package/ui/util/README.md +0 -153
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# SchemaInput
|
|
2
|
+
|
|
3
|
+
Schema-driven input dispatch. `SchemaInput` inspects a `Schema` instance and renders the right control automatically — the same mechanism [`Form`](/ui/Form) uses to turn a `DataSchema` into a complete set of inputs.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- `required` defaults to whether the schema is required (i.e. not wrapped in an `OptionalSchema` or `NullableSchema`); override it explicitly when needed.
|
|
8
|
+
- It throws an `UnexpectedError` if no input matches the schema type.
|
|
9
|
+
- `SchemaField` wraps the chosen input in a [`Field`](/ui/Field) with its label and message; pass `children` to override the input while keeping the field chrome.
|
|
10
|
+
- Every input it dispatches to is a standalone, controlled component extending `ValueInputProps<O>` — see the prop contract below.
|
|
11
|
+
|
|
12
|
+
The schema-to-input mapping:
|
|
13
|
+
|
|
14
|
+
| Schema type | Rendered as |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `StringSchema` | [`TextInput`](/ui/TextInput) |
|
|
17
|
+
| `NumberSchema` | [`NumberInput`](/ui/NumberInput) (formatted on blur) |
|
|
18
|
+
| `DateSchema` | [`DateInput`](/ui/DateInput) |
|
|
19
|
+
| `BooleanSchema` | [`CheckboxInput`](/ui/CheckboxInput) |
|
|
20
|
+
| `ChoiceSchema` (≤ 8 options) | [`ChoiceRadioInputs`](/ui/ChoiceRadioInputs) |
|
|
21
|
+
| `ChoiceSchema` (> 8 options) | [`SelectInput`](/ui/SelectInput) |
|
|
22
|
+
| `ArraySchema` | [`ArrayInput`](/ui/ArrayInput) |
|
|
23
|
+
| `DictionarySchema` | [`DictionaryInput`](/ui/DictionaryInput) |
|
|
24
|
+
| `DataSchema` | [`DataInput`](/ui/DataInput) |
|
|
25
|
+
|
|
26
|
+
The shared value-input prop contract (`ValueInputProps<O>`):
|
|
27
|
+
|
|
28
|
+
| Prop | Contract |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `name` | HTML field name |
|
|
31
|
+
| `value` | Current value |
|
|
32
|
+
| `onValue(v)` | Called on every change |
|
|
33
|
+
| `required` | Marks the field as required |
|
|
34
|
+
| `disabled` | Disables the control |
|
|
35
|
+
| `message` | Inline error string |
|
|
36
|
+
|
|
37
|
+
[`DataInput`](/ui/DataInput) renders a row of `SchemaInput` elements for each property of a nested data object, and propagates sub-field errors from a `"key: message\n…"` formatted `message` string. `ArrayInput` and `DictionaryInput` both accept an `items` schema to render a repeatable list of sub-inputs with add/remove buttons.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### Dispatch on a single schema
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { SchemaInput } from "shelving/ui";
|
|
45
|
+
import { StringSchema, NumberSchema } from "shelving/schema";
|
|
46
|
+
|
|
47
|
+
<SchemaInput name="email" schema={new StringSchema({ title: "Email" })} /> // -> <TextInput>
|
|
48
|
+
<SchemaInput name="age" schema={new NumberSchema({ title: "Age" })} /> // -> <NumberInput>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Wrapped in a field
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { SchemaField } from "shelving/ui";
|
|
55
|
+
|
|
56
|
+
<SchemaField name="email" schema={EMAIL_SCHEMA} /> // <Field> wrapping a <TextInput>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## See also
|
|
60
|
+
|
|
61
|
+
- [`Form`](/ui/Form) — drives `SchemaInput` for every property of its schema.
|
|
62
|
+
- [`Field`](/ui/Field) — the label + input + error wrapper `SchemaField` composes.
|
|
63
|
+
- [schema](/schema) — the `Schema` types `SchemaInput` dispatches on.
|
|
64
|
+
- [ui](/ui) — top-level UI module index.
|
package/ui/form/SchemaInput.tsx
CHANGED
|
@@ -61,6 +61,7 @@ export interface SchemaInputProps<T extends Schema, I = never> extends ValueInpu
|
|
|
61
61
|
* @param props Props including the `schema` plus value input props.
|
|
62
62
|
* @returns The matching input element for the schema.
|
|
63
63
|
* @throws `UnexpectedError` if no input matches the schema type.
|
|
64
|
+
* @kind component
|
|
64
65
|
* @example <SchemaInput name="email" schema={EMAIL} /> // Outputs a `<TextInput>` for the "email" property.
|
|
65
66
|
* @example <SchemaInput name="age" schema={AGE} /> // Outputs a `<NumberInput>` for the "age" property.
|
|
66
67
|
* @see https://dhoulb.github.io/shelving/ui/form/SchemaInput/SchemaInput
|
package/ui/inline/Code.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface CodeProps extends ColorVariants, TypographyVariants, OptionalCh
|
|
|
32
32
|
* Inline code span — renders a `<code>` element.
|
|
33
33
|
* - Pass `plain` to drop the default background and padding.
|
|
34
34
|
*
|
|
35
|
+
* @kind component
|
|
35
36
|
* @param props Colour and typography variants, `children`, plus an optional `plain` toggle.
|
|
36
37
|
* @returns Rendered `<code>` element.
|
|
37
38
|
* @example <Code>npm install</Code>
|
package/ui/inline/Code.js
CHANGED
|
@@ -24,6 +24,7 @@ export const CODE_PROSE_CLASS = getModuleClass(CODE_CSS, "prose");
|
|
|
24
24
|
* Inline code span — renders a `<code>` element.
|
|
25
25
|
* - Pass `plain` to drop the default background and padding.
|
|
26
26
|
*
|
|
27
|
+
* @kind component
|
|
27
28
|
* @param props Colour and typography variants, `children`, plus an optional `plain` toggle.
|
|
28
29
|
* @returns Rendered `<code>` element.
|
|
29
30
|
* @example <Code>npm install</Code>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Code
|
|
2
|
+
|
|
3
|
+
An inline code span — renders a `<code>` element with monospace type and a subtle tinted background. `Code.tsx` exports four siblings that share the same monospace styling but carry different HTML semantics:
|
|
4
|
+
|
|
5
|
+
| Component | HTML element | Use for |
|
|
6
|
+
| ---------- | ------------ | ------------------------------- |
|
|
7
|
+
| `Code` | `<code>` | Inline code fragments |
|
|
8
|
+
| `Keyboard` | `<kbd>` | Keyboard input, e.g. `Ctrl+S` |
|
|
9
|
+
| `Sample` | `<samp>` | Program output |
|
|
10
|
+
| `Variable` | `<var>` | Variable names in documentation |
|
|
11
|
+
|
|
12
|
+
**Things to know:**
|
|
13
|
+
|
|
14
|
+
- Pick the sibling whose semantics match — they all look the same but mean different things to assistive tech and search.
|
|
15
|
+
- Pass `plain` to drop the default background and inline padding (useful when the code already sits inside a tinted container).
|
|
16
|
+
- Painted from the [tint ladder](/ui/TINT_CLASS): the background is `--tint-90` and the text `--tint-00`, so it re-tints with its surrounding scope.
|
|
17
|
+
- Inside [`Prose`](/ui/Prose) raw `<code>` / `<kbd>` / `<samp>` / `<var>` pick up the same styling, and code inside a `<pre>` drops the inline box automatically.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Inline code and keyboard input
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { Code, Keyboard, Sample } from "shelving/ui";
|
|
25
|
+
|
|
26
|
+
<p>Run <Code>npm install</Code>, then press <Keyboard>Enter</Keyboard>.</p>
|
|
27
|
+
<p>It prints <Sample>Done.</Sample></p>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Plain (no background)
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Code } from "shelving/ui";
|
|
34
|
+
|
|
35
|
+
<Code plain>const x = 1;</Code>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Styling
|
|
39
|
+
|
|
40
|
+
`Code` paints from the [tint ladder](/ui/TINT_CLASS); the box (`background` / `color`) reads ladder steps directly, while type, padding, and radius have per-property hooks.
|
|
41
|
+
|
|
42
|
+
| Variable | Styles | Default |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `--code-font` | Font family | `var(--font-code)` |
|
|
45
|
+
| `--code-weight` | Font weight | `var(--weight-code)` |
|
|
46
|
+
| `--code-size` | Font size | `var(--size-smaller)` |
|
|
47
|
+
| `--code-leading` | Line height | `var(--leading)` |
|
|
48
|
+
| `--code-padding` | Inline padding (non-`plain`) | `var(--space-xxsmall)` |
|
|
49
|
+
| `--code-radius` | Corner radius (non-`plain`) | `var(--radius-xxsmall)` |
|
|
50
|
+
|
|
51
|
+
**Global tokens it reads:** `--font-code`, `--weight-code`, `--size-smaller`, `--leading`, `--space-xxsmall`, `--radius-xxsmall`, and the tint-ladder steps `--tint-00` / `--tint-90` for the box fill and text.
|
|
52
|
+
|
|
53
|
+
## See also
|
|
54
|
+
|
|
55
|
+
- [`Preformatted`](/ui/Preformatted) — block-level `<pre>` for multi-line code.
|
|
56
|
+
- [`Mark`](/ui/Mark) — highlight a run of text rather than mark it as code.
|
|
57
|
+
- [`Prose`](/ui/Prose) — styles raw `<code>` and friends inside longform content.
|
|
58
|
+
- [`ui`](/ui) — the styling system: tint ladder and theming.
|
package/ui/inline/Code.tsx
CHANGED
|
@@ -39,6 +39,7 @@ export interface CodeProps extends ColorVariants, TypographyVariants, OptionalCh
|
|
|
39
39
|
* Inline code span — renders a `<code>` element.
|
|
40
40
|
* - Pass `plain` to drop the default background and padding.
|
|
41
41
|
*
|
|
42
|
+
* @kind component
|
|
42
43
|
* @param props Colour and typography variants, `children`, plus an optional `plain` toggle.
|
|
43
44
|
* @returns Rendered `<code>` element.
|
|
44
45
|
* @example <Code>npm install</Code>
|
package/ui/inline/Link.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface LinkProps extends ClickableProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* Inline link — delegates to `Clickable`, rendering an `<a>` (when `href` is set) or `<button>` (when `onClick` is set).
|
|
24
24
|
*
|
|
25
|
+
* @kind component
|
|
25
26
|
* @param props Clickable props such as `href`, `onClick`, `title`, and `children`.
|
|
26
27
|
* @returns Rendered inline `<a>` or `<button>` element.
|
|
27
28
|
* @example <Link href="/about">About us</Link>
|
package/ui/inline/Link.js
CHANGED
|
@@ -17,6 +17,7 @@ export const LINK_PROSE_CLASS = getModuleClass(LINK_CSS, "prose");
|
|
|
17
17
|
/**
|
|
18
18
|
* Inline link — delegates to `Clickable`, rendering an `<a>` (when `href` is set) or `<button>` (when `onClick` is set).
|
|
19
19
|
*
|
|
20
|
+
* @kind component
|
|
20
21
|
* @param props Clickable props such as `href`, `onClick`, `title`, and `children`.
|
|
21
22
|
* @returns Rendered inline `<a>` or `<button>` element.
|
|
22
23
|
* @example <Link href="/about">About us</Link>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Link
|
|
2
|
+
|
|
3
|
+
An inline link or action. Delegates to [`Clickable`](/ui/Clickable), rendering an `<a>` when `href` is provided or a `<button>` when `onClick` is provided — so the same component covers both navigation and in-page actions. Prefer it over a raw `<a>` inside React components.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- It handles busy state, URL resolution, and active-page highlighting automatically via the shared `Clickable` helper.
|
|
8
|
+
- An `<a>` (any actual link) shows an underline that disappears on hover; a `<button>` variant carries no underline.
|
|
9
|
+
- Reach for `Link` for inline text links; for standalone calls to action use a button-styled component instead.
|
|
10
|
+
- Inside [`Prose`](/ui/Prose) a raw `<a>` picks up the same styling, so Markdown-rendered links match component ones.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Link inside body copy
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Paragraph, Link } from "shelving/ui";
|
|
18
|
+
|
|
19
|
+
<Paragraph>
|
|
20
|
+
Read our <Link href="/privacy">privacy policy</Link> for details.
|
|
21
|
+
</Paragraph>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Action button
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { Link } from "shelving/ui";
|
|
28
|
+
|
|
29
|
+
<Link onClick={() => save()}>Save now</Link>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Styling
|
|
33
|
+
|
|
34
|
+
`Link` exposes a couple of inline hooks; the link colour comes from the global `--color-link` token.
|
|
35
|
+
|
|
36
|
+
| Variable | Styles | Default |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `--link-weight` | Text colour and font weight | `var(--color-link)` colour / `var(--weight-strong)` weight |
|
|
39
|
+
|
|
40
|
+
**Global tokens it reads:** `--color-link`, `--weight-strong`, and `--stroke-normal` (the underline thickness).
|
|
41
|
+
|
|
42
|
+
## See also
|
|
43
|
+
|
|
44
|
+
- [`Clickable`](/ui/Clickable) — the underlying primitive that renders `<a>` vs `<button>`.
|
|
45
|
+
- [`Strong`](/ui/Strong) — emphasis for runs of text that are not links.
|
|
46
|
+
- [`Prose`](/ui/Prose) — styles raw `<a>` inside longform content.
|
|
47
|
+
- [`ui`](/ui) — the styling system and theming tokens.
|
package/ui/inline/Link.tsx
CHANGED
|
@@ -27,6 +27,7 @@ export interface LinkProps extends ClickableProps {}
|
|
|
27
27
|
/**
|
|
28
28
|
* Inline link — delegates to `Clickable`, rendering an `<a>` (when `href` is set) or `<button>` (when `onClick` is set).
|
|
29
29
|
*
|
|
30
|
+
* @kind component
|
|
30
31
|
* @param props Clickable props such as `href`, `onClick`, `title`, and `children`.
|
|
31
32
|
* @returns Rendered inline `<a>` or `<button>` element.
|
|
32
33
|
* @example <Link href="/about">About us</Link>
|
package/ui/inline/Mark.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface MarkProps extends OptionalChildProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* Highlighted text — renders a `<mark>` element to call attention to a run of text.
|
|
24
24
|
*
|
|
25
|
+
* @kind component
|
|
25
26
|
* @param props The `children` to highlight.
|
|
26
27
|
* @returns Rendered `<mark>` element.
|
|
27
28
|
* @example <Mark>search term</Mark>
|
package/ui/inline/Mark.js
CHANGED
|
@@ -16,6 +16,7 @@ export const MARK_PROSE_CLASS = getModuleClass(MARK_CSS, "prose");
|
|
|
16
16
|
/**
|
|
17
17
|
* Highlighted text — renders a `<mark>` element to call attention to a run of text.
|
|
18
18
|
*
|
|
19
|
+
* @kind component
|
|
19
20
|
* @param props The `children` to highlight.
|
|
20
21
|
* @returns Rendered `<mark>` element.
|
|
21
22
|
* @example <Mark>search term</Mark>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Mark
|
|
2
|
+
|
|
3
|
+
Highlighted text — renders a `<mark>` element to call attention to a run of text, such as a matched search term. Painted as a small inline pill with a yellow background by default.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- Use it for relevance highlighting (search hits, the current match), not for general emphasis — reach for [`Strong`](/ui/Strong) or [`Emphasis`](/ui/Emphasis) for that.
|
|
8
|
+
- It is a self-contained inline pill: it adds its own inline padding and rounded corners.
|
|
9
|
+
- Inside [`Prose`](/ui/Prose) a raw `<mark>` picks up the same styling, so Markdown-rendered highlights match component ones.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Highlighted search term
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Mark } from "shelving/ui";
|
|
17
|
+
|
|
18
|
+
<p>Files are stored in <Mark>UTF-8</Mark> encoding.</p>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Styling
|
|
22
|
+
|
|
23
|
+
`Mark` is a fixed-palette highlight: it paints from dedicated colour hooks rather than the tint ladder.
|
|
24
|
+
|
|
25
|
+
| Variable | Styles | Default |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `--mark-color-bg` | Background fill | `var(--light-yellow)` |
|
|
28
|
+
| `--mark-color-text` | Text colour | `var(--dark-yellow)` |
|
|
29
|
+
| `--mark-padding` | Inline padding | `0.375em` |
|
|
30
|
+
| `--mark-radius` | Corner radius | `var(--radius-xxsmall)` |
|
|
31
|
+
| `--mark-weight` | Font weight | `var(--weight-strong)` |
|
|
32
|
+
|
|
33
|
+
**Global tokens it reads:** `--light-yellow`, `--dark-yellow`, `--radius-xxsmall`, and `--weight-strong`.
|
|
34
|
+
|
|
35
|
+
## See also
|
|
36
|
+
|
|
37
|
+
- [`Strong`](/ui/Strong) — strong importance rather than relevance highlighting.
|
|
38
|
+
- [`Emphasis`](/ui/Emphasis) — stress emphasis (italic) for a run of text.
|
|
39
|
+
- [`Code`](/ui/Code) — inline code rather than a highlight.
|
|
40
|
+
- [`ui`](/ui) — the styling system and theming tokens.
|
package/ui/inline/Mark.tsx
CHANGED
|
@@ -27,6 +27,7 @@ export interface MarkProps extends OptionalChildProps {}
|
|
|
27
27
|
/**
|
|
28
28
|
* Highlighted text — renders a `<mark>` element to call attention to a run of text.
|
|
29
29
|
*
|
|
30
|
+
* @kind component
|
|
30
31
|
* @param props The `children` to highlight.
|
|
31
32
|
* @returns Rendered `<mark>` element.
|
|
32
33
|
* @example <Mark>search term</Mark>
|
package/ui/inline/Strong.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface StrongProps extends OptionalChildProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* Strong importance — renders a `<strong>` element for text of strong importance (typically bold).
|
|
24
24
|
*
|
|
25
|
+
* @kind component
|
|
25
26
|
* @param props The `children` to render with strong importance.
|
|
26
27
|
* @returns Rendered `<strong>` element.
|
|
27
28
|
* @example <Strong>Warning</Strong>
|
package/ui/inline/Strong.js
CHANGED
|
@@ -16,6 +16,7 @@ export const STRONG_PROSE_CLASS = getModuleClass(STRONG_CSS, "prose");
|
|
|
16
16
|
/**
|
|
17
17
|
* Strong importance — renders a `<strong>` element for text of strong importance (typically bold).
|
|
18
18
|
*
|
|
19
|
+
* @kind component
|
|
19
20
|
* @param props The `children` to render with strong importance.
|
|
20
21
|
* @returns Rendered `<strong>` element.
|
|
21
22
|
* @example <Strong>Warning</Strong>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Strong
|
|
2
|
+
|
|
3
|
+
Strong importance — renders a `<strong>` element for text that carries strong importance, seriousness, or urgency (typically shown bold). Prefer it over a raw `<strong>` or `<b>` inside React components so the semantics and class names stay consistent.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- Use `Strong` for importance, [`Emphasis`](/ui/Emphasis) for stress emphasis (italic), and [`Mark`](/ui/Mark) for relevance highlighting — they are not interchangeable.
|
|
8
|
+
- It only sets the font weight; it inherits colour and size from the surrounding text.
|
|
9
|
+
- Inside [`Prose`](/ui/Prose) raw `<strong>` / `<b>` pick up the same styling, so Markdown-rendered bold text matches component ones.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Strong importance in body copy
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Paragraph, Strong } from "shelving/ui";
|
|
17
|
+
|
|
18
|
+
<Paragraph>
|
|
19
|
+
Press save before leaving. <Strong>Unsaved changes will be lost.</Strong>
|
|
20
|
+
</Paragraph>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Styling
|
|
24
|
+
|
|
25
|
+
`Strong` has no own theming hooks — it sets `font-weight: var(--weight-strong)` and inherits everything else from its surroundings.
|
|
26
|
+
|
|
27
|
+
**Global tokens it reads:** `--weight-strong`.
|
|
28
|
+
|
|
29
|
+
## See also
|
|
30
|
+
|
|
31
|
+
- [`Emphasis`](/ui/Emphasis) — stress emphasis (italic `<em>`) rather than importance.
|
|
32
|
+
- [`Mark`](/ui/Mark) — highlight a run of text by relevance.
|
|
33
|
+
- [`Small`](/ui/Small) — de-emphasised fine print.
|
|
34
|
+
- [`ui`](/ui) — the styling system and theming tokens.
|
package/ui/inline/Strong.tsx
CHANGED
|
@@ -27,6 +27,7 @@ export interface StrongProps extends OptionalChildProps {}
|
|
|
27
27
|
/**
|
|
28
28
|
* Strong importance — renders a `<strong>` element for text of strong importance (typically bold).
|
|
29
29
|
*
|
|
30
|
+
* @kind component
|
|
30
31
|
* @param props The `children` to render with strong importance.
|
|
31
32
|
* @returns Rendered `<strong>` element.
|
|
32
33
|
* @example <Strong>Warning</Strong>
|
|
@@ -12,6 +12,7 @@ export interface CenteredLayoutProps extends OptionalChildProps {
|
|
|
12
12
|
* Layout that centres its content with no header/footer and a narrow max-width.
|
|
13
13
|
* - Used for e.g. login/register/error/form pages where the content is the only focus.
|
|
14
14
|
*
|
|
15
|
+
* @kind component
|
|
15
16
|
* @param children The content to centre.
|
|
16
17
|
* @param fullWidth Drop the narrow max-width and let content fill the width (defaults to `false`).
|
|
17
18
|
* @returns The centred layout element.
|
|
@@ -7,6 +7,7 @@ import { LAYOUT_CLASS } from "./Layout.js";
|
|
|
7
7
|
* Layout that centres its content with no header/footer and a narrow max-width.
|
|
8
8
|
* - Used for e.g. login/register/error/form pages where the content is the only focus.
|
|
9
9
|
*
|
|
10
|
+
* @kind component
|
|
10
11
|
* @param children The content to centre.
|
|
11
12
|
* @param fullWidth Drop the narrow max-width and let content fill the width (defaults to `false`).
|
|
12
13
|
* @returns The centred layout element.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# CenteredLayout
|
|
2
|
+
|
|
3
|
+
A full-viewport layout that centres its content horizontally inside a narrow max-width column. Good for login, registration, error, and other focused single-purpose pages where the content is the only thing on screen.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- Pass `fullWidth` to drop the max-width constraint while keeping the centred positioning — use it when the content itself needs to fill the width.
|
|
8
|
+
- Like the other full-viewport layouts it owns scroll, padding, and safe-area insets so individual pages don't have to.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { CenteredLayout, Section } from "shelving/ui";
|
|
14
|
+
|
|
15
|
+
function LoginPage() {
|
|
16
|
+
return (
|
|
17
|
+
<CenteredLayout>
|
|
18
|
+
<Section narrow>
|
|
19
|
+
<LoginForm/>
|
|
20
|
+
</Section>
|
|
21
|
+
</CenteredLayout>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Layouts compose naturally as [`Router`](/ui/Router) route values — wrap a group of routes in a shared layout, then route further inside it.
|
|
27
|
+
|
|
28
|
+
## Styling
|
|
29
|
+
|
|
30
|
+
This layout exposes no own `--centered-layout-*` hooks. The inner column is capped at the global `--width-wide` token (dropped when `fullWidth` is set), and the outer element composes the shared `.layout` behaviour, so it reads the layout hooks `--layout-space`, `--layout-padding`, and `--layout-inset-top` / `-bottom` / `-left` / `-right`.
|
|
31
|
+
|
|
32
|
+
**Global tokens it reads** — `--width-wide`.
|
|
33
|
+
|
|
34
|
+
## See also
|
|
35
|
+
|
|
36
|
+
- [`SidebarLayout`](/ui/SidebarLayout) — the other full-viewport layout, with a fixed side column
|
|
37
|
+
- [`Page`](/ui/Page) — sits above layouts in the tree
|
|
38
|
+
- [`Router`](/ui/Router) — wrap route groups in a shared layout
|
|
@@ -18,6 +18,7 @@ export interface CenteredLayoutProps extends OptionalChildProps {
|
|
|
18
18
|
* Layout that centres its content with no header/footer and a narrow max-width.
|
|
19
19
|
* - Used for e.g. login/register/error/form pages where the content is the only focus.
|
|
20
20
|
*
|
|
21
|
+
* @kind component
|
|
21
22
|
* @param children The content to centre.
|
|
22
23
|
* @param fullWidth Drop the narrow max-width and let content fill the width (defaults to `false`).
|
|
23
24
|
* @returns The centred layout element.
|
|
@@ -19,6 +19,7 @@ export interface SidebarLayoutProps extends OptionalChildProps {
|
|
|
19
19
|
* - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
|
|
20
20
|
* - Use the `--sidebar-layout-width`, `--sidebar-layout-bg`, `--sidebar-layout-border`, and `--sidebar-layout-color-border` custom properties to override defaults.
|
|
21
21
|
*
|
|
22
|
+
* @kind component
|
|
22
23
|
* @param sidebar The side-column content, rendered inside a `<nav>`.
|
|
23
24
|
* @param children The main scrollable content.
|
|
24
25
|
* @param right Render the sidebar on the right rather than the left (defaults to `false`).
|
|
@@ -14,6 +14,7 @@ import SIDEBAR_LAYOUT_CSS from "./SidebarLayout.module.css";
|
|
|
14
14
|
* - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
|
|
15
15
|
* - Use the `--sidebar-layout-width`, `--sidebar-layout-bg`, `--sidebar-layout-border`, and `--sidebar-layout-color-border` custom properties to override defaults.
|
|
16
16
|
*
|
|
17
|
+
* @kind component
|
|
17
18
|
* @param sidebar The side-column content, rendered inside a `<nav>`.
|
|
18
19
|
* @param children The main scrollable content.
|
|
19
20
|
* @param right Render the sidebar on the right rather than the left (defaults to `false`).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SidebarLayout
|
|
2
|
+
|
|
3
|
+
A full-viewport layout with a fixed-width side column next to a scrollable main content column. The sidebar renders as a `<nav>` landmark — it almost always holds the primary navigation. On narrow viewports it collapses to an off-canvas drawer toggled by a single burger/close button.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- Pass `right` to place the sidebar on the right rather than the left.
|
|
8
|
+
- The sidebar renders as `<nav>`, so it is a navigation landmark without extra markup — drop a [`Menu`](/ui/Menu) inside it.
|
|
9
|
+
- While the drawer is open an overlay dims the page; clicking the overlay closes it.
|
|
10
|
+
- Inside a [`Navigation`](/ui/Navigation) context the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
|
|
11
|
+
- The layout owns scroll, padding, and safe-area insets so individual pages don't have to.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { SidebarLayout, Menu, MenuItem, Router } from "shelving/ui";
|
|
17
|
+
|
|
18
|
+
function AppShell() {
|
|
19
|
+
const nav = (
|
|
20
|
+
<Menu>
|
|
21
|
+
<MenuItem href="/dashboard">Dashboard</MenuItem>
|
|
22
|
+
<MenuItem href="/users">Users</MenuItem>
|
|
23
|
+
<MenuItem href="/settings">Settings</MenuItem>
|
|
24
|
+
</Menu>
|
|
25
|
+
);
|
|
26
|
+
return (
|
|
27
|
+
<SidebarLayout sidebar={nav}>
|
|
28
|
+
<Router routes={ROUTES}/>
|
|
29
|
+
</SidebarLayout>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Layouts compose naturally as [`Router`](/ui/Router) route values — wrap a group of routes in a shared layout, then route further inside it.
|
|
35
|
+
|
|
36
|
+
### Keyboard-aware safe area
|
|
37
|
+
|
|
38
|
+
`useSafeKeyboardArea()` (exported alongside the layouts) tracks the dynamic viewport and writes a `--layout-inset-bottom` custom property reflecting the space hidden behind the on-screen keyboard. This is an iOS Safari workaround until `interactive-widget` viewport support lands.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useSafeKeyboardArea } from "shelving/ui";
|
|
42
|
+
|
|
43
|
+
useEffect(useSafeKeyboardArea, []);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Styling
|
|
47
|
+
|
|
48
|
+
| Variable | Styles | Default |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `--sidebar-layout-width` | Width of the side column (and drawer) | `17.5rem` |
|
|
51
|
+
| `--sidebar-layout-background` | Page background while the layout is mounted | `var(--tint-100)` |
|
|
52
|
+
| `--sidebar-layout-sidebar-background` | Sidebar column fill | `var(--tint-90)` |
|
|
53
|
+
| `--sidebar-layout-content-background` | Main content column fill | `var(--tint-100)` |
|
|
54
|
+
| `--sidebar-layout-border` | Divider between sidebar and content | `var(--stroke-normal) solid var(--tint-80)` |
|
|
55
|
+
|
|
56
|
+
The content column composes the shared `.layout` behaviour, so it also reads the layout hooks `--layout-space`, `--layout-padding`, `--layout-inset-top` / `-bottom` / `-left` / `-right`, and `--layout-body-bg`.
|
|
57
|
+
|
|
58
|
+
**Global tokens it reads** — the tint ladder `--tint-80` / `--tint-90` / `--tint-100`, plus `--space-normal`, `--stroke-normal`, `--duration-normal`, and `--color-shadow`.
|
|
59
|
+
|
|
60
|
+
## See also
|
|
61
|
+
|
|
62
|
+
- [`CenteredLayout`](/ui/CenteredLayout) — the other full-viewport layout, for focused single-column pages
|
|
63
|
+
- [`Menu`](/ui/Menu) / [`MenuItem`](/ui/MenuItem) — navigation links for the sidebar
|
|
64
|
+
- [`Router`](/ui/Router) — wrap route groups in a shared layout
|
|
65
|
+
- [`Page`](/ui/Page) — sits above layouts in the tree
|
|
@@ -27,6 +27,7 @@ export interface SidebarLayoutProps extends OptionalChildProps {
|
|
|
27
27
|
* - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
|
|
28
28
|
* - Use the `--sidebar-layout-width`, `--sidebar-layout-bg`, `--sidebar-layout-border`, and `--sidebar-layout-color-border` custom properties to override defaults.
|
|
29
29
|
*
|
|
30
|
+
* @kind component
|
|
30
31
|
* @param sidebar The side-column content, rendered inside a `<nav>`.
|
|
31
32
|
* @param children The main scrollable content.
|
|
32
33
|
* @param right Render the sidebar on the right rather than the left (defaults to `false`).
|
package/ui/menu/Menu.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface MenuProps extends OptionalChildProps {
|
|
|
13
13
|
* - Renders as a bare `<menu>` element — semantically equivalent to `<ul>` per HTML spec but more meaningful for menu contexts. Place inside a `<nav>` (or use the sidebar-style nav at the layout level) if a navigation landmark is needed.
|
|
14
14
|
* - Nested `<Menu>` instances (typically inside a `<MenuItem>`) get indented via the `.menu .menu` CSS rule.
|
|
15
15
|
*
|
|
16
|
+
* @kind component
|
|
16
17
|
* @param children The `<MenuItem>` entries to list.
|
|
17
18
|
* @returns The menu element.
|
|
18
19
|
* @example <Menu><MenuItem href="/home">Home</MenuItem></Menu>
|
|
@@ -36,6 +37,7 @@ export interface MenuItemProps extends ClickableProps {
|
|
|
36
37
|
* - Reads the current page URL from `<Meta>` and computes `active` / `proud` against its own `href`.
|
|
37
38
|
* - Splits `children` into `[label, ...after]`: label goes inside the `<a>`; `after` is rendered as siblings below it, only when proud.
|
|
38
39
|
*
|
|
40
|
+
* @kind component
|
|
39
41
|
* @param href The link target, used to compute `active`/`proud` against the current URL.
|
|
40
42
|
* @param children The label (first node) and optional submenu (remaining nodes).
|
|
41
43
|
* @param props Additional `<Clickable>` props.
|
package/ui/menu/Menu.js
CHANGED
|
@@ -15,6 +15,7 @@ const MENU_ACTIVE_CLASS = getModuleClass(MENU_CSS, "active");
|
|
|
15
15
|
* - Renders as a bare `<menu>` element — semantically equivalent to `<ul>` per HTML spec but more meaningful for menu contexts. Place inside a `<nav>` (or use the sidebar-style nav at the layout level) if a navigation landmark is needed.
|
|
16
16
|
* - Nested `<Menu>` instances (typically inside a `<MenuItem>`) get indented via the `.menu .menu` CSS rule.
|
|
17
17
|
*
|
|
18
|
+
* @kind component
|
|
18
19
|
* @param children The `<MenuItem>` entries to list.
|
|
19
20
|
* @returns The menu element.
|
|
20
21
|
* @example <Menu><MenuItem href="/home">Home</MenuItem></Menu>
|
|
@@ -28,6 +29,7 @@ export function Menu({ children }) {
|
|
|
28
29
|
* - Reads the current page URL from `<Meta>` and computes `active` / `proud` against its own `href`.
|
|
29
30
|
* - Splits `children` into `[label, ...after]`: label goes inside the `<a>`; `after` is rendered as siblings below it, only when proud.
|
|
30
31
|
*
|
|
32
|
+
* @kind component
|
|
31
33
|
* @param href The link target, used to compute `active`/`proud` against the current URL.
|
|
32
34
|
* @param children The label (first node) and optional submenu (remaining nodes).
|
|
33
35
|
* @param props Additional `<Clickable>` props.
|
package/ui/menu/Menu.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
A `<menu>` list of [`MenuItem`](/ui/MenuItem) children — the container for URL-aware navigation in sidebars, dropdowns, and any other list of links.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- Renders as a bare `<menu>` element (semantically equivalent to `<ul>` but more meaningful for menus). Place it inside a `<nav>` — or a [`SidebarLayout`](/ui/SidebarLayout) sidebar, which is already a `<nav>` landmark — if a navigation landmark is needed.
|
|
8
|
+
- Nesting a `<Menu>` inside a [`MenuItem`](/ui/MenuItem) gets indented automatically via the `.menu .menu` descendant rule.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { Menu, MenuItem } from "shelving/ui";
|
|
14
|
+
|
|
15
|
+
<Menu>
|
|
16
|
+
<MenuItem href="/dashboard">Dashboard</MenuItem>
|
|
17
|
+
<MenuItem href="/users">
|
|
18
|
+
Users
|
|
19
|
+
<Menu>
|
|
20
|
+
<MenuItem href="/users/active">Active</MenuItem>
|
|
21
|
+
<MenuItem href="/users/archived">Archived</MenuItem>
|
|
22
|
+
</Menu>
|
|
23
|
+
</MenuItem>
|
|
24
|
+
<MenuItem href="/settings">Settings</MenuItem>
|
|
25
|
+
</Menu>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Styling
|
|
29
|
+
|
|
30
|
+
| Variable | Styles | Default |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `--menu-gap` | Vertical gap between items | `var(--space-xxsmall)` |
|
|
33
|
+
| `--menu-font` | Font family | `var(--font-body)` |
|
|
34
|
+
| `--menu-size` | Font size | `var(--size-normal)` |
|
|
35
|
+
| `--menu-leading` | Line height | `var(--leading)` |
|
|
36
|
+
| `--menu-color` | Text colour | `var(--tint-00)` |
|
|
37
|
+
| `--menu-nested-space` | Block margin around a nested submenu | `var(--space-xxsmall)` |
|
|
38
|
+
| `--menu-padding` | Item link padding (also insets the nested border) | `var(--space-xxsmall)` |
|
|
39
|
+
| `--menu-nested-border` | Nested submenu left-border width | `var(--stroke-focus)` |
|
|
40
|
+
| `--menu-nested-color-border` | Nested submenu left-border colour | `var(--tint-50)` |
|
|
41
|
+
| `--menu-nested-indent` | Nested submenu left padding | `var(--space-xsmall)` |
|
|
42
|
+
|
|
43
|
+
Item-state hooks (`--menu-hover-*`, `--menu-proud-*`, `--menu-active-*`, `--menu-radius`, `--menu-focus-border`) are documented on [`MenuItem`](/ui/MenuItem).
|
|
44
|
+
|
|
45
|
+
**Global tokens it reads** — the tint ladder `--tint-00` / `--tint-50`, plus `--space-xxsmall` / `--space-xsmall`, `--font-body`, `--size-normal`, `--leading`, and `--stroke-focus`.
|
|
46
|
+
|
|
47
|
+
## See also
|
|
48
|
+
|
|
49
|
+
- [`MenuItem`](/ui/MenuItem) — the individual link entries
|
|
50
|
+
- [`SidebarLayout`](/ui/SidebarLayout) — renders a `<nav>` that typically contains a `<Menu>`
|
|
51
|
+
- [`Router`](/ui/Router) — provides the URL context items read
|
package/ui/menu/Menu.tsx
CHANGED
|
@@ -25,6 +25,7 @@ export interface MenuProps extends OptionalChildProps {}
|
|
|
25
25
|
* - Renders as a bare `<menu>` element — semantically equivalent to `<ul>` per HTML spec but more meaningful for menu contexts. Place inside a `<nav>` (or use the sidebar-style nav at the layout level) if a navigation landmark is needed.
|
|
26
26
|
* - Nested `<Menu>` instances (typically inside a `<MenuItem>`) get indented via the `.menu .menu` CSS rule.
|
|
27
27
|
*
|
|
28
|
+
* @kind component
|
|
28
29
|
* @param children The `<MenuItem>` entries to list.
|
|
29
30
|
* @returns The menu element.
|
|
30
31
|
* @example <Menu><MenuItem href="/home">Home</MenuItem></Menu>
|
|
@@ -52,6 +53,7 @@ export interface MenuItemProps extends ClickableProps {
|
|
|
52
53
|
* - Reads the current page URL from `<Meta>` and computes `active` / `proud` against its own `href`.
|
|
53
54
|
* - Splits `children` into `[label, ...after]`: label goes inside the `<a>`; `after` is rendered as siblings below it, only when proud.
|
|
54
55
|
*
|
|
56
|
+
* @kind component
|
|
55
57
|
* @param href The link target, used to compute `active`/`proud` against the current URL.
|
|
56
58
|
* @param children The label (first node) and optional submenu (remaining nodes).
|
|
57
59
|
* @param props Additional `<Clickable>` props.
|