shelving 1.258.10 → 1.259.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 +21 -0
- package/ui/block/Details.js +17 -0
- package/ui/block/Details.module.css +117 -0
- package/ui/block/Details.tsx +39 -0
- package/ui/block/Heading.module.css +1 -0
- package/ui/block/Subheading.module.css +1 -0
- package/ui/block/Title.module.css +1 -0
- package/ui/block/index.d.ts +1 -0
- package/ui/block/index.js +1 -0
- package/ui/block/index.ts +1 -0
- package/ui/misc/Icon.module.css +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shelving",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.259.1",
|
|
4
4
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"main": "./index.js",
|
|
10
10
|
"module": "./index.js",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@biomejs/biome": "^2.5.
|
|
12
|
+
"@biomejs/biome": "^2.5.1",
|
|
13
13
|
"@google-cloud/firestore": "^8.6.0",
|
|
14
14
|
"@heroicons/react": "^2.2.0",
|
|
15
15
|
"@types/bun": "^1.3.14",
|
|
16
16
|
"@types/react": "^19.2.17",
|
|
17
17
|
"@types/react-dom": "^19.2.3",
|
|
18
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
18
|
+
"@typescript/native-preview": "^7.0.0-dev.20260627.2",
|
|
19
19
|
"firebase": "^12.15.0",
|
|
20
20
|
"react": "^19.3.0-canary-fef12a01-20260413",
|
|
21
21
|
"react-dom": "^19.3.0-canary-fef12a01-20260413",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import { type BlockVariants } from "../style/Block.js";
|
|
3
|
+
/** Props for `DetailsItem` — a single collapsible disclosure. */
|
|
4
|
+
export interface DetailsProps extends BlockVariants {
|
|
5
|
+
/** Content of the always-visible summary (e.g. a question). */
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/** Whether the item starts expanded. */
|
|
8
|
+
open?: boolean | undefined;
|
|
9
|
+
/** Shared group name — items with the same `name` open exclusively (only one at a time). */
|
|
10
|
+
name?: string | undefined;
|
|
11
|
+
/** Content revealed when the item is expanded. */
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A single collapsible panel within an `Details`, built on native `<details>` and `<summary>`
|
|
16
|
+
* - Panel animates to its true height (where `interpolate-size` + `::details-content` are supported),
|
|
17
|
+
* - Give sibling items a shared `name` to make them open exclusively.
|
|
18
|
+
*
|
|
19
|
+
* @kind component
|
|
20
|
+
*/
|
|
21
|
+
export declare function Details({ title, open, name, children, ...props }: DetailsProps): ReactElement;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronUpIcon } from "@heroicons/react/24/outline";
|
|
3
|
+
import { getBlockClass } from "../style/Block.js";
|
|
4
|
+
import { getClass } from "../util/css.js";
|
|
5
|
+
import DETAILS_CSS from "./Details.module.css";
|
|
6
|
+
const DETAILS_CLASS = DETAILS_CSS.details;
|
|
7
|
+
const DETAILS_SUMMARY_CLASS = DETAILS_CSS.summary;
|
|
8
|
+
/**
|
|
9
|
+
* A single collapsible panel within an `Details`, built on native `<details>` and `<summary>`
|
|
10
|
+
* - Panel animates to its true height (where `interpolate-size` + `::details-content` are supported),
|
|
11
|
+
* - Give sibling items a shared `name` to make them open exclusively.
|
|
12
|
+
*
|
|
13
|
+
* @kind component
|
|
14
|
+
*/
|
|
15
|
+
export function Details({ title, open = false, name, children, ...props }) {
|
|
16
|
+
return (_jsxs("details", { className: getClass(DETAILS_CLASS, getBlockClass(props)), open: open, name: name, children: [_jsxs("summary", { className: DETAILS_SUMMARY_CLASS, children: [_jsx("span", { children: title }), _jsx(ChevronUpIcon, {})] }), children] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
@import "../style/layers.css";
|
|
2
|
+
@import "../style/Space.module.css";
|
|
3
|
+
@import "../style/Radius.module.css";
|
|
4
|
+
@import "../style/Stroke.module.css";
|
|
5
|
+
@import "../style/Color.module.css";
|
|
6
|
+
@import "../style/Duration.module.css";
|
|
7
|
+
@import "../style/Tint.module.css";
|
|
8
|
+
|
|
9
|
+
@layer components {
|
|
10
|
+
.prose details,
|
|
11
|
+
.details {
|
|
12
|
+
/* Box */
|
|
13
|
+
margin-block: var(--details-space, var(--space-paragraph));
|
|
14
|
+
border: 0;
|
|
15
|
+
|
|
16
|
+
/* Nested */
|
|
17
|
+
& + & {
|
|
18
|
+
border-block-start: var(--details-border, var(--stroke-normal) solid var(--tint-90));
|
|
19
|
+
padding-top: var(--details-space, var(--space-paragraph));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Title */
|
|
23
|
+
summary {
|
|
24
|
+
/* Box */
|
|
25
|
+
position: relative;
|
|
26
|
+
margin: 0;
|
|
27
|
+
padding: 0;
|
|
28
|
+
|
|
29
|
+
/* Style */
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
outline: none;
|
|
32
|
+
|
|
33
|
+
/* Typography */
|
|
34
|
+
font-weight: var(--weight-strong);
|
|
35
|
+
|
|
36
|
+
/* Pseudo-elements */
|
|
37
|
+
&::marker {
|
|
38
|
+
color: var(--details-marker-color, var(--tint-80));
|
|
39
|
+
}
|
|
40
|
+
&::before {
|
|
41
|
+
position: absolute;
|
|
42
|
+
content: "";
|
|
43
|
+
inset: calc(0px - var(--space-normal));
|
|
44
|
+
border-radius: var(--details-radius, var(--radius-xsmall));
|
|
45
|
+
outline: var(--stroke-focus) solid var(--color-focus);
|
|
46
|
+
outline-offset: calc(0px - var(--stroke-normal));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Title (with chevron icon) */
|
|
51
|
+
.summary {
|
|
52
|
+
/* Box */
|
|
53
|
+
display: flex;
|
|
54
|
+
|
|
55
|
+
/* Contents */
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
gap: var(--space-normal);
|
|
59
|
+
|
|
60
|
+
/* Children */
|
|
61
|
+
[data-slot="icon"] {
|
|
62
|
+
flex: none;
|
|
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
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Content */
|
|
73
|
+
&::details-content {
|
|
74
|
+
/* Box */
|
|
75
|
+
padding: 0;
|
|
76
|
+
margin: 0;
|
|
77
|
+
block-size: 0;
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
|
|
80
|
+
/* Style */
|
|
81
|
+
opacity: 0;
|
|
82
|
+
interpolate-size: allow-keywords;
|
|
83
|
+
transition:
|
|
84
|
+
var(--details-transition, all var(--duration-fast)),
|
|
85
|
+
content-visibility var(--duration-fast) ease allow-discrete;
|
|
86
|
+
|
|
87
|
+
/* Add margin between the summary and content that gets swallowed by the animation */
|
|
88
|
+
&::before {
|
|
89
|
+
content: "";
|
|
90
|
+
height: 0;
|
|
91
|
+
margin-block-end: var(--details-gap, var(--space-paragraph));
|
|
92
|
+
display: block;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* States */
|
|
97
|
+
&[open] {
|
|
98
|
+
.summary {
|
|
99
|
+
[data-slot="icon"] {
|
|
100
|
+
transform: rotate(0deg);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
&::details-content {
|
|
104
|
+
block-size: fit-content;
|
|
105
|
+
opacity: 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@layer overrides {
|
|
112
|
+
.details {
|
|
113
|
+
summary:not(:focus-visible)::before {
|
|
114
|
+
outline: 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ChevronUpIcon } from "@heroicons/react/24/outline";
|
|
2
|
+
import type { ReactElement, ReactNode } from "react";
|
|
3
|
+
import { type BlockVariants, getBlockClass } from "../style/Block.js";
|
|
4
|
+
import { getClass } from "../util/css.js";
|
|
5
|
+
import DETAILS_CSS from "./Details.module.css";
|
|
6
|
+
|
|
7
|
+
const DETAILS_CLASS = DETAILS_CSS.details;
|
|
8
|
+
const DETAILS_SUMMARY_CLASS = DETAILS_CSS.summary;
|
|
9
|
+
|
|
10
|
+
/** Props for `DetailsItem` — a single collapsible disclosure. */
|
|
11
|
+
export interface DetailsProps extends BlockVariants {
|
|
12
|
+
/** Content of the always-visible summary (e.g. a question). */
|
|
13
|
+
title: ReactNode;
|
|
14
|
+
/** Whether the item starts expanded. */
|
|
15
|
+
open?: boolean | undefined;
|
|
16
|
+
/** Shared group name — items with the same `name` open exclusively (only one at a time). */
|
|
17
|
+
name?: string | undefined;
|
|
18
|
+
/** Content revealed when the item is expanded. */
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A single collapsible panel within an `Details`, built on native `<details>` and `<summary>`
|
|
24
|
+
* - Panel animates to its true height (where `interpolate-size` + `::details-content` are supported),
|
|
25
|
+
* - Give sibling items a shared `name` to make them open exclusively.
|
|
26
|
+
*
|
|
27
|
+
* @kind component
|
|
28
|
+
*/
|
|
29
|
+
export function Details({ title, open = false, name, children, ...props }: DetailsProps): ReactElement {
|
|
30
|
+
return (
|
|
31
|
+
<details className={getClass(DETAILS_CLASS, getBlockClass(props))} open={open} name={name}>
|
|
32
|
+
<summary className={DETAILS_SUMMARY_CLASS}>
|
|
33
|
+
<span>{title}</span>
|
|
34
|
+
<ChevronUpIcon />
|
|
35
|
+
</summary>
|
|
36
|
+
{children}
|
|
37
|
+
</details>
|
|
38
|
+
);
|
|
39
|
+
}
|
package/ui/block/index.d.ts
CHANGED
package/ui/block/index.js
CHANGED
package/ui/block/index.ts
CHANGED
package/ui/misc/Icon.module.css
CHANGED