@claralight-design/abweb-navbar 0.1.4 → 0.2.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/NavHeader.module.css +41 -8
- package/NavHeader.tsx +84 -36
- package/package.json +1 -1
package/NavHeader.module.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
30
30
|
align-items: center;
|
|
31
31
|
overflow: hidden;
|
|
32
|
-
padding: 3px 6px;
|
|
32
|
+
padding: 3px 6px 6px calc(6px + var(--nav-header-left-padding, 0px));
|
|
33
33
|
border-radius: 48px;
|
|
34
34
|
gap: 12px;
|
|
35
35
|
transform: translateY(0);
|
|
@@ -41,12 +41,14 @@
|
|
|
41
41
|
corner-shape: unset;
|
|
42
42
|
will-change: transform;
|
|
43
43
|
box-sizing: border-box;
|
|
44
|
+
|
|
45
|
+
--backdrop-filter: blur(12px) saturate(1.05);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
.blurEffect {
|
|
47
49
|
position: absolute;
|
|
48
50
|
inset: -10px 0 auto;
|
|
49
|
-
height:
|
|
51
|
+
height: 72px;
|
|
50
52
|
width: 120vw;
|
|
51
53
|
z-index: 0;
|
|
52
54
|
pointer-events: none;
|
|
@@ -183,6 +185,12 @@
|
|
|
183
185
|
display: inline-flex;
|
|
184
186
|
}
|
|
185
187
|
|
|
188
|
+
.navCustomItem {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
min-height: 40px;
|
|
192
|
+
}
|
|
193
|
+
|
|
186
194
|
.navLink {
|
|
187
195
|
corner-shape: unset;
|
|
188
196
|
min-height: 40px;
|
|
@@ -190,7 +198,6 @@
|
|
|
190
198
|
border: none;
|
|
191
199
|
border-radius: 999px;
|
|
192
200
|
background: transparent;
|
|
193
|
-
color: color-mix(in srgb, var(--color-text) 72%, transparent);
|
|
194
201
|
display: inline-flex;
|
|
195
202
|
align-items: center;
|
|
196
203
|
justify-content: center;
|
|
@@ -203,22 +210,28 @@
|
|
|
203
210
|
font-family: inherit;
|
|
204
211
|
font-size: 15px;
|
|
205
212
|
font-weight: 600;
|
|
213
|
+
color: var(--color-text);
|
|
214
|
+
opacity: 0.7;
|
|
206
215
|
}
|
|
207
216
|
|
|
208
217
|
.navLink:hover,
|
|
209
218
|
.logotypeWrapper:hover {
|
|
210
219
|
background: color-mix(in srgb, var(--color-text) 8%, transparent);
|
|
211
|
-
|
|
220
|
+
opacity: 1;
|
|
221
|
+
backdrop-filter: var(--backdrop-filter);
|
|
212
222
|
}
|
|
213
223
|
|
|
214
224
|
.navLink:active,
|
|
215
225
|
.logotypeWrapper:active {
|
|
226
|
+
opacity: 0.55;
|
|
216
227
|
transform: scale(0.96);
|
|
217
228
|
}
|
|
218
229
|
|
|
219
230
|
.navLinkActive {
|
|
220
231
|
color: var(--color-text);
|
|
221
232
|
background: color-mix(in srgb, var(--color-text) 10%, transparent);
|
|
233
|
+
opacity: 0.8;
|
|
234
|
+
backdrop-filter: var(--backdrop-filter);
|
|
222
235
|
}
|
|
223
236
|
|
|
224
237
|
.desktopLabel {
|
|
@@ -228,8 +241,8 @@
|
|
|
228
241
|
font-weight: 600;
|
|
229
242
|
}
|
|
230
243
|
|
|
231
|
-
.desktopLabel svg {
|
|
232
|
-
max-height:
|
|
244
|
+
.desktopLabel svg.logotype, .desktopLabel :global(svg.logotype) {
|
|
245
|
+
max-height: 12px;
|
|
233
246
|
}
|
|
234
247
|
|
|
235
248
|
.mobileMenu {
|
|
@@ -322,7 +335,7 @@
|
|
|
322
335
|
justify-content: center;
|
|
323
336
|
min-height: 72px;
|
|
324
337
|
height: 72px;
|
|
325
|
-
padding: 11px
|
|
338
|
+
padding: 11px 28px 11px 0px;
|
|
326
339
|
border: none;
|
|
327
340
|
border-radius: calc(var(--radius-root) * 1.55);
|
|
328
341
|
background: transparent;
|
|
@@ -331,15 +344,23 @@
|
|
|
331
344
|
box-sizing: border-box;
|
|
332
345
|
gap: 12px;
|
|
333
346
|
user-select: none;
|
|
334
|
-
transition: background 0.2s ease-out, opacity 0.2s ease, transform 0.15s ease;
|
|
347
|
+
transition: background 0.2s ease-out, opacity 0.2s ease, transform 0.15s ease, padding 0.2s ease-in-out;
|
|
335
348
|
font-size: 30px;
|
|
336
349
|
font-weight: 600;
|
|
337
350
|
cursor: pointer;
|
|
338
351
|
font-family: inherit;
|
|
339
352
|
}
|
|
340
353
|
|
|
354
|
+
.menuCustomItem {
|
|
355
|
+
width: 100%;
|
|
356
|
+
display: inline-flex;
|
|
357
|
+
align-items: center;
|
|
358
|
+
justify-content: center;
|
|
359
|
+
}
|
|
360
|
+
|
|
341
361
|
.menuLink:hover {
|
|
342
362
|
color: var(--color-text);
|
|
363
|
+
padding: 11px 11px 11px 11px;
|
|
343
364
|
}
|
|
344
365
|
|
|
345
366
|
.menuItemMarker {
|
|
@@ -373,6 +394,14 @@
|
|
|
373
394
|
color: var(--color-text);
|
|
374
395
|
}
|
|
375
396
|
|
|
397
|
+
.dividingLine {
|
|
398
|
+
height: 12px;
|
|
399
|
+
width: 2px;
|
|
400
|
+
border-radius: 2px;
|
|
401
|
+
background-color: var(--color-text);
|
|
402
|
+
opacity: 0.4;
|
|
403
|
+
}
|
|
404
|
+
|
|
376
405
|
@media (min-width: 960px) {
|
|
377
406
|
.desktopNav {
|
|
378
407
|
display: flex;
|
|
@@ -409,6 +438,10 @@
|
|
|
409
438
|
justify-content: center;
|
|
410
439
|
width: 100%;
|
|
411
440
|
}
|
|
441
|
+
|
|
442
|
+
.dividingLine {
|
|
443
|
+
display: none;
|
|
444
|
+
}
|
|
412
445
|
}
|
|
413
446
|
|
|
414
447
|
@media (prefers-reduced-motion: reduce) {
|
package/NavHeader.tsx
CHANGED
|
@@ -15,6 +15,7 @@ export type NavHeaderItem = {
|
|
|
15
15
|
ariaLabel: string
|
|
16
16
|
href?: string
|
|
17
17
|
external?: boolean
|
|
18
|
+
hideInMobileMenu?: boolean
|
|
18
19
|
active?: boolean
|
|
19
20
|
matchPath?: string
|
|
20
21
|
onClick?: (
|
|
@@ -29,6 +30,7 @@ export type NavHeaderProps = {
|
|
|
29
30
|
variant?: 'default' | 'docs' | (string & {})
|
|
30
31
|
showHeaderBlur?: boolean
|
|
31
32
|
navItems?: NavHeaderItem[]
|
|
33
|
+
leftPadding?: number | string
|
|
32
34
|
leftSlot?: React.ReactNode
|
|
33
35
|
logo?: React.ReactNode
|
|
34
36
|
brandName?: string
|
|
@@ -94,6 +96,14 @@ const renderDesktopItem = (
|
|
|
94
96
|
)
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
if (!item.onClick) {
|
|
100
|
+
return (
|
|
101
|
+
<div className={styles.navCustomItem} aria-label={item.ariaLabel}>
|
|
102
|
+
{renderItemLabel(item)}
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
return (
|
|
98
108
|
<button
|
|
99
109
|
type='button'
|
|
@@ -118,7 +128,9 @@ const renderMobileItem = (
|
|
|
118
128
|
const content = (
|
|
119
129
|
<>
|
|
120
130
|
<span aria-hidden className={styles.menuItemMarker}>
|
|
121
|
-
/
|
|
131
|
+
<svg height="23" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
132
|
+
<path d="M2.21289 12H0.291016L5.73047 0H7.65234L2.21289 12Z" fill="white" fill-opacity="0.5" />
|
|
133
|
+
</svg>
|
|
122
134
|
</span>
|
|
123
135
|
<span className={styles.menuLabel}>{renderItemLabel(item)}</span>
|
|
124
136
|
</>
|
|
@@ -139,6 +151,14 @@ const renderMobileItem = (
|
|
|
139
151
|
)
|
|
140
152
|
}
|
|
141
153
|
|
|
154
|
+
if (!item.onClick) {
|
|
155
|
+
return (
|
|
156
|
+
<div className={styles.menuCustomItem} aria-label={item.ariaLabel}>
|
|
157
|
+
{renderItemLabel(item)}
|
|
158
|
+
</div>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
142
162
|
return (
|
|
143
163
|
<button
|
|
144
164
|
type='button'
|
|
@@ -156,6 +176,7 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
156
176
|
variant = 'default',
|
|
157
177
|
showHeaderBlur = true,
|
|
158
178
|
navItems = [],
|
|
179
|
+
leftPadding = 0,
|
|
159
180
|
leftSlot,
|
|
160
181
|
logo,
|
|
161
182
|
brandName = 'Brand',
|
|
@@ -167,8 +188,13 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
167
188
|
const [menuOpen, setMenuOpen] = useState(false)
|
|
168
189
|
|
|
169
190
|
const resolvedLabels = { ...DEFAULT_LABELS, ...labels }
|
|
170
|
-
const
|
|
191
|
+
const desktopNavItems = navItems
|
|
192
|
+
const mobileNavItems = navItems.filter((item) => !item.hideInMobileMenu)
|
|
193
|
+
const hasDesktopNavItems = desktopNavItems.length > 0
|
|
194
|
+
const hasMobileNavItems = mobileNavItems.length > 0
|
|
171
195
|
const resolvedLogoAriaLabel = logoAriaLabel ?? brandName
|
|
196
|
+
const resolvedLeftPadding =
|
|
197
|
+
typeof leftPadding === 'number' ? `${leftPadding}px` : leftPadding
|
|
172
198
|
|
|
173
199
|
const brandContent = logo ?? <span className={styles.brandName}>{brandName}</span>
|
|
174
200
|
|
|
@@ -179,8 +205,15 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
179
205
|
data-variant={variant}
|
|
180
206
|
>
|
|
181
207
|
{showHeaderBlur && <BlurEffect className={styles.blurEffect} position="top" intensity={100} aria-hidden />}
|
|
182
|
-
<header
|
|
183
|
-
{
|
|
208
|
+
<header
|
|
209
|
+
className={styles.inner}
|
|
210
|
+
style={
|
|
211
|
+
{
|
|
212
|
+
'--nav-header-left-padding': resolvedLeftPadding,
|
|
213
|
+
} as React.CSSProperties
|
|
214
|
+
}
|
|
215
|
+
>
|
|
216
|
+
{hasMobileNavItems && (
|
|
184
217
|
<div className={styles.mobileMenu}>
|
|
185
218
|
<Drawer.Root
|
|
186
219
|
open={menuOpen}
|
|
@@ -224,7 +257,7 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
224
257
|
className={styles.menuNav}
|
|
225
258
|
aria-label={resolvedLabels.menu}
|
|
226
259
|
>
|
|
227
|
-
{
|
|
260
|
+
{mobileNavItems.map((item) => {
|
|
228
261
|
const key =
|
|
229
262
|
item.id ??
|
|
230
263
|
item.href ??
|
|
@@ -241,14 +274,26 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
241
274
|
)
|
|
242
275
|
)
|
|
243
276
|
|
|
277
|
+
if (item.href || item.onClick) {
|
|
278
|
+
return (
|
|
279
|
+
<Drawer.Close asChild key={key}>
|
|
280
|
+
{renderMobileItem(
|
|
281
|
+
item,
|
|
282
|
+
styles.menuLink,
|
|
283
|
+
isActive
|
|
284
|
+
)}
|
|
285
|
+
</Drawer.Close>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
244
289
|
return (
|
|
245
|
-
<
|
|
290
|
+
<div key={key}>
|
|
246
291
|
{renderMobileItem(
|
|
247
292
|
item,
|
|
248
293
|
styles.menuLink,
|
|
249
294
|
isActive
|
|
250
295
|
)}
|
|
251
|
-
</
|
|
296
|
+
</div>
|
|
252
297
|
)
|
|
253
298
|
})}
|
|
254
299
|
</nav>
|
|
@@ -280,37 +325,40 @@ const NavHeader: React.FC<NavHeaderProps> = ({
|
|
|
280
325
|
</div>
|
|
281
326
|
</div>
|
|
282
327
|
|
|
283
|
-
{
|
|
284
|
-
|
|
285
|
-
className={styles.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
item.
|
|
293
|
-
|
|
294
|
-
item.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
328
|
+
{hasDesktopNavItems && (
|
|
329
|
+
<>
|
|
330
|
+
<span className={styles.dividingLine} />
|
|
331
|
+
<nav
|
|
332
|
+
className={styles.desktopNav}
|
|
333
|
+
aria-label={resolvedLabels.menu}
|
|
334
|
+
>
|
|
335
|
+
<div className={styles.navList}>
|
|
336
|
+
{desktopNavItems.map((item) => {
|
|
337
|
+
const key = item.id ?? item.href ?? item.ariaLabel
|
|
338
|
+
const isActive =
|
|
339
|
+
item.active ??
|
|
340
|
+
Boolean(
|
|
341
|
+
item.href &&
|
|
342
|
+
!item.external &&
|
|
343
|
+
isMenuItemActive(
|
|
344
|
+
currentPath,
|
|
345
|
+
item.matchPath ?? item.href
|
|
346
|
+
)
|
|
299
347
|
)
|
|
300
|
-
)
|
|
301
348
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
349
|
+
return (
|
|
350
|
+
<div className={styles.navItem} key={key}>
|
|
351
|
+
{renderDesktopItem(
|
|
352
|
+
item,
|
|
353
|
+
styles.navLink,
|
|
354
|
+
isActive
|
|
355
|
+
)}
|
|
356
|
+
</div>
|
|
357
|
+
)
|
|
358
|
+
})}
|
|
359
|
+
</div>
|
|
360
|
+
</nav>
|
|
361
|
+
</>
|
|
314
362
|
)}
|
|
315
363
|
</div>
|
|
316
364
|
</header>
|