design-system-next 2.21.10 → 2.22.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/design-system-next.es.d.ts +136 -67
- package/dist/design-system-next.es.js +6499 -6565
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +13 -13
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/package.json +1 -1
- package/src/components/list/list-item/list-item.ts +48 -48
- package/src/components/sidepanel/sidepanel.ts +24 -14
- package/src/components/sidepanel/sidepanel.vue +10 -2
- package/src/components/sidepanel/stacking-sidepanel/stacking-sidepanel.vue +3 -1
- package/src/components/sidepanel/stacking-sidepanel/use-stacking-sidepanel.ts +35 -6
- package/src/components/sidepanel/use-sidepanel.ts +25 -11
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import type { PropType, ExtractPropTypes } from 'vue';
|
|
2
|
-
import type { MenuListType } from '../list';
|
|
3
|
-
|
|
4
|
-
export const listItemPropTypes = {
|
|
5
|
-
item: {
|
|
6
|
-
type: Object as PropType<MenuListType>,
|
|
7
|
-
required: true,
|
|
8
|
-
},
|
|
9
|
-
isSelected: {
|
|
10
|
-
type: Boolean,
|
|
11
|
-
required: true,
|
|
12
|
-
},
|
|
13
|
-
classes: {
|
|
14
|
-
type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
|
|
15
|
-
required: true,
|
|
16
|
-
},
|
|
17
|
-
multiSelect: {
|
|
18
|
-
type: Boolean,
|
|
19
|
-
default: false,
|
|
20
|
-
},
|
|
21
|
-
lozenge: {
|
|
22
|
-
type: Boolean,
|
|
23
|
-
default: false,
|
|
24
|
-
},
|
|
25
|
-
ladderized: {
|
|
26
|
-
type: Boolean,
|
|
27
|
-
default: false,
|
|
28
|
-
},
|
|
29
|
-
noCheck: {
|
|
30
|
-
type: Boolean,
|
|
31
|
-
default: false,
|
|
32
|
-
},
|
|
33
|
-
itemIcon: {
|
|
34
|
-
type: String,
|
|
35
|
-
default: '',
|
|
36
|
-
},
|
|
37
|
-
disabledUnselectedItems: {
|
|
38
|
-
type: Boolean,
|
|
39
|
-
default: false,
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const listItemEmitTypes = {
|
|
44
|
-
select: () => true,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
|
|
48
|
-
export type ListItemEmitTypes = typeof listItemEmitTypes;
|
|
1
|
+
import type { PropType, ExtractPropTypes } from 'vue';
|
|
2
|
+
import type { MenuListType } from '../list';
|
|
3
|
+
|
|
4
|
+
export const listItemPropTypes = {
|
|
5
|
+
item: {
|
|
6
|
+
type: Object as PropType<MenuListType>,
|
|
7
|
+
required: true,
|
|
8
|
+
},
|
|
9
|
+
isSelected: {
|
|
10
|
+
type: Boolean,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
classes: {
|
|
14
|
+
type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
multiSelect: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false,
|
|
20
|
+
},
|
|
21
|
+
lozenge: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
ladderized: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
noCheck: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false,
|
|
32
|
+
},
|
|
33
|
+
itemIcon: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '',
|
|
36
|
+
},
|
|
37
|
+
disabledUnselectedItems: {
|
|
38
|
+
type: Boolean,
|
|
39
|
+
default: false,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const listItemEmitTypes = {
|
|
44
|
+
select: () => true,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
|
|
48
|
+
export type ListItemEmitTypes = typeof listItemEmitTypes;
|
|
@@ -5,9 +5,9 @@ const SIDEPANEL_POSITION = ['right'] as const;
|
|
|
5
5
|
|
|
6
6
|
export const sidepanelPropTypes = {
|
|
7
7
|
/**
|
|
8
|
-
* @description Controls whether the side panel is open.
|
|
8
|
+
* @description Controls whether the side panel is open.
|
|
9
9
|
* Set to `true` to display the side panel or `false` to hide it.
|
|
10
|
-
|
|
10
|
+
*/
|
|
11
11
|
isOpen: {
|
|
12
12
|
type: Boolean,
|
|
13
13
|
default: false,
|
|
@@ -15,16 +15,16 @@ export const sidepanelPropTypes = {
|
|
|
15
15
|
/**
|
|
16
16
|
* @description The title displayed in the side panel's header.
|
|
17
17
|
* If not provided, defaults to 'Sidepanel Header'.
|
|
18
|
-
|
|
18
|
+
*/
|
|
19
19
|
headerTitle: {
|
|
20
20
|
type: String,
|
|
21
|
-
default: 'Sidepanel Header'
|
|
21
|
+
default: 'Sidepanel Header',
|
|
22
22
|
},
|
|
23
23
|
/**
|
|
24
24
|
* @description Specifies the size of the side panel.
|
|
25
25
|
* Acceptable values are: `'sm'`, `'md'`, `'lg'`, `'xl'`.
|
|
26
26
|
* Defaults to `'sm'`.
|
|
27
|
-
|
|
27
|
+
*/
|
|
28
28
|
size: {
|
|
29
29
|
type: String as PropType<(typeof SIDEPANEL_SIZE)[number]>,
|
|
30
30
|
validator: (value: (typeof SIDEPANEL_SIZE)[number]) => SIDEPANEL_SIZE.includes(value),
|
|
@@ -34,7 +34,7 @@ export const sidepanelPropTypes = {
|
|
|
34
34
|
* @description Sets the height of the side panel.
|
|
35
35
|
* Accepts a string (e.g., `'500px'`, `'70vh'`) or a number (interpreted as pixels).
|
|
36
36
|
* Defaults to `'calc(100vh - 32px)'`.
|
|
37
|
-
|
|
37
|
+
*/
|
|
38
38
|
height: {
|
|
39
39
|
type: [String, Number],
|
|
40
40
|
default: 'calc(100vh - 32px)',
|
|
@@ -43,16 +43,16 @@ export const sidepanelPropTypes = {
|
|
|
43
43
|
* @description Controls the visibility of the side panel header.
|
|
44
44
|
* Set to `true` to hide the header, or `false` to display it.
|
|
45
45
|
* Defaults to `false`.
|
|
46
|
-
|
|
46
|
+
*/
|
|
47
47
|
hideHeader: {
|
|
48
48
|
type: Boolean,
|
|
49
|
-
default: false
|
|
49
|
+
default: false,
|
|
50
50
|
},
|
|
51
51
|
/**
|
|
52
52
|
* @description Specifies the position of the side panel.
|
|
53
53
|
* Currently, only `'right'` is supported.
|
|
54
54
|
* Defaults to `'right'`.
|
|
55
|
-
|
|
55
|
+
*/
|
|
56
56
|
position: {
|
|
57
57
|
type: String as PropType<(typeof SIDEPANEL_POSITION)[number]>,
|
|
58
58
|
validator: (value: (typeof SIDEPANEL_POSITION)[number]) => SIDEPANEL_POSITION.includes(value),
|
|
@@ -62,16 +62,16 @@ export const sidepanelPropTypes = {
|
|
|
62
62
|
* @description Determines whether a backdrop is displayed behind the side panel.
|
|
63
63
|
* Set to `true` to enable the backdrop, or `false` to disable it.
|
|
64
64
|
* Defaults to `true`.
|
|
65
|
-
|
|
65
|
+
*/
|
|
66
66
|
hasBackdrop: {
|
|
67
67
|
type: Boolean,
|
|
68
|
-
default: true
|
|
68
|
+
default: true,
|
|
69
69
|
},
|
|
70
70
|
/**
|
|
71
71
|
* @description Controls whether clicking outside the side panel should close it.
|
|
72
72
|
* Set to `true` to enable closing on outside click, or `false` to disable it.
|
|
73
73
|
* Defaults to `false`.
|
|
74
|
-
|
|
74
|
+
*/
|
|
75
75
|
closeOutside: {
|
|
76
76
|
type: Boolean,
|
|
77
77
|
default: true,
|
|
@@ -80,7 +80,7 @@ export const sidepanelPropTypes = {
|
|
|
80
80
|
* @description Controls whether clicking ESC button should close it.
|
|
81
81
|
* Set to `true` to enable closing on ESC button click, or `false` to disable it.
|
|
82
82
|
* Defaults to `true`.
|
|
83
|
-
|
|
83
|
+
*/
|
|
84
84
|
escapeClose: {
|
|
85
85
|
type: Boolean,
|
|
86
86
|
default: true,
|
|
@@ -92,12 +92,22 @@ export const sidepanelPropTypes = {
|
|
|
92
92
|
footerNoPadding: {
|
|
93
93
|
type: Boolean,
|
|
94
94
|
default: false,
|
|
95
|
+
},
|
|
96
|
+
isExpandable: {
|
|
97
|
+
type: Boolean,
|
|
98
|
+
default: false
|
|
99
|
+
},
|
|
100
|
+
isExpanded: {
|
|
101
|
+
type: Boolean,
|
|
102
|
+
default: false
|
|
95
103
|
}
|
|
96
|
-
}
|
|
104
|
+
};
|
|
97
105
|
|
|
98
106
|
export const sidepanelEmitTypes = {
|
|
99
107
|
close: Function,
|
|
100
108
|
onClose: Function,
|
|
109
|
+
shrink: Function,
|
|
110
|
+
expand: Function,
|
|
101
111
|
};
|
|
102
112
|
|
|
103
113
|
export type SidepanelPropTypes = ExtractPropTypes<typeof sidepanelPropTypes>;
|
|
@@ -24,7 +24,15 @@
|
|
|
24
24
|
<div id="sidepanel-title" :class="sidepanelClasses.sidepanelHeaderTitleClasses">
|
|
25
25
|
{{ headerTitle }}
|
|
26
26
|
</div>
|
|
27
|
-
<
|
|
27
|
+
<div class="spr-flex spr-items-center spr-gap-size-spacing-3xs">
|
|
28
|
+
<Icon
|
|
29
|
+
v-if="props.isExpandable"
|
|
30
|
+
:class="sidepanelClasses.sidepanelHeaderIconClasses"
|
|
31
|
+
:icon="isExpanded ? 'ph:arrows-in-simple' : 'ph:arrows-out-simple'"
|
|
32
|
+
@click="handlePanelExpansion"
|
|
33
|
+
/>
|
|
34
|
+
<Icon :class="sidepanelClasses.sidepanelHeaderIconClasses" icon="ph:x" @click="handleClose" />
|
|
35
|
+
</div>
|
|
28
36
|
</div>
|
|
29
37
|
<div v-else>
|
|
30
38
|
<slot name="header"></slot>
|
|
@@ -51,5 +59,5 @@ import { sidepanelPropTypes, sidepanelEmitTypes } from './sidepanel';
|
|
|
51
59
|
const props = defineProps(sidepanelPropTypes);
|
|
52
60
|
const emit = defineEmits(sidepanelEmitTypes);
|
|
53
61
|
|
|
54
|
-
const { sidepanelClasses, sidepanelRef, handleClose } = useSidepanel(props, emit);
|
|
62
|
+
const { sidepanelClasses, sidepanelRef, handleClose, isExpanded, handlePanelExpansion } = useSidepanel(props, emit);
|
|
55
63
|
</script>
|
|
@@ -29,11 +29,13 @@ const stackingSidepanelBase = useTemplateRef('stacking-sidepanel-base');
|
|
|
29
29
|
const props = defineProps(stackingSidePanelProps);
|
|
30
30
|
const emits = defineEmits(stackingSidePanelEmits);
|
|
31
31
|
|
|
32
|
-
const { showPanel, hidePanel, stackingSidepanelClasses, stackingSidepanelBaseTransform, activePanels } =
|
|
32
|
+
const { showPanel, hidePanel, stackingSidepanelClasses, stackingSidepanelBaseTransform, activePanels, handleExpandPanel, expandedPanel } =
|
|
33
33
|
useStackingSidepanel(props, emits, stackingSidepanelBase);
|
|
34
34
|
|
|
35
35
|
defineExpose({
|
|
36
36
|
showPanel,
|
|
37
37
|
hidePanel,
|
|
38
|
+
handleExpandPanel,
|
|
39
|
+
expandedPanel
|
|
38
40
|
});
|
|
39
41
|
</script>
|
|
@@ -9,6 +9,8 @@ export const useStackingSidepanel = (
|
|
|
9
9
|
stackingSidepanelBase: Readonly<ShallowRef<HTMLDivElement | null>>,
|
|
10
10
|
) => {
|
|
11
11
|
const activePanels = useVModel(props, 'stack', emits, { deep: true });
|
|
12
|
+
const expandedPanel = ref('');
|
|
13
|
+
const isTransitioning = ref(false);
|
|
12
14
|
|
|
13
15
|
// Ensure activePanels is an array
|
|
14
16
|
watchDeep(activePanels, (newValue) => {
|
|
@@ -17,6 +19,7 @@ export const useStackingSidepanel = (
|
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
const showPanel = (name: string) => {
|
|
22
|
+
expandedPanel.value = '';
|
|
20
23
|
if (!activePanels.value.includes(name)) {
|
|
21
24
|
activePanels.value.push(name);
|
|
22
25
|
// Update transform immediately
|
|
@@ -25,17 +28,20 @@ export const useStackingSidepanel = (
|
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
const hidePanel = (name: string) => {
|
|
31
|
+
expandedPanel.value = '';
|
|
28
32
|
const index = activePanels.value.indexOf(name);
|
|
29
33
|
if (index !== -1) {
|
|
30
|
-
activePanels.value.splice(index, 1);
|
|
31
|
-
// Undo resize tracker two times of history
|
|
32
|
-
undoResizeTracker();
|
|
34
|
+
activePanels.value.splice(index, 1);
|
|
33
35
|
undoResizeTracker();
|
|
34
36
|
// Update transform immediately
|
|
35
37
|
updateTransform();
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
|
|
41
|
+
const handleExpandPanel = (action: 'expand' | 'shrink', name: string) => {
|
|
42
|
+
expandedPanel.value = action === 'expand' ? name : '';
|
|
43
|
+
};
|
|
44
|
+
|
|
39
45
|
// Styling for the stacking sidepanel
|
|
40
46
|
const stackingSidepanelBaseTransform = ref('transform: translateX()');
|
|
41
47
|
// Track the width of the stacking sidepanel base
|
|
@@ -43,10 +49,13 @@ export const useStackingSidepanel = (
|
|
|
43
49
|
const { history, undo: undoResizeTracker } = useRefHistory(resizeTracker);
|
|
44
50
|
|
|
45
51
|
// Watch for changes in the active panels to update the transform
|
|
46
|
-
useResizeObserver(stackingSidepanelBase, (entries) => {
|
|
52
|
+
useResizeObserver(stackingSidepanelBase, (entries) => {
|
|
53
|
+
//stop observer if panel is expanding to stop population of history of resizeTracker
|
|
54
|
+
if (!!isTransitioning.value || !!expandedPanel.value) return;
|
|
55
|
+
|
|
47
56
|
const entry = entries[0];
|
|
48
57
|
const { width } = entry.contentRect;
|
|
49
|
-
resizeTracker.value = resizeTracker.value !== width ? width : resizeTracker.value;
|
|
58
|
+
resizeTracker.value = resizeTracker.value !== width ? width : resizeTracker.value;
|
|
50
59
|
updateTransform();
|
|
51
60
|
});
|
|
52
61
|
|
|
@@ -58,7 +67,14 @@ export const useStackingSidepanel = (
|
|
|
58
67
|
return;
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
let snapshot = history.value[0].snapshot;
|
|
71
|
+
|
|
72
|
+
const numOfActivePanels = activePanels.value.length - 1;
|
|
73
|
+
const numOfSnapshotHistory = history.value.length - 1;
|
|
74
|
+
snapshot = history.value[numOfSnapshotHistory - numOfActivePanels]?.snapshot;
|
|
75
|
+
if(!snapshot) return
|
|
76
|
+
|
|
77
|
+
stackingSidepanelBaseTransform.value = `transform: translateX(${snapshot}px);`;
|
|
62
78
|
};
|
|
63
79
|
|
|
64
80
|
// Watch for changes in active panels and update transform immediately
|
|
@@ -70,6 +86,17 @@ export const useStackingSidepanel = (
|
|
|
70
86
|
{ flush: 'post' },
|
|
71
87
|
);
|
|
72
88
|
|
|
89
|
+
watch(
|
|
90
|
+
expandedPanel,
|
|
91
|
+
() => {
|
|
92
|
+
// transition delay of expanding panel
|
|
93
|
+
isTransitioning.value = true;
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
isTransitioning.value = false;
|
|
96
|
+
}, 150);
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
73
100
|
const stackingSidepanelClasses = computed(() => {
|
|
74
101
|
const sidepanelStackBackdropClasses =
|
|
75
102
|
'spr-fixed spr-left-0 spr-top-0 spr-z-[1010] spr-h-full spr-w-full spr-bg-mushroom-700/60';
|
|
@@ -114,5 +141,7 @@ export const useStackingSidepanel = (
|
|
|
114
141
|
stackingSidepanelClasses,
|
|
115
142
|
stackingSidepanelBaseTransform,
|
|
116
143
|
activePanels,
|
|
144
|
+
expandedPanel,
|
|
145
|
+
handleExpandPanel,
|
|
117
146
|
};
|
|
118
147
|
};
|
|
@@ -19,16 +19,20 @@ interface SidepanelClasses {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<SidepanelEmitTypes>['emit']) => {
|
|
22
|
-
const { size, position, isStacking, footerNoPadding } = toRefs(props);
|
|
22
|
+
const { size, position, isStacking, footerNoPadding, isExpanded } = toRefs(props);
|
|
23
23
|
|
|
24
24
|
const sidepanelClasses: ComputedRef<SidepanelClasses> = computed(() => {
|
|
25
25
|
const sidepanelBaseClasses = classNames(
|
|
26
|
-
'spr-right-4 spr-top-1/2 spr-z-[1015] spr-flex spr-h-full spr-min-h-[200px] spr-translate-y-[-50%] spr-flex-col spr-rounded-border-radius-xl spr-bg-white-50 spr-drop-shadow',
|
|
26
|
+
'spr-right-4 spr-top-1/2 spr-z-[1015] spr-flex spr-h-full spr-min-h-[200px] spr-translate-y-[-50%] spr-flex-col spr-rounded-border-radius-xl spr-bg-white-50 spr-drop-shadow spr-transition-all spr-ease-[ease-in-out] spr-duration-[150ms]',
|
|
27
27
|
{
|
|
28
28
|
'spr-fixed': !isStacking.value,
|
|
29
|
-
'spr-w-[360px]
|
|
30
|
-
'spr-w-[420px]
|
|
31
|
-
'spr-w-[480px]
|
|
29
|
+
'spr-w-[360px]': size.value === 'sm' && !isExpanded.value,
|
|
30
|
+
'spr-w-[420px]': size.value === 'md' && !isExpanded.value,
|
|
31
|
+
'spr-w-[480px]': size.value === 'lg' && !isExpanded.value,
|
|
32
|
+
'[@media(max-width:360px)]:spr-w-[calc(100vw-35px)]': size.value === 'sm' && !isExpanded.value && !isStacking.value,
|
|
33
|
+
'[@media(max-width:420px)]:spr-w-[calc(100vw-35px)]': size.value === 'md' && !isExpanded.value && !isStacking.value,
|
|
34
|
+
'[@media(max-width:480px)]:spr-w-[calc(100vw-35px)]': size.value === 'lg' && !isExpanded.value && !isStacking.value,
|
|
35
|
+
'spr-w-[calc(100vw-50px)]': isExpanded.value,
|
|
32
36
|
},
|
|
33
37
|
);
|
|
34
38
|
|
|
@@ -45,13 +49,13 @@ export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<Sidep
|
|
|
45
49
|
const sidepanelFooterClasses = classNames(
|
|
46
50
|
'spr-bottom-0 spr-left-0 spr-w-full spr-rounded-b-border-radius-xl spr-border-0 spr-border-t spr-border-solid spr-border-mushroom-200 spr-bg-white-50 ',
|
|
47
51
|
{
|
|
48
|
-
'spr-py-3': !footerNoPadding.value
|
|
49
|
-
}
|
|
52
|
+
'spr-py-3': !footerNoPadding.value,
|
|
53
|
+
},
|
|
50
54
|
);
|
|
51
55
|
|
|
52
|
-
const sidepanelTransitionActiveClasses = classNames(
|
|
53
|
-
|
|
54
|
-
);
|
|
56
|
+
const sidepanelTransitionActiveClasses = classNames({
|
|
57
|
+
'spr-transition-all spr-duration-[150ms] spr-ease-[ease-in-out]': !isStacking.value,
|
|
58
|
+
});
|
|
55
59
|
|
|
56
60
|
const sidepanelTransitionHiddenClasses = classNames('spr-opacity-0', {
|
|
57
61
|
'spr-translate-x-full -spr-translate-y-2/4': !isStacking.value && position.value === 'right',
|
|
@@ -84,6 +88,14 @@ export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<Sidep
|
|
|
84
88
|
emit('close');
|
|
85
89
|
};
|
|
86
90
|
|
|
91
|
+
const handlePanelExpansion = () => {
|
|
92
|
+
if (isExpanded.value) {
|
|
93
|
+
emit('shrink');
|
|
94
|
+
} else {
|
|
95
|
+
emit('expand');
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
87
99
|
let ignoreClick = false;
|
|
88
100
|
|
|
89
101
|
const handleClickOutside = (event: MouseEvent) => {
|
|
@@ -111,7 +123,7 @@ export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<Sidep
|
|
|
111
123
|
emit('onClose');
|
|
112
124
|
}
|
|
113
125
|
},
|
|
114
|
-
);
|
|
126
|
+
);
|
|
115
127
|
|
|
116
128
|
onMounted(() => {
|
|
117
129
|
document.addEventListener('click', handleClickOutside);
|
|
@@ -126,6 +138,8 @@ export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<Sidep
|
|
|
126
138
|
return {
|
|
127
139
|
sidepanelClasses,
|
|
128
140
|
sidepanelRef,
|
|
141
|
+
isExpanded,
|
|
129
142
|
handleClose,
|
|
143
|
+
handlePanelExpansion,
|
|
130
144
|
};
|
|
131
145
|
};
|