@duskmoon-dev/el-bottom-navigation 0.5.0 → 0.6.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,7 +202,7 @@ 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 },
@@ -245,9 +238,9 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
245
238
  }
246
239
  _handleKeydown(event) {
247
240
  const target = event.target;
248
- if (!target.classList.contains("nav-item"))
241
+ if (!target.classList.contains("bottom-nav-item"))
249
242
  return;
250
- const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
243
+ const items = Array.from(this.shadowRoot.querySelectorAll(".bottom-nav-item:not([disabled])"));
251
244
  const currentIndex = items.indexOf(target);
252
245
  let nextIndex = -1;
253
246
  switch (event.key) {
@@ -279,16 +272,16 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
279
272
  items[nextIndex].focus();
280
273
  }
281
274
  }
282
- _renderItem(item, index) {
275
+ _renderItem(item) {
283
276
  const isSelected = item.value === this.value;
284
277
  const Tag = item.href ? "a" : "button";
285
278
  const hrefAttr = item.href ? `href="${item.href}"` : "";
286
279
  const disabledAttr = item.disabled ? "disabled" : "";
287
280
  const typeAttr = Tag === "button" ? 'type="button"' : "";
288
281
  return `
289
- <div class="nav-item-wrapper">
282
+ <div class="bottom-nav-item-wrapper">
290
283
  <${Tag}
291
- class="nav-item"
284
+ class="bottom-nav-item"
292
285
  part="item"
293
286
  role="tab"
294
287
  tabindex="${item.disabled ? "-1" : "0"}"
@@ -299,11 +292,11 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
299
292
  ${typeAttr}
300
293
  >
301
294
  ${item.icon ? `
302
- <span class="nav-icon" part="icon">
295
+ <span class="bottom-nav-icon" part="icon">
303
296
  ${item.icon}
304
297
  </span>
305
298
  ` : ""}
306
- <span class="nav-label" part="label">${item.label}</span>
299
+ <span class="bottom-nav-label" part="label">${item.label}</span>
307
300
  </${Tag}>
308
301
  </div>
309
302
  `;
@@ -312,7 +305,7 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
312
305
  const hasItems = this.items && this.items.length > 0;
313
306
  return `
314
307
  <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
+ ${hasItems ? this.items.map((item) => this._renderItem(item)).join("") : "<slot></slot>"}
316
309
  </nav>
317
310
  `;
318
311
  }
@@ -325,5 +318,5 @@ function register() {
325
318
  }
326
319
  }
327
320
 
328
- //# debugId=F376226EE32C567964756E2164756E21
321
+ //# debugId=7664EAFB67B1782864756E2164756E21
329
322
  //# 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 };\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('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=\"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": "7664EAFB67B1782864756E2164756E21",
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,7 +202,7 @@ 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 },
@@ -245,9 +238,9 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
245
238
  }
246
239
  _handleKeydown(event) {
247
240
  const target = event.target;
248
- if (!target.classList.contains("nav-item"))
241
+ if (!target.classList.contains("bottom-nav-item"))
249
242
  return;
250
- const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
243
+ const items = Array.from(this.shadowRoot.querySelectorAll(".bottom-nav-item:not([disabled])"));
251
244
  const currentIndex = items.indexOf(target);
252
245
  let nextIndex = -1;
253
246
  switch (event.key) {
@@ -279,16 +272,16 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
279
272
  items[nextIndex].focus();
280
273
  }
281
274
  }
282
- _renderItem(item, index) {
275
+ _renderItem(item) {
283
276
  const isSelected = item.value === this.value;
284
277
  const Tag = item.href ? "a" : "button";
285
278
  const hrefAttr = item.href ? `href="${item.href}"` : "";
286
279
  const disabledAttr = item.disabled ? "disabled" : "";
287
280
  const typeAttr = Tag === "button" ? 'type="button"' : "";
288
281
  return `
289
- <div class="nav-item-wrapper">
282
+ <div class="bottom-nav-item-wrapper">
290
283
  <${Tag}
291
- class="nav-item"
284
+ class="bottom-nav-item"
292
285
  part="item"
293
286
  role="tab"
294
287
  tabindex="${item.disabled ? "-1" : "0"}"
@@ -299,11 +292,11 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
299
292
  ${typeAttr}
300
293
  >
301
294
  ${item.icon ? `
302
- <span class="nav-icon" part="icon">
295
+ <span class="bottom-nav-icon" part="icon">
303
296
  ${item.icon}
304
297
  </span>
305
298
  ` : ""}
306
- <span class="nav-label" part="label">${item.label}</span>
299
+ <span class="bottom-nav-label" part="label">${item.label}</span>
307
300
  </${Tag}>
308
301
  </div>
309
302
  `;
@@ -312,7 +305,7 @@ class ElDmBottomNavigation extends import_el_core.BaseElement {
312
305
  const hasItems = this.items && this.items.length > 0;
313
306
  return `
314
307
  <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
+ ${hasItems ? this.items.map((item) => this._renderItem(item)).join("") : "<slot></slot>"}
316
309
  </nav>
317
310
  `;
318
311
  }
@@ -328,5 +321,5 @@ function register() {
328
321
  // src/register.ts
329
322
  register();
330
323
 
331
- //# debugId=D05C25A3A10DC4D464756E2164756E21
324
+ //# debugId=3140AC23DA61283D64756E2164756E21
332
325
  //# sourceMappingURL=register.js.map