shelving 1.214.1 → 1.215.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.214.1",
3
+ "version": "1.215.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,7 +11,8 @@ export interface SidebarLayoutProps {
11
11
  /**
12
12
  * Layout with a fixed-width side column (typically navigation) next to a scrollable main content column.
13
13
  * - The sidebar is rendered as `<nav>` — it almost always contains the page's primary navigation.
14
- * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by the "show menu" / "close" buttons.
14
+ * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by a single menu button that switches between a burger and a close icon.
15
+ * - While the drawer is open an overlay dims the rest of the page; clicking the overlay closes the drawer.
15
16
  * - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
16
17
  * - Use the `--sidebar-layout-width` and `--sidebar-layout-bg` custom properties to override defaults.
17
18
  */
@@ -10,7 +10,8 @@ import SIDEBAR_LAYOUT_CSS from "./SidebarLayout.module.css";
10
10
  /**
11
11
  * Layout with a fixed-width side column (typically navigation) next to a scrollable main content column.
12
12
  * - The sidebar is rendered as `<nav>` — it almost always contains the page's primary navigation.
13
- * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by the "show menu" / "close" buttons.
13
+ * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by a single menu button that switches between a burger and a close icon.
14
+ * - While the drawer is open an overlay dims the rest of the page; clicking the overlay closes the drawer.
14
15
  * - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
15
16
  * - Use the `--sidebar-layout-width` and `--sidebar-layout-bg` custom properties to override defaults.
16
17
  */
@@ -22,8 +23,9 @@ export function SidebarLayout({ sidebar, children, right = false }) {
22
23
  if (href)
23
24
  setOpen(false);
24
25
  }, [href]);
25
- const sidebarEl = (_jsxs("nav", { className: getClass(SIDEBAR_LAYOUT_CSS.sidebar, open && SIDEBAR_LAYOUT_CSS.open), children: [_jsx("div", { className: SIDEBAR_LAYOUT_CSS.close, children: _jsx(Button, { plain: true, fit: true, title: "Close menu", onClick: () => setOpen(false), children: _jsx(XMarkIcon, {}) }) }), sidebar] }, "sidebar"));
26
- const contentEl = (_jsxs("div", { className: getClass(LAYOUT_CSS.layout, SIDEBAR_LAYOUT_CSS.content), children: [_jsx("div", { className: SIDEBAR_LAYOUT_CSS.show, children: _jsx(Button, { plain: true, fit: true, title: "Show menu", onClick: () => setOpen(true), children: _jsx(Bars3Icon, {}) }) }), _jsx("div", { className: SIDEBAR_LAYOUT_CSS.contentInner, children: children })] }, "content"));
27
- return (_jsx("main", { className: getClass(SIDEBAR_LAYOUT_CSS.main, LAYOUT_CSS.layout), children: right ? [contentEl, sidebarEl] : [sidebarEl, contentEl] }));
26
+ const sidebarEl = (_jsx("nav", { className: getClass(SIDEBAR_LAYOUT_CSS.sidebar, open && SIDEBAR_LAYOUT_CSS.open), children: sidebar }, "sidebar"));
27
+ const contentEl = (_jsxs("div", { className: getClass(LAYOUT_CSS.layout, SIDEBAR_LAYOUT_CSS.content), children: [_jsx("div", { className: SIDEBAR_LAYOUT_CSS.toggle, children: _jsx(Button, { fit: true, cyan: !open, orange: open, plain: true, title: open ? "Close menu" : "Show menu", onClick: () => setOpen(o => !o), children: open ? _jsx(XMarkIcon, {}) : _jsx(Bars3Icon, {}) }) }), _jsx("div", { className: SIDEBAR_LAYOUT_CSS.contentInner, children: children })] }, "content"));
28
+ const overlayEl = open && (_jsx("button", { type: "button", className: SIDEBAR_LAYOUT_CSS.overlay, "aria-label": "Close menu", onClick: () => setOpen(false) }, "overlay"));
29
+ return (_jsx("main", { className: getClass(SIDEBAR_LAYOUT_CSS.main, LAYOUT_CSS.layout), children: right ? [contentEl, sidebarEl, overlayEl] : [sidebarEl, contentEl, overlayEl] }));
28
30
  }
29
31
  export { SIDEBAR_LAYOUT_CSS };
@@ -7,7 +7,8 @@
7
7
  * layout padding, safe-area insets, and `overflow: hidden auto` scroll behaviour.
8
8
  *
9
9
  * On narrow viewports the sidebar becomes an off-canvas drawer that slides off the left edge of the
10
- * screen; the `.show` / `.close` buttons toggle it (both are hidden entirely on wide viewports).
10
+ * screen; the `.toggle` button opens/closes it and the `.overlay` dims the page behind the open
11
+ * drawer (both are hidden entirely on wide viewports).
11
12
  */
