shelving 1.286.0 → 1.286.1
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/package.json +3 -3
- package/ui/block/Details.d.ts +12 -7
- package/ui/block/Details.js +9 -7
- package/ui/block/Details.md +63 -0
- package/ui/block/Details.module.css +7 -24
- package/ui/block/Details.tsx +17 -11
- package/ui/button/FullscreenButton.js +1 -1
- package/ui/button/FullscreenButton.tsx +1 -1
- package/ui/button/RetryButton.js +1 -1
- package/ui/button/RetryButton.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shelving",
|
|
3
|
-
"version": "1.286.
|
|
3
|
+
"version": "1.286.1",
|
|
4
4
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"main": "./index.js",
|
|
10
10
|
"module": "./index.js",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@biomejs/biome": "^2.5.
|
|
12
|
+
"@biomejs/biome": "^2.5.15",
|
|
13
13
|
"@heroicons/react": "^2.2.0",
|
|
14
14
|
"@types/bun": "^1.4.2",
|
|
15
15
|
"@types/react": "^19.3.0",
|
|
16
16
|
"@types/react-dom": "^19.3.0",
|
|
17
|
-
"stylelint": "^17.
|
|
17
|
+
"stylelint": "^17.16.0",
|
|
18
18
|
"stylelint-config-standard": "^40.0.0",
|
|
19
19
|
"typescript": "^7.0.2"
|
|
20
20
|
},
|
package/ui/block/Details.d.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from "react";
|
|
2
2
|
import { type BlockVariants } from "../style/Block.js";
|
|
3
3
|
import type { ClassProps } from "../util/props.js";
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Props for `<Details>` — the summary title, the revealed content, and the open state.
|
|
6
|
+
*
|
|
7
|
+
* @see https://shelving.cc/ui/DetailsProps
|
|
8
|
+
*/
|
|
5
9
|
export interface DetailsProps extends BlockVariants, ClassProps {
|
|
6
10
|
/** Content of the always-visible summary (e.g. a question). */
|
|
7
11
|
title: ReactNode;
|
|
8
|
-
/** Whether the
|
|
12
|
+
/** Whether the panel starts expanded. */
|
|
9
13
|
open?: boolean | undefined;
|
|
10
|
-
/** Shared group name —
|
|
14
|
+
/** Shared group name — panels with the same `name` open exclusively (only one at a time). */
|
|
11
15
|
name?: string | undefined;
|
|
12
|
-
/** Content revealed when the
|
|
16
|
+
/** Content revealed when the panel is expanded. */
|
|
13
17
|
children: ReactNode;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
|
-
* A
|
|
17
|
-
* -
|
|
18
|
-
* - Give sibling
|
|
20
|
+
* A collapsible panel with a title that is always visible, built on native `<details>` and `<summary>`.
|
|
21
|
+
* - The panel animates to its true height (where `interpolate-size` and `::details-content` are supported).
|
|
22
|
+
* - Give sibling panels a shared `name` to make them open exclusively.
|
|
19
23
|
*
|
|
20
24
|
* @kind component
|
|
25
|
+
* @see https://shelving.cc/ui/Details
|
|
21
26
|
*/
|
|
22
27
|
export declare function Details({ title, open, name, children, className, ...props }: DetailsProps): ReactElement;
|
package/ui/block/Details.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ChevronUpIcon } from "@heroicons/react/24/
|
|
2
|
+
import { ChevronUpIcon } from "@heroicons/react/24/solid";
|
|
3
3
|
import { getBlockClass } from "../style/Block.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getFlexClass } from "../style/Flex.js";
|
|
5
|
+
import { getClass, getModuleClass } from "../util/css.js";
|
|
5
6
|
import DETAILS_CSS from "./Details.module.css";
|
|
6
|
-
const DETAILS_CLASS = DETAILS_CSS
|
|
7
|
-
const DETAILS_SUMMARY_CLASS = DETAILS_CSS
|
|
7
|
+
const DETAILS_CLASS = getModuleClass(DETAILS_CSS, "details");
|
|
8
|
+
const DETAILS_SUMMARY_CLASS = getClass(getModuleClass(DETAILS_CSS, "summary"), getFlexClass({ between: true, gap: "normal" }));
|
|
8
9
|
/**
|
|
9
|
-
* A
|
|
10
|
-
* -
|
|
11
|
-
* - Give sibling
|
|
10
|
+
* A collapsible panel with a title that is always visible, built on native `<details>` and `<summary>`.
|
|
11
|
+
* - The panel animates to its true height (where `interpolate-size` and `::details-content` are supported).
|
|
12
|
+
* - Give sibling panels a shared `name` to make them open exclusively.
|
|
12
13
|
*
|
|
13
14
|
* @kind component
|
|
15
|
+
* @see https://shelving.cc/ui/Details
|
|
14
16
|
*/
|
|
15
17
|
export function Details({ title, open = false, name, children, className, ...props }) {
|
|
16
18
|
return (_jsxs("details", { className: getClass(DETAILS_CLASS, getBlockClass(props), className), open: open, name: name, children: [_jsxs("summary", { className: DETAILS_SUMMARY_CLASS, children: [_jsx("span", { children: title }), _jsx(ChevronUpIcon, {})] }), children] }));
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Details
|
|
2
|
+
|
|
3
|
+
A collapsible panel. The title is always visible. The content shows when the user opens the panel. Built on the native `<details>` and `<summary>` elements, so it works with the keyboard and without JavaScript.
|
|
4
|
+
|
|
5
|
+
**Things to know:**
|
|
6
|
+
|
|
7
|
+
- A chevron on the right of the title points down when the panel is closed and up when it is open.
|
|
8
|
+
- The panel animates to its true height where the browser supports `interpolate-size` and `::details-content`. Other browsers open it at once.
|
|
9
|
+
- Give sibling panels the same `name` to make them open exclusively: when one opens, the others close.
|
|
10
|
+
- Two or more panels next to each other get a divider line between them.
|
|
11
|
+
- A raw `<details>` inside `.prose` gets the same spacing and divider, but it keeps the browser's own marker in place of the chevron.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Single panel
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Details, Paragraph } from "shelving/ui";
|
|
19
|
+
|
|
20
|
+
<Details title="What is shelving?">
|
|
21
|
+
<Paragraph>A TypeScript data toolkit.</Paragraph>
|
|
22
|
+
</Details>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Open by default
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { Details, Paragraph } from "shelving/ui";
|
|
29
|
+
|
|
30
|
+
<Details title="Release notes" open>
|
|
31
|
+
<Paragraph>Bug fixes and small improvements.</Paragraph>
|
|
32
|
+
</Details>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Exclusive group (FAQ)
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { Details, Paragraph } from "shelving/ui";
|
|
39
|
+
|
|
40
|
+
// Only one answer is open at a time.
|
|
41
|
+
<Details name="faq" title="Is it free?">
|
|
42
|
+
<Paragraph>Yes.</Paragraph>
|
|
43
|
+
</Details>
|
|
44
|
+
<Details name="faq" title="Does it work with React?">
|
|
45
|
+
<Paragraph>Yes, through `shelving/ui`.</Paragraph>
|
|
46
|
+
</Details>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Styling
|
|
50
|
+
|
|
51
|
+
`Details` paints from the [tint ladder](/ui/TINT_CLASS). Override these hooks at `:root` (or any ancestor scope) to retheme. Apply `color=` / `status=` to an ancestor scope to recolour the chevron and divider together.
|
|
52
|
+
|
|
53
|
+
| Variable | Styles | Default |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `--details-space` | Outer block margin, and the padding above a divider | `var(--space-paragraph)` (16px) |
|
|
56
|
+
| `--details-border` | Divider between panels next to each other | `var(--stroke-normal) solid var(--tint-90)` |
|
|
57
|
+
| `--details-marker-color` | Colour of the browser's marker on a raw `<details>` in `.prose` | `var(--tint-80)` |
|
|
58
|
+
| `--details-radius` | Corner radius of the title's focus ring | `var(--radius-xsmall)` (8px) |
|
|
59
|
+
| `--details-icon-color` | Chevron colour | `var(--tint-50)` |
|
|
60
|
+
| `--details-transition` | Open/close animation and chevron turn | `all var(--duration-fast)` (150ms) |
|
|
61
|
+
| `--details-gap` | Space between the title and the content | `var(--space-paragraph)` (16px) |
|
|
62
|
+
|
|
63
|
+
**Global tokens it reads:** the tint ladder `--tint-50` / `--tint-80` / `--tint-90`, plus `--space-paragraph`, `--space-normal`, `--radius-xsmall`, `--stroke-normal`, `--stroke-focus`, `--color-focus`, `--duration-fast` and `--size-icon` (chevron size, from `getFlexClass`).
|
|
@@ -48,26 +48,11 @@
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
/* Title (
|
|
52
|
-
.summary {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
/* Contents */
|
|
57
|
-
align-items: center;
|
|
58
|
-
justify-content: space-between;
|
|
59
|
-
gap: var(--space-normal);
|
|
60
|
-
|
|
61
|
-
/* Children */
|
|
62
|
-
[data-slot="icon"] {
|
|
63
|
-
width: var(--size-icon);
|
|
64
|
-
height: var(--size-icon);
|
|
65
|
-
color: var(--color-gray);
|
|
66
|
-
transform: rotate(180deg);
|
|
67
|
-
transition: var(--details-transition, all var(--duration-fast));
|
|
68
|
-
border-radius: var(--radius-xxsmall);
|
|
69
|
-
flex: none;
|
|
70
|
-
}
|
|
51
|
+
/* Title chevron (the summary's flex class sets its size). Points down while closed. */
|
|
52
|
+
.summary [data-slot="icon"] {
|
|
53
|
+
color: var(--details-icon-color, var(--tint-50));
|
|
54
|
+
transform: rotate(180deg);
|
|
55
|
+
transition: var(--details-transition, all var(--duration-fast));
|
|
71
56
|
}
|
|
72
57
|
|
|
73
58
|
/* Content */
|
|
@@ -96,10 +81,8 @@
|
|
|
96
81
|
|
|
97
82
|
/* States */
|
|
98
83
|
&[open] {
|
|
99
|
-
.summary {
|
|
100
|
-
|
|
101
|
-
transform: rotate(0deg);
|
|
102
|
-
}
|
|
84
|
+
.summary [data-slot="icon"] {
|
|
85
|
+
transform: rotate(0deg);
|
|
103
86
|
}
|
|
104
87
|
|
|
105
88
|
&::details-content {
|
package/ui/block/Details.tsx
CHANGED
|
@@ -1,31 +1,37 @@
|
|
|
1
|
-
import { ChevronUpIcon } from "@heroicons/react/24/
|
|
1
|
+
import { ChevronUpIcon } from "@heroicons/react/24/solid";
|
|
2
2
|
import type { ReactElement, ReactNode } from "react";
|
|
3
3
|
import { type BlockVariants, getBlockClass } from "../style/Block.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getFlexClass } from "../style/Flex.js";
|
|
5
|
+
import { getClass, getModuleClass } from "../util/css.js";
|
|
5
6
|
import type { ClassProps } from "../util/props.js";
|
|
6
7
|
import DETAILS_CSS from "./Details.module.css";
|
|
7
8
|
|
|
8
|
-
const DETAILS_CLASS = DETAILS_CSS
|
|
9
|
-
const DETAILS_SUMMARY_CLASS = DETAILS_CSS
|
|
9
|
+
const DETAILS_CLASS = getModuleClass(DETAILS_CSS, "details");
|
|
10
|
+
const DETAILS_SUMMARY_CLASS = getClass(getModuleClass(DETAILS_CSS, "summary"), getFlexClass({ between: true, gap: "normal" }));
|
|
10
11
|
|
|
11
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Props for `<Details>` — the summary title, the revealed content, and the open state.
|
|
14
|
+
*
|
|
15
|
+
* @see https://shelving.cc/ui/DetailsProps
|
|
16
|
+
*/
|
|
12
17
|
export interface DetailsProps extends BlockVariants, ClassProps {
|
|
13
18
|
/** Content of the always-visible summary (e.g. a question). */
|
|
14
19
|
title: ReactNode;
|
|
15
|
-
/** Whether the
|
|
20
|
+
/** Whether the panel starts expanded. */
|
|
16
21
|
open?: boolean | undefined;
|
|
17
|
-
/** Shared group name —
|
|
22
|
+
/** Shared group name — panels with the same `name` open exclusively (only one at a time). */
|
|
18
23
|
name?: string | undefined;
|
|
19
|
-
/** Content revealed when the
|
|
24
|
+
/** Content revealed when the panel is expanded. */
|
|
20
25
|
children: ReactNode;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
/**
|
|
24
|
-
* A
|
|
25
|
-
* -
|
|
26
|
-
* - Give sibling
|
|
29
|
+
* A collapsible panel with a title that is always visible, built on native `<details>` and `<summary>`.
|
|
30
|
+
* - The panel animates to its true height (where `interpolate-size` and `::details-content` are supported).
|
|
31
|
+
* - Give sibling panels a shared `name` to make them open exclusively.
|
|
27
32
|
*
|
|
28
33
|
* @kind component
|
|
34
|
+
* @see https://shelving.cc/ui/Details
|
|
29
35
|
*/
|
|
30
36
|
export function Details({ title, open = false, name, children, className, ...props }: DetailsProps): ReactElement {
|
|
31
37
|
return (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/
|
|
2
|
+
import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/24/solid";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Button } from "./Button.js";
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/
|
|
1
|
+
import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/24/solid";
|
|
2
2
|
import { type ReactElement, useEffect, useState } from "react";
|
|
3
3
|
import type { ClassProps } from "../util/props.js";
|
|
4
4
|
import { Button, type ButtonVariants } from "./Button.js";
|
package/ui/button/RetryButton.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowPathIcon } from "@heroicons/react/
|
|
2
|
+
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
|
3
3
|
import { createContext, use } from "react";
|
|
4
4
|
import { Button } from "./Button.js";
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArrowPathIcon } from "@heroicons/react/
|
|
1
|
+
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
|
2
2
|
import { createContext, type ReactElement, use } from "react";
|
|
3
3
|
import type { Callback } from "../../util/function.js";
|
|
4
4
|
import type { ClassProps, OptionalChildProps } from "../util/index.js";
|