@classic-homes/theme-svelte 1.15.3 → 1.17.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/__tests__/alert-dialog-dismiss.test.js +54 -0
- package/dist/__tests__/dropdown-trigger.test.js +30 -0
- package/dist/__tests__/public-layout-drawer.test.js +116 -0
- package/dist/__tests__/sidebar-docs-parity.test.js +134 -0
- package/dist/__tests__/sidebar-items.test.js +59 -0
- package/dist/lib/components/AlertDialog.svelte +19 -2
- package/dist/lib/components/Button.svelte +1 -31
- package/dist/lib/components/Button.svelte.d.ts +9 -6
- package/dist/lib/components/DataPanel.svelte +13 -3
- package/dist/lib/components/DropdownMenu.svelte +18 -1
- package/dist/lib/components/DropdownMenu.svelte.d.ts +8 -0
- package/dist/lib/components/button-variants.d.ts +119 -0
- package/dist/lib/components/button-variants.js +29 -0
- package/dist/lib/components/layout/DashboardLayout.svelte +10 -0
- package/dist/lib/components/layout/DashboardLayout.svelte.d.ts +4 -0
- package/dist/lib/components/layout/Header.svelte +3 -1
- package/dist/lib/components/layout/PublicLayout.svelte +151 -44
- package/dist/lib/components/layout/PublicLayout.svelte.d.ts +8 -10
- package/dist/lib/components/layout/Sidebar.svelte +45 -27
- package/dist/lib/components/layout/Sidebar.svelte.d.ts +5 -0
- package/dist/lib/components/layout/sidebar/SidebarFlyout.svelte +54 -32
- package/dist/lib/components/layout/sidebar/SidebarNavItem.svelte +62 -35
- package/dist/lib/components/layout/sidebar/SidebarNavItem.svelte.d.ts +5 -0
- package/dist/lib/components/layout/sidebar/SidebarSection.svelte +16 -1
- package/dist/lib/components/layout/sidebar/SidebarSection.svelte.d.ts +4 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/stores/sidebar.svelte.d.ts +4 -4
- package/dist/lib/stores/sidebar.svelte.js +12 -4
- package/package.json +1 -1
|
@@ -95,6 +95,59 @@
|
|
|
95
95
|
}
|
|
96
96
|
</script>
|
|
97
97
|
|
|
98
|
+
{#snippet childLinks(children: NavItem[], depth: number)}
|
|
99
|
+
{#each children as child (child.id)}
|
|
100
|
+
{#if child.href}
|
|
101
|
+
<a
|
|
102
|
+
href={child.disabled ? undefined : child.href}
|
|
103
|
+
class={cn(
|
|
104
|
+
'flex items-center gap-2 rounded-md px-3 py-2 text-sm',
|
|
105
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
106
|
+
isLight
|
|
107
|
+
? 'text-foreground hover:bg-accent hover:text-accent-foreground'
|
|
108
|
+
: 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
109
|
+
child.active &&
|
|
110
|
+
(isLight
|
|
111
|
+
? 'bg-primary/10 text-primary'
|
|
112
|
+
: 'bg-sidebar-primary text-sidebar-primary-foreground'),
|
|
113
|
+
child.disabled && 'opacity-50 pointer-events-none cursor-not-allowed'
|
|
114
|
+
)}
|
|
115
|
+
style="margin-left: {0.5 + depth * 0.75}rem"
|
|
116
|
+
target={child.external ? '_blank' : undefined}
|
|
117
|
+
rel={child.external ? 'noopener noreferrer' : undefined}
|
|
118
|
+
aria-disabled={child.disabled || undefined}
|
|
119
|
+
tabindex={child.disabled ? -1 : undefined}
|
|
120
|
+
onclick={(e) => {
|
|
121
|
+
if (child.disabled) {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
onNavigate?.(child);
|
|
126
|
+
}}
|
|
127
|
+
role="menuitem"
|
|
128
|
+
>
|
|
129
|
+
{child.name}
|
|
130
|
+
{@render navBadge(child.badge)}
|
|
131
|
+
</a>
|
|
132
|
+
{:else if child.children?.length}
|
|
133
|
+
<!-- A nested group without its own page: a label over its entries -->
|
|
134
|
+
<div
|
|
135
|
+
class={cn(
|
|
136
|
+
'px-3 pt-2 pb-1 text-xs font-semibold',
|
|
137
|
+
isLight ? 'text-muted-foreground' : 'text-sidebar-foreground/60'
|
|
138
|
+
)}
|
|
139
|
+
style="margin-left: {0.5 + depth * 0.75}rem"
|
|
140
|
+
role="presentation"
|
|
141
|
+
>
|
|
142
|
+
{child.name}
|
|
143
|
+
</div>
|
|
144
|
+
{/if}
|
|
145
|
+
{#if child.children?.length}
|
|
146
|
+
{@render childLinks(child.children, depth + 1)}
|
|
147
|
+
{/if}
|
|
148
|
+
{/each}
|
|
149
|
+
{/snippet}
|
|
150
|
+
|
|
98
151
|
{#snippet navBadge(badge: string | number | undefined)}
|
|
99
152
|
{#if badge !== undefined}
|
|
100
153
|
<span
|
|
@@ -169,38 +222,7 @@
|
|
|
169
222
|
<div
|
|
170
223
|
class={cn('border-t mt-1 pt-1', isLight ? 'border-border' : 'border-sidebar-foreground/20')}
|
|
171
224
|
>
|
|
172
|
-
{
|
|
173
|
-
<a
|
|
174
|
-
href={child.disabled ? undefined : child.href}
|
|
175
|
-
class={cn(
|
|
176
|
-
'flex items-center gap-2 rounded-md px-3 py-2 text-sm ml-2',
|
|
177
|
-
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
178
|
-
isLight
|
|
179
|
-
? 'text-foreground hover:bg-accent hover:text-accent-foreground'
|
|
180
|
-
: 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
181
|
-
child.active &&
|
|
182
|
-
(isLight
|
|
183
|
-
? 'bg-primary/10 text-primary'
|
|
184
|
-
: 'bg-sidebar-primary text-sidebar-primary-foreground'),
|
|
185
|
-
child.disabled && 'opacity-50 pointer-events-none cursor-not-allowed'
|
|
186
|
-
)}
|
|
187
|
-
target={child.external ? '_blank' : undefined}
|
|
188
|
-
rel={child.external ? 'noopener noreferrer' : undefined}
|
|
189
|
-
aria-disabled={child.disabled || undefined}
|
|
190
|
-
tabindex={child.disabled ? -1 : undefined}
|
|
191
|
-
onclick={(e) => {
|
|
192
|
-
if (child.disabled) {
|
|
193
|
-
e.preventDefault();
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
onNavigate?.(child);
|
|
197
|
-
}}
|
|
198
|
-
role="menuitem"
|
|
199
|
-
>
|
|
200
|
-
{child.name}
|
|
201
|
-
{@render navBadge(child.badge)}
|
|
202
|
-
</a>
|
|
203
|
-
{/each}
|
|
225
|
+
{@render childLinks(item.children, 0)}
|
|
204
226
|
</div>
|
|
205
227
|
{/if}
|
|
206
228
|
</div>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SidebarNavItem - Individual navigation item component
|
|
4
4
|
*
|
|
5
5
|
* Handles:
|
|
6
|
-
* - Items with children (expandable submenu)
|
|
6
|
+
* - Items with children (expandable submenu), nested to any depth
|
|
7
7
|
* - Items without children (simple links/buttons)
|
|
8
8
|
* - Collapsed mode (icons only with flyout)
|
|
9
9
|
* - Disabled and loading states
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import type { NavItem } from '../../../types/layout.js';
|
|
14
14
|
import { cn } from '../../../utils.js';
|
|
15
15
|
import { sidebarStore } from '../../../stores/sidebar.svelte.js';
|
|
16
|
+
import Icon, { type IconName } from '../../Icon.svelte';
|
|
17
|
+
import SidebarNavItem from './SidebarNavItem.svelte';
|
|
16
18
|
|
|
17
19
|
interface Props {
|
|
18
20
|
/** The navigation item to render */
|
|
@@ -39,6 +41,10 @@
|
|
|
39
41
|
onMouseEnter?: (item: NavItem, event: MouseEvent) => void;
|
|
40
42
|
/** Callback when mouse leaves item (for flyout) */
|
|
41
43
|
onMouseLeave?: () => void;
|
|
44
|
+
/** Expanding this item closes `siblingIds`, and its children behave the same way */
|
|
45
|
+
autoCollapse?: boolean;
|
|
46
|
+
/** IDs of expandable items alongside this one */
|
|
47
|
+
siblingIds?: string[];
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
let {
|
|
@@ -54,6 +60,8 @@
|
|
|
54
60
|
onNavigate,
|
|
55
61
|
onMouseEnter,
|
|
56
62
|
onMouseLeave,
|
|
63
|
+
autoCollapse = false,
|
|
64
|
+
siblingIds = [],
|
|
57
65
|
}: Props = $props();
|
|
58
66
|
|
|
59
67
|
// Highlight matching text in item names
|
|
@@ -79,9 +87,14 @@
|
|
|
79
87
|
const isExpanded = $derived(sidebarStore.isItemExpanded(item.id));
|
|
80
88
|
|
|
81
89
|
function toggleItem() {
|
|
82
|
-
sidebarStore.toggleItem(item.id);
|
|
90
|
+
sidebarStore.toggleItem(item.id, autoCollapse ? siblingIds : []);
|
|
83
91
|
}
|
|
84
92
|
|
|
93
|
+
// Children that can expand: siblings to each other under autoCollapse
|
|
94
|
+
const expandableChildIds = $derived(
|
|
95
|
+
autoCollapse ? (item.children ?? []).filter((c) => c.children?.length).map((c) => c.id) : []
|
|
96
|
+
);
|
|
97
|
+
|
|
85
98
|
function getItemStateClasses(active?: boolean, disabled?: boolean): string {
|
|
86
99
|
return cn(
|
|
87
100
|
isLight &&
|
|
@@ -142,10 +155,10 @@
|
|
|
142
155
|
{@render icon(navItem)}
|
|
143
156
|
</span>
|
|
144
157
|
{:else if navItem.icon}
|
|
158
|
+
<!-- No icon renderer given: draw the named theme icon. Items without an
|
|
159
|
+
icon render nothing, so they take no gutter. -->
|
|
145
160
|
<span class="h-5 w-5 shrink-0 flex items-center justify-center">
|
|
146
|
-
<
|
|
147
|
-
<circle cx="12" cy="12" r="10" stroke-width="2" />
|
|
148
|
-
</svg>
|
|
161
|
+
<Icon name={navItem.icon as IconName} size={20} />
|
|
149
162
|
</span>
|
|
150
163
|
{/if}
|
|
151
164
|
{/snippet}
|
|
@@ -264,7 +277,7 @@
|
|
|
264
277
|
<a
|
|
265
278
|
href={item.disabled ? undefined : item.href}
|
|
266
279
|
class={cn(
|
|
267
|
-
'flex flex-1 items-center gap-3 px-3 py-2 text-sm font-medium',
|
|
280
|
+
'flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-sm font-medium',
|
|
268
281
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
269
282
|
'group-hover:underline underline-offset-2',
|
|
270
283
|
isLight && !item.active && 'text-foreground group-hover:text-accent-foreground',
|
|
@@ -292,7 +305,7 @@
|
|
|
292
305
|
<button
|
|
293
306
|
type="button"
|
|
294
307
|
class={cn(
|
|
295
|
-
'flex flex-1 items-center gap-3 px-3 py-2 text-sm font-medium text-left',
|
|
308
|
+
'flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-sm font-medium text-left',
|
|
296
309
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
297
310
|
isLight && !item.active && 'text-foreground group-hover:text-accent-foreground',
|
|
298
311
|
isLight && item.active && 'text-primary',
|
|
@@ -359,33 +372,47 @@
|
|
|
359
372
|
|
|
360
373
|
{#if isExpanded}
|
|
361
374
|
<ul class="mt-1 space-y-1 pl-4 overflow-hidden" transition:slide={{ duration: 200 }}>
|
|
362
|
-
{#each item.children as child}
|
|
375
|
+
{#each item.children ?? [] as child (child.id)}
|
|
363
376
|
<li>
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
377
|
+
{#if child.children?.length}
|
|
378
|
+
<!-- A nested category: same expandable row, one level deeper -->
|
|
379
|
+
<SidebarNavItem
|
|
380
|
+
item={child}
|
|
381
|
+
{isLight}
|
|
382
|
+
{isMobile}
|
|
383
|
+
{icon}
|
|
384
|
+
{searchQuery}
|
|
385
|
+
{onNavigate}
|
|
386
|
+
{autoCollapse}
|
|
387
|
+
siblingIds={expandableChildIds}
|
|
388
|
+
/>
|
|
389
|
+
{:else}
|
|
390
|
+
<a
|
|
391
|
+
href={child.disabled ? undefined : child.href}
|
|
392
|
+
class={cn(
|
|
393
|
+
'flex min-w-0 items-center gap-3 rounded-md px-3 py-2 text-sm font-medium',
|
|
394
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
395
|
+
getItemStateClasses(child.active, child.disabled)
|
|
396
|
+
)}
|
|
397
|
+
target={child.external ? '_blank' : undefined}
|
|
398
|
+
rel={child.external ? 'noopener noreferrer' : undefined}
|
|
399
|
+
aria-current={child.active ? 'page' : undefined}
|
|
400
|
+
aria-disabled={child.disabled || undefined}
|
|
401
|
+
tabindex={child.disabled ? -1 : undefined}
|
|
402
|
+
onclick={(e) => {
|
|
403
|
+
if (child.disabled) {
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
onNavigate?.(child);
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
{@render navIcon(child)}
|
|
411
|
+
{@render highlightedName(child.name, highlightText(child.name, searchQuery))}
|
|
412
|
+
{@render navBadge(child.badge)}
|
|
413
|
+
{#if child.external}{@render externalIndicator()}{/if}
|
|
414
|
+
</a>
|
|
415
|
+
{/if}
|
|
389
416
|
</li>
|
|
390
417
|
{/each}
|
|
391
418
|
</ul>
|
|
@@ -408,7 +435,7 @@
|
|
|
408
435
|
<a
|
|
409
436
|
href={item.disabled ? undefined : item.href}
|
|
410
437
|
class={cn(
|
|
411
|
-
'flex flex-1 items-center gap-3 px-3 py-2 text-sm font-medium relative',
|
|
438
|
+
'flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-sm font-medium relative',
|
|
412
439
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
413
440
|
isLight && !item.active && 'text-foreground group-hover:text-accent-foreground',
|
|
414
441
|
isLight && item.active && 'text-primary',
|
|
@@ -455,7 +482,7 @@
|
|
|
455
482
|
<button
|
|
456
483
|
type="button"
|
|
457
484
|
class={cn(
|
|
458
|
-
'flex flex-1 items-center gap-3 px-3 py-2 text-sm font-medium text-left relative',
|
|
485
|
+
'flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-sm font-medium text-left relative',
|
|
459
486
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
460
487
|
isLight && !item.active && 'text-foreground group-hover:text-accent-foreground',
|
|
461
488
|
isLight && item.active && 'text-primary',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { NavItem } from '../../../types/layout.js';
|
|
3
|
+
import SidebarNavItem from './SidebarNavItem.svelte';
|
|
3
4
|
interface Props {
|
|
4
5
|
/** The navigation item to render */
|
|
5
6
|
item: NavItem;
|
|
@@ -27,6 +28,10 @@ interface Props {
|
|
|
27
28
|
onMouseEnter?: (item: NavItem, event: MouseEvent) => void;
|
|
28
29
|
/** Callback when mouse leaves item (for flyout) */
|
|
29
30
|
onMouseLeave?: () => void;
|
|
31
|
+
/** Expanding this item closes `siblingIds`, and its children behave the same way */
|
|
32
|
+
autoCollapse?: boolean;
|
|
33
|
+
/** IDs of expandable items alongside this one */
|
|
34
|
+
siblingIds?: string[];
|
|
30
35
|
}
|
|
31
36
|
declare const SidebarNavItem: import("svelte").Component<Props, {}, "">;
|
|
32
37
|
type SidebarNavItem = ReturnType<typeof SidebarNavItem>;
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
onItemMouseEnter?: (item: NavItem, event: MouseEvent) => void;
|
|
37
37
|
/** Callback when mouse leaves an item (for flyout) */
|
|
38
38
|
onItemMouseLeave?: () => void;
|
|
39
|
+
/** Opening this section (or an item in it) closes its siblings */
|
|
40
|
+
autoCollapse?: boolean;
|
|
41
|
+
/** IDs of the sections alongside this one, closed on expand when `autoCollapse` is set */
|
|
42
|
+
siblingSectionIds?: string[];
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
let {
|
|
@@ -51,12 +55,19 @@
|
|
|
51
55
|
onNavigate,
|
|
52
56
|
onItemMouseEnter,
|
|
53
57
|
onItemMouseLeave,
|
|
58
|
+
autoCollapse = false,
|
|
59
|
+
siblingSectionIds = [],
|
|
54
60
|
}: Props = $props();
|
|
55
61
|
|
|
62
|
+
// Items here that can expand: the siblings an expanding item closes under autoCollapse
|
|
63
|
+
const expandableItemIds = $derived(
|
|
64
|
+
autoCollapse ? section.items.filter((i) => i.children?.length).map((i) => i.id) : []
|
|
65
|
+
);
|
|
66
|
+
|
|
56
67
|
const isExpanded = $derived(sidebarStore.isSectionExpanded(section.id));
|
|
57
68
|
|
|
58
69
|
function toggleSection() {
|
|
59
|
-
sidebarStore.toggleSection(section.id);
|
|
70
|
+
sidebarStore.toggleSection(section.id, autoCollapse ? siblingSectionIds : []);
|
|
60
71
|
}
|
|
61
72
|
</script>
|
|
62
73
|
|
|
@@ -125,6 +136,8 @@
|
|
|
125
136
|
{onNavigate}
|
|
126
137
|
onMouseEnter={onItemMouseEnter}
|
|
127
138
|
onMouseLeave={onItemMouseLeave}
|
|
139
|
+
{autoCollapse}
|
|
140
|
+
siblingIds={expandableItemIds}
|
|
128
141
|
/>
|
|
129
142
|
</li>
|
|
130
143
|
{/each}
|
|
@@ -151,6 +164,8 @@
|
|
|
151
164
|
{onNavigate}
|
|
152
165
|
onMouseEnter={onItemMouseEnter}
|
|
153
166
|
onMouseLeave={onItemMouseLeave}
|
|
167
|
+
{autoCollapse}
|
|
168
|
+
siblingIds={expandableItemIds}
|
|
154
169
|
/>
|
|
155
170
|
</li>
|
|
156
171
|
{/each}
|
|
@@ -27,6 +27,10 @@ interface Props {
|
|
|
27
27
|
onItemMouseEnter?: (item: NavItem, event: MouseEvent) => void;
|
|
28
28
|
/** Callback when mouse leaves an item (for flyout) */
|
|
29
29
|
onItemMouseLeave?: () => void;
|
|
30
|
+
/** Opening this section (or an item in it) closes its siblings */
|
|
31
|
+
autoCollapse?: boolean;
|
|
32
|
+
/** IDs of the sections alongside this one, closed on expand when `autoCollapse` is set */
|
|
33
|
+
siblingSectionIds?: string[];
|
|
30
34
|
}
|
|
31
35
|
declare const SidebarSection: import("svelte").Component<Props, {}, "">;
|
|
32
36
|
type SidebarSection = ReturnType<typeof SidebarSection>;
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* All components use Svelte 5 runes syntax ($props, $state, $derived, etc.)
|
|
8
8
|
*/
|
|
9
9
|
export { default as Button } from './components/Button.svelte';
|
|
10
|
+
export { buttonVariants, type ButtonVariants } from './components/button-variants.js';
|
|
10
11
|
export { default as Input } from './components/Input.svelte';
|
|
11
12
|
export { default as PasswordInput } from './components/PasswordInput.svelte';
|
|
12
13
|
export { default as Label } from './components/Label.svelte';
|
package/dist/lib/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
// Core UI Components
|
|
10
10
|
export { default as Button } from './components/Button.svelte';
|
|
11
|
+
export { buttonVariants } from './components/button-variants.js';
|
|
11
12
|
export { default as Input } from './components/Input.svelte';
|
|
12
13
|
export { default as PasswordInput } from './components/PasswordInput.svelte';
|
|
13
14
|
export { default as Label } from './components/Label.svelte';
|
|
@@ -59,13 +59,13 @@ declare class SidebarStore {
|
|
|
59
59
|
*/
|
|
60
60
|
setMobile(isMobile: boolean): void;
|
|
61
61
|
/**
|
|
62
|
-
* Toggle section expansion state
|
|
62
|
+
* Toggle section expansion state. When expanding, sections in `collapseOnExpand` close.
|
|
63
63
|
*/
|
|
64
|
-
toggleSection(sectionId: string): void;
|
|
64
|
+
toggleSection(sectionId: string, collapseOnExpand?: string[]): void;
|
|
65
65
|
/**
|
|
66
|
-
* Toggle item expansion state
|
|
66
|
+
* Toggle item expansion state. When expanding, items in `collapseOnExpand` close.
|
|
67
67
|
*/
|
|
68
|
-
toggleItem(itemId: string): void;
|
|
68
|
+
toggleItem(itemId: string, collapseOnExpand?: string[]): void;
|
|
69
69
|
/**
|
|
70
70
|
* Check if a section is expanded
|
|
71
71
|
*/
|
|
@@ -160,29 +160,37 @@ class SidebarStore {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
|
-
* Toggle section expansion state
|
|
163
|
+
* Toggle section expansion state. When expanding, sections in `collapseOnExpand` close.
|
|
164
164
|
*/
|
|
165
|
-
toggleSection(sectionId) {
|
|
165
|
+
toggleSection(sectionId, collapseOnExpand = []) {
|
|
166
166
|
const newSet = new Set(this.expandedSections);
|
|
167
167
|
if (newSet.has(sectionId)) {
|
|
168
168
|
newSet.delete(sectionId);
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
171
|
newSet.add(sectionId);
|
|
172
|
+
// Accordion behaviour: opening one closes these (its siblings)
|
|
173
|
+
for (const id of collapseOnExpand)
|
|
174
|
+
if (id !== sectionId)
|
|
175
|
+
newSet.delete(id);
|
|
172
176
|
}
|
|
173
177
|
this.expandedSections = newSet;
|
|
174
178
|
__classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persistExpansion).call(this);
|
|
175
179
|
}
|
|
176
180
|
/**
|
|
177
|
-
* Toggle item expansion state
|
|
181
|
+
* Toggle item expansion state. When expanding, items in `collapseOnExpand` close.
|
|
178
182
|
*/
|
|
179
|
-
toggleItem(itemId) {
|
|
183
|
+
toggleItem(itemId, collapseOnExpand = []) {
|
|
180
184
|
const newSet = new Set(this.expandedItems);
|
|
181
185
|
if (newSet.has(itemId)) {
|
|
182
186
|
newSet.delete(itemId);
|
|
183
187
|
}
|
|
184
188
|
else {
|
|
185
189
|
newSet.add(itemId);
|
|
190
|
+
// Accordion behaviour: opening one closes these (its siblings)
|
|
191
|
+
for (const id of collapseOnExpand)
|
|
192
|
+
if (id !== itemId)
|
|
193
|
+
newSet.delete(id);
|
|
186
194
|
}
|
|
187
195
|
this.expandedItems = newSet;
|
|
188
196
|
__classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persistExpansion).call(this);
|