@duskmoon-dev/el-bottom-navigation 0.4.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/dist/cjs/index.js +329 -0
- package/dist/cjs/index.js.map +11 -0
- package/dist/cjs/register.js +332 -0
- package/dist/cjs/register.js.map +12 -0
- package/dist/esm/index.js +297 -0
- package/dist/esm/index.js.map +11 -0
- package/dist/esm/register.js +296 -0
- package/dist/esm/register.js.map +12 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/el-dm-bottom-navigation.d.ts +85 -0
- package/dist/types/el-dm-bottom-navigation.d.ts.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/register.d.ts +2 -0
- package/dist/types/register.d.ts.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var exports_src = {};
|
|
31
|
+
__export(exports_src, {
|
|
32
|
+
register: () => register,
|
|
33
|
+
ElDmBottomNavigation: () => ElDmBottomNavigation
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(exports_src);
|
|
36
|
+
|
|
37
|
+
// src/el-dm-bottom-navigation.ts
|
|
38
|
+
var import_el_core = require("@duskmoon-dev/el-core");
|
|
39
|
+
var styles = import_el_core.css`
|
|
40
|
+
:host {
|
|
41
|
+
--bottom-nav-height: 56px;
|
|
42
|
+
--bottom-nav-bg: var(--color-surface, #ffffff);
|
|
43
|
+
--bottom-nav-border: var(--color-border, #e5e7eb);
|
|
44
|
+
--bottom-nav-text: var(--color-text-secondary, #6b7280);
|
|
45
|
+
--bottom-nav-text-active: var(--color-primary, #3b82f6);
|
|
46
|
+
--bottom-nav-icon-size: 24px;
|
|
47
|
+
--bottom-nav-label-size: 0.75rem;
|
|
48
|
+
--bottom-nav-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1);
|
|
49
|
+
|
|
50
|
+
display: block;
|
|
51
|
+
position: fixed;
|
|
52
|
+
bottom: 0;
|
|
53
|
+
left: 0;
|
|
54
|
+
right: 0;
|
|
55
|
+
z-index: 1000;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
:host([hidden]) {
|
|
59
|
+
display: none !important;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:host([position='static']) {
|
|
63
|
+
position: static;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:host([position='sticky']) {
|
|
67
|
+
position: sticky;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.bottom-nav {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: space-around;
|
|
74
|
+
height: var(--bottom-nav-height);
|
|
75
|
+
background: var(--bottom-nav-bg);
|
|
76
|
+
border-top: 1px solid var(--bottom-nav-border);
|
|
77
|
+
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
|
+
|
|
84
|
+
.nav-item {
|
|
85
|
+
flex: 1;
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
gap: 2px;
|
|
91
|
+
padding: 6px 12px;
|
|
92
|
+
min-width: 0;
|
|
93
|
+
max-width: 168px;
|
|
94
|
+
height: 100%;
|
|
95
|
+
background: transparent;
|
|
96
|
+
border: none;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
color: var(--bottom-nav-text);
|
|
99
|
+
text-decoration: none;
|
|
100
|
+
transition:
|
|
101
|
+
color 0.2s ease,
|
|
102
|
+
transform 0.1s ease;
|
|
103
|
+
-webkit-tap-highlight-color: transparent;
|
|
104
|
+
user-select: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.nav-item:focus {
|
|
108
|
+
outline: none;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.nav-item:focus-visible {
|
|
112
|
+
outline: 2px solid var(--bottom-nav-text-active);
|
|
113
|
+
outline-offset: -2px;
|
|
114
|
+
border-radius: 4px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.nav-item:active:not([disabled]) {
|
|
118
|
+
transform: scale(0.95);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.nav-item[aria-selected='true'],
|
|
122
|
+
.nav-item.active {
|
|
123
|
+
color: var(--bottom-nav-text-active);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.nav-item[disabled] {
|
|
127
|
+
opacity: 0.5;
|
|
128
|
+
cursor: not-allowed;
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.nav-icon {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
width: var(--bottom-nav-icon-size);
|
|
137
|
+
height: var(--bottom-nav-icon-size);
|
|
138
|
+
flex-shrink: 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.nav-icon ::slotted(*),
|
|
142
|
+
.nav-icon svg,
|
|
143
|
+
.nav-icon img {
|
|
144
|
+
width: 100%;
|
|
145
|
+
height: 100%;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.nav-label {
|
|
149
|
+
font-size: var(--bottom-nav-label-size);
|
|
150
|
+
font-weight: 500;
|
|
151
|
+
line-height: 1.2;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
overflow: hidden;
|
|
154
|
+
text-overflow: ellipsis;
|
|
155
|
+
max-width: 100%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Hide labels on very small screens */
|
|
159
|
+
@media (max-width: 320px) {
|
|
160
|
+
.nav-label {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.nav-icon {
|
|
165
|
+
width: 28px;
|
|
166
|
+
height: 28px;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Color variants */
|
|
171
|
+
:host([color='secondary']) {
|
|
172
|
+
--bottom-nav-text-active: var(--color-secondary, #8b5cf6);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
:host([color='success']) {
|
|
176
|
+
--bottom-nav-text-active: var(--color-success, #22c55e);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
:host([color='warning']) {
|
|
180
|
+
--bottom-nav-text-active: var(--color-warning, #f59e0b);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
:host([color='error']) {
|
|
184
|
+
--bottom-nav-text-active: var(--color-error, #ef4444);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Badge indicator for items */
|
|
188
|
+
.nav-item-badge {
|
|
189
|
+
position: absolute;
|
|
190
|
+
top: 4px;
|
|
191
|
+
right: calc(50% - 18px);
|
|
192
|
+
min-width: 8px;
|
|
193
|
+
height: 8px;
|
|
194
|
+
background: var(--color-error, #ef4444);
|
|
195
|
+
border-radius: 50%;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.nav-item-wrapper {
|
|
199
|
+
position: relative;
|
|
200
|
+
flex: 1;
|
|
201
|
+
display: flex;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
max-width: 168px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Slot for custom items */
|
|
207
|
+
::slotted(el-dm-bottom-navigation-item) {
|
|
208
|
+
flex: 1;
|
|
209
|
+
}
|
|
210
|
+
`;
|
|
211
|
+
|
|
212
|
+
class ElDmBottomNavigation extends import_el_core.BaseElement {
|
|
213
|
+
static properties = {
|
|
214
|
+
items: { type: Array, reflect: false, default: [] },
|
|
215
|
+
value: { type: String, reflect: true },
|
|
216
|
+
color: { type: String, reflect: true, default: "primary" },
|
|
217
|
+
position: { type: String, reflect: true, default: "fixed" }
|
|
218
|
+
};
|
|
219
|
+
constructor() {
|
|
220
|
+
super();
|
|
221
|
+
this.attachStyles(styles);
|
|
222
|
+
}
|
|
223
|
+
connectedCallback() {
|
|
224
|
+
super.connectedCallback();
|
|
225
|
+
this.addEventListener("click", this._handleClick.bind(this));
|
|
226
|
+
this.addEventListener("keydown", this._handleKeydown.bind(this));
|
|
227
|
+
}
|
|
228
|
+
disconnectedCallback() {
|
|
229
|
+
super.disconnectedCallback();
|
|
230
|
+
this.removeEventListener("click", this._handleClick.bind(this));
|
|
231
|
+
this.removeEventListener("keydown", this._handleKeydown.bind(this));
|
|
232
|
+
}
|
|
233
|
+
_handleClick(event) {
|
|
234
|
+
const target = event.target;
|
|
235
|
+
const navItem = target.closest("[data-value]");
|
|
236
|
+
if (!navItem || navItem.hasAttribute("disabled")) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const value = navItem.dataset.value;
|
|
240
|
+
if (value && value !== this.value) {
|
|
241
|
+
const item = this.items.find((i) => i.value === value);
|
|
242
|
+
this.value = value;
|
|
243
|
+
this.emit("change", { value, item });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
_handleKeydown(event) {
|
|
247
|
+
const target = event.target;
|
|
248
|
+
if (!target.classList.contains("nav-item"))
|
|
249
|
+
return;
|
|
250
|
+
const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
|
|
251
|
+
const currentIndex = items.indexOf(target);
|
|
252
|
+
let nextIndex = -1;
|
|
253
|
+
switch (event.key) {
|
|
254
|
+
case "ArrowLeft":
|
|
255
|
+
case "ArrowUp":
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
|
|
258
|
+
break;
|
|
259
|
+
case "ArrowRight":
|
|
260
|
+
case "ArrowDown":
|
|
261
|
+
event.preventDefault();
|
|
262
|
+
nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
|
|
263
|
+
break;
|
|
264
|
+
case "Home":
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
nextIndex = 0;
|
|
267
|
+
break;
|
|
268
|
+
case "End":
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
nextIndex = items.length - 1;
|
|
271
|
+
break;
|
|
272
|
+
case "Enter":
|
|
273
|
+
case " ":
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
target.click();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (nextIndex >= 0 && items[nextIndex]) {
|
|
279
|
+
items[nextIndex].focus();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
_renderItem(item, index) {
|
|
283
|
+
const isSelected = item.value === this.value;
|
|
284
|
+
const Tag = item.href ? "a" : "button";
|
|
285
|
+
const hrefAttr = item.href ? `href="${item.href}"` : "";
|
|
286
|
+
const disabledAttr = item.disabled ? "disabled" : "";
|
|
287
|
+
const typeAttr = Tag === "button" ? 'type="button"' : "";
|
|
288
|
+
return `
|
|
289
|
+
<div class="nav-item-wrapper">
|
|
290
|
+
<${Tag}
|
|
291
|
+
class="nav-item"
|
|
292
|
+
part="item"
|
|
293
|
+
role="tab"
|
|
294
|
+
tabindex="${item.disabled ? "-1" : "0"}"
|
|
295
|
+
aria-selected="${isSelected}"
|
|
296
|
+
data-value="${item.value}"
|
|
297
|
+
${hrefAttr}
|
|
298
|
+
${disabledAttr}
|
|
299
|
+
${typeAttr}
|
|
300
|
+
>
|
|
301
|
+
${item.icon ? `
|
|
302
|
+
<span class="nav-icon" part="icon">
|
|
303
|
+
${item.icon}
|
|
304
|
+
</span>
|
|
305
|
+
` : ""}
|
|
306
|
+
<span class="nav-label" part="label">${item.label}</span>
|
|
307
|
+
</${Tag}>
|
|
308
|
+
</div>
|
|
309
|
+
`;
|
|
310
|
+
}
|
|
311
|
+
render() {
|
|
312
|
+
const hasItems = this.items && this.items.length > 0;
|
|
313
|
+
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>"}
|
|
316
|
+
</nav>
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/index.ts
|
|
322
|
+
function register() {
|
|
323
|
+
if (!customElements.get("el-dm-bottom-navigation")) {
|
|
324
|
+
customElements.define("el-dm-bottom-navigation", ElDmBottomNavigation);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
//# debugId=F376226EE32C567964756E2164756E21
|
|
329
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/el-dm-bottom-navigation.ts", "../../src/index.ts"],
|
|
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",
|
|
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
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "F376226EE32C567964756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var exports_src = {};
|
|
31
|
+
__export(exports_src, {
|
|
32
|
+
register: () => register,
|
|
33
|
+
ElDmBottomNavigation: () => ElDmBottomNavigation
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(exports_src);
|
|
36
|
+
|
|
37
|
+
// src/el-dm-bottom-navigation.ts
|
|
38
|
+
var import_el_core = require("@duskmoon-dev/el-core");
|
|
39
|
+
var styles = import_el_core.css`
|
|
40
|
+
:host {
|
|
41
|
+
--bottom-nav-height: 56px;
|
|
42
|
+
--bottom-nav-bg: var(--color-surface, #ffffff);
|
|
43
|
+
--bottom-nav-border: var(--color-border, #e5e7eb);
|
|
44
|
+
--bottom-nav-text: var(--color-text-secondary, #6b7280);
|
|
45
|
+
--bottom-nav-text-active: var(--color-primary, #3b82f6);
|
|
46
|
+
--bottom-nav-icon-size: 24px;
|
|
47
|
+
--bottom-nav-label-size: 0.75rem;
|
|
48
|
+
--bottom-nav-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1);
|
|
49
|
+
|
|
50
|
+
display: block;
|
|
51
|
+
position: fixed;
|
|
52
|
+
bottom: 0;
|
|
53
|
+
left: 0;
|
|
54
|
+
right: 0;
|
|
55
|
+
z-index: 1000;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
:host([hidden]) {
|
|
59
|
+
display: none !important;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:host([position='static']) {
|
|
63
|
+
position: static;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:host([position='sticky']) {
|
|
67
|
+
position: sticky;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.bottom-nav {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: space-around;
|
|
74
|
+
height: var(--bottom-nav-height);
|
|
75
|
+
background: var(--bottom-nav-bg);
|
|
76
|
+
border-top: 1px solid var(--bottom-nav-border);
|
|
77
|
+
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
|
+
|
|
84
|
+
.nav-item {
|
|
85
|
+
flex: 1;
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
gap: 2px;
|
|
91
|
+
padding: 6px 12px;
|
|
92
|
+
min-width: 0;
|
|
93
|
+
max-width: 168px;
|
|
94
|
+
height: 100%;
|
|
95
|
+
background: transparent;
|
|
96
|
+
border: none;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
color: var(--bottom-nav-text);
|
|
99
|
+
text-decoration: none;
|
|
100
|
+
transition:
|
|
101
|
+
color 0.2s ease,
|
|
102
|
+
transform 0.1s ease;
|
|
103
|
+
-webkit-tap-highlight-color: transparent;
|
|
104
|
+
user-select: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.nav-item:focus {
|
|
108
|
+
outline: none;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.nav-item:focus-visible {
|
|
112
|
+
outline: 2px solid var(--bottom-nav-text-active);
|
|
113
|
+
outline-offset: -2px;
|
|
114
|
+
border-radius: 4px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.nav-item:active:not([disabled]) {
|
|
118
|
+
transform: scale(0.95);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.nav-item[aria-selected='true'],
|
|
122
|
+
.nav-item.active {
|
|
123
|
+
color: var(--bottom-nav-text-active);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.nav-item[disabled] {
|
|
127
|
+
opacity: 0.5;
|
|
128
|
+
cursor: not-allowed;
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.nav-icon {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
width: var(--bottom-nav-icon-size);
|
|
137
|
+
height: var(--bottom-nav-icon-size);
|
|
138
|
+
flex-shrink: 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.nav-icon ::slotted(*),
|
|
142
|
+
.nav-icon svg,
|
|
143
|
+
.nav-icon img {
|
|
144
|
+
width: 100%;
|
|
145
|
+
height: 100%;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.nav-label {
|
|
149
|
+
font-size: var(--bottom-nav-label-size);
|
|
150
|
+
font-weight: 500;
|
|
151
|
+
line-height: 1.2;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
overflow: hidden;
|
|
154
|
+
text-overflow: ellipsis;
|
|
155
|
+
max-width: 100%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Hide labels on very small screens */
|
|
159
|
+
@media (max-width: 320px) {
|
|
160
|
+
.nav-label {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.nav-icon {
|
|
165
|
+
width: 28px;
|
|
166
|
+
height: 28px;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Color variants */
|
|
171
|
+
:host([color='secondary']) {
|
|
172
|
+
--bottom-nav-text-active: var(--color-secondary, #8b5cf6);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
:host([color='success']) {
|
|
176
|
+
--bottom-nav-text-active: var(--color-success, #22c55e);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
:host([color='warning']) {
|
|
180
|
+
--bottom-nav-text-active: var(--color-warning, #f59e0b);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
:host([color='error']) {
|
|
184
|
+
--bottom-nav-text-active: var(--color-error, #ef4444);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Badge indicator for items */
|
|
188
|
+
.nav-item-badge {
|
|
189
|
+
position: absolute;
|
|
190
|
+
top: 4px;
|
|
191
|
+
right: calc(50% - 18px);
|
|
192
|
+
min-width: 8px;
|
|
193
|
+
height: 8px;
|
|
194
|
+
background: var(--color-error, #ef4444);
|
|
195
|
+
border-radius: 50%;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.nav-item-wrapper {
|
|
199
|
+
position: relative;
|
|
200
|
+
flex: 1;
|
|
201
|
+
display: flex;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
max-width: 168px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Slot for custom items */
|
|
207
|
+
::slotted(el-dm-bottom-navigation-item) {
|
|
208
|
+
flex: 1;
|
|
209
|
+
}
|
|
210
|
+
`;
|
|
211
|
+
|
|
212
|
+
class ElDmBottomNavigation extends import_el_core.BaseElement {
|
|
213
|
+
static properties = {
|
|
214
|
+
items: { type: Array, reflect: false, default: [] },
|
|
215
|
+
value: { type: String, reflect: true },
|
|
216
|
+
color: { type: String, reflect: true, default: "primary" },
|
|
217
|
+
position: { type: String, reflect: true, default: "fixed" }
|
|
218
|
+
};
|
|
219
|
+
constructor() {
|
|
220
|
+
super();
|
|
221
|
+
this.attachStyles(styles);
|
|
222
|
+
}
|
|
223
|
+
connectedCallback() {
|
|
224
|
+
super.connectedCallback();
|
|
225
|
+
this.addEventListener("click", this._handleClick.bind(this));
|
|
226
|
+
this.addEventListener("keydown", this._handleKeydown.bind(this));
|
|
227
|
+
}
|
|
228
|
+
disconnectedCallback() {
|
|
229
|
+
super.disconnectedCallback();
|
|
230
|
+
this.removeEventListener("click", this._handleClick.bind(this));
|
|
231
|
+
this.removeEventListener("keydown", this._handleKeydown.bind(this));
|
|
232
|
+
}
|
|
233
|
+
_handleClick(event) {
|
|
234
|
+
const target = event.target;
|
|
235
|
+
const navItem = target.closest("[data-value]");
|
|
236
|
+
if (!navItem || navItem.hasAttribute("disabled")) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const value = navItem.dataset.value;
|
|
240
|
+
if (value && value !== this.value) {
|
|
241
|
+
const item = this.items.find((i) => i.value === value);
|
|
242
|
+
this.value = value;
|
|
243
|
+
this.emit("change", { value, item });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
_handleKeydown(event) {
|
|
247
|
+
const target = event.target;
|
|
248
|
+
if (!target.classList.contains("nav-item"))
|
|
249
|
+
return;
|
|
250
|
+
const items = Array.from(this.shadowRoot.querySelectorAll(".nav-item:not([disabled])"));
|
|
251
|
+
const currentIndex = items.indexOf(target);
|
|
252
|
+
let nextIndex = -1;
|
|
253
|
+
switch (event.key) {
|
|
254
|
+
case "ArrowLeft":
|
|
255
|
+
case "ArrowUp":
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
|
|
258
|
+
break;
|
|
259
|
+
case "ArrowRight":
|
|
260
|
+
case "ArrowDown":
|
|
261
|
+
event.preventDefault();
|
|
262
|
+
nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
|
|
263
|
+
break;
|
|
264
|
+
case "Home":
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
nextIndex = 0;
|
|
267
|
+
break;
|
|
268
|
+
case "End":
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
nextIndex = items.length - 1;
|
|
271
|
+
break;
|
|
272
|
+
case "Enter":
|
|
273
|
+
case " ":
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
target.click();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (nextIndex >= 0 && items[nextIndex]) {
|
|
279
|
+
items[nextIndex].focus();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
_renderItem(item, index) {
|
|
283
|
+
const isSelected = item.value === this.value;
|
|
284
|
+
const Tag = item.href ? "a" : "button";
|
|
285
|
+
const hrefAttr = item.href ? `href="${item.href}"` : "";
|
|
286
|
+
const disabledAttr = item.disabled ? "disabled" : "";
|
|
287
|
+
const typeAttr = Tag === "button" ? 'type="button"' : "";
|
|
288
|
+
return `
|
|
289
|
+
<div class="nav-item-wrapper">
|
|
290
|
+
<${Tag}
|
|
291
|
+
class="nav-item"
|
|
292
|
+
part="item"
|
|
293
|
+
role="tab"
|
|
294
|
+
tabindex="${item.disabled ? "-1" : "0"}"
|
|
295
|
+
aria-selected="${isSelected}"
|
|
296
|
+
data-value="${item.value}"
|
|
297
|
+
${hrefAttr}
|
|
298
|
+
${disabledAttr}
|
|
299
|
+
${typeAttr}
|
|
300
|
+
>
|
|
301
|
+
${item.icon ? `
|
|
302
|
+
<span class="nav-icon" part="icon">
|
|
303
|
+
${item.icon}
|
|
304
|
+
</span>
|
|
305
|
+
` : ""}
|
|
306
|
+
<span class="nav-label" part="label">${item.label}</span>
|
|
307
|
+
</${Tag}>
|
|
308
|
+
</div>
|
|
309
|
+
`;
|
|
310
|
+
}
|
|
311
|
+
render() {
|
|
312
|
+
const hasItems = this.items && this.items.length > 0;
|
|
313
|
+
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>"}
|
|
316
|
+
</nav>
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/index.ts
|
|
322
|
+
function register() {
|
|
323
|
+
if (!customElements.get("el-dm-bottom-navigation")) {
|
|
324
|
+
customElements.define("el-dm-bottom-navigation", ElDmBottomNavigation);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/register.ts
|
|
329
|
+
register();
|
|
330
|
+
|
|
331
|
+
//# debugId=D05C25A3A10DC4D464756E2164756E21
|
|
332
|
+
//# sourceMappingURL=register.js.map
|