ab-nextjs-components 0.1.5 → 0.1.7
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/CHANGELOG.md +10 -0
- package/README.md +9 -0
- package/ab-logo/ab-logo.svg +1 -0
- package/ab-logo/index.tsx +9 -7
- package/ab-menu/index.tsx +10 -7
- package/ab-menu/styles.module.css +5 -0
- package/ab-navbar/index.tsx +1 -1
- package/ab-sidebar/index.tsx +2 -2
- package/package.json +3 -2
- package/server/ab-logo/ab-logo.svg +1 -0
- package/server/ab-logo/index.tsx +9 -7
- package/server/ab-navbar/index.tsx +1 -1
- package/server/ab-sidebar/index.tsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 0.1.7 — 2026-10-05
|
|
2
|
+
|
|
3
|
+
- **AbNavbar:** root `<nav>` sets `data-ab-part="bottomBar"` (client + server)
|
|
4
|
+
|
|
5
|
+
## 0.1.6 — 2026-10-05
|
|
6
|
+
|
|
7
|
+
- **AbSidebar:** renders `<nav data-ab-part="sidebar">` (was `<aside>`) so aside dialogs/menus never hit the sidebar
|
|
8
|
+
- **AbMenu:** sets `data-id={id}` (keeps `id`) and `data-id` / `menu-item` on items so `useAbMenu` can open it; cancel is `li[role=close-menu]`
|
|
9
|
+
- **AbLogo:** ships `ab-logo/ab-logo.svg` and defaults `src` to an inlined data URI of that asset; mask types without `src`/`mask` defer to `ab-nextjs-theme` `--app-logo-url`
|
|
10
|
+
|
|
1
11
|
## 0.1.5 — 2026-10-03
|
|
2
12
|
|
|
3
13
|
- Publish to npm automatically from GitHub Actions with Trusted Publishing (OIDC + provenance, no NPM_TOKEN)
|
package/README.md
CHANGED
|
@@ -44,6 +44,15 @@
|
|
|
44
44
|
- Package ships as TypeScript (`type: module`) with a `supportedComponents` catalog
|
|
45
45
|
- Phase 2 Adapt complete; Phase 4 + Skip-override (Phase 5 components) complete (local)
|
|
46
46
|
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Sidebar, menu & logo (0.1.6)
|
|
50
|
+
|
|
51
|
+
* `<AbSidebar>` is a **`<nav data-ab-part="sidebar">`** (not `<aside>`). Pair with `ab-nextjs-core@^0.1.4` + `ab-nextjs-hooks@^0.1.4` so aside dialogs target `aside.AbAsideLayout`.
|
|
52
|
+
* `<AbMenu id>` also sets **`data-id`**, so `useAbMenu` can find it.
|
|
53
|
+
* `<AbLogo>` defaults to the Ab logo **shipped in this package** (data URI / `ab-logo/ab-logo.svg`). Pass `src` to override.
|
|
54
|
+
|
|
55
|
+
|
|
47
56
|
## Getting Started
|
|
48
57
|
|
|
49
58
|
### Installation
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 24 24"><path fill="#A67C52" d="m1.8 20.5 9.3-17v17zM22.2 7.7l-9.3-4.2v17l9.3-4.2-4.7-4.3z"/><path d="m12.9 20.5 9.3-4.2-9.3-8.6z" opacity=".1"/></svg>
|
package/ab-logo/index.tsx
CHANGED
|
@@ -40,7 +40,7 @@ export type AbLogoType = 'contained' | 'outlined' | 'hollow' | 'naked';
|
|
|
40
40
|
export interface AbLogoProps {
|
|
41
41
|
type?: AbLogoType;
|
|
42
42
|
className?: string;
|
|
43
|
-
/** Optional image src (contained). Defaults to
|
|
43
|
+
/** Optional image src (contained). Defaults to the Ab logo shipped in this package (data URI). */
|
|
44
44
|
src?: string;
|
|
45
45
|
/** Optional CSS mask value for outlined/hollow/naked. */
|
|
46
46
|
mask?: string;
|
|
@@ -48,7 +48,8 @@ export interface AbLogoProps {
|
|
|
48
48
|
size?: number | string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
/** Inlined Ab logo shipped with this package (also at `ab-logo/ab-logo.svg`). */
|
|
52
|
+
const DEFAULT_SRC = 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xml%3Aspace%3D%22preserve%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23A67C52%22%20d%3D%22m1.8%2020.5%209.3-17v17zM22.2%207.7l-9.3-4.2v17l9.3-4.2-4.7-4.3z%22/%3E%3Cpath%20d%3D%22m12.9%2020.5%209.3-4.2-9.3-8.6z%22%20opacity%3D%22.1%22/%3E%3C/svg%3E';
|
|
52
53
|
|
|
53
54
|
const AbLogo = ({
|
|
54
55
|
type = 'naked',
|
|
@@ -72,7 +73,9 @@ const AbLogo = ({
|
|
|
72
73
|
);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
// With no `mask`/`src`, leave the mask to `ab-nextjs-theme` (`--app-logo-url` / `.app-logo`).
|
|
77
|
+
// When `mask` or `src` is set, apply it inline (src becomes a CSS mask url).
|
|
78
|
+
const maskValue = mask ?? (src ? `url('${src}') no-repeat 50% 50%` : undefined);
|
|
76
79
|
return (
|
|
77
80
|
<span
|
|
78
81
|
className={clsx('AbLogo', 'app-logo', styles.abLogo, className)}
|
|
@@ -81,10 +84,9 @@ const AbLogo = ({
|
|
|
81
84
|
aria-label={alt}
|
|
82
85
|
style={{
|
|
83
86
|
...(dim ? { width: dim, height: dim } : {}),
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
maskSize: 'cover',
|
|
87
|
+
...(maskValue
|
|
88
|
+
? { WebkitMask: maskValue, mask: maskValue, WebkitMaskSize: 'cover', maskSize: 'cover' }
|
|
89
|
+
: {}),
|
|
88
90
|
}}
|
|
89
91
|
/>
|
|
90
92
|
);
|
package/ab-menu/index.tsx
CHANGED
|
@@ -60,6 +60,7 @@ const AbMenu = forwardRef<HTMLMenuElement, AbMenuProps>(function AbMenu(
|
|
|
60
60
|
<menu
|
|
61
61
|
ref={ref}
|
|
62
62
|
id={id}
|
|
63
|
+
data-id={id}
|
|
63
64
|
hidden={hidden}
|
|
64
65
|
data-active={isActive ? 'true' : 'false'}
|
|
65
66
|
className={clsx('AbMenu', styles.abMenu, isActive && styles.isActive, className)}
|
|
@@ -85,7 +86,7 @@ const AbMenu = forwardRef<HTMLMenuElement, AbMenuProps>(function AbMenu(
|
|
|
85
86
|
);
|
|
86
87
|
if (item.href && !item.disabled) {
|
|
87
88
|
return (
|
|
88
|
-
<li key={item.id} className={itemClass} data-action={item.action}>
|
|
89
|
+
<li key={item.id} className={clsx('menu-item', itemClass)} data-id={item.id} data-action={item.action}>
|
|
89
90
|
<Link href={item.href} className={styles.abMenuLink} onClick={item.onClick}>
|
|
90
91
|
{body}
|
|
91
92
|
</Link>
|
|
@@ -93,7 +94,7 @@ const AbMenu = forwardRef<HTMLMenuElement, AbMenuProps>(function AbMenu(
|
|
|
93
94
|
);
|
|
94
95
|
}
|
|
95
96
|
return (
|
|
96
|
-
<li key={item.id} className={itemClass} data-action={item.action}>
|
|
97
|
+
<li key={item.id} className={clsx('menu-item', itemClass)} data-id={item.id} data-action={item.action}>
|
|
97
98
|
<button
|
|
98
99
|
type="button"
|
|
99
100
|
className={styles.abMenuButton}
|
|
@@ -105,12 +106,14 @@ const AbMenu = forwardRef<HTMLMenuElement, AbMenuProps>(function AbMenu(
|
|
|
105
106
|
</li>
|
|
106
107
|
);
|
|
107
108
|
})}
|
|
109
|
+
{isCancelable ? (
|
|
110
|
+
<li role="close-menu" className={styles.abMenuCancelItem}>
|
|
111
|
+
<button type="button" className={styles.abMenuCancel} onClick={onCancel}>
|
|
112
|
+
{cancelLabel}
|
|
113
|
+
</button>
|
|
114
|
+
</li>
|
|
115
|
+
) : null}
|
|
108
116
|
</ul>
|
|
109
|
-
{isCancelable ? (
|
|
110
|
-
<button type="button" className={styles.abMenuCancel} onClick={onCancel}>
|
|
111
|
-
{cancelLabel}
|
|
112
|
-
</button>
|
|
113
|
-
) : null}
|
|
114
117
|
</menu>
|
|
115
118
|
);
|
|
116
119
|
});
|
package/ab-navbar/index.tsx
CHANGED
|
@@ -40,7 +40,7 @@ const AbNavbar = ({
|
|
|
40
40
|
}: AbNavbarProps): ReactElement => {
|
|
41
41
|
const pathname = usePathname() ?? '';
|
|
42
42
|
return (
|
|
43
|
-
<nav data-type={type} className={clsx('AbNavbar', styles.abNavbar, className)} aria-label="Primary">
|
|
43
|
+
<nav data-type={type} data-ab-part="bottomBar" className={clsx('AbNavbar', styles.abNavbar, className)} aria-label="Primary">
|
|
44
44
|
<ul className={styles.abNavbarList}>
|
|
45
45
|
{links.map((link) => {
|
|
46
46
|
const active = page ? page === link.value : pathname === link.href || pathname.startsWith(`${link.href}/`);
|
package/ab-sidebar/index.tsx
CHANGED
|
@@ -44,7 +44,7 @@ const AbSidebar = ({
|
|
|
44
44
|
}: AbSidebarProps): ReactElement => {
|
|
45
45
|
const pathname = usePathname() ?? '';
|
|
46
46
|
return (
|
|
47
|
-
<
|
|
47
|
+
<nav data-type={type} data-ab-part="sidebar" className={clsx('AbSidebar', styles.abSidebar, className)} aria-label="Sidebar">
|
|
48
48
|
<Link href={brandHref} className={styles.abSidebarBrand}>
|
|
49
49
|
<span className="material-symbols-rounded" aria-hidden>apps</span>
|
|
50
50
|
<span>{brandLabel}</span>
|
|
@@ -64,7 +64,7 @@ const AbSidebar = ({
|
|
|
64
64
|
);
|
|
65
65
|
})}
|
|
66
66
|
</ul>
|
|
67
|
-
</
|
|
67
|
+
</nav>
|
|
68
68
|
);
|
|
69
69
|
};
|
|
70
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ab-nextjs-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "\ud83d\ude80 A lightweight collection of server & client React components created by Abraham Ukachi, and optimized for Next.js applications \ud83d\ude0e.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -101,7 +101,8 @@
|
|
|
101
101
|
"ab-product-item",
|
|
102
102
|
"ab-switch-back",
|
|
103
103
|
"ab-demo-box",
|
|
104
|
-
"ab-demo-code"
|
|
104
|
+
"ab-demo-code",
|
|
105
|
+
"ab-logo/ab-logo.svg"
|
|
105
106
|
],
|
|
106
107
|
"exports": {
|
|
107
108
|
".": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 24 24"><path fill="#A67C52" d="m1.8 20.5 9.3-17v17zM22.2 7.7l-9.3-4.2v17l9.3-4.2-4.7-4.3z"/><path d="m12.9 20.5 9.3-4.2-9.3-8.6z" opacity=".1"/></svg>
|
package/server/ab-logo/index.tsx
CHANGED
|
@@ -39,7 +39,7 @@ export type AbLogoType = 'contained' | 'outlined' | 'hollow' | 'naked';
|
|
|
39
39
|
export interface AbLogoProps {
|
|
40
40
|
type?: AbLogoType;
|
|
41
41
|
className?: string;
|
|
42
|
-
/** Optional image src (contained). Defaults to
|
|
42
|
+
/** Optional image src (contained). Defaults to the Ab logo shipped in this package (data URI). */
|
|
43
43
|
src?: string;
|
|
44
44
|
/** Optional CSS mask value for outlined/hollow/naked. */
|
|
45
45
|
mask?: string;
|
|
@@ -47,7 +47,8 @@ export interface AbLogoProps {
|
|
|
47
47
|
size?: number | string;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
/** Inlined Ab logo shipped with this package (also at `ab-logo/ab-logo.svg`). */
|
|
51
|
+
const DEFAULT_SRC = 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xml%3Aspace%3D%22preserve%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23A67C52%22%20d%3D%22m1.8%2020.5%209.3-17v17zM22.2%207.7l-9.3-4.2v17l9.3-4.2-4.7-4.3z%22/%3E%3Cpath%20d%3D%22m12.9%2020.5%209.3-4.2-9.3-8.6z%22%20opacity%3D%22.1%22/%3E%3C/svg%3E';
|
|
51
52
|
|
|
52
53
|
const AbLogo = ({
|
|
53
54
|
type = 'naked',
|
|
@@ -71,7 +72,9 @@ const AbLogo = ({
|
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
// With no `mask`/`src`, leave the mask to `ab-nextjs-theme` (`--app-logo-url` / `.app-logo`).
|
|
76
|
+
// When `mask` or `src` is set, apply it inline (src becomes a CSS mask url).
|
|
77
|
+
const maskValue = mask ?? (src ? `url('${src}') no-repeat 50% 50%` : undefined);
|
|
75
78
|
return (
|
|
76
79
|
<span
|
|
77
80
|
className={clsx('AbLogo', 'app-logo', styles.abLogo, className)}
|
|
@@ -80,10 +83,9 @@ const AbLogo = ({
|
|
|
80
83
|
aria-label={alt}
|
|
81
84
|
style={{
|
|
82
85
|
...(dim ? { width: dim, height: dim } : {}),
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
maskSize: 'cover',
|
|
86
|
+
...(maskValue
|
|
87
|
+
? { WebkitMask: maskValue, mask: maskValue, WebkitMaskSize: 'cover', maskSize: 'cover' }
|
|
88
|
+
: {}),
|
|
87
89
|
}}
|
|
88
90
|
/>
|
|
89
91
|
);
|
|
@@ -36,7 +36,7 @@ const AbNavbar = ({
|
|
|
36
36
|
links = [],
|
|
37
37
|
}: AbNavbarProps): ReactElement => {
|
|
38
38
|
return (
|
|
39
|
-
<nav data-type={type} className={clsx('AbNavbar', styles.abNavbar, className)} aria-label="Primary">
|
|
39
|
+
<nav data-type={type} data-ab-part="bottomBar" className={clsx('AbNavbar', styles.abNavbar, className)} aria-label="Primary">
|
|
40
40
|
<ul className={styles.abNavbarList}>
|
|
41
41
|
{links.map((link) => {
|
|
42
42
|
const active = page === link.value;
|
|
@@ -40,7 +40,7 @@ const AbSidebar = ({
|
|
|
40
40
|
brandLabel = 'abElements',
|
|
41
41
|
}: AbSidebarProps): ReactElement => {
|
|
42
42
|
return (
|
|
43
|
-
<
|
|
43
|
+
<nav data-type={type} data-ab-part="sidebar" className={clsx('AbSidebar', styles.abSidebar, className)} aria-label="Sidebar">
|
|
44
44
|
<Link href={brandHref} className={styles.abSidebarBrand}>
|
|
45
45
|
<span className="material-symbols-rounded" aria-hidden>apps</span>
|
|
46
46
|
<span>{brandLabel}</span>
|
|
@@ -60,7 +60,7 @@ const AbSidebar = ({
|
|
|
60
60
|
);
|
|
61
61
|
})}
|
|
62
62
|
</ul>
|
|
63
|
-
</
|
|
63
|
+
</nav>
|
|
64
64
|
);
|
|
65
65
|
};
|
|
66
66
|
|