le-kit 0.3.1 → 0.3.2
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/{le-button_13.cjs.entry.js → le-bar_16.cjs.entry.js} +951 -5
- package/dist/cjs/le-kit.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/le-bar/le-bar.js +59 -7
- package/dist/collection/components/le-bar/le-bar.js.map +1 -1
- package/dist/collection/components/le-component/le-component.js +1 -1
- package/dist/collection/components/le-component/le-component.js.map +1 -1
- package/dist/collection/components/le-navigation/le-navigation.js +3 -3
- package/dist/collection/components/le-navigation/le-navigation.js.map +1 -1
- package/dist/collection/components/le-select/le-select.js +3 -3
- package/dist/collection/components/le-select/le-select.js.map +1 -1
- package/dist/collection/dist/components/assets/custom-elements.json +1169 -1151
- package/dist/components/assets/custom-elements.json +1169 -1151
- package/dist/components/le-bar2.js +40 -7
- package/dist/components/le-bar2.js.map +1 -1
- package/dist/components/le-button2.js +4 -4
- package/dist/components/le-button2.js.map +1 -1
- package/dist/components/le-navigation.js +2 -2
- package/dist/components/le-navigation.js.map +1 -1
- package/dist/docs.json +33 -4
- package/dist/esm/{le-button_13.entry.js → le-bar_16.entry.js} +951 -8
- package/dist/esm/le-kit.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/le-kit/dist/components/assets/custom-elements.json +1169 -1151
- package/dist/le-kit/le-kit.esm.js +1 -1
- package/dist/le-kit/p-dea78542.entry.js +2 -0
- package/dist/le-kit/p-dea78542.entry.js.map +1 -0
- package/dist/types/components/le-bar/le-bar.d.ts +6 -0
- package/dist/types/components.d.ts +14 -4
- package/package.json +1 -1
- package/dist/cjs/le-bar.cjs.entry.js +0 -428
- package/dist/cjs/le-icon.cjs.entry.js +0 -110
- package/dist/cjs/le-navigation.cjs.entry.js +0 -393
- package/dist/esm/le-bar.entry.js +0 -426
- package/dist/esm/le-bar.entry.js.map +0 -1
- package/dist/esm/le-icon.entry.js +0 -108
- package/dist/esm/le-icon.entry.js.map +0 -1
- package/dist/esm/le-navigation.entry.js +0 -391
- package/dist/esm/le-navigation.entry.js.map +0 -1
- package/dist/le-kit/p-0efce278.entry.js +0 -2
- package/dist/le-kit/p-0efce278.entry.js.map +0 -1
- package/dist/le-kit/p-2102a152.entry.js +0 -2
- package/dist/le-kit/p-2102a152.entry.js.map +0 -1
- package/dist/le-kit/p-53d9c363.entry.js +0 -2
- package/dist/le-kit/p-53d9c363.entry.js.map +0 -1
- package/dist/le-kit/p-94f774af.entry.js +0 -2
- package/dist/le-kit/p-94f774af.entry.js.map +0 -1
|
@@ -4,6 +4,459 @@ var index = require('./index-CNRmviSz.js');
|
|
|
4
4
|
var utils = require('./utils-CZG22_vQ.js');
|
|
5
5
|
var index$1 = require('./index.cjs.js');
|
|
6
6
|
|
|
7
|
+
const leBarCss = () => `:host{display:block;--le-bar-gap:var(--le-spacing-2);--le-bar-padding:var(--le-spacing-2);--le-bar-min-height:2.5rem;--le-bar-background:transparent;--le-bar-border-color:var(--le-color-border);--le-bar-border-radius:var(--le-radius-md);--le-bar-button-size:2rem;--le-bar-button-color:var(--le-color-text-primary);--le-bar-button-hover-bg:var(--le-color-gray-100);--le-bar-button-border-radius:var(--le-radius-sm);--le-bar-arrow-size:1.5rem;--le-bar-popover-min-width:200px;--le-bar-popover-gap:var(--le-spacing-1)}.bar-container{display:flex;align-items:center;gap:var(--le-bar-gap);min-height:var(--le-bar-min-height);background:var(--le-bar-background);border-radius:var(--le-bar-border-radius);padding:var(--le-bar-padding)}.bar-container.align-start{justify-content:flex-start}.bar-container.align-end .bar-items{justify-content:flex-end}.bar-container.align-center .bar-items{justify-content:center}.bar-container.align-stretch .bar-items{justify-content:space-evenly}.bar-items{display:flex;flex-wrap:wrap;align-items:center;gap:var(--le-bar-gap);overflow:hidden;min-width:0;flex:1 1 0%;position:relative}.bar-items[style*="height"]{overflow:hidden}.bar-items.is-scrollable{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}.bar-items.is-scrollable::-webkit-scrollbar{display:none}.bar-items.is-scrollable ::slotted(*){scroll-snap-align:start;flex-shrink:0}.bar-items.is-wrapping{flex-wrap:wrap;overflow:visible;height:auto !important}.bar-controls{display:flex;align-items:center;gap:var(--le-spacing-1);flex-shrink:0}.bar-controls-start{order:-1}.bar-controls-end{order:1}.bar-more-button,.bar-hamburger-button,.bar-all-menu-button{display:inline-flex;align-items:center;justify-content:center;width:var(--le-bar-button-size);height:var(--le-bar-button-size);padding:0;border:none;background:transparent;color:var(--le-bar-button-color);border-radius:var(--le-bar-button-border-radius);cursor:pointer;transition:background-color 0.15s ease}.bar-more-button:hover,.bar-hamburger-button:hover,.bar-all-menu-button:hover{background:var(--le-bar-button-hover-bg)}.bar-more-button:focus-visible,.bar-hamburger-button:focus-visible,.bar-all-menu-button:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.bar-arrow{display:inline-flex;align-items:center;justify-content:center;width:var(--le-bar-arrow-size);height:var(--le-bar-arrow-size);padding:0;border:none;background:transparent;color:var(--le-bar-button-color);border-radius:var(--le-bar-button-border-radius);cursor:pointer;transition:background-color 0.15s ease, opacity 0.15s ease}.bar-arrow:hover:not(:disabled){background:var(--le-bar-button-hover-bg)}.bar-arrow:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.bar-arrow:disabled,.bar-arrow.disabled{opacity:0.3;cursor:not-allowed}.arrow-icon-start{transform:rotate(90deg)}.arrow-icon-end{transform:rotate(-90deg)}.bar-overflow-trigger,.bar-all-menu-trigger{display:inline-flex}.bar-popover-content{display:flex;flex-direction:column;gap:var(--le-bar-popover-gap);min-width:var(--le-bar-popover-min-width);padding:var(--le-spacing-2)}.bar-popover-item{cursor:pointer}.bar-popover-item:hover{background:var(--le-bar-button-hover-bg);border-radius:var(--le-bar-button-border-radius)}:host(.hamburger-active) .bar-items{visibility:hidden;pointer-events:none}`;
|
|
8
|
+
|
|
9
|
+
const LeBar = class {
|
|
10
|
+
constructor(hostRef) {
|
|
11
|
+
index.registerInstance(this, hostRef);
|
|
12
|
+
this.leBarOverflowChange = index.createEvent(this, "leBarOverflowChange");
|
|
13
|
+
}
|
|
14
|
+
get el() { return index.getElement(this); }
|
|
15
|
+
/**
|
|
16
|
+
* Overflow behavior when items don't fit on one row.
|
|
17
|
+
* - `more`: Overflow items appear in a "more" dropdown
|
|
18
|
+
* - `scroll`: Items scroll horizontally with optional arrows
|
|
19
|
+
* - `hamburger`: All items go into a hamburger menu if any overflow
|
|
20
|
+
* - `wrap`: Items wrap to additional rows
|
|
21
|
+
*/
|
|
22
|
+
overflow = 'more';
|
|
23
|
+
/**
|
|
24
|
+
* Alignment of items within the bar (maps to justify-content).
|
|
25
|
+
*/
|
|
26
|
+
alignItems = 'start';
|
|
27
|
+
/**
|
|
28
|
+
* Show scroll arrows when overflow is "scroll".
|
|
29
|
+
*/
|
|
30
|
+
arrows = false;
|
|
31
|
+
/**
|
|
32
|
+
* Disable the internal overflow popover.
|
|
33
|
+
* When true, the bar still detects overflow and hides items,
|
|
34
|
+
* but doesn't render its own popover. Use this when providing
|
|
35
|
+
* custom overflow handling via the leBarOverflowChange event.
|
|
36
|
+
*/
|
|
37
|
+
disablePopover = false;
|
|
38
|
+
/**
|
|
39
|
+
* Minimum number of visible items required when using "more" overflow mode.
|
|
40
|
+
* If fewer items would be visible, the bar falls back to hamburger mode.
|
|
41
|
+
* Only applies when overflow is "more".
|
|
42
|
+
*/
|
|
43
|
+
minVisibleItems = 0;
|
|
44
|
+
/**
|
|
45
|
+
* Show an "all items" menu button.
|
|
46
|
+
* - `false`: Don't show
|
|
47
|
+
* - `true` or `'end'`: Show at end
|
|
48
|
+
* - `'start'`: Show at start
|
|
49
|
+
*/
|
|
50
|
+
showAllMenu = false;
|
|
51
|
+
/**
|
|
52
|
+
* Emitted when overflow state changes.
|
|
53
|
+
*/
|
|
54
|
+
leBarOverflowChange;
|
|
55
|
+
/** Whether the hamburger/more popover is open */
|
|
56
|
+
popoverOpen = false;
|
|
57
|
+
/** Whether hamburger mode is active (for hamburger overflow) */
|
|
58
|
+
hamburgerActive = false;
|
|
59
|
+
/** IDs of items that are overflowing */
|
|
60
|
+
overflowingIds = new Set();
|
|
61
|
+
/** Whether we can scroll left */
|
|
62
|
+
canScrollStart = false;
|
|
63
|
+
/** Whether we can scroll right */
|
|
64
|
+
canScrollEnd = false;
|
|
65
|
+
/** Whether the all-menu popover is open */
|
|
66
|
+
allMenuOpen = false;
|
|
67
|
+
/** Current height of the items container (for overflow handling) */
|
|
68
|
+
containerHeight = null;
|
|
69
|
+
itemsContainerEl;
|
|
70
|
+
moreButtonEl;
|
|
71
|
+
resizeObserver;
|
|
72
|
+
mutationObserver;
|
|
73
|
+
instanceId = utils.generateId('le-bar');
|
|
74
|
+
// Map to track item elements and their IDs
|
|
75
|
+
itemMap = new Map();
|
|
76
|
+
// Prevent multiple recalculations in the same frame
|
|
77
|
+
pendingRecalc = null;
|
|
78
|
+
handleOverflowChange() {
|
|
79
|
+
this.resetOverflowState();
|
|
80
|
+
this.scheduleOverflowRecalc();
|
|
81
|
+
}
|
|
82
|
+
handleSlotChange() {
|
|
83
|
+
this.scheduleOverflowRecalc();
|
|
84
|
+
}
|
|
85
|
+
connectedCallback() {
|
|
86
|
+
this.setupObservers();
|
|
87
|
+
}
|
|
88
|
+
componentDidLoad() {
|
|
89
|
+
this.scheduleOverflowRecalc();
|
|
90
|
+
}
|
|
91
|
+
componentDidRender() {
|
|
92
|
+
// Recalculate after render in case children changed
|
|
93
|
+
this.scheduleOverflowRecalc();
|
|
94
|
+
}
|
|
95
|
+
disconnectedCallback() {
|
|
96
|
+
this.resizeObserver?.disconnect();
|
|
97
|
+
this.mutationObserver?.disconnect();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Force recalculation of overflow state.
|
|
101
|
+
*/
|
|
102
|
+
async recalculate() {
|
|
103
|
+
this.computeOverflow();
|
|
104
|
+
}
|
|
105
|
+
setupObservers() {
|
|
106
|
+
// ResizeObserver for container size changes
|
|
107
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
108
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
109
|
+
this.computeOverflow();
|
|
110
|
+
this.updateScrollState();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// MutationObserver for child changes
|
|
114
|
+
this.mutationObserver = new MutationObserver(() => {
|
|
115
|
+
this.scheduleOverflowRecalc();
|
|
116
|
+
});
|
|
117
|
+
this.mutationObserver.observe(this.el, {
|
|
118
|
+
childList: true,
|
|
119
|
+
subtree: false,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
observeContainer(el) {
|
|
123
|
+
if (!this.resizeObserver)
|
|
124
|
+
return;
|
|
125
|
+
this.resizeObserver.disconnect();
|
|
126
|
+
if (el)
|
|
127
|
+
this.resizeObserver.observe(el);
|
|
128
|
+
}
|
|
129
|
+
scheduleOverflowRecalc() {
|
|
130
|
+
// Debounce recalculations to prevent infinite loops
|
|
131
|
+
if (this.pendingRecalc !== null) {
|
|
132
|
+
cancelAnimationFrame(this.pendingRecalc);
|
|
133
|
+
}
|
|
134
|
+
this.pendingRecalc = requestAnimationFrame(() => {
|
|
135
|
+
this.pendingRecalc = null;
|
|
136
|
+
this.computeOverflow();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
resetOverflowState() {
|
|
140
|
+
this.hamburgerActive = false;
|
|
141
|
+
this.overflowingIds = new Set();
|
|
142
|
+
this.containerHeight = null;
|
|
143
|
+
this.popoverOpen = false;
|
|
144
|
+
}
|
|
145
|
+
getSlottedItems() {
|
|
146
|
+
// Get direct children from the light DOM (excluding named slot elements)
|
|
147
|
+
return Array.from(this.el.children).filter((el) => el instanceof HTMLElement && !el.hasAttribute('slot'));
|
|
148
|
+
}
|
|
149
|
+
getItemId(el, index) {
|
|
150
|
+
return el.id || el.dataset.barId || `${this.instanceId}-item-${index}`;
|
|
151
|
+
}
|
|
152
|
+
computeOverflow() {
|
|
153
|
+
if (this.overflow === 'wrap' || this.overflow === 'scroll') {
|
|
154
|
+
// No overflow handling needed for wrap/scroll modes
|
|
155
|
+
this.resetOverflowState();
|
|
156
|
+
this.updateScrollState();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const container = this.itemsContainerEl;
|
|
160
|
+
if (!container)
|
|
161
|
+
return;
|
|
162
|
+
const items = this.getSlottedItems();
|
|
163
|
+
if (items.length === 0) {
|
|
164
|
+
this.resetOverflowState();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Build item map
|
|
168
|
+
this.itemMap.clear();
|
|
169
|
+
items.forEach((item, index) => {
|
|
170
|
+
const id = this.getItemId(item, index);
|
|
171
|
+
this.itemMap.set(id, item);
|
|
172
|
+
});
|
|
173
|
+
// Get the position of items to determine which are on the first row
|
|
174
|
+
const itemRects = items.map((item, index) => ({
|
|
175
|
+
item,
|
|
176
|
+
id: this.getItemId(item, index),
|
|
177
|
+
rect: item.getBoundingClientRect(),
|
|
178
|
+
}));
|
|
179
|
+
if (itemRects.length === 0) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Find the first row's top position (accounting for vertical alignment)
|
|
183
|
+
const containerRect = container.getBoundingClientRect();
|
|
184
|
+
const topValues = itemRects.map(i => i.rect.top - containerRect.top);
|
|
185
|
+
const minTop = Math.min(...topValues);
|
|
186
|
+
// Items are on the first row if their top is close to minTop
|
|
187
|
+
// Allow some tolerance for alignment differences
|
|
188
|
+
const tolerance = 15;
|
|
189
|
+
const firstRowItems = itemRects.filter(i => i.rect.top - containerRect.top <= minTop + tolerance);
|
|
190
|
+
const overflowItems = itemRects.filter(i => i.rect.top - containerRect.top > minTop + tolerance);
|
|
191
|
+
// Calculate the height of the first row
|
|
192
|
+
const firstRowBottom = firstRowItems.length > 0
|
|
193
|
+
? Math.max(...firstRowItems.map(i => i.rect.bottom - containerRect.top))
|
|
194
|
+
: 0;
|
|
195
|
+
if (this.overflow === 'hamburger') {
|
|
196
|
+
// In hamburger mode, if ANY item overflows, all go into the menu
|
|
197
|
+
const shouldHamburger = overflowItems.length > 0;
|
|
198
|
+
if (shouldHamburger !== this.hamburgerActive) {
|
|
199
|
+
this.hamburgerActive = shouldHamburger;
|
|
200
|
+
this.emitOverflowChange();
|
|
201
|
+
}
|
|
202
|
+
// Set height to show only first row (or hide all if hamburger is active)
|
|
203
|
+
if (shouldHamburger && firstRowBottom > 0) {
|
|
204
|
+
this.containerHeight = firstRowBottom;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
this.containerHeight = null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// 'more' mode
|
|
212
|
+
let newOverflowingIds = new Set(overflowItems.map(i => i.id));
|
|
213
|
+
// Check if we need to make room for the "more" button
|
|
214
|
+
if (newOverflowingIds.size > 0 && this.moreButtonEl) {
|
|
215
|
+
const moreRect = this.moreButtonEl.getBoundingClientRect();
|
|
216
|
+
const moreTop = moreRect.top - containerRect.top;
|
|
217
|
+
// If "more" button is not on the first row, we need to hide one more item
|
|
218
|
+
if (moreTop > minTop + tolerance) {
|
|
219
|
+
// Find the last visible item and move it to overflow
|
|
220
|
+
const lastVisible = firstRowItems[firstRowItems.length - 1];
|
|
221
|
+
if (lastVisible) {
|
|
222
|
+
newOverflowingIds.add(lastVisible.id);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Check if we should fallback to hamburger mode
|
|
227
|
+
// This happens when minVisibleItems is set and fewer items would be visible
|
|
228
|
+
const visibleCount = items.length - newOverflowingIds.size;
|
|
229
|
+
const shouldFallbackToHamburger = this.minVisibleItems > 0 &&
|
|
230
|
+
newOverflowingIds.size > 0 &&
|
|
231
|
+
visibleCount < this.minVisibleItems;
|
|
232
|
+
if (shouldFallbackToHamburger) {
|
|
233
|
+
// Switch to hamburger mode - all items go into the menu
|
|
234
|
+
if (!this.hamburgerActive) {
|
|
235
|
+
this.hamburgerActive = true;
|
|
236
|
+
this.overflowingIds = new Set();
|
|
237
|
+
this.emitOverflowChange();
|
|
238
|
+
}
|
|
239
|
+
// Set height to show only first row
|
|
240
|
+
if (firstRowBottom > 0) {
|
|
241
|
+
this.containerHeight = firstRowBottom;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
this.containerHeight = null;
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Not falling back to hamburger - ensure hamburgerActive is false
|
|
249
|
+
if (this.hamburgerActive) {
|
|
250
|
+
this.hamburgerActive = false;
|
|
251
|
+
}
|
|
252
|
+
// Check if overflow state changed
|
|
253
|
+
const hasChanged = (newOverflowingIds?.size ?? 0) !== (this.overflowingIds?.size ?? 0) ||
|
|
254
|
+
![...newOverflowingIds].every(id => this.overflowingIds?.has(id));
|
|
255
|
+
if (hasChanged) {
|
|
256
|
+
this.overflowingIds = newOverflowingIds;
|
|
257
|
+
this.emitOverflowChange();
|
|
258
|
+
}
|
|
259
|
+
// Set container height to show only first row
|
|
260
|
+
if ((newOverflowingIds?.size ?? 0) > 0 && firstRowBottom > 0) {
|
|
261
|
+
this.containerHeight = firstRowBottom;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
this.containerHeight = null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
emitOverflowChange() {
|
|
269
|
+
this.leBarOverflowChange.emit({
|
|
270
|
+
overflowingIds: [...(this.overflowingIds ?? [])],
|
|
271
|
+
hamburgerActive: this.hamburgerActive,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
updateScrollState() {
|
|
275
|
+
if (this.overflow !== 'scroll' || !this.itemsContainerEl) {
|
|
276
|
+
this.canScrollStart = false;
|
|
277
|
+
this.canScrollEnd = false;
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const el = this.itemsContainerEl;
|
|
281
|
+
this.canScrollStart = el.scrollLeft > 0;
|
|
282
|
+
this.canScrollEnd = el.scrollLeft < el.scrollWidth - el.clientWidth - 1;
|
|
283
|
+
}
|
|
284
|
+
handleScroll = () => {
|
|
285
|
+
this.updateScrollState();
|
|
286
|
+
};
|
|
287
|
+
scrollToStart = () => {
|
|
288
|
+
if (!this.itemsContainerEl)
|
|
289
|
+
return;
|
|
290
|
+
const items = this.getSlottedItems();
|
|
291
|
+
const container = this.itemsContainerEl;
|
|
292
|
+
// Find the scroll position of the previous item
|
|
293
|
+
const currentScroll = container.scrollLeft;
|
|
294
|
+
let targetScroll = 0;
|
|
295
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
296
|
+
const item = items[i];
|
|
297
|
+
// Calculate item's left edge relative to container's scroll position
|
|
298
|
+
const itemLeft = item.offsetLeft - container.offsetLeft;
|
|
299
|
+
// If this item starts before current scroll position, scroll to it
|
|
300
|
+
if (itemLeft < currentScroll - 1) {
|
|
301
|
+
targetScroll = itemLeft;
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
container.scrollTo({ left: targetScroll, behavior: 'smooth' });
|
|
306
|
+
// Update scroll state after animation
|
|
307
|
+
setTimeout(() => this.updateScrollState(), 300);
|
|
308
|
+
};
|
|
309
|
+
scrollToEnd = () => {
|
|
310
|
+
if (!this.itemsContainerEl)
|
|
311
|
+
return;
|
|
312
|
+
const container = this.itemsContainerEl;
|
|
313
|
+
const items = this.getSlottedItems();
|
|
314
|
+
if (items.length === 0)
|
|
315
|
+
return;
|
|
316
|
+
const containerWidth = container.clientWidth;
|
|
317
|
+
const currentScroll = container.scrollLeft;
|
|
318
|
+
let targetScroll = container.scrollWidth - containerWidth;
|
|
319
|
+
for (const item of items) {
|
|
320
|
+
// Calculate item's right edge relative to container
|
|
321
|
+
const itemLeft = item.offsetLeft - container.offsetLeft;
|
|
322
|
+
// If this is the next item to scroll to from left to right then scroll to it
|
|
323
|
+
if (itemLeft > currentScroll + 1) {
|
|
324
|
+
targetScroll = itemLeft;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
container.scrollTo({ left: Math.max(0, targetScroll), behavior: 'smooth' });
|
|
329
|
+
// Update scroll state after animation
|
|
330
|
+
setTimeout(() => this.updateScrollState(), 300);
|
|
331
|
+
};
|
|
332
|
+
togglePopover = () => {
|
|
333
|
+
this.popoverOpen = !this.popoverOpen;
|
|
334
|
+
};
|
|
335
|
+
closePopover = () => {
|
|
336
|
+
this.popoverOpen = false;
|
|
337
|
+
};
|
|
338
|
+
toggleAllMenu = () => {
|
|
339
|
+
this.allMenuOpen = !this.allMenuOpen;
|
|
340
|
+
};
|
|
341
|
+
closeAllMenu = () => {
|
|
342
|
+
this.allMenuOpen = false;
|
|
343
|
+
};
|
|
344
|
+
handleItemClick = (_e, id) => {
|
|
345
|
+
// Close popover when an item inside is clicked
|
|
346
|
+
const originalItem = this.itemMap.get(id);
|
|
347
|
+
if (originalItem) {
|
|
348
|
+
// Clone the click to the original item
|
|
349
|
+
const cloneEvent = new MouseEvent('click', {
|
|
350
|
+
bubbles: true,
|
|
351
|
+
cancelable: true,
|
|
352
|
+
view: window,
|
|
353
|
+
});
|
|
354
|
+
originalItem.dispatchEvent(cloneEvent);
|
|
355
|
+
}
|
|
356
|
+
this.closePopover();
|
|
357
|
+
this.closeAllMenu();
|
|
358
|
+
};
|
|
359
|
+
renderMoreButton() {
|
|
360
|
+
const hasSlottedMore = this.el.querySelector('[slot="more"]');
|
|
361
|
+
return (index.h("button", { class: "bar-more-button", part: "more-button", ref: el => (this.moreButtonEl = el), onClick: this.togglePopover, "aria-expanded": String(this.popoverOpen), "aria-haspopup": "true" }, hasSlottedMore ? index.h("slot", { name: "more" }) : index.h("le-icon", { name: "ellipsis-horizontal" })));
|
|
362
|
+
}
|
|
363
|
+
renderHamburgerButton() {
|
|
364
|
+
const hasSlottedHamburger = this.el.querySelector('[slot="hamburger"]');
|
|
365
|
+
return (index.h("button", { class: "bar-hamburger-button", part: "hamburger-button", onClick: this.togglePopover, "aria-expanded": String(this.popoverOpen), "aria-haspopup": "true" }, hasSlottedHamburger ? index.h("slot", { name: "hamburger" }) : index.h("le-icon", { name: "hamburger" })));
|
|
366
|
+
}
|
|
367
|
+
renderScrollArrows() {
|
|
368
|
+
if (!this.arrows || this.overflow !== 'scroll')
|
|
369
|
+
return null;
|
|
370
|
+
const hasSlottedStartArrow = this.el.querySelector('[slot="start-arrow"]');
|
|
371
|
+
const hasSlottedEndArrow = this.el.querySelector('[slot="end-arrow"]');
|
|
372
|
+
return [
|
|
373
|
+
index.h("button", { class: utils.classnames('bar-arrow', 'bar-arrow-start', {
|
|
374
|
+
disabled: !this.canScrollStart,
|
|
375
|
+
}), part: "arrow-start", onClick: this.scrollToStart, disabled: !this.canScrollStart, "aria-label": "Scroll to start" }, hasSlottedStartArrow ? (index.h("slot", { name: "start-arrow" })) : (index.h("le-icon", { name: "chevron-down", class: "arrow-icon-start" }))),
|
|
376
|
+
index.h("button", { class: utils.classnames('bar-arrow', 'bar-arrow-end', {
|
|
377
|
+
disabled: !this.canScrollEnd,
|
|
378
|
+
}), part: "arrow-end", onClick: this.scrollToEnd, disabled: !this.canScrollEnd, "aria-label": "Scroll to end" }, hasSlottedEndArrow ? (index.h("slot", { name: "end-arrow" })) : (index.h("le-icon", { name: "chevron-down", class: "arrow-icon-end" }))),
|
|
379
|
+
];
|
|
380
|
+
}
|
|
381
|
+
renderAllMenuButton() {
|
|
382
|
+
if (!this.showAllMenu)
|
|
383
|
+
return null;
|
|
384
|
+
const hasSlottedAllMenu = this.el.querySelector('[slot="all-menu"]');
|
|
385
|
+
return (index.h("button", { class: "bar-all-menu-button", part: "all-menu-button", onClick: this.toggleAllMenu, "aria-expanded": String(this.allMenuOpen), "aria-haspopup": "true" }, hasSlottedAllMenu ? index.h("slot", { name: "all-menu" }) : index.h("le-icon", { name: "hamburger" })));
|
|
386
|
+
}
|
|
387
|
+
renderPopoverContent(itemsToShow) {
|
|
388
|
+
return (index.h("div", { class: "bar-popover-content", part: "popover-content" }, itemsToShow.map(({ id, item }) => (index.h("div", { class: "bar-popover-item", key: id, onClick: (e) => this.handleItemClick(e, id), innerHTML: item.outerHTML })))));
|
|
389
|
+
}
|
|
390
|
+
renderOverflowPopover() {
|
|
391
|
+
if (this.overflow !== 'more' && this.overflow !== 'hamburger')
|
|
392
|
+
return null;
|
|
393
|
+
const items = this.getSlottedItems();
|
|
394
|
+
let itemsToShow = [];
|
|
395
|
+
if (this.overflow === 'hamburger' && this.hamburgerActive) {
|
|
396
|
+
// Show all items in hamburger mode
|
|
397
|
+
itemsToShow = items.map((item, index) => ({
|
|
398
|
+
id: this.getItemId(item, index),
|
|
399
|
+
item,
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
else if (this.overflow === 'more' && (this.overflowingIds?.size ?? 0) > 0) {
|
|
403
|
+
// Show only overflowing items
|
|
404
|
+
itemsToShow = items
|
|
405
|
+
.map((item, index) => ({
|
|
406
|
+
id: this.getItemId(item, index),
|
|
407
|
+
item,
|
|
408
|
+
}))
|
|
409
|
+
.filter(({ id }) => this.overflowingIds?.has(id));
|
|
410
|
+
}
|
|
411
|
+
if (itemsToShow.length === 0)
|
|
412
|
+
return null;
|
|
413
|
+
return (index.h("le-popover", { mode: "default", open: this.popoverOpen, position: "bottom", align: "end", showClose: false, closeOnClickOutside: true, closeOnEscape: true, onLePopoverClose: this.closePopover }, index.h("div", { slot: "trigger", class: "bar-overflow-trigger" }, this.overflow === 'hamburger' ? this.renderHamburgerButton() : this.renderMoreButton()), this.renderPopoverContent(itemsToShow)));
|
|
414
|
+
}
|
|
415
|
+
renderAllMenuPopover() {
|
|
416
|
+
if (!this.showAllMenu)
|
|
417
|
+
return null;
|
|
418
|
+
const items = this.getSlottedItems();
|
|
419
|
+
const itemsToShow = items.map((item, index) => ({
|
|
420
|
+
id: this.getItemId(item, index),
|
|
421
|
+
item,
|
|
422
|
+
}));
|
|
423
|
+
const position = this.showAllMenu === 'start' ? 'start' : 'end';
|
|
424
|
+
return (index.h("le-popover", { mode: "default", open: this.allMenuOpen, position: "bottom", align: position, showClose: false, closeOnClickOutside: true, closeOnEscape: true, onLePopoverClose: this.closeAllMenu }, index.h("div", { slot: "trigger", class: "bar-all-menu-trigger" }, this.renderAllMenuButton()), this.renderPopoverContent(itemsToShow)));
|
|
425
|
+
}
|
|
426
|
+
render() {
|
|
427
|
+
const showOverflowButton = !this.disablePopover &&
|
|
428
|
+
((this.overflow === 'more' && (this.overflowingIds?.size ?? 0) > 0) ||
|
|
429
|
+
(this.overflow === 'hamburger' && this.hamburgerActive));
|
|
430
|
+
const containerStyle = {};
|
|
431
|
+
if (this.containerHeight !== null &&
|
|
432
|
+
(this.overflow === 'more' || this.overflow === 'hamburger')) {
|
|
433
|
+
containerStyle.height = `${this.containerHeight}px`;
|
|
434
|
+
}
|
|
435
|
+
const showAllMenuAtStart = this.showAllMenu === 'start';
|
|
436
|
+
const showAllMenuAtEnd = this.showAllMenu === true || this.showAllMenu === 'end';
|
|
437
|
+
return (index.h(index.Host, { key: '56d04e4504ed7ce1d8e78a825c71c71c074d0b62', class: utils.classnames({
|
|
438
|
+
'overflow-more': this.overflow === 'more',
|
|
439
|
+
'overflow-scroll': this.overflow === 'scroll',
|
|
440
|
+
'overflow-hamburger': this.overflow === 'hamburger',
|
|
441
|
+
'overflow-wrap': this.overflow === 'wrap',
|
|
442
|
+
'hamburger-active': this.hamburgerActive,
|
|
443
|
+
'has-overflow': (this.overflowingIds?.size ?? 0) > 0 || this.hamburgerActive,
|
|
444
|
+
}) }, index.h("div", { key: '4e7aeb4c84a9964e19012c3d05827fa8406988b0', class: utils.classnames('bar-container', {
|
|
445
|
+
[`align-${this.alignItems}`]: true,
|
|
446
|
+
}), part: "container" }, this.overflow === 'scroll' && this.arrows && (index.h("div", { key: '2e3ae04c00e88e5055216dbc5b6d53574c450470', class: "bar-controls bar-controls-start" }, this.renderScrollArrows()?.[0])), showAllMenuAtStart && (index.h("div", { key: '9628c8dc2b15d9358baad63b19c75fd933eeb19a', class: "bar-controls bar-controls-start" }, this.renderAllMenuPopover())), index.h("div", { key: 'd1feb9603d0ff4247852aadb62cb920a5f5a1921', class: utils.classnames('bar-items', {
|
|
447
|
+
'is-scrollable': this.overflow === 'scroll',
|
|
448
|
+
'is-wrapping': this.overflow === 'wrap',
|
|
449
|
+
}), style: containerStyle, ref: el => {
|
|
450
|
+
this.itemsContainerEl = el;
|
|
451
|
+
this.observeContainer(el);
|
|
452
|
+
}, onScroll: this.overflow === 'scroll' ? this.handleScroll : undefined }, index.h("slot", { key: '338698e038b9df4c7b163017ceb0675b834160e4' })), showOverflowButton && (index.h("div", { key: 'd619fcda1b0c28247af60899f73cc076b0517787', class: "bar-controls bar-controls-end" }, this.renderOverflowPopover())), showAllMenuAtEnd && (index.h("div", { key: 'fd9fef90194aabb8d48e77c8f7615daa5d7297ac', class: "bar-controls bar-controls-end" }, this.renderAllMenuPopover())), this.overflow === 'scroll' && this.arrows && (index.h("div", { key: 'bcffb914e2788767c3765351a3eeae771f3e115f', class: "bar-controls bar-controls-end" }, this.renderScrollArrows()?.[1])))));
|
|
453
|
+
}
|
|
454
|
+
static get watchers() { return {
|
|
455
|
+
"overflow": ["handleOverflowChange"]
|
|
456
|
+
}; }
|
|
457
|
+
};
|
|
458
|
+
LeBar.style = leBarCss();
|
|
459
|
+
|
|
7
460
|
const leButtonCss = () => `:host{display:inline-block;--le-button-border-radius:var(--le-radius-md);--le-button-padding-x:var(--le-spacing-3);--le-button-padding-y:var(--le-spacing-1);--le-button-padding:var(--le-button-padding-y) var(--le-button-padding-x);--le-button-small-padding:0.25rem;--le-button-font-size:var(--le-font-size-md);--le-button-font-weight:var(--le-font-weight-medium);--le-button-transition:var(--le-transition-fast);--le-transition-easing:ease-in-out;--le-button-icon-aspect-ratio:1;--le-button-color:var(--le-color-primary-contrast);--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-bg-system:var(--le-color-black);--_btn-color:var(--le-button-color);--_btn-border-color:var(--le-color-primary)}:host([full-width]){display:block;width:100%}.le-button-container{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;gap:var(--le-spacing-3);width:100%;padding:var(--le-button-padding);border:1px solid var(--_btn-border-color);border-radius:var(--le-button-border-radius);background:var(--_btn-bg);color:var(--_btn-color);font-family:var(--le-font-family-base);font-size:var(--le-button-font-size);font-weight:var(--le-button-font-weight);line-height:var(--le-line-height-tight);text-decoration:none;cursor:pointer;transition:background-color var(--le-button-transition) var(--le-transition-easing),
|
|
8
461
|
border-color var(--le-button-transition) var(--le-transition-easing),
|
|
9
462
|
box-shadow var(--le-button-transition) var(--le-transition-easing),
|
|
@@ -437,7 +890,7 @@ const LeComponent = class {
|
|
|
437
890
|
const enumMatch = type.match(/^'[^']+'/);
|
|
438
891
|
if (enumMatch) {
|
|
439
892
|
const options = type.split('|').map(opt => opt.trim().replace(/'/g, ''));
|
|
440
|
-
return (index.h("div", { class: "property-field" }, index.h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && index.h("span", { class: "property-hint" }, attr.description)), index.h("le-select", { options: [...options.map(opt => ({ label: opt, value: opt }))], "full-width": true, value: value ?? attr.default?.replace(/'/g, ''), placeholder: attr.default?.replace(/'/g, ''),
|
|
893
|
+
return (index.h("div", { class: "property-field" }, index.h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && index.h("span", { class: "property-hint" }, attr.description)), index.h("le-select", { options: [...options.map(opt => ({ label: opt, value: opt }))], "full-width": true, value: value ?? attr.default?.replace(/'/g, ''), placeholder: attr.default?.replace(/'/g, ''), onChange: (e) => this.handlePropertyChange(attr.name, e.detail.value, type) })));
|
|
441
894
|
}
|
|
442
895
|
// Boolean type
|
|
443
896
|
if (type === 'boolean') {
|
|
@@ -1123,6 +1576,496 @@ const LeHeader = class {
|
|
|
1123
1576
|
};
|
|
1124
1577
|
LeHeader.style = leHeaderCss();
|
|
1125
1578
|
|
|
1579
|
+
const leIconCss = () => `:host{display:inline-block;width:var(--le-icon-size, var(--le-size-4));height:var(--le-icon-size, var(--le-size-4));color:var(--le-icon-color, var(--le-color-text-primary))}:host svg{display:block;fill:currentColor}`;
|
|
1580
|
+
|
|
1581
|
+
const iconCache = {};
|
|
1582
|
+
const requestCache = {};
|
|
1583
|
+
async function fetchIcon({ name }) {
|
|
1584
|
+
if (iconCache[name]) {
|
|
1585
|
+
return iconCache[name];
|
|
1586
|
+
}
|
|
1587
|
+
if (!requestCache[name]) {
|
|
1588
|
+
console.log(`Fetching icon "${name}"`, index.getAssetPath(`./assets/icons/${name}.json`));
|
|
1589
|
+
requestCache[name] = fetch(index.getAssetPath(`./assets/icons/${name}.json`))
|
|
1590
|
+
.then(resp => resp.json())
|
|
1591
|
+
.catch(() => {
|
|
1592
|
+
console.error(`"${name}" is not a valid name`);
|
|
1593
|
+
return '';
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
const path = await requestCache[name];
|
|
1597
|
+
iconCache[name] = path;
|
|
1598
|
+
return path;
|
|
1599
|
+
}
|
|
1600
|
+
const LeIcon = class {
|
|
1601
|
+
constructor(hostRef) {
|
|
1602
|
+
index.registerInstance(this, hostRef);
|
|
1603
|
+
}
|
|
1604
|
+
get el() { return index.getElement(this); }
|
|
1605
|
+
/**
|
|
1606
|
+
* Name of the icon to display. Corresponds to a JSON file in the assets folder.
|
|
1607
|
+
* For example, "search" will load the "search.json" file.
|
|
1608
|
+
*/
|
|
1609
|
+
name = null;
|
|
1610
|
+
/**
|
|
1611
|
+
* Size of the icon in pixels. Default is 16.
|
|
1612
|
+
*/
|
|
1613
|
+
size = 16;
|
|
1614
|
+
iconData = null;
|
|
1615
|
+
visible = false;
|
|
1616
|
+
async loadIconData() {
|
|
1617
|
+
const { name, visible } = this;
|
|
1618
|
+
if (!name || !visible) {
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
this.iconData = await fetchIcon({ name });
|
|
1622
|
+
}
|
|
1623
|
+
intersectionObserver;
|
|
1624
|
+
connectedCallback() {
|
|
1625
|
+
this.waitUntilVisible(() => {
|
|
1626
|
+
this.visible = true;
|
|
1627
|
+
this.loadIconData();
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1630
|
+
disconnectedCallback() {
|
|
1631
|
+
if (this.intersectionObserver) {
|
|
1632
|
+
this.intersectionObserver.disconnect();
|
|
1633
|
+
this.intersectionObserver = null;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
async componentWillLoad() {
|
|
1637
|
+
this.loadIconData();
|
|
1638
|
+
}
|
|
1639
|
+
waitUntilVisible(callback) {
|
|
1640
|
+
if (typeof window === 'undefined' ||
|
|
1641
|
+
!window.IntersectionObserver) {
|
|
1642
|
+
callback();
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
this.intersectionObserver = new IntersectionObserver(entries => {
|
|
1646
|
+
entries.forEach(entry => {
|
|
1647
|
+
if (entry.isIntersecting) {
|
|
1648
|
+
this.intersectionObserver.disconnect();
|
|
1649
|
+
this.intersectionObserver = null;
|
|
1650
|
+
callback();
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}, { rootMargin: '50px' });
|
|
1654
|
+
this.intersectionObserver.observe(this.el);
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Renders the SVG content out of a JSON data in a format:
|
|
1658
|
+
* { "viewBox": "...", children: [{ "tag": "g", ""children": [ ... ], ...attrs }, ...] }
|
|
1659
|
+
*
|
|
1660
|
+
* @returns JSX.Element | null
|
|
1661
|
+
*/
|
|
1662
|
+
renderSVGContent(children) {
|
|
1663
|
+
if (!children || children.length === 0) {
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
const createElement = node => {
|
|
1667
|
+
const { tag, children, ...attrs } = node;
|
|
1668
|
+
return index.h(tag, attrs, children ? children.map(createElement) : null);
|
|
1669
|
+
};
|
|
1670
|
+
const svgElements = children.map(createElement);
|
|
1671
|
+
return svgElements;
|
|
1672
|
+
}
|
|
1673
|
+
render() {
|
|
1674
|
+
return (index.h("svg", { key: 'ef551908a289cd765ae88ded83b99057d510e142', xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", height: this.size || 16, width: this.size || 16, viewBox: this.iconData?.viewBox || `0 0 ${this.size || 16} ${this.size || 16}` }, this.renderSVGContent(this.iconData?.children)));
|
|
1675
|
+
}
|
|
1676
|
+
static get assetsDirs() { return ["assets/icons"]; }
|
|
1677
|
+
static get watchers() { return {
|
|
1678
|
+
"name": ["loadIconData"]
|
|
1679
|
+
}; }
|
|
1680
|
+
};
|
|
1681
|
+
LeIcon.style = leIconCss();
|
|
1682
|
+
|
|
1683
|
+
const leNavigationCss = () => `:host{display:block;--le-nav-radius:var(--le-radius-md);--le-nav-gap:var(--le-spacing-2);--le-nav-item-padding-x:var(--le-spacing-1);--le-nav-item-padding-y:var(--le-spacing-2);--le-nav-item-gap:var(--le-spacing-2);--le-nav-color:var(--le-color-text-primary);--le-nav-muted:var(--le-color-text-secondary);--le-nav-hover-bg:var(--le-color-gray-100);--le-nav-selected-bg:var(--le-color-primary);--le-nav-selected-color:var(--le-color-primary-contrast)}:host([orientation='horizontal']:not([wrap])){flex:1 1 0%;min-width:0}.nav-vertical{display:flex;flex-direction:column;gap:var(--le-nav-gap)}.nav-search{width:100%}.nav-search-input{--le-input-radius:var(--le-radius-md)}.nav-empty{padding:var(--le-spacing-2);color:var(--le-nav-muted);font-size:var(--le-font-size-sm)}.nav-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--le-spacing-1)}.nav-row{display:flex;align-items:stretch;gap:var(--le-spacing-1);border-radius:var(--le-nav-radius)}.nav-row:hover{background:var(--le-nav-hover-bg)}.nav-toggle,.nav-toggle-spacer{box-sizing:border-box;width:var(--le-spacing-4);min-width:var(--le-spacing-4);display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:var(--le-nav-radius);color:inherit}.nav-toggle{background:transparent;cursor:pointer;opacity:0.4}.nav-toggle:hover:not(:disabled){opacity:1}.nav-toggle:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px;opacity:1}.nav-chevron{display:inline-block;transition:transform var(--le-transition-fast)}.nav-chevron svg{display:block;width:var(--le-spacing-4);height:var(--le-spacing-4)}.nav-node>div>button>.nav-chevron{transform:rotate(-90deg)}.nav-node.open>div>button>.nav-chevron{transform:rotate(0deg)}.nav-item{flex:1;display:inline-flex;align-items:center;gap:var(--le-nav-item-gap);padding:var(--le-nav-item-padding-y) var(--le-nav-item-padding-x) var(--le-nav-item-padding-y) 0;border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;text-decoration:none;color:var(--le-nav-color);font-family:var(--le-font-family-base);font-size:var(--le-font-size-md);line-height:var(--le-line-height-tight);cursor:pointer}.nav-item:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.nav-node.selected>.nav-row{background:var(--le-nav-selected-bg);color:var(--le-nav-selected-color)}.nav-node.selected>.nav-row>.nav-item{color:inherit}.nav-node.disabled>.nav-row>.nav-item{opacity:0.5;cursor:not-allowed}.nav-text{display:flex;flex-direction:column;min-width:0}.nav-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav-description{color:color-mix(in srgb, var(--le-nav-muted) 90%, transparent);font-size:var(--le-font-size-sm);line-height:var(--le-line-height-tight)}.nav-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.nav-icon-end{margin-left:auto}.nav-children{margin-top:var(--le-spacing-1)}.nav-horizontal-wrapper{display:flex;align-items:center;gap:var(--le-spacing-2)}.nav-bar{flex:1 1 0%;min-width:0;--le-bar-gap:var(--le-spacing-2)}.nav-bar.align-end{--le-bar-justify:flex-end}.nav-bar.align-center{--le-bar-justify:center}.nav-bar.align-space-between{--le-bar-justify:space-between}.h-item{display:flex;align-items:center}.h-link{display:inline-flex;align-items:center;gap:var(--le-spacing-2);padding:var(--le-spacing-2) var(--le-spacing-3);border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;text-decoration:none;color:var(--le-nav-color);font-family:var(--le-font-family-base);font-size:var(--le-font-size-md);cursor:pointer}.h-link:hover{background:var(--le-nav-hover-bg)}.h-link:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.h-link.disabled,.h-trigger.disabled{opacity:0.5;pointer-events:none}.h-link.selected,.h-trigger.selected{background:var(--le-nav-selected-bg);color:var(--le-nav-selected-color)}.h-label{white-space:nowrap}.h-trigger{display:inline-flex;align-items:center;gap:var(--le-spacing-1);border-radius:var(--le-nav-radius)}.h-submenu-toggle{width:var(--le-spacing-3);height:var(--le-spacing-3);display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:var(--le-nav-radius);background:transparent;color:currentColor;cursor:pointer}.h-submenu-toggle:hover{background:var(--le-nav-hover-bg)}.overflow-trigger{display:inline-flex;align-items:center;justify-content:center;gap:var(--le-spacing-2);padding:var(--le-spacing-2) var(--le-spacing-3);border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;color:var(--le-nav-color);cursor:pointer;font-family:var(--le-font-family-base);font-size:var(--le-font-size-md)}.overflow-trigger:hover{background:var(--le-nav-hover-bg)}.overflow-trigger:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.nav-overflow-trigger{display:flex;align-items:center}le-popover::part(content){padding:var(--le-spacing-1)}`;
|
|
1684
|
+
|
|
1685
|
+
const LeNavigation = class {
|
|
1686
|
+
constructor(hostRef) {
|
|
1687
|
+
index.registerInstance(this, hostRef);
|
|
1688
|
+
this.leNavItemSelect = index.createEvent(this, "leNavItemSelect");
|
|
1689
|
+
this.leNavItemToggle = index.createEvent(this, "leNavItemToggle");
|
|
1690
|
+
}
|
|
1691
|
+
get el() { return index.getElement(this); }
|
|
1692
|
+
/**
|
|
1693
|
+
* Navigation items.
|
|
1694
|
+
* Can be passed as an array or JSON string (same pattern as le-select).
|
|
1695
|
+
*/
|
|
1696
|
+
items = [];
|
|
1697
|
+
/**
|
|
1698
|
+
* Layout orientation.
|
|
1699
|
+
*/
|
|
1700
|
+
orientation = 'horizontal';
|
|
1701
|
+
/**
|
|
1702
|
+
* Horizontal wrapping behavior.
|
|
1703
|
+
* If false, overflow behavior depends on `overflowMode`.
|
|
1704
|
+
*/
|
|
1705
|
+
wrap = false;
|
|
1706
|
+
/**
|
|
1707
|
+
* Overflow behavior for horizontal, non-wrapping menus.
|
|
1708
|
+
* - more: moves overflow items into a "More" popover
|
|
1709
|
+
* - hamburger: turns the whole nav into a hamburger popover
|
|
1710
|
+
*/
|
|
1711
|
+
overflowMode = 'more';
|
|
1712
|
+
/**
|
|
1713
|
+
* Minimum number of visible top-level items required to use the "More" overflow.
|
|
1714
|
+
* If fewer would be visible, the navigation falls back to hamburger.
|
|
1715
|
+
*/
|
|
1716
|
+
minVisibleItemsForMore = 2;
|
|
1717
|
+
/**
|
|
1718
|
+
* Alignment of the menu items within the navigation bar.
|
|
1719
|
+
*/
|
|
1720
|
+
align = 'start';
|
|
1721
|
+
/**
|
|
1722
|
+
* Active url for automatic selection.
|
|
1723
|
+
*/
|
|
1724
|
+
activeUrl = '';
|
|
1725
|
+
/**
|
|
1726
|
+
* Enables a search input for the vertical navigation.
|
|
1727
|
+
*/
|
|
1728
|
+
searchable = false;
|
|
1729
|
+
/**
|
|
1730
|
+
* Placeholder text for the search input.
|
|
1731
|
+
*/
|
|
1732
|
+
searchPlaceholder = 'Search...';
|
|
1733
|
+
/**
|
|
1734
|
+
* Text shown when no items match the filter.
|
|
1735
|
+
*/
|
|
1736
|
+
emptyText = 'No results found';
|
|
1737
|
+
/**
|
|
1738
|
+
* Whether submenu popovers should include a filter input.
|
|
1739
|
+
*/
|
|
1740
|
+
submenuSearchable = false;
|
|
1741
|
+
/**
|
|
1742
|
+
* Fired when a navigation item is activated.
|
|
1743
|
+
*
|
|
1744
|
+
* This event is cancelable. Call `event.preventDefault()` to prevent
|
|
1745
|
+
* default browser navigation and implement custom routing.
|
|
1746
|
+
*/
|
|
1747
|
+
leNavItemSelect;
|
|
1748
|
+
/**
|
|
1749
|
+
* Fired when a tree branch is toggled.
|
|
1750
|
+
*/
|
|
1751
|
+
leNavItemToggle;
|
|
1752
|
+
searchQuery = '';
|
|
1753
|
+
openState = {};
|
|
1754
|
+
/** IDs of items currently in overflow (from le-bar) */
|
|
1755
|
+
overflowIds = [];
|
|
1756
|
+
/** Whether hamburger mode is active (from le-bar) */
|
|
1757
|
+
hamburgerActive = false;
|
|
1758
|
+
submenuQueries = {};
|
|
1759
|
+
/** Whether the overflow popover is open */
|
|
1760
|
+
overflowPopoverOpen = false;
|
|
1761
|
+
popoverRefs = new Map();
|
|
1762
|
+
instanceId = utils.generateId('le-nav');
|
|
1763
|
+
partFromOptionPart(base, part) {
|
|
1764
|
+
const raw = (part ?? '').trim();
|
|
1765
|
+
if (!raw)
|
|
1766
|
+
return base;
|
|
1767
|
+
const tokens = raw
|
|
1768
|
+
.split(/\s+/)
|
|
1769
|
+
.map(t => t.replace(/[^a-zA-Z0-9_-]/g, ''))
|
|
1770
|
+
.filter(Boolean);
|
|
1771
|
+
if (tokens.length === 0)
|
|
1772
|
+
return base;
|
|
1773
|
+
return [base, ...tokens.map(t => `${base}-${t}`)].join(' ');
|
|
1774
|
+
}
|
|
1775
|
+
handleLayoutInputsChange() {
|
|
1776
|
+
// Reset overflow state when layout inputs change
|
|
1777
|
+
this.overflowIds = [];
|
|
1778
|
+
this.hamburgerActive = false;
|
|
1779
|
+
}
|
|
1780
|
+
disconnectedCallback() {
|
|
1781
|
+
// Cleanup if needed
|
|
1782
|
+
}
|
|
1783
|
+
get parsedItems() {
|
|
1784
|
+
if (typeof this.items === 'string') {
|
|
1785
|
+
try {
|
|
1786
|
+
return JSON.parse(this.items);
|
|
1787
|
+
}
|
|
1788
|
+
catch {
|
|
1789
|
+
return [];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return this.items;
|
|
1793
|
+
}
|
|
1794
|
+
getItemId(item, path) {
|
|
1795
|
+
return item.id ?? `${this.instanceId}:${path}`;
|
|
1796
|
+
}
|
|
1797
|
+
getChildItems(item) {
|
|
1798
|
+
return Array.isArray(item.children) ? item.children : [];
|
|
1799
|
+
}
|
|
1800
|
+
isOpen(item, id) {
|
|
1801
|
+
const fromState = this.openState[id];
|
|
1802
|
+
if (typeof fromState === 'boolean')
|
|
1803
|
+
return fromState;
|
|
1804
|
+
return !!item.open;
|
|
1805
|
+
}
|
|
1806
|
+
setOpen(id, open) {
|
|
1807
|
+
if (this.openState[id] === open)
|
|
1808
|
+
return;
|
|
1809
|
+
this.openState = {
|
|
1810
|
+
...this.openState,
|
|
1811
|
+
[id]: open,
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
matchesQuery(option, query) {
|
|
1815
|
+
if (!query)
|
|
1816
|
+
return true;
|
|
1817
|
+
const q = query.toLowerCase();
|
|
1818
|
+
return (option.label.toLowerCase().includes(q) ||
|
|
1819
|
+
(option.description?.toLowerCase().includes(q) ?? false));
|
|
1820
|
+
}
|
|
1821
|
+
filterTree(items, query, pathPrefix, autoOpen) {
|
|
1822
|
+
if (!query)
|
|
1823
|
+
return items;
|
|
1824
|
+
const result = [];
|
|
1825
|
+
items.forEach((item, index) => {
|
|
1826
|
+
const path = pathPrefix ? `${pathPrefix}.${index}` : String(index);
|
|
1827
|
+
const id = this.getItemId(item, path);
|
|
1828
|
+
const children = this.getChildItems(item);
|
|
1829
|
+
const filteredChildren = this.filterTree(children, query, path, autoOpen);
|
|
1830
|
+
const selfMatch = this.matchesQuery(item, query);
|
|
1831
|
+
const childMatch = filteredChildren.length > 0;
|
|
1832
|
+
if (selfMatch || childMatch) {
|
|
1833
|
+
if (childMatch) {
|
|
1834
|
+
autoOpen.add(id);
|
|
1835
|
+
}
|
|
1836
|
+
if (childMatch && filteredChildren !== children) {
|
|
1837
|
+
result.push({
|
|
1838
|
+
...item,
|
|
1839
|
+
children: filteredChildren,
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
else {
|
|
1843
|
+
result.push(item);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
});
|
|
1847
|
+
return result;
|
|
1848
|
+
}
|
|
1849
|
+
handleItemSelect = (e, item, id) => {
|
|
1850
|
+
if (item.disabled) {
|
|
1851
|
+
e.preventDefault();
|
|
1852
|
+
e.stopPropagation();
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
const emitted = this.leNavItemSelect.emit({
|
|
1856
|
+
item,
|
|
1857
|
+
id,
|
|
1858
|
+
href: item.href,
|
|
1859
|
+
originalEvent: e,
|
|
1860
|
+
});
|
|
1861
|
+
if (emitted.defaultPrevented) {
|
|
1862
|
+
e.preventDefault();
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
handleToggle = (e, item, id) => {
|
|
1866
|
+
e.preventDefault();
|
|
1867
|
+
e.stopPropagation();
|
|
1868
|
+
if (item.disabled)
|
|
1869
|
+
return;
|
|
1870
|
+
const next = !this.isOpen(item, id);
|
|
1871
|
+
this.setOpen(id, next);
|
|
1872
|
+
this.leNavItemToggle.emit({
|
|
1873
|
+
item,
|
|
1874
|
+
id,
|
|
1875
|
+
open: next,
|
|
1876
|
+
originalEvent: e,
|
|
1877
|
+
});
|
|
1878
|
+
};
|
|
1879
|
+
handleSearchInput = (e) => {
|
|
1880
|
+
const target = e.target;
|
|
1881
|
+
this.searchQuery = target.value;
|
|
1882
|
+
};
|
|
1883
|
+
handleSubmenuSearchInput = (submenuId, e) => {
|
|
1884
|
+
const target = e.target;
|
|
1885
|
+
const value = target.value;
|
|
1886
|
+
if (this.submenuQueries[submenuId] === value)
|
|
1887
|
+
return;
|
|
1888
|
+
this.submenuQueries = {
|
|
1889
|
+
...this.submenuQueries,
|
|
1890
|
+
[submenuId]: value,
|
|
1891
|
+
};
|
|
1892
|
+
// Position may change as items filter.
|
|
1893
|
+
requestAnimationFrame(() => this.popoverRefs.get(submenuId)?.updatePosition());
|
|
1894
|
+
};
|
|
1895
|
+
handleBarOverflowChange = (e) => {
|
|
1896
|
+
this.overflowIds = e.detail.overflowingIds || [];
|
|
1897
|
+
this.hamburgerActive = e.detail.hamburgerActive || false;
|
|
1898
|
+
};
|
|
1899
|
+
openOverflowPopover = () => {
|
|
1900
|
+
this.overflowPopoverOpen = true;
|
|
1901
|
+
};
|
|
1902
|
+
closeOverflowPopover = () => {
|
|
1903
|
+
this.overflowPopoverOpen = false;
|
|
1904
|
+
};
|
|
1905
|
+
renderVerticalList(items, { depth, pathPrefix, autoOpenIds, searchable, searchQuery, searchPlaceholder, emptyText, submenuId, closePopover, }) {
|
|
1906
|
+
const query = searchQuery ?? '';
|
|
1907
|
+
const openFromSearch = autoOpenIds ?? new Set();
|
|
1908
|
+
const filtered = query ? this.filterTree(items, query, pathPrefix, openFromSearch) : items;
|
|
1909
|
+
return (index.h("div", { class: utils.classnames('nav-vertical', { 'is-submenu': !!submenuId }) }, searchable && (index.h("div", { class: "nav-search" }, index.h("le-string-input", { mode: "default", class: "nav-search-input", placeholder: searchPlaceholder ?? 'Search...', value: query, onInput: (e) => submenuId ? this.handleSubmenuSearchInput(submenuId, e) : this.handleSearchInput(e) }))), filtered.length === 0 ? (index.h("div", { class: "nav-empty" }, emptyText ?? this.emptyText)) : (index.h("ul", { class: "nav-list", role: "tree" }, filtered.map((item, index$1) => {
|
|
1910
|
+
const path = pathPrefix ? `${pathPrefix}.${index$1}` : String(index$1);
|
|
1911
|
+
const id = this.getItemId(item, path);
|
|
1912
|
+
const children = this.getChildItems(item);
|
|
1913
|
+
const hasChildren = children.length > 0;
|
|
1914
|
+
const open = hasChildren && (this.isOpen(item, id) || openFromSearch.has(id));
|
|
1915
|
+
const paddingLeft = `calc(var(--le-nav-item-padding-x) + ${depth} * var(--le-spacing-4))`;
|
|
1916
|
+
const TagType = item.href && !item.disabled ? 'a' : 'button';
|
|
1917
|
+
const attrs = TagType === 'a'
|
|
1918
|
+
? { href: item.href, role: 'treeitem' }
|
|
1919
|
+
: { type: 'button', role: 'treeitem' };
|
|
1920
|
+
const itemPart = this.partFromOptionPart('item', item.part);
|
|
1921
|
+
return (index.h("li", { class: utils.classnames('nav-node', {
|
|
1922
|
+
'disabled': item.disabled,
|
|
1923
|
+
'selected': item.selected || (this.activeUrl && item.href === this.activeUrl),
|
|
1924
|
+
open,
|
|
1925
|
+
'has-children': hasChildren,
|
|
1926
|
+
}), key: id, role: "none" }, index.h("div", { class: "nav-row", style: { paddingLeft } }, hasChildren ? (index.h("button", { type: "button", class: "nav-toggle", "aria-label": open ? 'Collapse' : 'Expand', "aria-expanded": open ? 'true' : 'false', onClick: (e) => this.handleToggle(e, item, id), disabled: item.disabled }, index.h("le-icon", { name: "chevron-down", class: "nav-chevron", "aria-hidden": "true" }))) : (index.h("span", { class: "nav-toggle-spacer", "aria-hidden": "true" })), index.h(TagType, { class: "nav-item", part: itemPart, ...attrs, "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => {
|
|
1927
|
+
// For buttons, also toggle if this is a purely structural node.
|
|
1928
|
+
this.handleItemSelect(e, item, id);
|
|
1929
|
+
if (!item.href && hasChildren && !item.disabled) {
|
|
1930
|
+
this.handleToggle(e, item, id);
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
if (!item.disabled && closePopover) {
|
|
1934
|
+
closePopover();
|
|
1935
|
+
}
|
|
1936
|
+
} }, item.iconStart && (index.h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), index.h("span", { class: "nav-text" }, index.h("span", { class: "nav-label" }, item.label), item.description && (index.h("span", { class: "nav-description" }, item.description))), item.iconEnd && (index.h("span", { class: "nav-icon nav-icon-end", "aria-hidden": "true" }, item.iconEnd)))), hasChildren && (index.h("le-collapse", { class: "nav-children", closed: !open, noFading: true, role: "group" }, this.renderVerticalList(children, {
|
|
1937
|
+
depth: depth + 1,
|
|
1938
|
+
pathPrefix: path,
|
|
1939
|
+
autoOpenIds: openFromSearch,
|
|
1940
|
+
submenuId,
|
|
1941
|
+
closePopover,
|
|
1942
|
+
})))));
|
|
1943
|
+
})))));
|
|
1944
|
+
}
|
|
1945
|
+
renderHorizontalItem(item, index$1) {
|
|
1946
|
+
const id = this.getItemId(item, String(index$1));
|
|
1947
|
+
const children = this.getChildItems(item);
|
|
1948
|
+
const hasChildren = children.length > 0;
|
|
1949
|
+
if (!hasChildren) {
|
|
1950
|
+
const TagType = item.href && !item.disabled ? 'a' : 'button';
|
|
1951
|
+
const attrs = TagType === 'a'
|
|
1952
|
+
? { href: item.href, role: 'menuitem' }
|
|
1953
|
+
: { type: 'button', role: 'menuitem' };
|
|
1954
|
+
const itemPart = this.partFromOptionPart('item', item.part);
|
|
1955
|
+
return (index.h("div", { class: "h-item", "data-bar-id": id }, index.h(TagType, { class: utils.classnames('h-link', {
|
|
1956
|
+
disabled: item.disabled,
|
|
1957
|
+
selected: item.selected || (this.activeUrl && item.href === this.activeUrl),
|
|
1958
|
+
}), part: itemPart, ...attrs, "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => this.handleItemSelect(e, item, id) }, item.iconStart && (index.h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), index.h("span", { class: "h-label" }, item.label), item.iconEnd && (index.h("span", { class: "nav-icon nav-icon-end", "aria-hidden": "true" }, item.iconEnd)))));
|
|
1959
|
+
}
|
|
1960
|
+
const submenuId = id;
|
|
1961
|
+
const itemPart = this.partFromOptionPart('item', item.part);
|
|
1962
|
+
return (index.h("div", { class: "h-item", "data-bar-id": id }, index.h("le-popover", { ref: el => {
|
|
1963
|
+
if (el)
|
|
1964
|
+
this.popoverRefs.set(submenuId, el);
|
|
1965
|
+
}, mode: "default", showClose: false, closeOnClickOutside: true, closeOnEscape: true, position: "bottom", align: "start", minWidth: "240px" }, index.h("div", { slot: "trigger", class: utils.classnames('h-trigger', {
|
|
1966
|
+
disabled: item.disabled,
|
|
1967
|
+
selected: item.selected || (this.activeUrl && item.href === this.activeUrl),
|
|
1968
|
+
}), part: itemPart, role: "menuitem", "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => {
|
|
1969
|
+
// Don’t let le-popover auto-toggle from its internal wrapper.
|
|
1970
|
+
e.stopPropagation();
|
|
1971
|
+
if (item.disabled)
|
|
1972
|
+
return;
|
|
1973
|
+
if (item.href) {
|
|
1974
|
+
this.handleItemSelect(e, item, id);
|
|
1975
|
+
this.popoverRefs.get(submenuId)?.hide();
|
|
1976
|
+
}
|
|
1977
|
+
else {
|
|
1978
|
+
this.popoverRefs.get(submenuId)?.toggle();
|
|
1979
|
+
}
|
|
1980
|
+
} }, item.href ? (index.h("a", { class: "h-link", href: item.href, onClick: (e) => {
|
|
1981
|
+
e.stopPropagation();
|
|
1982
|
+
this.handleItemSelect(e, item, id);
|
|
1983
|
+
} }, item.iconStart && (index.h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), index.h("span", { class: "h-label" }, item.label), index.h("span", { class: "nav-chevron", "aria-hidden": "true" }, index.h("le-icon", { name: "chevron-down" })))) : (index.h("button", { type: "button", class: "h-link", onClick: (e) => {
|
|
1984
|
+
e.stopPropagation();
|
|
1985
|
+
if (item.disabled)
|
|
1986
|
+
return;
|
|
1987
|
+
this.popoverRefs.get(submenuId)?.toggle();
|
|
1988
|
+
} }, item.iconStart && (index.h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), index.h("span", { class: "h-label" }, item.label), index.h("span", { class: "nav-chevron", "aria-hidden": "true" }, index.h("le-icon", { name: "chevron-down" }))))), index.h("div", { class: "popover-menu" }, this.renderVerticalList(children, {
|
|
1989
|
+
depth: 0,
|
|
1990
|
+
pathPrefix: String(index$1),
|
|
1991
|
+
searchable: this.submenuSearchable,
|
|
1992
|
+
searchQuery: this.submenuQueries[submenuId] ?? '',
|
|
1993
|
+
searchPlaceholder: this.searchPlaceholder,
|
|
1994
|
+
emptyText: this.emptyText,
|
|
1995
|
+
submenuId,
|
|
1996
|
+
closePopover: () => this.popoverRefs.get(submenuId)?.hide(),
|
|
1997
|
+
})))));
|
|
1998
|
+
}
|
|
1999
|
+
getOverflowMode() {
|
|
2000
|
+
if (this.wrap)
|
|
2001
|
+
return 'wrap';
|
|
2002
|
+
return this.overflowMode;
|
|
2003
|
+
}
|
|
2004
|
+
getBarAlignment() {
|
|
2005
|
+
// Map le-navigation align to le-bar alignItems
|
|
2006
|
+
// 'space-between' doesn't map directly, use 'stretch' as closest
|
|
2007
|
+
if (this.align === 'space-between')
|
|
2008
|
+
return 'stretch';
|
|
2009
|
+
return this.align;
|
|
2010
|
+
}
|
|
2011
|
+
renderOverflowPopover() {
|
|
2012
|
+
const items = this.parsedItems;
|
|
2013
|
+
const overflowSet = new Set(this.overflowIds || []);
|
|
2014
|
+
// Determine which items to show in the popover
|
|
2015
|
+
let itemsToShow;
|
|
2016
|
+
if (this.hamburgerActive) {
|
|
2017
|
+
// In hamburger mode, show all items
|
|
2018
|
+
itemsToShow = items;
|
|
2019
|
+
}
|
|
2020
|
+
else {
|
|
2021
|
+
// In "more" mode, show only overflow items
|
|
2022
|
+
itemsToShow = items.filter((item, index) => {
|
|
2023
|
+
const id = this.getItemId(item, String(index));
|
|
2024
|
+
return overflowSet.has(id);
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
if (itemsToShow.length === 0)
|
|
2028
|
+
return null;
|
|
2029
|
+
const isHamburger = this.hamburgerActive;
|
|
2030
|
+
return (index.h("le-popover", { mode: "default", open: this.overflowPopoverOpen, showClose: false, closeOnClickOutside: true, closeOnEscape: true, position: "bottom", align: "end", minWidth: "260px", onLePopoverClose: this.closeOverflowPopover }, index.h("button", { slot: "trigger", type: "button", class: "overflow-trigger", part: isHamburger ? 'hamburger-trigger' : 'more-trigger', "aria-label": isHamburger ? 'Open menu' : 'More', onClick: this.openOverflowPopover }, index.h("slot", { name: isHamburger ? 'hamburger-trigger' : 'more-trigger' }, index.h("le-icon", { name: isHamburger ? 'hamburger' : 'ellipsis-horizontal' }))), index.h("div", { class: "popover-menu" }, this.renderVerticalList(itemsToShow, {
|
|
2031
|
+
depth: 0,
|
|
2032
|
+
pathPrefix: '',
|
|
2033
|
+
closePopover: this.closeOverflowPopover,
|
|
2034
|
+
}))));
|
|
2035
|
+
}
|
|
2036
|
+
renderHorizontal() {
|
|
2037
|
+
const items = this.parsedItems;
|
|
2038
|
+
const overflowMode = this.getOverflowMode();
|
|
2039
|
+
const showOverflowButton = (this.overflowIds?.length ?? 0) > 0 || this.hamburgerActive;
|
|
2040
|
+
return (index.h("div", { class: "nav-horizontal-wrapper" }, index.h("le-bar", { class: utils.classnames('nav-bar', {
|
|
2041
|
+
'align-end': this.align === 'end',
|
|
2042
|
+
'align-center': this.align === 'center',
|
|
2043
|
+
'align-space-between': this.align === 'space-between',
|
|
2044
|
+
}), overflow: overflowMode, alignItems: this.getBarAlignment(), disablePopover: true, minVisibleItems: this.minVisibleItemsForMore, onLeBarOverflowChange: this.handleBarOverflowChange }, items.map((item, index) => this.renderHorizontalItem(item, index))), showOverflowButton && this.renderOverflowPopover()));
|
|
2045
|
+
}
|
|
2046
|
+
render() {
|
|
2047
|
+
const items = this.parsedItems;
|
|
2048
|
+
if (this.orientation === 'horizontal') {
|
|
2049
|
+
return (index.h(index.Host, null, index.h("le-component", { component: "le-navigation" }, this.renderHorizontal())));
|
|
2050
|
+
}
|
|
2051
|
+
return (index.h(index.Host, null, index.h("le-component", { component: "le-navigation" }, this.renderVerticalList(items, {
|
|
2052
|
+
depth: 0,
|
|
2053
|
+
pathPrefix: '',
|
|
2054
|
+
searchable: this.searchable,
|
|
2055
|
+
searchQuery: this.searchQuery,
|
|
2056
|
+
searchPlaceholder: this.searchPlaceholder,
|
|
2057
|
+
emptyText: this.emptyText,
|
|
2058
|
+
}))));
|
|
2059
|
+
}
|
|
2060
|
+
static get watchers() { return {
|
|
2061
|
+
"items": ["handleLayoutInputsChange"],
|
|
2062
|
+
"orientation": ["handleLayoutInputsChange"],
|
|
2063
|
+
"wrap": ["handleLayoutInputsChange"],
|
|
2064
|
+
"overflowMode": ["handleLayoutInputsChange"]
|
|
2065
|
+
}; }
|
|
2066
|
+
};
|
|
2067
|
+
LeNavigation.style = leNavigationCss();
|
|
2068
|
+
|
|
1126
2069
|
const lePopoverCss = () => `/* ============================================
|
|
1127
2070
|
le-popover.css
|
|
1128
2071
|
Popover using native HTML Popover API
|
|
@@ -2074,7 +3017,7 @@ const leSelectCss = () => `:host{display:inline-block;min-width:150px;--le-selec
|
|
|
2074
3017
|
const LeSelect = class {
|
|
2075
3018
|
constructor(hostRef) {
|
|
2076
3019
|
index.registerInstance(this, hostRef);
|
|
2077
|
-
this.leChange = index.createEvent(this, "
|
|
3020
|
+
this.leChange = index.createEvent(this, "change");
|
|
2078
3021
|
this.leOpen = index.createEvent(this, "leOpen");
|
|
2079
3022
|
this.leClose = index.createEvent(this, "leClose");
|
|
2080
3023
|
}
|
|
@@ -2236,13 +3179,13 @@ const LeSelect = class {
|
|
|
2236
3179
|
}
|
|
2237
3180
|
render() {
|
|
2238
3181
|
const hasValue = this.selectedOption !== undefined;
|
|
2239
|
-
return (index.h("le-component", { key: '
|
|
3182
|
+
return (index.h("le-component", { key: '1d67b699f3638ef75a15fecdbba80a531ea90681', component: "le-select" }, index.h("le-dropdown-base", { key: '9a52d99cdf1f0f0c1b9de6e10f5a694b580469ab', ref: el => (this.dropdownEl = el), options: this.parsedOptions, value: this.value, disabled: this.disabled, filterFn: this.searchable ? this.filterOption : undefined, filterQuery: this.searchQuery, onLeOptionSelect: this.handleOptionSelect, onLeDropdownOpen: this.handleDropdownOpen, onLeDropdownClose: this.handleDropdownClose, fullWidth: this.fullWidth }, index.h("le-button", { key: '20c02507679ed44cca089e15801ac8f57cbe3938', variant: this.variant && this.variant !== 'default' ? this.variant : 'outlined', slot: "trigger", align: "space-between", class: {
|
|
2240
3183
|
'select-trigger': true,
|
|
2241
3184
|
'has-value': hasValue,
|
|
2242
3185
|
'is-open': this.open,
|
|
2243
3186
|
}, mode: "default", size: this.size, disabled: this.disabled, "aria-haspopup": "listbox", "aria-expanded": this.open ? 'true' : 'false', onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeyDown, fullWidth: this.fullWidth, iconStart: hasValue && this.selectedOption?.iconStart
|
|
2244
3187
|
? this.renderIcon(this.selectedOption.iconStart)
|
|
2245
|
-
: null, iconEnd: index.h("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("path", { d: "M4 6l4 4 4-4" })) }, index.h("span", { key: '
|
|
3188
|
+
: null, iconEnd: index.h("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("path", { d: "M4 6l4 4 4-4" })) }, index.h("span", { key: '5eea76015ea63775315e5bf46e7b99c65cd5bc22', class: "trigger-label" }, hasValue ? this.selectedOption.label : this.placeholder)), this.searchable && this.open && (index.h("div", { key: 'c3cb84ae7d333ee84d40639fae5ebea7ba4eda36', class: "multiselect-search", slot: "header" }, index.h("le-string-input", { key: '1e887755cb1ec376f49d4bda1e86d5bb0709fbce', mode: "default", inputRef: el => (this.inputEl = el), class: "search-input", placeholder: "Search...", value: this.searchQuery, onInput: this.handleSearchInput })))), this.name && index.h("input", { key: '1cbcbe00822aeda2ccfecedef506f0de01c1b010', type: "hidden", name: this.name, value: this.value?.toString() ?? '' })));
|
|
2246
3189
|
}
|
|
2247
3190
|
static get watchers() { return {
|
|
2248
3191
|
"value": ["handleValueChange"],
|
|
@@ -2733,6 +3676,7 @@ const LeStringInput = class {
|
|
|
2733
3676
|
};
|
|
2734
3677
|
LeStringInput.style = leStringInputCss();
|
|
2735
3678
|
|
|
3679
|
+
exports.le_bar = LeBar;
|
|
2736
3680
|
exports.le_button = LeButton;
|
|
2737
3681
|
exports.le_checkbox = LeCheckbox;
|
|
2738
3682
|
exports.le_collapse = LeCollapse;
|
|
@@ -2740,10 +3684,12 @@ exports.le_component = LeComponent;
|
|
|
2740
3684
|
exports.le_current_heading = LeCurrentHeading;
|
|
2741
3685
|
exports.le_dropdown_base = LeDropdownBase;
|
|
2742
3686
|
exports.le_header = LeHeader;
|
|
3687
|
+
exports.le_icon = LeIcon;
|
|
3688
|
+
exports.le_navigation = LeNavigation;
|
|
2743
3689
|
exports.le_popover = LePopover;
|
|
2744
3690
|
exports.le_popup = LePopup;
|
|
2745
3691
|
exports.le_scroll_progress = LeScrollProgress;
|
|
2746
3692
|
exports.le_select = LeSelect;
|
|
2747
3693
|
exports.le_slot = LeSlot;
|
|
2748
3694
|
exports.le_string_input = LeStringInput;
|
|
2749
|
-
//# sourceMappingURL=le-button.le-checkbox.le-collapse.le-component.le-current-heading.le-dropdown-base.le-header.le-popover.le-popup.le-scroll-progress.le-select.le-slot.le-string-input.entry.cjs.js.map
|
|
3695
|
+
//# sourceMappingURL=le-bar.le-button.le-checkbox.le-collapse.le-component.le-current-heading.le-dropdown-base.le-header.le-icon.le-navigation.le-popover.le-popup.le-scroll-progress.le-select.le-slot.le-string-input.entry.cjs.js.map
|