12
13
 
13
14
  .main {
@@ -37,16 +38,25 @@
37
38
  margin: 0 auto;
38
39
  }
39
40
 
40
- /* Wrappers for the menu toggle buttons — hidden on wide viewports, shown on narrow ones (see media query). */
41
- .show,
42
- .close {
41
+ /* Wrapper for the menu toggle button — hidden on wide viewports, shown on narrow ones (see media query). */
42
+ .toggle {
43
43
  display: none;
44
- margin-bottom: var(--space-xsmall);
44
+ width: fit-content;
45
+ margin: 0 0 0 auto;
45
46
  }
46
47
 
47
- /* The close button sits at the top of the sidebar, aligned to its trailing edge. */
48
- .close {
49
- justify-content: flex-end;
48
+ /* Full-page dimmer behind the open drawer hidden on wide viewports. */
49
+ .overlay {
50
+ display: none;
51
+ }
52
+
53
+ @keyframes overlay-fade-in {
54
+ from {
55
+ opacity: 0;
56
+ }
57
+ to {
58
+ opacity: 1;
59
+ }
50
60
  }
51
61
 
52
62
  /* On narrow viewports the sidebar becomes an off-canvas drawer that slides in from the left. */
@@ -68,8 +78,24 @@
68
78
  transform: translateX(0);
69
79
  box-shadow: 0 0 1.5rem var(--color-overlay);
70
80
  }
71
- .show,
72
- .close {
73
- display: flex;
81
+ /* Pin the toggle button to the top-right so it stays reachable while the content column scrolls. */
82
+ .toggle {
83
+ display: block;
84
+ position: sticky;
85
+ top: 0;
86
+ z-index: 110;
87
+ }
88
+ /* Dim the page behind the open drawer; clicking the overlay closes it. */
89
+ .overlay {
90
+ display: block;
91
+ position: fixed;
92
+ inset: 0;
93
+ z-index: 90;
94
+ margin: 0;
95
+ padding: 0;
96
+ border: 0;
97
+ background: var(--color-overlay);
98
+ cursor: pointer;
99
+ animation: overlay-fade-in var(--duration-normal) ease-in-out;
74
100
  }
75
101
  }
@@ -19,7 +19,8 @@ export interface SidebarLayoutProps {
19
19
  /**
20
20
  * Layout with a fixed-width side column (typically navigation) next to a scrollable main content column.
21
21
  * - The sidebar is rendered as `<nav>` — it almost always contains the page's primary navigation.
22
- * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by the "show menu" / "close" buttons.
22
+ * - On narrow viewports the sidebar becomes an off-canvas drawer toggled by a single menu button that switches between a burger and a close icon.
23
+ * - While the drawer is open an overlay dims the rest of the page; clicking the overlay closes the drawer.
23
24
  * - Inside a `<Navigation>` the drawer closes itself whenever the route changes (e.g. tapping a sidebar link).
24
25
  * - Use the `--sidebar-layout-width` and `--sidebar-layout-bg` custom properties to override defaults.
25
26
  */
@@ -34,26 +35,26 @@ export function SidebarLayout({ sidebar, children, right = false }: SidebarLayou
34
35
 
35
36
  const sidebarEl = (
36
37
  <nav key="sidebar" className={getClass(SIDEBAR_LAYOUT_CSS.sidebar, open && SIDEBAR_LAYOUT_CSS.open)}>
37
- <div className={SIDEBAR_LAYOUT_CSS.close}>
38
- <Button plain fit title="Close menu" onClick={() => setOpen(false)}>
39
- <XMarkIcon />
40
- </Button>
41
- </div>
42
38
  {sidebar}
43
39
  </nav>
44
40
  );
45
41
  const contentEl = (
46
42
  <div key="content" className={getClass(LAYOUT_CSS.layout, SIDEBAR_LAYOUT_CSS.content)}>
47
- <div className={SIDEBAR_LAYOUT_CSS.show}>
48
- <Button plain fit title="Show menu" onClick={() => setOpen(true)}>
49
- <Bars3Icon />
43
+ <div className={SIDEBAR_LAYOUT_CSS.toggle}>
44
+ <Button fit cyan={!open} orange={open} plain title={open ? "Close menu" : "Show menu"} onClick={() => setOpen(o => !o)}>
45
+ {open ? <XMarkIcon /> : <Bars3Icon />}
50
46
  </Button>
51
47
  </div>
52
48
  <div className={SIDEBAR_LAYOUT_CSS.contentInner}>{children}</div>
53
49
  </div>
54
50
  );
51
+ const overlayEl = open && (
52
+ <button key="overlay" type="button" className={SIDEBAR_LAYOUT_CSS.overlay} aria-label="Close menu" onClick={() => setOpen(false)} />
53
+ );
55
54
  return (
56
- <main className={getClass(SIDEBAR_LAYOUT_CSS.main, LAYOUT_CSS.layout)}>{right ? [contentEl, sidebarEl] : [sidebarEl, contentEl]}</main>
55
+ <main className={getClass(SIDEBAR_LAYOUT_CSS.main, LAYOUT_CSS.layout)}>
56
+ {right ? [contentEl, sidebarEl, overlayEl] : [sidebarEl, contentEl, overlayEl]}
57
+ </main>
57
58
  );
58
59
  }
59
60
 
@@ -3,61 +3,91 @@
3
3
  --primary-text: var(--color-blue);
4
4
  --primary-contrast: var(--color-white);
5
5
  --primary-surface: color-mix(in srgb, var(--primary-text) 12%, white);
6
+ --primary-border: color-mix(in srgb, var(--primary-text) 40%, transparent);
6
7
 
7
8
  /* Secondary colors */
8
9
  --secondary-text: var(--color-purple);
9
10
  --secondary-contrast: var(--color-white);
10
11
  --secondary-surface: color-mix(in srgb, var(--secondary-text) 12%, white);
12
+ --secondary-border: color-mix(in srgb, var(--secondary-text) 40%, transparent);
11
13
 
12
14
  /* Tertiary colors */
13
15
  --tertiary-text: var(--color-cyan);
14
16
  --tertiary-contrast: var(--color-white);
15
17
  --tertiary-surface: color-mix(in srgb, var(--tertiary-text) 12%, white);
18
+ --tertiary-border: color-mix(in srgb, var(--tertiary-text) 40%, transparent);
16
19
 
17
20
  /* Quiet colors */
18
21
  --quiet-text: var(--color-quiet);
19
22
  --quiet-contrast: var(--color-contrast);
20
- --quiet-surface: var(--color-surface);
23
+ --quiet-surface: color-mix(in srgb, var(--quiet-text) 12%, white);
24
+ --quiet-border: color-mix(in srgb, var(--quiet-text) 40%, transparent);
25
+
26
+ /* Black */
27
+ --black-text: var(--color-black);
28
+ --black-contrast: var(--color-white);
29
+ --black-surface: color-mix(in srgb, var(--black-text) 12%, white);
30
+ --black-border: color-mix(in srgb, var(--black-text) 40%, transparent);
31
+
32
+ /* White */
33
+ --white-text: var(--color-white);
34
+ --white-contrast: var(--color-black);
35
+ --white-surface: color-mix(in srgb, var(--white-text) 12%, white);
36
+ --white-border: color-mix(in srgb, var(--white-text) 40%, transparent);
37
+
38
+ /* Gray */
39
+ --gray-text: var(--color-gray);
40
+ --gray-contrast: var(--color-white);
41
+ --gray-surface: color-mix(in srgb, var(--gray-text) 12%, white);
42
+ --gray-border: color-mix(in srgb, var(--gray-text) 40%, transparent);
21
43
 
22
44
  /* Red */
23
45
  --red-text: var(--color-red);
24
46
  --red-contrast: var(--color-white);
25
47
  --red-surface: color-mix(in srgb, var(--red-text) 12%, white);
48
+ --red-border: color-mix(in srgb, var(--red-text) 40%, transparent);
26
49
 
27
50
  /* Orange */
28
51
  --orange-text: var(--color-orange);
29
- --orange-contrast: var(--color-black);
52
+ --orange-contrast: var(--color-white);
30
53
  --orange-surface: color-mix(in srgb, var(--orange-text) 12%, white);
54
+ --orange-border: color-mix(in srgb, var(--orange-text) 40%, transparent);
31
55
 
32
56
  /* Yellow */
33
57
  --yellow-text: var(--color-yellow);
34
58
  --yellow-contrast: var(--color-black);
35
59
  --yellow-surface: color-mix(in srgb, var(--yellow-text) 12%, white);
60
+ --yellow-border: color-mix(in srgb, var(--yellow-text) 40%, transparent);
36
61
 
37
62
  /* Green */
38
63
  --green-text: var(--color-green);
39
64
  --green-contrast: var(--color-black);
40
65
  --green-surface: color-mix(in srgb, var(--green-text) 12%, white);
66
+ --green-border: color-mix(in srgb, var(--green-text) 40%, transparent);
41
67
 
42
68
  /* Cyan */
43
69
  --cyan-text: var(--color-cyan);
44
70
  --cyan-contrast: var(--color-black);
45
71
  --cyan-surface: color-mix(in srgb, var(--cyan-text) 12%, white);
72
+ --cyan-border: color-mix(in srgb, var(--cyan-text) 40%, transparent);
46
73
 
47
74
  /* Blue */
48
75
  --blue-text: var(--color-blue);
49
76
  --blue-contrast: var(--color-white);
50
77
  --blue-surface: color-mix(in srgb, var(--blue-text) 12%, white);
78
+ --blue-border: color-mix(in srgb, var(--blue-text) 40%, transparent);
51
79
 
52
80
  /* Purple */
53
81
  --purple-text: var(--color-purple);
54
82
  --purple-contrast: var(--color-white);
55
83
  --purple-surface: color-mix(in srgb, var(--purple-text) 12%, white);
84
+ --purple-border: color-mix(in srgb, var(--purple-text) 40%, transparent);
56
85
 
57
86
  /* Pink */
58
87
  --pink-text: var(--color-pink);
59
88
  --pink-contrast: var(--color-white);
60
89
  --pink-surface: color-mix(in srgb, var(--pink-text) 12%, white);
90
+ --pink-border: color-mix(in srgb, var(--pink-text) 40%, transparent);
61
91
  }
62
92
 
63
93
  .primary {
@@ -66,6 +96,7 @@
66
96
  --color-link: var(--primary-text);
67
97
  --color-quiet: var(--primary-text);
68
98
  --color-surface: var(--primary-surface);
99
+ --color-border: var(--primary-border);
69
100
  }
70
101
 
71
102
  .secondary {
@@ -74,6 +105,7 @@
74
105
  --color-link: var(--secondary-text);
75
106
  --color-quiet: var(--secondary-text);
76
107
  --color-surface: var(--secondary-surface);
108
+ --color-border: var(--secondary-border);
77
109
  }
78
110
 
79
111
  .tertiary {
@@ -82,6 +114,7 @@
82
114
  --color-link: var(--tertiary-text);
83
115
  --color-quiet: var(--tertiary-text);
84
116
  --color-surface: var(--tertiary-surface);
117
+ --color-border: var(--tertiary-border);
85
118
  }
86
119
 
87
120
  .quiet {
@@ -90,6 +123,7 @@
90
123
  --color-link: var(--quiet-text);
91
124
  --color-quiet: var(--quiet-text);
92
125
  --color-surface: var(--quiet-surface);
126
+ --color-border: var(--quiet-border);
93
127
  }
94
128
 
95
129
  .red {
@@ -98,6 +132,7 @@
98
132
  --color-link: var(--red-text);
99
133
  --color-quiet: var(--red-text);
100
134
  --color-surface: var(--red-surface);
135
+ --color-border: var(--red-border);
101
136
  }
102
137
 
103
138
  .orange {
@@ -106,6 +141,7 @@
106
141
  --color-link: var(--orange-text);
107
142
  --color-quiet: var(--orange-text);
108
143
  --color-surface: var(--orange-surface);
144
+ --color-border: var(--orange-border);
109
145
  }
110
146
 
111
147
  .yellow {
@@ -114,6 +150,7 @@
114
150
  --color-link: var(--yellow-text);
115
151
  --color-quiet: var(--yellow-text);
116
152
  --color-surface: var(--yellow-surface);
153
+ --color-border: var(--yellow-border);
117
154
  }
118
155
 
119
156
  .green {
@@ -122,6 +159,7 @@
122
159
  --color-link: var(--green-text);
123
160
  --color-quiet: var(--green-text);
124
161
  --color-surface: var(--green-surface);
162
+ --color-border: var(--green-border);
125
163
  }
126
164
 
127
165
  .cyan {
@@ -130,6 +168,7 @@
130
168
  --color-link: var(--cyan-text);
131
169
  --color-quiet: var(--cyan-text);
132
170
  --color-surface: var(--cyan-surface);
171
+ --color-border: var(--cyan-border);
133
172
  }
134
173
 
135
174
  .blue {
@@ -138,6 +177,7 @@
138
177
  --color-link: var(--blue-text);
139
178
  --color-quiet: var(--blue-text);
140
179
  --color-surface: var(--blue-surface);
180
+ --color-border: var(--blue-border);
141
181
  }
142
182
 
143
183
  .purple {
@@ -146,6 +186,7 @@
146
186
  --color-link: var(--purple-text);
147
187
  --color-quiet: var(--purple-text);
148
188
  --color-surface: var(--purple-surface);
189
+ --color-border: var(--purple-border);
149
190
  }
150
191
 
151
192
  .pink {
@@ -154,4 +195,5 @@
154
195
  --color-link: var(--pink-text);
155
196
  --color-quiet: var(--pink-text);
156
197
  --color-surface: var(--pink-surface);
198
+ --color-border: var(--pink-border);
157
199
  }