ab-nextjs-components 0.1.5 → 0.1.6

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.1.6 — 2026-10-05
2
+
3
+ - **AbSidebar:** renders `<nav data-ab-part="sidebar">` (was `<aside>`) so aside dialogs/menus never hit the sidebar
4
+ - **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]`
5
+ - **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`
6
+
1
7
  ## 0.1.5 — 2026-10-03
2
8
 
3
9
  - 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 ab-nextjs-icons Ab logo. */
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
- const DEFAULT_SRC = '/ab-nextjs-icons/logos/ab-logo.svg';
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
- const maskValue = mask ?? `url('${DEFAULT_SRC}') no-repeat 50% 50%`;
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
- WebkitMask: maskValue,
85
- mask: maskValue,
86
- WebkitMaskSize: 'cover',
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
  });
@@ -97,3 +97,8 @@
97
97
  font-weight: 600;
98
98
  cursor: pointer;
99
99
  }
100
+
101
+ .abMenuCancelItem {
102
+ list-style: none;
103
+ width: 100%;
104
+ }
@@ -44,7 +44,7 @@ const AbSidebar = ({
44
44
  }: AbSidebarProps): ReactElement => {
45
45
  const pathname = usePathname() ?? '';
46
46
  return (
47
- <aside data-type={type} className={clsx('AbSidebar', styles.abSidebar, className)} aria-label="Sidebar">
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
- </aside>
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.5",
3
+ "version": "0.1.6",
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>
@@ -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 ab-nextjs-icons Ab logo. */
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
- const DEFAULT_SRC = '/ab-nextjs-icons/logos/ab-logo.svg';
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
- const maskValue = mask ?? `url('${DEFAULT_SRC}') no-repeat 50% 50%`;
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
- WebkitMask: maskValue,
84
- mask: maskValue,
85
- WebkitMaskSize: 'cover',
86
- maskSize: 'cover',
86
+ ...(maskValue
87
+ ? { WebkitMask: maskValue, mask: maskValue, WebkitMaskSize: 'cover', maskSize: 'cover' }
88
+ : {}),
87
89
  }}
88
90
  />
89
91
  );
@@ -40,7 +40,7 @@ const AbSidebar = ({
40
40
  brandLabel = 'abElements',
41
41
  }: AbSidebarProps): ReactElement => {
42
42
  return (
43
- <aside data-type={type} className={clsx('AbSidebar', styles.abSidebar, className)} aria-label="Sidebar">
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
- </aside>
63
+ </nav>
64
64
  );
65
65
  };
66
66