@14ch/svelte-ui 0.0.28 → 0.0.30
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/assets/styles/variables.scss +28 -24
- package/dist/components/Nav.svelte +168 -46
- package/dist/components/Nav.svelte.d.ts +7 -3
- package/dist/components/NavItem.svelte +439 -60
- package/dist/components/NavItem.svelte.d.ts +20 -3
- package/dist/components/Tab.svelte +44 -118
- package/dist/components/Tab.svelte.d.ts +8 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +0 -1
- package/dist/types/menuItem.d.ts +1 -0
- package/dist/types/propOptions.d.ts +10 -1
- package/package.json +1 -1
- package/dist/components/TabItem.svelte +0 -219
- package/dist/components/TabItem.svelte.d.ts +0 -19
|
@@ -358,21 +358,6 @@
|
|
|
358
358
|
--svelte-ui-segmented-control-selected-text-color: var(--svelte-ui-text-on-filled-color);
|
|
359
359
|
--svelte-ui-segmented-control-hover-overlay: var(--svelte-ui-hover-overlay);
|
|
360
360
|
|
|
361
|
-
/* Tab */
|
|
362
|
-
--svelte-ui-tab-min-height: var(--svelte-ui-form-height);
|
|
363
|
-
--svelte-ui-tab-item-text-color: var(--svelte-ui-text-color);
|
|
364
|
-
--svelte-ui-tab-item-selected-text-color: var(--svelte-ui-primary-color);
|
|
365
|
-
--svelte-ui-tab-item-selected-bar-color: var(--svelte-ui-primary-color);
|
|
366
|
-
--svelte-ui-tab-item-padding-x: 16px;
|
|
367
|
-
--svelte-ui-tab-item-padding-y: 8px;
|
|
368
|
-
--svelte-ui-tab-item-padding: var(--svelte-ui-tab-item-padding-y)
|
|
369
|
-
var(--svelte-ui-tab-item-padding-x);
|
|
370
|
-
--svelte-ui-tab-item-icon-gap: 8px;
|
|
371
|
-
--svelte-ui-tab-item-selected-bar-offset: 0px;
|
|
372
|
-
--svelte-ui-tab-item-selected-bar-height: 4px;
|
|
373
|
-
--svelte-ui-tab-item-selected-bar-radius: 3px 3px 0 0;
|
|
374
|
-
--svelte-ui-tab-item-disabled-opacity: var(--svelte-ui-disabled-opacity);
|
|
375
|
-
|
|
376
361
|
/* Nav */
|
|
377
362
|
--svelte-ui-nav-item-text-color: var(--svelte-ui-text-color);
|
|
378
363
|
--svelte-ui-nav-item-selected-text-color: var(--svelte-ui-primary-color);
|
|
@@ -382,23 +367,42 @@
|
|
|
382
367
|
var(--svelte-ui-primary-color) 16%,
|
|
383
368
|
transparent
|
|
384
369
|
);
|
|
385
|
-
|
|
386
|
-
--svelte-ui-nav-item-
|
|
387
|
-
--svelte-ui-nav-item-selected-
|
|
370
|
+
/* Nav: underline style(Tab はこれを参照するエイリアス) */
|
|
371
|
+
--svelte-ui-nav-item-underline-text-color: var(--svelte-ui-text-color);
|
|
372
|
+
--svelte-ui-nav-item-underline-selected-text-color: var(--svelte-ui-primary-color);
|
|
373
|
+
--svelte-ui-nav-item-underline-bar-color: var(--svelte-ui-primary-color);
|
|
374
|
+
--svelte-ui-nav-item-underline-bar-offset: 0px;
|
|
375
|
+
--svelte-ui-nav-item-underline-bar-height: 4px;
|
|
376
|
+
--svelte-ui-nav-item-underline-bar-radius: 3px 3px 0 0;
|
|
377
|
+
|
|
378
|
+
/* Tab */
|
|
379
|
+
--svelte-ui-tab-min-height: var(--svelte-ui-form-height);
|
|
388
380
|
--svelte-ui-nav-item-min-height: 40px;
|
|
389
381
|
--svelte-ui-nav-item-icon-gap: 8px;
|
|
390
382
|
--svelte-ui-nav-item-disabled-opacity: var(--svelte-ui-disabled-opacity);
|
|
383
|
+
--svelte-ui-nav-item-padding-x: 12px;
|
|
384
|
+
--svelte-ui-nav-item-padding-y: 8px;
|
|
385
|
+
--svelte-ui-nav-item-padding: var(--svelte-ui-nav-item-padding-y)
|
|
386
|
+
var(--svelte-ui-nav-item-padding-x);
|
|
387
|
+
--svelte-ui-nav-item-border-radius: var(--svelte-ui-border-radius);
|
|
388
|
+
--svelte-ui-nav-item-label-line-height: 1.3;
|
|
391
389
|
/* Nav: mobile-tab */
|
|
392
390
|
--svelte-ui-nav-mobile-min-height: 56px;
|
|
393
391
|
--svelte-ui-nav-mobile-item-padding: 8px;
|
|
394
392
|
--svelte-ui-nav-mobile-item-icon-gap: 8px;
|
|
395
393
|
--svelte-ui-nav-mobile-item-font-size: 0.75rem;
|
|
396
|
-
--svelte-ui-nav-item-padding: 8px 12px;
|
|
397
|
-
--svelte-ui-nav-item-border-radius: var(--svelte-ui-border-radius);
|
|
398
394
|
/* Nav: vertical */
|
|
399
395
|
--svelte-ui-nav-vertical-item-gap: 8px;
|
|
400
396
|
/* Nav: horizontal */
|
|
401
397
|
--svelte-ui-nav-horizontal-item-gap: 8px;
|
|
398
|
+
/* Nav: sub-menu */
|
|
399
|
+
--svelte-ui-nav-sub-popup-min-width: 160px;
|
|
400
|
+
--svelte-ui-nav-sub-popup-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
401
|
+
--svelte-ui-nav-sub-bar-min-height: 48px;
|
|
402
|
+
--svelte-ui-nav-item-child-indent: 32px;
|
|
403
|
+
--svelte-ui-nav-bottom-sheet-overlay-bg: rgba(0, 0, 0, 0.4);
|
|
404
|
+
--svelte-ui-nav-bottom-sheet-border-radius: 16px 16px 0 0;
|
|
405
|
+
--svelte-ui-nav-bottom-sheet-padding: 16px 8px;
|
|
402
406
|
|
|
403
407
|
/* Input */
|
|
404
408
|
--svelte-ui-input-height: var(--svelte-ui-form-height);
|
|
@@ -879,10 +883,10 @@
|
|
|
879
883
|
--svelte-ui-slider-custom-thumb-focus-shadow: 0 0 0 3px Highlight;
|
|
880
884
|
--svelte-ui-slider-custom-thumb-color: HighlightText;
|
|
881
885
|
|
|
882
|
-
/*
|
|
883
|
-
--svelte-ui-
|
|
884
|
-
--svelte-ui-
|
|
885
|
-
--svelte-ui-
|
|
886
|
+
/* Nav: underline */
|
|
887
|
+
--svelte-ui-nav-item-underline-text-color: CanvasText;
|
|
888
|
+
--svelte-ui-nav-item-underline-selected-text-color: Highlight;
|
|
889
|
+
--svelte-ui-nav-item-underline-bar-color: Highlight;
|
|
886
890
|
|
|
887
891
|
/* Radio */
|
|
888
892
|
--svelte-ui-radio-border-color: CanvasText;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import NavItem from './NavItem.svelte';
|
|
5
5
|
import type { NavItemSelectedStyle } from './NavItem.svelte';
|
|
6
6
|
import type { MenuItem } from '../types/menuItem';
|
|
7
|
-
import type { NavVariant } from '../types/propOptions';
|
|
7
|
+
import type { NavVariant, ChildrenVariant } from '../types/propOptions';
|
|
8
8
|
import { subscribeUrlChange } from '../utils/urlChange';
|
|
9
9
|
import { getCurrentPath, matchPath } from '../utils/navPath';
|
|
10
10
|
import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
// =========================================================================
|
|
15
15
|
export type NavProps = {
|
|
16
16
|
// 基本プロパティ
|
|
17
|
-
/** `{ label, href, icon?, disabled? }[]` */
|
|
17
|
+
/** `{ label, href, icon?, children?, disabled? }[]` */
|
|
18
18
|
navItems?: MenuItem[];
|
|
19
|
-
/** Layout variant. @default '
|
|
19
|
+
/** Layout variant. @default 'horizontal' */
|
|
20
20
|
variant?: NavVariant;
|
|
21
21
|
/** Prepended to each item's href for active-state matching. */
|
|
22
22
|
pathPrefix?: string;
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
/** Visual style for the selected item. */
|
|
40
40
|
selectedStyle?: NavItemSelectedStyle;
|
|
41
41
|
gap?: number | string;
|
|
42
|
+
/** How child items are displayed. Defaults to `accordion` (vertical), `bar` (horizontal), `bottom-sheet` (mobile). */
|
|
43
|
+
childrenVariant?: ChildrenVariant;
|
|
44
|
+
/** Show chevron icon on parent items. @default true */
|
|
45
|
+
chevron?: boolean;
|
|
42
46
|
|
|
43
47
|
// ARIA/アクセシビリティ
|
|
44
48
|
ariaLabel?: string;
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
let {
|
|
49
53
|
// 基本プロパティ
|
|
50
54
|
navItems = [],
|
|
51
|
-
variant = '
|
|
55
|
+
variant = 'horizontal',
|
|
52
56
|
pathPrefix = '',
|
|
53
57
|
customPathMatcher,
|
|
54
58
|
currentPath,
|
|
@@ -66,6 +70,8 @@
|
|
|
66
70
|
// スタイル/レイアウト
|
|
67
71
|
selectedStyle,
|
|
68
72
|
gap,
|
|
73
|
+
childrenVariant = variant === 'mobile' ? 'bottom-sheet' : variant === 'vertical' ? 'accordion' : 'bar',
|
|
74
|
+
chevron,
|
|
69
75
|
|
|
70
76
|
// ARIA/アクセシビリティ
|
|
71
77
|
ariaLabel,
|
|
@@ -73,6 +79,11 @@
|
|
|
73
79
|
}: NavProps = $props();
|
|
74
80
|
|
|
75
81
|
let resolvedCurrentPath = $state('');
|
|
82
|
+
let navEl: HTMLElement | undefined = $state();
|
|
83
|
+
let subBarEl: HTMLElement | undefined = $state();
|
|
84
|
+
|
|
85
|
+
// bar/accordion モード: 展開中の親アイテム($state.raw で Proxy ラップを避け === 比較を正常にする)
|
|
86
|
+
let expandedParent: MenuItem | null = $state.raw(null);
|
|
76
87
|
|
|
77
88
|
// =========================================================================
|
|
78
89
|
// Effects
|
|
@@ -84,25 +95,58 @@
|
|
|
84
95
|
$effect(() => {
|
|
85
96
|
return subscribeUrlChange(() => {
|
|
86
97
|
resolvedCurrentPath = getCurrentPath(currentPath);
|
|
98
|
+
if (childrenVariant !== 'accordion') expandedParent = null;
|
|
87
99
|
});
|
|
88
100
|
});
|
|
89
101
|
|
|
102
|
+
// accordion モード: アクティブな子を持つ親を自動展開
|
|
103
|
+
$effect(() => {
|
|
104
|
+
if (childrenVariant !== 'accordion' || !resolvedCurrentPath) return;
|
|
105
|
+
const activeParent = navItems.find((item) =>
|
|
106
|
+
item.children?.some(
|
|
107
|
+
(child) =>
|
|
108
|
+
child.href &&
|
|
109
|
+
matchPath(resolvedCurrentPath, child.href, child, pathPrefix, customPathMatcher)
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
if (activeParent) expandedParent = activeParent;
|
|
113
|
+
});
|
|
114
|
+
|
|
90
115
|
// =========================================================================
|
|
91
116
|
// Methods
|
|
92
117
|
// =========================================================================
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
118
|
+
const focusExpandedParent = () => {
|
|
119
|
+
if (!expandedParent || !navEl) return;
|
|
120
|
+
const idx = navItems.indexOf(expandedParent);
|
|
121
|
+
const parentEls = Array.from(navEl.querySelectorAll<HTMLElement>('[data-nav-item]'));
|
|
122
|
+
parentEls[idx]?.focus();
|
|
123
|
+
};
|
|
95
124
|
|
|
125
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
126
|
+
// accordion/expanded は子アイテムも DOM 順で含める
|
|
127
|
+
const includeChildren = childrenVariant === 'accordion' || childrenVariant === 'expanded';
|
|
128
|
+
const selector = includeChildren ? '[data-nav-item], [data-nav-item-child]' : '[data-nav-item]';
|
|
96
129
|
const navItemEls = Array.from(
|
|
97
|
-
(event.currentTarget as HTMLElement).querySelectorAll(
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
(event.currentTarget as HTMLElement).querySelectorAll<HTMLElement>(selector)
|
|
131
|
+
).filter(el => el.tabIndex !== -1);
|
|
132
|
+
|
|
133
|
+
if (navItemEls.length === 0) return;
|
|
101
134
|
|
|
135
|
+
const currentIndex = navItemEls.indexOf(event.target as HTMLElement);
|
|
102
136
|
if (currentIndex === -1) return;
|
|
103
137
|
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
// bar モード: 展開中の親で ArrowDown → サブバーの最初の子へ
|
|
139
|
+
if (childrenVariant === 'bar' && event.key === 'ArrowDown' && showSubBar) {
|
|
140
|
+
const allNavItemEls = Array.from(
|
|
141
|
+
(event.currentTarget as HTMLElement).querySelectorAll<HTMLElement>('[data-nav-item]')
|
|
142
|
+
);
|
|
143
|
+
const expandedEl = allNavItemEls[navItems.indexOf(expandedParent!)];
|
|
144
|
+
if (expandedEl && expandedEl.contains(event.target as Node)) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
subBarEl?.querySelector<HTMLElement>('[data-nav-item-child]:not([tabindex="-1"])')?.focus();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
106
150
|
|
|
107
151
|
const isVertical = variant === 'vertical';
|
|
108
152
|
const prevKey = isVertical ? 'ArrowUp' : 'ArrowLeft';
|
|
@@ -111,28 +155,70 @@
|
|
|
111
155
|
switch (event.key) {
|
|
112
156
|
case prevKey:
|
|
113
157
|
event.preventDefault();
|
|
114
|
-
|
|
115
|
-
currentEnabledPosition > 0 ? currentEnabledPosition - 1 : enabledIndices.length - 1;
|
|
158
|
+
navItemEls[currentIndex > 0 ? currentIndex - 1 : navItemEls.length - 1]?.focus();
|
|
116
159
|
break;
|
|
117
160
|
case nextKey:
|
|
118
161
|
event.preventDefault();
|
|
119
|
-
|
|
120
|
-
currentEnabledPosition < enabledIndices.length - 1 ? currentEnabledPosition + 1 : 0;
|
|
162
|
+
navItemEls[currentIndex < navItemEls.length - 1 ? currentIndex + 1 : 0]?.focus();
|
|
121
163
|
break;
|
|
122
164
|
case 'Home':
|
|
123
165
|
event.preventDefault();
|
|
124
|
-
|
|
166
|
+
navItemEls[0]?.focus();
|
|
125
167
|
break;
|
|
126
168
|
case 'End':
|
|
127
169
|
event.preventDefault();
|
|
128
|
-
|
|
170
|
+
navItemEls[navItemEls.length - 1]?.focus();
|
|
129
171
|
break;
|
|
130
172
|
default:
|
|
131
173
|
return;
|
|
132
174
|
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const handleSubBarKeyDown = (event: KeyboardEvent) => {
|
|
178
|
+
const container = event.currentTarget as HTMLElement;
|
|
179
|
+
const items = Array.from(
|
|
180
|
+
container.querySelectorAll<HTMLElement>('[data-nav-item-child]:not([tabindex="-1"])')
|
|
181
|
+
);
|
|
182
|
+
const currentIndex = items.indexOf(event.target as HTMLElement);
|
|
183
|
+
if (currentIndex === -1) return;
|
|
133
184
|
|
|
134
|
-
|
|
135
|
-
|
|
185
|
+
switch (event.key) {
|
|
186
|
+
case 'ArrowLeft':
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
items[currentIndex > 0 ? currentIndex - 1 : items.length - 1]?.focus();
|
|
189
|
+
break;
|
|
190
|
+
case 'ArrowRight':
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
items[currentIndex < items.length - 1 ? currentIndex + 1 : 0]?.focus();
|
|
193
|
+
break;
|
|
194
|
+
case 'ArrowUp':
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
focusExpandedParent();
|
|
197
|
+
break;
|
|
198
|
+
case 'Home':
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
items[0]?.focus();
|
|
201
|
+
break;
|
|
202
|
+
case 'End':
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
items[items.length - 1]?.focus();
|
|
205
|
+
break;
|
|
206
|
+
case 'Escape':
|
|
207
|
+
event.preventDefault();
|
|
208
|
+
focusExpandedParent();
|
|
209
|
+
expandedParent = null;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const handleToggle = (item: MenuItem) => {
|
|
215
|
+
if (childrenVariant === 'accordion') {
|
|
216
|
+
// accordion: 開くのみ(再クリックで閉じない、他は自動的に閉じる)
|
|
217
|
+
expandedParent = item;
|
|
218
|
+
} else {
|
|
219
|
+
// bar: トグル
|
|
220
|
+
expandedParent = expandedParent === item ? null : item;
|
|
221
|
+
}
|
|
136
222
|
};
|
|
137
223
|
|
|
138
224
|
// =========================================================================
|
|
@@ -141,33 +227,37 @@
|
|
|
141
227
|
const selectedIndex = $derived.by(() => {
|
|
142
228
|
for (let i = 0; i < navItems.length; i++) {
|
|
143
229
|
const item = navItems[i];
|
|
144
|
-
if (
|
|
145
|
-
|
|
230
|
+
if (item.href && matchPath(resolvedCurrentPath, item.href, item, pathPrefix, customPathMatcher)) {
|
|
231
|
+
return i;
|
|
232
|
+
}
|
|
233
|
+
// bar モード: 子が選択されていれば親も選択とみなす
|
|
234
|
+
if (childrenVariant === 'bar' && item.children?.some(
|
|
235
|
+
(child) => child.href && matchPath(resolvedCurrentPath, child.href, child, pathPrefix, customPathMatcher)
|
|
236
|
+
)) {
|
|
146
237
|
return i;
|
|
147
238
|
}
|
|
148
239
|
}
|
|
149
240
|
return -1;
|
|
150
241
|
});
|
|
151
242
|
|
|
152
|
-
const
|
|
153
|
-
|
|
243
|
+
const showSubBar = $derived(
|
|
244
|
+
variant === 'horizontal' && childrenVariant === 'bar' && expandedParent != null
|
|
154
245
|
);
|
|
155
246
|
|
|
156
|
-
const
|
|
247
|
+
const isChildSelected = (child: MenuItem) =>
|
|
248
|
+
!!child.href && matchPath(resolvedCurrentPath, child.href, child, pathPrefix, customPathMatcher);
|
|
157
249
|
</script>
|
|
158
250
|
|
|
159
251
|
<nav
|
|
160
252
|
class="nav nav--{variant}"
|
|
161
|
-
role={isTabVariant ? 'tablist' : undefined}
|
|
162
253
|
aria-label={ariaLabelledby ? undefined : ariaLabel}
|
|
163
254
|
aria-labelledby={ariaLabelledby}
|
|
164
|
-
aria-orientation={variant === 'vertical' ? 'vertical' : 'horizontal'}
|
|
165
255
|
style:--internal-nav-gap={gap != null ? (typeof gap === 'number' ? `${gap}px` : gap) : undefined}
|
|
166
|
-
tabindex="-1"
|
|
167
256
|
{id}
|
|
168
|
-
onkeydown={handleKeyDown}
|
|
169
257
|
data-testid="nav"
|
|
258
|
+
bind:this={navEl}
|
|
170
259
|
>
|
|
260
|
+
<div style="display: contents" role="presentation" onkeydown={handleKeyDown}>
|
|
171
261
|
{#each navItems as item, index}
|
|
172
262
|
<NavItem
|
|
173
263
|
{item}
|
|
@@ -181,32 +271,47 @@
|
|
|
181
271
|
{iconOpticalSize}
|
|
182
272
|
{iconVariant}
|
|
183
273
|
{selectedStyle}
|
|
274
|
+
{childrenVariant}
|
|
275
|
+
{chevron}
|
|
276
|
+
{resolvedCurrentPath}
|
|
277
|
+
{customPathMatcher}
|
|
278
|
+
isChildrenExpanded={(childrenVariant === 'bar' || childrenVariant === 'accordion') && expandedParent === item}
|
|
279
|
+
onChildrenToggle={handleToggle}
|
|
280
|
+
onChildrenClose={() => { expandedParent = null; }}
|
|
184
281
|
/>
|
|
185
282
|
{/each}
|
|
283
|
+
</div>
|
|
186
284
|
</nav>
|
|
187
285
|
|
|
286
|
+
<!-- bar モード: 選択中の親の子アイテムを横バーとして表示 -->
|
|
287
|
+
{#if showSubBar && expandedParent?.children}
|
|
288
|
+
<div class="nav__sub-bar" role="menu" tabindex="-1" onkeydown={handleSubBarKeyDown} bind:this={subBarEl}>
|
|
289
|
+
{#each expandedParent.children as child}
|
|
290
|
+
<NavItem
|
|
291
|
+
item={child}
|
|
292
|
+
variant="horizontal"
|
|
293
|
+
{pathPrefix}
|
|
294
|
+
{iconFilled}
|
|
295
|
+
{iconWeight}
|
|
296
|
+
{iconGrade}
|
|
297
|
+
{iconOpticalSize}
|
|
298
|
+
{iconVariant}
|
|
299
|
+
{selectedStyle}
|
|
300
|
+
isChild={true}
|
|
301
|
+
{resolvedCurrentPath}
|
|
302
|
+
{customPathMatcher}
|
|
303
|
+
isSelected={isChildSelected(child)}
|
|
304
|
+
isDisabled={child.disabled ?? false}
|
|
305
|
+
/>
|
|
306
|
+
{/each}
|
|
307
|
+
</div>
|
|
308
|
+
{/if}
|
|
309
|
+
|
|
188
310
|
<style>.nav {
|
|
189
311
|
display: flex;
|
|
190
312
|
box-sizing: border-box;
|
|
191
313
|
}
|
|
192
314
|
|
|
193
|
-
.nav--tab {
|
|
194
|
-
flex-direction: row;
|
|
195
|
-
justify-content: start;
|
|
196
|
-
position: relative;
|
|
197
|
-
width: 100%;
|
|
198
|
-
height: 100%;
|
|
199
|
-
min-height: var(--svelte-ui-tab-min-height);
|
|
200
|
-
overflow-x: auto;
|
|
201
|
-
overflow-y: visible;
|
|
202
|
-
-ms-overflow-style: none;
|
|
203
|
-
overscroll-behavior: contain;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.nav--tab::-webkit-scrollbar {
|
|
207
|
-
display: none;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
315
|
.nav--mobile {
|
|
211
316
|
flex-direction: row;
|
|
212
317
|
width: 100%;
|
|
@@ -221,7 +326,24 @@
|
|
|
221
326
|
}
|
|
222
327
|
|
|
223
328
|
.nav--horizontal {
|
|
329
|
+
flex-direction: row;
|
|
330
|
+
justify-content: start;
|
|
331
|
+
align-items: center;
|
|
332
|
+
gap: var(--internal-nav-gap, var(--svelte-ui-nav-horizontal-item-gap));
|
|
333
|
+
overflow-x: auto;
|
|
334
|
+
overflow-y: visible;
|
|
335
|
+
-ms-overflow-style: none;
|
|
336
|
+
overscroll-behavior: none;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.nav--horizontal::-webkit-scrollbar {
|
|
340
|
+
display: none;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.nav__sub-bar {
|
|
344
|
+
display: flex;
|
|
224
345
|
flex-direction: row;
|
|
225
346
|
gap: var(--internal-nav-gap, var(--svelte-ui-nav-horizontal-item-gap));
|
|
226
347
|
align-items: center;
|
|
348
|
+
min-height: var(--svelte-ui-nav-sub-bar-min-height);
|
|
227
349
|
}</style>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { NavItemSelectedStyle } from './NavItem.svelte';
|
|
2
2
|
import type { MenuItem } from '../types/menuItem';
|
|
3
|
-
import type { NavVariant } from '../types/propOptions';
|
|
3
|
+
import type { NavVariant, ChildrenVariant } from '../types/propOptions';
|
|
4
4
|
import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
|
|
5
5
|
export type NavProps = {
|
|
6
|
-
/** `{ label, href, icon?, disabled? }[]` */
|
|
6
|
+
/** `{ label, href, icon?, children?, disabled? }[]` */
|
|
7
7
|
navItems?: MenuItem[];
|
|
8
|
-
/** Layout variant. @default '
|
|
8
|
+
/** Layout variant. @default 'horizontal' */
|
|
9
9
|
variant?: NavVariant;
|
|
10
10
|
/** Prepended to each item's href for active-state matching. */
|
|
11
11
|
pathPrefix?: string;
|
|
@@ -22,6 +22,10 @@ export type NavProps = {
|
|
|
22
22
|
/** Visual style for the selected item. */
|
|
23
23
|
selectedStyle?: NavItemSelectedStyle;
|
|
24
24
|
gap?: number | string;
|
|
25
|
+
/** How child items are displayed. Defaults to `accordion` (vertical), `bar` (horizontal), `bottom-sheet` (mobile). */
|
|
26
|
+
childrenVariant?: ChildrenVariant;
|
|
27
|
+
/** Show chevron icon on parent items. @default true */
|
|
28
|
+
chevron?: boolean;
|
|
25
29
|
ariaLabel?: string;
|
|
26
30
|
ariaLabelledby?: string;
|
|
27
31
|
};
|