@duskmoon-dev/el-bottom-navigation 0.5.0 → 0.7.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/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @duskmoon-dev/el-bottom-navigation
2
+
3
+ A mobile bottom navigation component built with Web Components.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @duskmoon-dev/el-bottom-navigation
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Auto-Register
14
+
15
+ ```typescript
16
+ import '@duskmoon-dev/el-bottom-navigation/register';
17
+ ```
18
+
19
+ ```html
20
+ <el-dm-bottom-navigation value="home"></el-dm-bottom-navigation>
21
+ ```
22
+
23
+ ### Manual Registration
24
+
25
+ ```typescript
26
+ import { ElDmBottomNavigation, register } from '@duskmoon-dev/el-bottom-navigation';
27
+
28
+ // Register with default tag name
29
+ register();
30
+
31
+ // Or register with custom tag name
32
+ customElements.define('my-bottom-nav', ElDmBottomNavigation);
33
+ ```
34
+
35
+ ### Setting Items via JavaScript
36
+
37
+ ```javascript
38
+ const nav = document.querySelector('el-dm-bottom-navigation');
39
+ nav.items = [
40
+ { value: 'home', label: 'Home', icon: '🏠' },
41
+ { value: 'search', label: 'Search', icon: '🔍' },
42
+ { value: 'favorites', label: 'Favorites', icon: '⭐' },
43
+ { value: 'profile', label: 'Profile', icon: '👤' },
44
+ ];
45
+ ```
46
+
47
+ ## Attributes
48
+
49
+ | Attribute | Type | Default | Description |
50
+ |-----------|------|---------|-------------|
51
+ | `value` | `string` | - | Currently selected item value |
52
+ | `color` | `string` | `'primary'` | Color variant |
53
+
54
+ ## CSS Parts
55
+
56
+ | Part | Description |
57
+ |------|-------------|
58
+ | `container` | The navigation container |
59
+ | `item` | Each navigation item |
60
+ | `icon` | The item icon |
61
+ | `label` | The item label |
62
+
63
+ ## Events
64
+
65
+ | Event | Detail | Description |
66
+ |-------|--------|-------------|
67
+ | `change` | `{ value, item }` | Fired when selection changes |
68
+
69
+ ## Examples
70
+
71
+ ### Basic
72
+
73
+ ```html
74
+ <el-dm-bottom-navigation id="nav" value="home"></el-dm-bottom-navigation>
75
+ <script>
76
+ document.querySelector('#nav').items = [
77
+ { value: 'home', label: 'Home', icon: '🏠' },
78
+ { value: 'explore', label: 'Explore', icon: '🧭' },
79
+ { value: 'cart', label: 'Cart', icon: '🛒' },
80
+ { value: 'account', label: 'Account', icon: '👤' },
81
+ ];
82
+ </script>
83
+ ```
84
+
85
+ ### With SVG Icons
86
+
87
+ ```javascript
88
+ nav.items = [
89
+ {
90
+ value: 'home',
91
+ label: 'Home',
92
+ icon: '<svg>...</svg>'
93
+ },
94
+ // ...
95
+ ];
96
+ ```
97
+
98
+ ### Handling Selection
99
+
100
+ ```javascript
101
+ const nav = document.querySelector('el-dm-bottom-navigation');
102
+ nav.addEventListener('change', (e) => {
103
+ console.log('Selected:', e.detail.value);
104
+ // Navigate to the selected section
105
+ navigateTo(e.detail.value);
106
+ });
107
+ ```
108
+
109
+ ### With Badge
110
+
111
+ ```javascript
112
+ nav.items = [
113
+ { value: 'home', label: 'Home', icon: '🏠' },
114
+ { value: 'notifications', label: 'Notifications', icon: '🔔', badge: 5 },
115
+ { value: 'messages', label: 'Messages', icon: '💬', badge: 'new' },
116
+ ];
117
+ ```
118
+
119
+ ### Fixed to Bottom
120
+
121
+ ```css
122
+ el-dm-bottom-navigation {
123
+ position: fixed;
124
+ bottom: 0;
125
+ left: 0;
126
+ right: 0;
127
+ }
128
+ ```
129
+
130
+ ## License
131
+
132
+ MIT
package/dist/cjs/index.js CHANGED
@@ -35,8 +35,10 @@ __export(exports_src, {
35
35
  module.exports = __toCommonJS(exports_src);
36
36
 
37
37
  // src/el-dm-bottom-navigation.ts
38
- var import_el_core = require("@duskmoon-dev/el-core");
39
- var styles = import_el_core.css`
38
+ var import_el_base = require("@duskmoon-dev/el-base");
39
+ var import_bottom_navigation = require("@duskmoon-dev/core/components/bottom-navigation");
40
+ var coreStyles = import_bottom_navigation.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
41
+ var styles = import_el_base.css`
40
42
  :host {
41
43
  --bottom-nav-height: 56px;
42
44
  --bottom-nav-bg: var(--color-surface, #ffffff);
@@ -67,36 +69,27 @@ var styles = import_el_core.css`
67
69
  position: sticky;
68
70
  }
69
71
 
72
+ /* Import core bottom-navigation styles */
73
+ ${coreStyles}
74
+
75
+ /* Override core's fixed positioning — :host handles it */
70
76
  .bottom-nav {
71
- display: flex;
72
- align-items: center;
73
- justify-content: space-around;
77
+ position: static;
74
78
  height: var(--bottom-nav-height);
79
+ min-height: auto;
75
80
  background: var(--bottom-nav-bg);
76
81
  border-top: 1px solid var(--bottom-nav-border);
77
82
  box-shadow: var(--bottom-nav-shadow);
78
- padding: 0;
79
- margin: 0;
80
- /* Safe area for iOS devices */
81
- padding-bottom: env(safe-area-inset-bottom, 0);
82
83
  }
83
84
 
84
- .nav-item {
85
- flex: 1;
86
- display: flex;
87
- flex-direction: column;
88
- align-items: center;
89
- justify-content: center;
85
+ /* Override core item styles with our custom properties */
86
+ .bottom-nav-item {
90
87
  gap: 2px;
91
88
  padding: 6px 12px;
92
89
  min-width: 0;
93
90
  max-width: 168px;
94
91
  height: 100%;
95
- background: transparent;
96
- border: none;
97
- cursor: pointer;
98
92
  color: var(--bottom-nav-text);
99
- text-decoration: none;
100
93
  transition:
101
94
  color 0.2s ease,
102
95
  transform 0.1s ease;
@@ -104,32 +97,32 @@ var styles = import_el_core.css`
104
97
  user-select: none;
105
98
  }
106
99
 
107
- .nav-item:focus {
100
+ .bottom-nav-item:focus {
108
101
  outline: none;
109
102
  }
110
103
 
111
- .nav-item:focus-visible {
104
+ .bottom-nav-item:focus-visible {
112
105
  outline: 2px solid var(--bottom-nav-text-active);
113
106
  outline-offset: -2px;
114
107
  border-radius: 4px;
115
108
  }
116
109
 
117
- .nav-item:active:not([disabled]) {
110
+ .bottom-nav-item:active:not([disabled]) {
118
111
  transform: scale(0.95);
119
112
  }
120
113
 
121
- .nav-item[aria-selected='true'],
122
- .nav-item.active {
114
+ .bottom-nav-item[aria-selected='true'],
115
+ .bottom-nav-item.active {
123
116
  color: var(--bottom-nav-text-active);
124
117
  }
125
118
 
126
- .nav-item[disabled] {
119
+ .bottom-nav-item[disabled] {
127
120
  opacity: 0.5;
128
121
  cursor: not-allowed;
129
122
  pointer-events: none;
130
123
  }
131
124
 
132
- .nav-icon {
125
+ .bottom-nav-icon {
133
126
  display: flex;
134
127
  align-items: center;
135
128
  justify-content: center;
@@ -138,14 +131,14 @@ var styles = import_el_core.css`
138
131
  flex-shrink: 0;
139
132
  }
140
133
 
141
- .nav-icon ::slotted(*),
142
- .nav-icon svg,
143
- .nav-icon img {
134
+ .bottom-nav-icon ::slotted(*),
135
+ .bottom-nav-icon svg,
136
+ .bottom-nav-icon img {
144
137
  width: 100%;
145
138
  height: 100%;
146
139
  }
147
140
 
148
- .nav-label {
141
+ .bottom-nav-label {
149
142
  font-size: var(--bottom-nav-label-size);
150
143
  font-weight: 500;
151
144
  line-height: 1.2;
@@ -157,11 +150,11 @@ var styles = import_el_core.css`
157
150
 
158
151
  /* Hide labels on very small screens */
159
152
  @media (max-width: 320px) {
160
- .nav-label {
153
+ .bottom-nav-label {
161
154
  display: none;
162
155
  }
163
156
 
164
- .nav-icon {
157
+ .bottom-nav-icon {
165
158
  width: 28px;
166
159
  height: 28px;
167
160
  }
@@ -185,7 +178,7 @@ var styles = import_el_core.css`
185
178
  }
186
179
 
187
180
  /* Badge indicator for items */
188
- .nav-item-badge {
181
+ .bottom-nav-badge {
189
182
  position: absolute;
190
183
  top: 4px;
191
184
  right: calc(50% - 18px);
@@ -195,7 +188,7 @@ var styles = import_el_core.css`
195
188
  border-radius: 50%;
196
189
  }
197
190
 
198
- .nav-item-wrapper {
191
+ .bottom-nav-item-wrapper {
199
192
  position: relative;
200
193
  flex: 1;
201
194
  display: flex;
@@ -209,12 +202,13 @@ var styles = import_el_core.css`
209
202
  }
210
203
  `;
211
204
 
212
- class ElDmBottomNavigation extends import_el_core.BaseElement {
205
+ class ElDmBottomNavigation extends import_el_base.BaseElement {
213
206
  static properties = {
214
207
  items: { type: Array, reflect: false, default: [] },
215
208
  value: { type: String, reflect: true },
216
209
  color: { type: String, reflect: true, default: "primary" },
217
- position: { type: String, reflect: true, default: "fixed" }
210
+ position: { type: String, reflect: true, default: "fixed" },
211
+ navLabel: { type: String, reflect: true, attribute: "nav-label", default: "Bottom navigation" }
218
212
  };
219
213
  constructor() {
220
214
  super();
@@ -245,9 +239,9 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
245
239
  }
246
240
  _handleKeydown(event) {
247
241
  const target = event.target;
248
- if (!target.classList.contains("nav-item"))
242
+ if (!target.classList.contains("bottom-nav-item"))
249
243
  return;
250
- const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
244
+ const items = Array.from(this.shadowRoot.querySelectorAll(".bottom-nav-item:not([disabled])"));
251
245
  const currentIndex = items.indexOf(target);
252
246
  let nextIndex = -1;
253
247
  switch (event.key) {
@@ -279,16 +273,16 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
279
273
  items[nextIndex].focus();
280
274
  }
281
275
  }
282
- _renderItem(item, index) {
276
+ _renderItem(item) {
283
277
  const isSelected = item.value === this.value;
284
278
  const Tag = item.href ? "a" : "button";
285
279
  const hrefAttr = item.href ? `href="${item.href}"` : "";
286
280
  const disabledAttr = item.disabled ? "disabled" : "";
287
281
  const typeAttr = Tag === "button" ? 'type="button"' : "";
288
282
  return `
289
- <div class="nav-item-wrapper">
283
+ <div class="bottom-nav-item-wrapper">
290
284
  <${Tag}
291
- class="nav-item"
285
+ class="bottom-nav-item"
292
286
  part="item"
293
287
  role="tab"
294
288
  tabindex="${item.disabled ? "-1" : "0"}"
@@ -299,11 +293,11 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
299
293
  ${typeAttr}
300
294
  >
301
295
  ${item.icon ? `
302
- <span class="nav-icon" part="icon">
296
+ <span class="bottom-nav-icon" part="icon">
303
297
  ${item.icon}
304
298
  </span>
305
299
  ` : ""}
306
- <span class="nav-label" part="label">${item.label}</span>
300
+ <span class="bottom-nav-label" part="label">${item.label}</span>
307
301
  </${Tag}>
308
302
  </div>
309
303
  `;
@@ -311,8 +305,8 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
311
305
  render() {
312
306
  const hasItems = this.items && this.items.length > 0;
313
307
  return `
314
- <nav class="bottom-nav" part="container" role="tablist" aria-label="Bottom navigation">
315
- ${hasItems ? this.items.map((item, i) => this._renderItem(item, i)).join("") : "<slot></slot>"}
308
+ <nav class="bottom-nav" part="container" role="tablist" aria-label="${this.navLabel || "Bottom navigation"}">
309
+ ${hasItems ? this.items.map((item) => this._renderItem(item)).join("") : "<slot></slot>"}
316
310
  </nav>
317
311
  `;
318
312
  }
@@ -325,5 +319,5 @@ function register() {
325
319
  }
326
320
  }
327
321
 
328
- //# debugId=F376226EE32C567964756E2164756E21
322
+ //# debugId=9EF0BCA97E98E53364756E2164756E21
329
323
  //# sourceMappingURL=index.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-bottom-navigation.ts", "../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * DuskMoon Bottom Navigation Element\n *\n * A mobile-first bottom navigation bar component with nav items and icons.\n * Fixed position at the bottom of the viewport for easy thumb access.\n *\n * @element el-dm-bottom-navigation\n *\n * @attr {Array} items - Array of navigation items with { value, label, icon? } structure\n * @attr {string} value - Currently selected item value\n * @attr {string} color - Color theme: primary, secondary, or custom color\n *\n * @slot - Default slot for custom nav items (el-dm-bottom-navigation-item)\n *\n * @csspart container - The navigation container\n * @csspart item - Individual navigation item\n * @csspart icon - Item icon container\n * @csspart label - Item label\n *\n * @fires change - Fired when selection changes, detail: { value, item }\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\n/**\n * Navigation item structure\n */\nexport interface BottomNavigationItem {\n /** Unique identifier for the item */\n value: string;\n /** Display label */\n label: string;\n /** Icon HTML or SVG string */\n icon?: string;\n /** Whether the item is disabled */\n disabled?: boolean;\n /** Optional href for link behavior */\n href?: string;\n}\n\nconst styles = css`\n :host {\n --bottom-nav-height: 56px;\n --bottom-nav-bg: var(--color-surface, #ffffff);\n --bottom-nav-border: var(--color-border, #e5e7eb);\n --bottom-nav-text: var(--color-text-secondary, #6b7280);\n --bottom-nav-text-active: var(--color-primary, #3b82f6);\n --bottom-nav-icon-size: 24px;\n --bottom-nav-label-size: 0.75rem;\n --bottom-nav-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1);\n\n display: block;\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 1000;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n :host([position='static']) {\n position: static;\n }\n\n :host([position='sticky']) {\n position: sticky;\n }\n\n .bottom-nav {\n display: flex;\n align-items: center;\n justify-content: space-around;\n height: var(--bottom-nav-height);\n background: var(--bottom-nav-bg);\n border-top: 1px solid var(--bottom-nav-border);\n box-shadow: var(--bottom-nav-shadow);\n padding: 0;\n margin: 0;\n /* Safe area for iOS devices */\n padding-bottom: env(safe-area-inset-bottom, 0);\n }\n\n .nav-item {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 6px 12px;\n min-width: 0;\n max-width: 168px;\n height: 100%;\n background: transparent;\n border: none;\n cursor: pointer;\n color: var(--bottom-nav-text);\n text-decoration: none;\n transition:\n color 0.2s ease,\n transform 0.1s ease;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n }\n\n .nav-item:focus {\n outline: none;\n }\n\n .nav-item:focus-visible {\n outline: 2px solid var(--bottom-nav-text-active);\n outline-offset: -2px;\n border-radius: 4px;\n }\n\n .nav-item:active:not([disabled]) {\n transform: scale(0.95);\n }\n\n .nav-item[aria-selected='true'],\n .nav-item.active {\n color: var(--bottom-nav-text-active);\n }\n\n .nav-item[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .nav-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bottom-nav-icon-size);\n height: var(--bottom-nav-icon-size);\n flex-shrink: 0;\n }\n\n .nav-icon ::slotted(*),\n .nav-icon svg,\n .nav-icon img {\n width: 100%;\n height: 100%;\n }\n\n .nav-label {\n font-size: var(--bottom-nav-label-size);\n font-weight: 500;\n line-height: 1.2;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n\n /* Hide labels on very small screens */\n @media (max-width: 320px) {\n .nav-label {\n display: none;\n }\n\n .nav-icon {\n width: 28px;\n height: 28px;\n }\n }\n\n /* Color variants */\n :host([color='secondary']) {\n --bottom-nav-text-active: var(--color-secondary, #8b5cf6);\n }\n\n :host([color='success']) {\n --bottom-nav-text-active: var(--color-success, #22c55e);\n }\n\n :host([color='warning']) {\n --bottom-nav-text-active: var(--color-warning, #f59e0b);\n }\n\n :host([color='error']) {\n --bottom-nav-text-active: var(--color-error, #ef4444);\n }\n\n /* Badge indicator for items */\n .nav-item-badge {\n position: absolute;\n top: 4px;\n right: calc(50% - 18px);\n min-width: 8px;\n height: 8px;\n background: var(--color-error, #ef4444);\n border-radius: 50%;\n }\n\n .nav-item-wrapper {\n position: relative;\n flex: 1;\n display: flex;\n justify-content: center;\n max-width: 168px;\n }\n\n /* Slot for custom items */\n ::slotted(el-dm-bottom-navigation-item) {\n flex: 1;\n }\n`;\n\nexport class ElDmBottomNavigation extends BaseElement {\n static properties = {\n items: { type: Array, reflect: false, default: [] },\n value: { type: String, reflect: true },\n color: { type: String, reflect: true, default: 'primary' },\n position: { type: String, reflect: true, default: 'fixed' },\n };\n\n /** Array of navigation items */\n declare items: BottomNavigationItem[];\n\n /** Currently selected item value */\n declare value: string;\n\n /** Color theme */\n declare color: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | string;\n\n /** Position of the navigation bar */\n declare position: 'fixed' | 'static' | 'sticky';\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('click', this._handleClick.bind(this));\n this.addEventListener('keydown', this._handleKeydown.bind(this));\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('click', this._handleClick.bind(this));\n this.removeEventListener('keydown', this._handleKeydown.bind(this));\n }\n\n /**\n * Handle click events on nav items\n */\n private _handleClick(event: MouseEvent): void {\n const target = event.target as HTMLElement;\n const navItem = target.closest('[data-value]') as HTMLElement | null;\n\n if (!navItem || navItem.hasAttribute('disabled')) {\n return;\n }\n\n const value = navItem.dataset.value;\n if (value && value !== this.value) {\n const item = this.items.find((i) => i.value === value);\n this.value = value;\n this.emit('change', { value, item });\n }\n }\n\n /**\n * Handle keyboard navigation\n */\n private _handleKeydown(event: KeyboardEvent): void {\n const target = event.target as HTMLElement;\n if (!target.classList.contains('nav-item')) return;\n\n const items = Array.from(this.shadowRoot.querySelectorAll('.nav-item:not([disabled])'));\n const currentIndex = items.indexOf(target);\n\n let nextIndex = -1;\n\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n break;\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n break;\n case 'Home':\n event.preventDefault();\n nextIndex = 0;\n break;\n case 'End':\n event.preventDefault();\n nextIndex = items.length - 1;\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n target.click();\n return;\n }\n\n if (nextIndex >= 0 && items[nextIndex]) {\n (items[nextIndex] as HTMLElement).focus();\n }\n }\n\n /**\n * Render a single navigation item\n */\n private _renderItem(item: BottomNavigationItem, index: number): string {\n const isSelected = item.value === this.value;\n const Tag = item.href ? 'a' : 'button';\n const hrefAttr = item.href ? `href=\"${item.href}\"` : '';\n const disabledAttr = item.disabled ? 'disabled' : '';\n const typeAttr = Tag === 'button' ? 'type=\"button\"' : '';\n\n return `\n <div class=\"nav-item-wrapper\">\n <${Tag}\n class=\"nav-item\"\n part=\"item\"\n role=\"tab\"\n tabindex=\"${item.disabled ? '-1' : '0'}\"\n aria-selected=\"${isSelected}\"\n data-value=\"${item.value}\"\n ${hrefAttr}\n ${disabledAttr}\n ${typeAttr}\n >\n ${\n item.icon\n ? `\n <span class=\"nav-icon\" part=\"icon\">\n ${item.icon}\n </span>\n `\n : ''\n }\n <span class=\"nav-label\" part=\"label\">${item.label}</span>\n </${Tag}>\n </div>\n `;\n }\n\n render(): string {\n const hasItems = this.items && this.items.length > 0;\n\n return `\n <nav class=\"bottom-nav\" part=\"container\" role=\"tablist\" aria-label=\"Bottom navigation\">\n ${hasItems ? this.items.map((item, i) => this._renderItem(item, i)).join('') : '<slot></slot>'}\n </nav>\n `;\n }\n}\n",
5
+ "/**\n * DuskMoon Bottom Navigation Element\n *\n * A mobile-first bottom navigation bar component with nav items and icons.\n * Fixed position at the bottom of the viewport for easy thumb access.\n *\n * @element el-dm-bottom-navigation\n *\n * @attr {Array} items - Array of navigation items with { value, label, icon? } structure\n * @attr {string} value - Currently selected item value\n * @attr {string} color - Color theme: primary, secondary, or custom color\n *\n * @slot - Default slot for custom nav items (el-dm-bottom-navigation-item)\n *\n * @csspart container - The navigation container\n * @csspart item - Individual navigation item\n * @csspart icon - Item icon container\n * @csspart label - Item label\n *\n * @fires change - Fired when selection changes, detail: { value, item }\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-base';\nimport { css as bottomNavCSS } from '@duskmoon-dev/core/components/bottom-navigation';\n\n/**\n * Navigation item structure\n */\nexport interface BottomNavigationItem {\n /** Unique identifier for the item */\n value: string;\n /** Display label */\n label: string;\n /** Icon HTML or SVG string */\n icon?: string;\n /** Whether the item is disabled */\n disabled?: boolean;\n /** Optional href for link behavior */\n href?: string;\n}\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = bottomNavCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n --bottom-nav-height: 56px;\n --bottom-nav-bg: var(--color-surface, #ffffff);\n --bottom-nav-border: var(--color-border, #e5e7eb);\n --bottom-nav-text: var(--color-text-secondary, #6b7280);\n --bottom-nav-text-active: var(--color-primary, #3b82f6);\n --bottom-nav-icon-size: 24px;\n --bottom-nav-label-size: 0.75rem;\n --bottom-nav-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1);\n\n display: block;\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 1000;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n :host([position='static']) {\n position: static;\n }\n\n :host([position='sticky']) {\n position: sticky;\n }\n\n /* Import core bottom-navigation styles */\n ${coreStyles}\n\n /* Override core's fixed positioning — :host handles it */\n .bottom-nav {\n position: static;\n height: var(--bottom-nav-height);\n min-height: auto;\n background: var(--bottom-nav-bg);\n border-top: 1px solid var(--bottom-nav-border);\n box-shadow: var(--bottom-nav-shadow);\n }\n\n /* Override core item styles with our custom properties */\n .bottom-nav-item {\n gap: 2px;\n padding: 6px 12px;\n min-width: 0;\n max-width: 168px;\n height: 100%;\n color: var(--bottom-nav-text);\n transition:\n color 0.2s ease,\n transform 0.1s ease;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n }\n\n .bottom-nav-item:focus {\n outline: none;\n }\n\n .bottom-nav-item:focus-visible {\n outline: 2px solid var(--bottom-nav-text-active);\n outline-offset: -2px;\n border-radius: 4px;\n }\n\n .bottom-nav-item:active:not([disabled]) {\n transform: scale(0.95);\n }\n\n .bottom-nav-item[aria-selected='true'],\n .bottom-nav-item.active {\n color: var(--bottom-nav-text-active);\n }\n\n .bottom-nav-item[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .bottom-nav-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bottom-nav-icon-size);\n height: var(--bottom-nav-icon-size);\n flex-shrink: 0;\n }\n\n .bottom-nav-icon ::slotted(*),\n .bottom-nav-icon svg,\n .bottom-nav-icon img {\n width: 100%;\n height: 100%;\n }\n\n .bottom-nav-label {\n font-size: var(--bottom-nav-label-size);\n font-weight: 500;\n line-height: 1.2;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n\n /* Hide labels on very small screens */\n @media (max-width: 320px) {\n .bottom-nav-label {\n display: none;\n }\n\n .bottom-nav-icon {\n width: 28px;\n height: 28px;\n }\n }\n\n /* Color variants */\n :host([color='secondary']) {\n --bottom-nav-text-active: var(--color-secondary, #8b5cf6);\n }\n\n :host([color='success']) {\n --bottom-nav-text-active: var(--color-success, #22c55e);\n }\n\n :host([color='warning']) {\n --bottom-nav-text-active: var(--color-warning, #f59e0b);\n }\n\n :host([color='error']) {\n --bottom-nav-text-active: var(--color-error, #ef4444);\n }\n\n /* Badge indicator for items */\n .bottom-nav-badge {\n position: absolute;\n top: 4px;\n right: calc(50% - 18px);\n min-width: 8px;\n height: 8px;\n background: var(--color-error, #ef4444);\n border-radius: 50%;\n }\n\n .bottom-nav-item-wrapper {\n position: relative;\n flex: 1;\n display: flex;\n justify-content: center;\n max-width: 168px;\n }\n\n /* Slot for custom items */\n ::slotted(el-dm-bottom-navigation-item) {\n flex: 1;\n }\n`;\n\nexport class ElDmBottomNavigation extends BaseElement {\n static properties = {\n items: { type: Array, reflect: false, default: [] },\n value: { type: String, reflect: true },\n color: { type: String, reflect: true, default: 'primary' },\n position: { type: String, reflect: true, default: 'fixed' },\n navLabel: { type: String, reflect: true, attribute: 'nav-label', default: 'Bottom navigation' },\n };\n\n /** Array of navigation items */\n declare items: BottomNavigationItem[];\n\n /** Currently selected item value */\n declare value: string;\n\n /** Color theme */\n declare color: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | string;\n\n /** Position of the navigation bar */\n declare position: 'fixed' | 'static' | 'sticky';\n\n /** Accessible label for the navigation landmark */\n declare navLabel: string;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('click', this._handleClick.bind(this));\n this.addEventListener('keydown', this._handleKeydown.bind(this));\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('click', this._handleClick.bind(this));\n this.removeEventListener('keydown', this._handleKeydown.bind(this));\n }\n\n /**\n * Handle click events on nav items\n */\n private _handleClick(event: MouseEvent): void {\n const target = event.target as HTMLElement;\n const navItem = target.closest('[data-value]') as HTMLElement | null;\n\n if (!navItem || navItem.hasAttribute('disabled')) {\n return;\n }\n\n const value = navItem.dataset.value;\n if (value && value !== this.value) {\n const item = this.items.find((i) => i.value === value);\n this.value = value;\n this.emit('change', { value, item });\n }\n }\n\n /**\n * Handle keyboard navigation\n */\n private _handleKeydown(event: KeyboardEvent): void {\n const target = event.target as HTMLElement;\n if (!target.classList.contains('bottom-nav-item')) return;\n\n const items = Array.from(this.shadowRoot.querySelectorAll('.bottom-nav-item:not([disabled])'));\n const currentIndex = items.indexOf(target);\n\n let nextIndex = -1;\n\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n break;\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n break;\n case 'Home':\n event.preventDefault();\n nextIndex = 0;\n break;\n case 'End':\n event.preventDefault();\n nextIndex = items.length - 1;\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n target.click();\n return;\n }\n\n if (nextIndex >= 0 && items[nextIndex]) {\n (items[nextIndex] as HTMLElement).focus();\n }\n }\n\n /**\n * Render a single navigation item\n */\n private _renderItem(item: BottomNavigationItem): string {\n const isSelected = item.value === this.value;\n const Tag = item.href ? 'a' : 'button';\n const hrefAttr = item.href ? `href=\"${item.href}\"` : '';\n const disabledAttr = item.disabled ? 'disabled' : '';\n const typeAttr = Tag === 'button' ? 'type=\"button\"' : '';\n\n return `\n <div class=\"bottom-nav-item-wrapper\">\n <${Tag}\n class=\"bottom-nav-item\"\n part=\"item\"\n role=\"tab\"\n tabindex=\"${item.disabled ? '-1' : '0'}\"\n aria-selected=\"${isSelected}\"\n data-value=\"${item.value}\"\n ${hrefAttr}\n ${disabledAttr}\n ${typeAttr}\n >\n ${\n item.icon\n ? `\n <span class=\"bottom-nav-icon\" part=\"icon\">\n ${item.icon}\n </span>\n `\n : ''\n }\n <span class=\"bottom-nav-label\" part=\"label\">${item.label}</span>\n </${Tag}>\n </div>\n `;\n }\n\n render(): string {\n const hasItems = this.items && this.items.length > 0;\n\n return `\n <nav class=\"bottom-nav\" part=\"container\" role=\"tablist\" aria-label=\"${this.navLabel || 'Bottom navigation'}\">\n ${hasItems ? this.items.map((item) => this._renderItem(item)).join('') : '<slot></slot>'}\n </nav>\n `;\n }\n}\n",
6
6
  "/**\n * @duskmoon-dev/el-bottom-navigation\n *\n * DuskMoon Bottom Navigation custom element\n */\n\nimport { ElDmBottomNavigation } from './el-dm-bottom-navigation.js';\n\nexport { ElDmBottomNavigation };\nexport type { BottomNavigationItem } from './el-dm-bottom-navigation.js';\n\n/**\n * Register the el-dm-bottom-navigation custom element\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-bottom-navigation';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-bottom-navigation')) {\n customElements.define('el-dm-bottom-navigation', ElDmBottomNavigation);\n }\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "F376226EE32C567964756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "9EF0BCA97E98E53364756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -35,8 +35,10 @@ __export(exports_src, {
35
35
  module.exports = __toCommonJS(exports_src);
36
36
 
37
37
  // src/el-dm-bottom-navigation.ts
38
- var import_el_core = require("@duskmoon-dev/el-core");
39
- var styles = import_el_core.css`
38
+ var import_el_base = require("@duskmoon-dev/el-base");
39
+ var import_bottom_navigation = require("@duskmoon-dev/core/components/bottom-navigation");
40
+ var coreStyles = import_bottom_navigation.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
41
+ var styles = import_el_base.css`
40
42
  :host {
41
43
  --bottom-nav-height: 56px;
42
44
  --bottom-nav-bg: var(--color-surface, #ffffff);
@@ -67,36 +69,27 @@ var styles = import_el_core.css`
67
69
  position: sticky;
68
70
  }
69
71
 
72
+ /* Import core bottom-navigation styles */
73
+ ${coreStyles}
74
+
75
+ /* Override core's fixed positioning — :host handles it */
70
76
  .bottom-nav {
71
- display: flex;
72
- align-items: center;
73
- justify-content: space-around;
77
+ position: static;
74
78
  height: var(--bottom-nav-height);
79
+ min-height: auto;
75
80
  background: var(--bottom-nav-bg);
76
81
  border-top: 1px solid var(--bottom-nav-border);
77
82
  box-shadow: var(--bottom-nav-shadow);
78
- padding: 0;
79
- margin: 0;
80
- /* Safe area for iOS devices */
81
- padding-bottom: env(safe-area-inset-bottom, 0);
82
83
  }
83
84
 
84
- .nav-item {
85
- flex: 1;
86
- display: flex;
87
- flex-direction: column;
88
- align-items: center;
89
- justify-content: center;
85
+ /* Override core item styles with our custom properties */
86
+ .bottom-nav-item {
90
87
  gap: 2px;
91
88
  padding: 6px 12px;
92
89
  min-width: 0;
93
90
  max-width: 168px;
94
91
  height: 100%;
95
- background: transparent;
96
- border: none;
97
- cursor: pointer;
98
92
  color: var(--bottom-nav-text);
99
- text-decoration: none;
100
93
  transition:
101
94
  color 0.2s ease,
102
95
  transform 0.1s ease;
@@ -104,32 +97,32 @@ var styles = import_el_core.css`
104
97
  user-select: none;
105
98
  }
106
99
 
107
- .nav-item:focus {
100
+ .bottom-nav-item:focus {
108
101
  outline: none;
109
102
  }
110
103
 
111
- .nav-item:focus-visible {
104
+ .bottom-nav-item:focus-visible {
112
105
  outline: 2px solid var(--bottom-nav-text-active);
113
106
  outline-offset: -2px;
114
107
  border-radius: 4px;
115
108
  }
116
109
 
117
- .nav-item:active:not([disabled]) {
110
+ .bottom-nav-item:active:not([disabled]) {
118
111
  transform: scale(0.95);
119
112
  }
120
113
 
121
- .nav-item[aria-selected='true'],
122
- .nav-item.active {
114
+ .bottom-nav-item[aria-selected='true'],
115
+ .bottom-nav-item.active {
123
116
  color: var(--bottom-nav-text-active);
124
117
  }
125
118
 
126
- .nav-item[disabled] {
119
+ .bottom-nav-item[disabled] {
127
120
  opacity: 0.5;
128
121
  cursor: not-allowed;
129
122
  pointer-events: none;
130
123
  }
131
124
 
132
- .nav-icon {
125
+ .bottom-nav-icon {
133
126
  display: flex;
134
127
  align-items: center;
135
128
  justify-content: center;
@@ -138,14 +131,14 @@ var styles = import_el_core.css`
138
131
  flex-shrink: 0;
139
132
  }
140
133
 
141
- .nav-icon ::slotted(*),
142
- .nav-icon svg,
143
- .nav-icon img {
134
+ .bottom-nav-icon ::slotted(*),
135
+ .bottom-nav-icon svg,
136
+ .bottom-nav-icon img {
144
137
  width: 100%;
145
138
  height: 100%;
146
139
  }
147
140
 
148
- .nav-label {
141
+ .bottom-nav-label {
149
142
  font-size: var(--bottom-nav-label-size);
150
143
  font-weight: 500;
151
144
  line-height: 1.2;
@@ -157,11 +150,11 @@ var styles = import_el_core.css`
157
150
 
158
151
  /* Hide labels on very small screens */
159
152
  @media (max-width: 320px) {
160
- .nav-label {
153
+ .bottom-nav-label {
161
154
  display: none;
162
155
  }
163
156
 
164
- .nav-icon {
157
+ .bottom-nav-icon {
165
158
  width: 28px;
166
159
  height: 28px;
167
160
  }
@@ -185,7 +178,7 @@ var styles = import_el_core.css`
185
178
  }
186
179
 
187
180
  /* Badge indicator for items */
188
- .nav-item-badge {
181
+ .bottom-nav-badge {
189
182
  position: absolute;
190
183
  top: 4px;
191
184
  right: calc(50% - 18px);
@@ -195,7 +188,7 @@ var styles = import_el_core.css`
195
188
  border-radius: 50%;
196
189
  }
197
190
 
198
- .nav-item-wrapper {
191
+ .bottom-nav-item-wrapper {
199
192
  position: relative;
200
193
  flex: 1;
201
194
  display: flex;
@@ -209,12 +202,13 @@ var styles = import_el_core.css`
209
202
  }
210
203
  `;
211
204
 
212
- class ElDmBottomNavigation extends import_el_core.BaseElement {
205
+ class ElDmBottomNavigation extends import_el_base.BaseElement {
213
206
  static properties = {
214
207
  items: { type: Array, reflect: false, default: [] },
215
208
  value: { type: String, reflect: true },
216
209
  color: { type: String, reflect: true, default: "primary" },
217
- position: { type: String, reflect: true, default: "fixed" }
210
+ position: { type: String, reflect: true, default: "fixed" },
211
+ navLabel: { type: String, reflect: true, attribute: "nav-label", default: "Bottom navigation" }
218
212
  };
219
213
  constructor() {
220
214
  super();
@@ -245,9 +239,9 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
245
239
  }
246
240
  _handleKeydown(event) {
247
241
  const target = event.target;
248
- if (!target.classList.contains("nav-item"))
242
+ if (!target.classList.contains("bottom-nav-item"))
249
243
  return;
250
- const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
244
+ const items = Array.from(this.shadowRoot.querySelectorAll(".bottom-nav-item:not([disabled])"));
251
245
  const currentIndex = items.indexOf(target);
252
246
  let nextIndex = -1;
253
247
  switch (event.key) {
@@ -279,16 +273,16 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
279
273
  items[nextIndex].focus();
280
274
  }
281
275
  }
282
- _renderItem(item, index) {
276
+ _renderItem(item) {
283
277
  const isSelected = item.value === this.value;
284
278
  const Tag = item.href ? "a" : "button";
285
279
  const hrefAttr = item.href ? `href="${item.href}"` : "";
286
280
  const disabledAttr = item.disabled ? "disabled" : "";
287
281
  const typeAttr = Tag === "button" ? 'type="button"' : "";
288
282
  return `
289
- <div class="nav-item-wrapper">
283
+ <div class="bottom-nav-item-wrapper">
290
284
  <${Tag}
291
- class="nav-item"
285
+ class="bottom-nav-item"
292
286
  part="item"
293
287
  role="tab"
294
288
  tabindex="${item.disabled ? "-1" : "0"}"
@@ -299,11 +293,11 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
299
293
  ${typeAttr}
300
294
  >
301
295
  ${item.icon ? `
302
- <span class="nav-icon" part="icon">
296
+ <span class="bottom-nav-icon" part="icon">
303
297
  ${item.icon}
304
298
  </span>
305
299
  ` : ""}
306
- <span class="nav-label" part="label">${item.label}</span>
300
+ <span class="bottom-nav-label" part="label">${item.label}</span>
307
301
  </${Tag}>
308
302
  </div>
309
303
  `;
@@ -311,8 +305,8 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
311
305
  render() {
312
306
  const hasItems = this.items && this.items.length > 0;
313
307
  return `
314
- <nav class="bottom-nav" part="container" role="tablist" aria-label="Bottom navigation">
315
- ${hasItems ? this.items.map((item, i) => this._renderItem(item, i)).join("") : "<slot></slot>"}
308
+ <nav class="bottom-nav" part="container" role="tablist" aria-label="${this.navLabel || "Bottom navigation"}">
309
+ ${hasItems ? this.items.map((item) => this._renderItem(item)).join("") : "<slot></slot>"}
316
310
  </nav>
317
311
  `;
318
312
  }
@@ -328,5 +322,5 @@ function register() {
328
322
  // src/register.ts
329
323
  register();
330
324
 
331
- //# debugId=D05C25A3A10DC4D464756E2164756E21
325
+ //# debugId=90D3108BFBBBEEE564756E2164756E21
332
326
  //# sourceMappingURL=register.js.map