@eturnity/eturnity_reusable_components 9.28.3-ZOO-3.0 → 9.28.3-panel-placement.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/package.json +1 -1
- package/src/assets/svgIcons/broom.svg +6 -0
- package/src/assets/svgIcons/length_2d_vertical.svg +5 -0
- package/src/assets/svgIcons/obstacle_flat_top.svg +3 -0
- package/src/assets/svgIcons/obstacle_sloped_top.svg +3 -0
- package/src/assets/svgIcons/outline_tool.svg +10 -10
- package/src/assets/tests/__mocks__/fileMock.js +1 -0
- package/src/components/buttons/buttonIcon/buttonIcon.spec.js +40 -0
- package/src/components/buttons/buttonIcon/index.vue +18 -0
- package/src/components/inputs/inputNumber/index.vue +10 -0
- package/src/components/inputs/switchField/index.vue +23 -14
- package/src/components/inputs/switchField/switchField.spec.js +3 -3
- package/src/components/inputs/toggle/index.vue +22 -1
- package/src/components/inputs/toggle/toggle.spec.js +9 -9
- package/src/components/navigationSideMenu/index.vue +7 -73
- package/src/components/spinner/index.vue +2 -1
- package/src/components/navigationSideMenu/index.spec.js +0 -145
- package/src/components/navigationSideMenu/navigationSideMenu.stories.js +0 -133
package/package.json
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Uploaded to svgrepo.com" width="800px" height="800px" viewBox="0 0 32 32" xml:space="preserve">
|
|
2
|
+
<style type="text/css">
|
|
3
|
+
.linesandangles_een{fill:#000000;}
|
|
4
|
+
</style>
|
|
5
|
+
<path class="linesandangles_een" d="M26.281,30l-2-8H25v-5h-8V2h-2v15H7v5h0.719l-2,8H26.281z M23.719,28H21v-4h-2v4h-2v-4h-2v4h-2 v-4h-2v4H8.281l1.5-6h12.438L23.719,28z M9,19h14v1H9V19z"/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="14" viewBox="0 0 10 14" fill="none">
|
|
2
|
+
<g transform="translate(10,0) rotate(90)">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.199219 9.85718V0.142822H1.75351L1.75352 9.85718H0.199219ZM5.38021 8.20572L2.14209 4.99999L5.38021 1.79425V4.19855L8.61833 4.19855V1.79425L11.8564 4.99999L8.61832 8.20572L8.61833 5.80142L5.38021 5.80142V8.20572ZM12.2449 0.142822V9.85718H13.7992V0.142822H12.2449Z" fill="white"/>
|
|
4
|
+
</g>
|
|
5
|
+
</svg>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<path d="M8.5 3.07846L6.00098 0.935599L6.00098 5.22131L8.5 3.07846Z" fill="white"/>
|
|
5
|
-
<
|
|
6
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.06409C2.55228 4.06409 3 3.61637 3 3.06409C3 2.5118 2.55228 2.06409 2 2.06409C1.44772 2.06409 1 2.5118 1 3.06409C1 3.61637 1.44772 4.06409 2 4.06409ZM2 5.06409C3.10457 5.06409 4 4.16866 4 3.06409C4 1.95952 3.10457 1.06409 2 1.06409C0.895431 1.06409 0 1.95952 0 3.06409C0 4.16866 0.895431 5.06409 2 5.06409Z" fill="white"/>
|
|
7
|
-
<
|
|
8
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.002 4.06421C12.5542 4.06421 13.002 3.61649 13.002 3.06421C13.002 2.51192 12.5542 2.06421 12.002 2.06421C11.4497 2.06421 11.002 2.51192 11.002 3.06421C11.002 3.61649 11.4497 4.06421 12.002 4.06421ZM12.002 5.06421C13.1065 5.06421 14.002 4.16878 14.002 3.06421C14.002 1.95964 13.1065 1.06421 12.002 1.06421C10.8974 1.06421 10.002 1.95964 10.002 3.06421C10.002 4.16878 10.8974 5.06421 12.002 5.06421Z" fill="white"/>
|
|
9
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.002 14.0643C12.5542 14.0643 13.002 13.6166 13.002 13.0643C13.002 12.512 12.5542 12.0643 12.002 12.0643C11.4497 12.0643 11.002 12.512 11.002 13.0643C11.002 13.6166 11.4497 14.0643 12.002 14.0643ZM12.002 15.0643C13.1065 15.0643 14.002 14.1688 14.002 13.0643C14.002 11.9597 13.1065 11.0643 12.002 11.0643C10.8974 11.0643 10.002 11.9597 10.002 13.0643C10.002 14.1688 10.8974 15.0643 12.002 15.0643Z" fill="white"/>
|
|
10
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 14.0644C2.55228 14.0644 3 13.6167 3 13.0644C3 12.5121 2.55228 12.0644 2 12.0644C1.44772 12.0644 1 12.5121 1 13.0644C1 13.6167 1.44772 14.0644 2 14.0644ZM2 15.0644C3.10457 15.0644 4 14.169 4 13.0644C4 11.9598 3.10457 11.0644 2 11.0644C0.895431 11.0644 0 11.9598 0 13.0644C0 14.169 0.895431 15.0644 2 15.0644Z" fill="white"/>
|
|
11
|
-
</svg>
|
|
2
|
+
<path transform="rotate(90 2.80078 4.06415)" fill="white" d="M2.8008 4.0642h8v1.6H2.8008Z" />
|
|
3
|
+
<path transform="rotate(-180 7.00195 3.8642)" fill="white" d="M7.002 3.8642h4v1.6H7.002Z" />
|
|
4
|
+
<path d="M8.5 3.07846L6.00098 0.935599L6.00098 5.22131L8.5 3.07846Z" fill="white" />
|
|
5
|
+
<path transform="rotate(-180 11.002 13.8643)" fill="white" d="M11.002 13.8643h8v1.6H11.002Z" />
|
|
6
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.06409C2.55228 4.06409 3 3.61637 3 3.06409C3 2.5118 2.55228 2.06409 2 2.06409C1.44772 2.06409 1 2.5118 1 3.06409C1 3.61637 1.44772 4.06409 2 4.06409ZM2 5.06409C3.10457 5.06409 4 4.16866 4 3.06409C4 1.95952 3.10457 1.06409 2 1.06409C0.895431 1.06409 0 1.95952 0 3.06409C0 4.16866 0.895431 5.06409 2 5.06409Z" fill="white" />
|
|
7
|
+
<path transform="rotate(90 12.7988 4.06433)" fill="white" d="M12.7988 4.0643h8v1.6H12.7988Z" />
|
|
8
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.002 4.06421C12.5542 4.06421 13.002 3.61649 13.002 3.06421C13.002 2.51192 12.5542 2.06421 12.002 2.06421C11.4497 2.06421 11.002 2.51192 11.002 3.06421C11.002 3.61649 11.4497 4.06421 12.002 4.06421ZM12.002 5.06421C13.1065 5.06421 14.002 4.16878 14.002 3.06421C14.002 1.95964 13.1065 1.06421 12.002 1.06421C10.8974 1.06421 10.002 1.95964 10.002 3.06421C10.002 4.16878 10.8974 5.06421 12.002 5.06421Z" fill="white" />
|
|
9
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.002 14.0643C12.5542 14.0643 13.002 13.6166 13.002 13.0643C13.002 12.512 12.5542 12.0643 12.002 12.0643C11.4497 12.0643 11.002 12.512 11.002 13.0643C11.002 13.6166 11.4497 14.0643 12.002 14.0643ZM12.002 15.0643C13.1065 15.0643 14.002 14.1688 14.002 13.0643C14.002 11.9597 13.1065 11.0643 12.002 11.0643C10.8974 11.0643 10.002 11.9597 10.002 13.0643C10.002 14.1688 10.8974 15.0643 12.002 15.0643Z" fill="white" />
|
|
10
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 14.0644C2.55228 14.0644 3 13.6167 3 13.0644C3 12.5121 2.55228 12.0644 2 12.0644C1.44772 12.0644 1 12.5121 1 13.0644C1 13.6167 1.44772 14.0644 2 14.0644ZM2 15.0644C3.10457 15.0644 4 14.169 4 13.0644C4 11.9598 3.10457 11.0644 2 11.0644C0.895431 11.0644 0 11.9598 0 13.0644C0 14.169 0.895431 15.0644 2 15.0644Z" fill="white" />
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'test-file-stub'
|
|
@@ -157,6 +157,46 @@ describe('ButtonIcon.vue', () => {
|
|
|
157
157
|
}
|
|
158
158
|
})
|
|
159
159
|
|
|
160
|
+
it('replaces the icon with a spinner while loading', async () => {
|
|
161
|
+
expect(wrapper.find('[data-test-id="spinner_container"]').exists()).toBe(
|
|
162
|
+
false
|
|
163
|
+
)
|
|
164
|
+
expect(wrapper.findComponent({ name: 'Icon' }).exists()).toBe(true)
|
|
165
|
+
|
|
166
|
+
await wrapper.setProps({ isLoading: true })
|
|
167
|
+
expect(wrapper.find('[data-test-id="spinner_container"]').exists()).toBe(
|
|
168
|
+
true
|
|
169
|
+
)
|
|
170
|
+
expect(wrapper.findComponent({ name: 'Icon' }).exists()).toBe(false)
|
|
171
|
+
|
|
172
|
+
await wrapper.setProps({ isLoading: false })
|
|
173
|
+
expect(wrapper.find('[data-test-id="spinner_container"]').exists()).toBe(
|
|
174
|
+
false
|
|
175
|
+
)
|
|
176
|
+
expect(wrapper.findComponent({ name: 'Icon' }).props('name')).toBe(
|
|
177
|
+
'settings'
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('keeps rendering the text while loading', async () => {
|
|
182
|
+
await wrapper.setProps({ isLoading: true })
|
|
183
|
+
expect(wrapper.find('[data-test-id="button-icon-text"]').text()).toBe(
|
|
184
|
+
'Click Me'
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('renders a white spinner on types with white button text', async () => {
|
|
189
|
+
await wrapper.setProps({ isLoading: true, type: 'primary' })
|
|
190
|
+
expect(wrapper.findComponent({ name: 'NewSpinner' }).props('isWhite')).toBe(
|
|
191
|
+
true
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
await wrapper.setProps({ type: 'secondary' })
|
|
195
|
+
expect(wrapper.findComponent({ name: 'NewSpinner' }).props('isWhite')).toBe(
|
|
196
|
+
false
|
|
197
|
+
)
|
|
198
|
+
})
|
|
199
|
+
|
|
160
200
|
it('renders caret based on showCaret prop', async () => {
|
|
161
201
|
await wrapper.setProps({ showCaret: true })
|
|
162
202
|
let caret = wrapper.find('[data-test-id="button-icon-caret"]')
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
:type="type"
|
|
29
29
|
:variant="variant"
|
|
30
30
|
>
|
|
31
|
+
<RCSpinner v-if="isLoading" :is-white="isSpinnerWhite" size="tiny" />
|
|
31
32
|
<Icon
|
|
33
|
+
v-else
|
|
32
34
|
:color="getIconColor"
|
|
33
35
|
:disable-hover="disableIconHover"
|
|
34
36
|
:fill-type="fillType"
|
|
@@ -83,9 +85,11 @@
|
|
|
83
85
|
// iconName="external_icon"
|
|
84
86
|
// fontColor="white"
|
|
85
87
|
// fontSize="12px"
|
|
88
|
+
// :isLoading="false" // swaps the icon for a spinner
|
|
86
89
|
// />
|
|
87
90
|
|
|
88
91
|
import Icon from '../../icon'
|
|
92
|
+
import RCSpinner from '../../spinner'
|
|
89
93
|
import styled from 'vue3-styled-components'
|
|
90
94
|
import theme from '../../../assets/theme'
|
|
91
95
|
|
|
@@ -419,6 +423,7 @@
|
|
|
419
423
|
ButtonWrapper,
|
|
420
424
|
IconContainer,
|
|
421
425
|
Icon,
|
|
426
|
+
RCSpinner,
|
|
422
427
|
NumberContainer,
|
|
423
428
|
NumberText,
|
|
424
429
|
CountBadge,
|
|
@@ -541,11 +546,24 @@
|
|
|
541
546
|
default: false,
|
|
542
547
|
type: Boolean,
|
|
543
548
|
},
|
|
549
|
+
isLoading: {
|
|
550
|
+
required: false,
|
|
551
|
+
default: false,
|
|
552
|
+
type: Boolean,
|
|
553
|
+
},
|
|
544
554
|
},
|
|
545
555
|
computed: {
|
|
546
556
|
theme() {
|
|
547
557
|
return theme
|
|
548
558
|
},
|
|
559
|
+
// The spinner only offers white/purple, so pick whichever contrasts with
|
|
560
|
+
// the button background the same way the label already does.
|
|
561
|
+
isSpinnerWhite() {
|
|
562
|
+
return (
|
|
563
|
+
this.theme.mainButton[this.appTheme][this.type][this.variant].default
|
|
564
|
+
.textColor === this.theme.colors.white
|
|
565
|
+
)
|
|
566
|
+
},
|
|
549
567
|
getIconColor() {
|
|
550
568
|
if (this.iconColor) return this.iconColor
|
|
551
569
|
if (this.isDisabled) {
|
|
@@ -484,6 +484,7 @@
|
|
|
484
484
|
display: flex;
|
|
485
485
|
gap: 10px;
|
|
486
486
|
align-items: center;
|
|
487
|
+
padding: ${(props) => (props.isInteractive ? '0 4px' : '0')};
|
|
487
488
|
cursor: ${(props) => (props.isInteractive ? 'ew-resize' : 'auto')};
|
|
488
489
|
border: ${(props) =>
|
|
489
490
|
props.alignItems == 'vertical'
|
|
@@ -729,6 +730,11 @@
|
|
|
729
730
|
required: false,
|
|
730
731
|
default: true,
|
|
731
732
|
},
|
|
733
|
+
undefinedState: {
|
|
734
|
+
type: Boolean,
|
|
735
|
+
required: false,
|
|
736
|
+
default: false,
|
|
737
|
+
},
|
|
732
738
|
allowNegative: {
|
|
733
739
|
type: Boolean,
|
|
734
740
|
required: false,
|
|
@@ -844,6 +850,7 @@
|
|
|
844
850
|
},
|
|
845
851
|
computed: {
|
|
846
852
|
displayedPlaceholder() {
|
|
853
|
+
if (this.undefinedState) return '-'
|
|
847
854
|
if (this.placeholder) return this.placeholder
|
|
848
855
|
if (this.defaultNumber)
|
|
849
856
|
return `${this.defaultNumber}${this.hasSpaceBetweenUnit ? ' ' : ''}${
|
|
@@ -1121,6 +1128,9 @@
|
|
|
1121
1128
|
}
|
|
1122
1129
|
},
|
|
1123
1130
|
formatWithCurrency(value) {
|
|
1131
|
+
if (this.undefinedState && !this.isFocused) {
|
|
1132
|
+
return '-'
|
|
1133
|
+
}
|
|
1124
1134
|
let adjustedMinValue =
|
|
1125
1135
|
value || value === 0
|
|
1126
1136
|
? value
|
|
@@ -31,15 +31,16 @@
|
|
|
31
31
|
:border-color="borderColor"
|
|
32
32
|
:color-mode="colorMode"
|
|
33
33
|
:data-id="item.hasOwnProperty('dataId') ? item.dataId : ''"
|
|
34
|
+
:disabled="!!item.disabled"
|
|
34
35
|
:height="height"
|
|
35
36
|
:inactive-border-color="inactiveBorderColor"
|
|
36
37
|
:inactive-color="inactiveColor"
|
|
37
|
-
:is-active="value == item.value"
|
|
38
|
+
:is-active="!undefinedState && value == item.value"
|
|
38
39
|
:primary-color="primaryColor"
|
|
39
40
|
:secondary-color="secondaryColor"
|
|
40
41
|
:size="size"
|
|
41
42
|
:width="item.width || 'auto'"
|
|
42
|
-
@click="selectItem(item
|
|
43
|
+
@click="selectItem(item)"
|
|
43
44
|
>
|
|
44
45
|
<OptionIconContainer v-if="item.icon">
|
|
45
46
|
<RCIcon
|
|
@@ -145,6 +146,7 @@
|
|
|
145
146
|
height: String,
|
|
146
147
|
borderColor: String,
|
|
147
148
|
inactiveBorderColor: String,
|
|
149
|
+
disabled: Boolean,
|
|
148
150
|
}
|
|
149
151
|
const SwitchOption = styled('div', optionAttrs)`
|
|
150
152
|
color: ${(props) =>
|
|
@@ -167,17 +169,19 @@
|
|
|
167
169
|
props.height
|
|
168
170
|
? props.height
|
|
169
171
|
: props.size === 'medium'
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
? '24px'
|
|
173
|
+
: props.size === 'small'
|
|
174
|
+
? '16px'
|
|
175
|
+
: '24px'};
|
|
174
176
|
padding: 0 10px;
|
|
175
177
|
margin-right: -1px;
|
|
176
178
|
transition: all 0.1s ease-in-out;
|
|
177
179
|
overflow: hidden;
|
|
178
180
|
gap: 5px;
|
|
181
|
+
opacity: ${(props) => (props.disabled ? 0.4 : 1)};
|
|
182
|
+
pointer-events: ${(props) => (props.disabled ? 'none' : 'auto')};
|
|
179
183
|
& :hover {
|
|
180
|
-
cursor: pointer;
|
|
184
|
+
cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
|
|
181
185
|
}
|
|
182
186
|
&:first-child {
|
|
183
187
|
border-radius: 4px 0 0 4px;
|
|
@@ -264,6 +268,11 @@
|
|
|
264
268
|
default: false,
|
|
265
269
|
type: Boolean,
|
|
266
270
|
},
|
|
271
|
+
undefinedState: {
|
|
272
|
+
required: false,
|
|
273
|
+
default: false,
|
|
274
|
+
type: Boolean,
|
|
275
|
+
},
|
|
267
276
|
},
|
|
268
277
|
data() {
|
|
269
278
|
return {
|
|
@@ -282,19 +291,19 @@
|
|
|
282
291
|
this.borderColor = this.secondaryColor
|
|
283
292
|
this.inactiveBorderColor = theme.semanticColors.teal[600]
|
|
284
293
|
} else {
|
|
285
|
-
this.primaryColor = theme.semanticColors.teal[
|
|
286
|
-
this.secondaryColor = theme.semanticColors.
|
|
287
|
-
this.inactiveColor = theme.semanticColors.
|
|
294
|
+
this.primaryColor = theme.semanticColors.teal[100]
|
|
295
|
+
this.secondaryColor = theme.semanticColors.purple[500]
|
|
296
|
+
this.inactiveColor = theme.semanticColors.purple[500]
|
|
288
297
|
this.borderColor = this.secondaryColor
|
|
289
|
-
this.inactiveBorderColor = theme.semanticColors.teal[
|
|
298
|
+
this.inactiveBorderColor = theme.semanticColors.teal[200]
|
|
290
299
|
}
|
|
291
300
|
},
|
|
292
301
|
methods: {
|
|
293
|
-
selectItem(
|
|
294
|
-
if (this.disabled) {
|
|
302
|
+
selectItem(item) {
|
|
303
|
+
if (this.disabled || item.disabled) {
|
|
295
304
|
return
|
|
296
305
|
}
|
|
297
|
-
this.$emit('on-switch-change', value)
|
|
306
|
+
this.$emit('on-switch-change', item.value)
|
|
298
307
|
},
|
|
299
308
|
},
|
|
300
309
|
}
|
|
@@ -65,9 +65,9 @@ describe('SwitchField', () => {
|
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
it('renders the info text only when a message is provided', () => {
|
|
68
|
-
expect(
|
|
69
|
-
|
|
70
|
-
)
|
|
68
|
+
expect(
|
|
69
|
+
mountSwitch({ label: 'Mode' }).findComponent(InfoText).exists()
|
|
70
|
+
).toBe(false)
|
|
71
71
|
expect(
|
|
72
72
|
mountSwitch({ label: 'Mode', infoTextMessage: 'Helpful hint' })
|
|
73
73
|
.findComponent(InfoText)
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
role="checkbox"
|
|
33
33
|
:size="size"
|
|
34
34
|
tabindex="0"
|
|
35
|
+
:undefined-state="undefinedState"
|
|
35
36
|
@keydown.space.prevent="onToggleChange"
|
|
36
37
|
>
|
|
37
38
|
<ToggleBackground
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
data-test-id="toggle_background"
|
|
42
43
|
:disabled="disabled"
|
|
43
44
|
:is-checked="isChecked"
|
|
45
|
+
:undefined-state="undefinedState"
|
|
44
46
|
/>
|
|
45
47
|
<ToggleDot
|
|
46
48
|
data-test-id="toggle_dot"
|
|
@@ -49,6 +51,7 @@
|
|
|
49
51
|
:size="size"
|
|
50
52
|
:toggle-color="toggleColor"
|
|
51
53
|
:toggle-margin="toggleMargin"
|
|
54
|
+
:undefined-state="undefinedState"
|
|
52
55
|
/>
|
|
53
56
|
</ToggleWrapper>
|
|
54
57
|
<LabelContainer
|
|
@@ -125,6 +128,7 @@
|
|
|
125
128
|
disabled: Boolean,
|
|
126
129
|
backgroundColor: String,
|
|
127
130
|
isChecked: Boolean,
|
|
131
|
+
undefinedState: Boolean,
|
|
128
132
|
}
|
|
129
133
|
const LabelText = styled('div', toggleAttrs)`
|
|
130
134
|
color: ${(props) =>
|
|
@@ -140,6 +144,8 @@
|
|
|
140
144
|
border: ${(props) =>
|
|
141
145
|
props.disabled
|
|
142
146
|
? '1px solid ' + props.theme.colors.disabled
|
|
147
|
+
: props.undefinedState
|
|
148
|
+
? '1px solid ' + props.theme.colors.grey3
|
|
143
149
|
: props.isChecked
|
|
144
150
|
? props.backgroundColor
|
|
145
151
|
? '1px solid ' + props.backgroundColor
|
|
@@ -175,6 +181,7 @@
|
|
|
175
181
|
backgroundColor: String,
|
|
176
182
|
isChecked: Boolean,
|
|
177
183
|
disabled: Boolean,
|
|
184
|
+
undefinedState: Boolean,
|
|
178
185
|
}
|
|
179
186
|
const ToggleBackground = styled('span', backgroundAttrs)`
|
|
180
187
|
display: block;
|
|
@@ -184,6 +191,8 @@
|
|
|
184
191
|
background-color: ${(props) =>
|
|
185
192
|
props.disabled
|
|
186
193
|
? props.theme.colors.grey5
|
|
194
|
+
: props.undefinedState
|
|
195
|
+
? props.theme.colors.grey3
|
|
187
196
|
: props.isChecked
|
|
188
197
|
? props.backgroundColor
|
|
189
198
|
? props.backgroundColor
|
|
@@ -198,6 +207,7 @@
|
|
|
198
207
|
size: String,
|
|
199
208
|
disabled: Boolean,
|
|
200
209
|
toggleMargin: String,
|
|
210
|
+
undefinedState: Boolean,
|
|
201
211
|
}
|
|
202
212
|
const ToggleDot = styled('span', toggleProps)`
|
|
203
213
|
position: absolute;
|
|
@@ -233,7 +243,13 @@
|
|
|
233
243
|
border-radius: 100%;
|
|
234
244
|
transition: transform 0.4s ease;
|
|
235
245
|
transform: ${(props) =>
|
|
236
|
-
props.
|
|
246
|
+
props.undefinedState
|
|
247
|
+
? props.size === 'medium'
|
|
248
|
+
? 'translateX(15px)'
|
|
249
|
+
: props.size === 'small'
|
|
250
|
+
? 'translateX(6px)'
|
|
251
|
+
: 'translateX(15px)'
|
|
252
|
+
: props.isChecked
|
|
237
253
|
? props.size === 'medium'
|
|
238
254
|
? 'translateX(25px)'
|
|
239
255
|
: props.size === 'small'
|
|
@@ -336,6 +352,11 @@
|
|
|
336
352
|
default: null,
|
|
337
353
|
required: false,
|
|
338
354
|
},
|
|
355
|
+
undefinedState: {
|
|
356
|
+
type: Boolean,
|
|
357
|
+
default: false,
|
|
358
|
+
required: false,
|
|
359
|
+
},
|
|
339
360
|
},
|
|
340
361
|
methods: {
|
|
341
362
|
onToggleChange() {
|
|
@@ -77,16 +77,16 @@ describe('RCToggle', () => {
|
|
|
77
77
|
expect(wrapper.find('[data-test-id="label_left_container"]').exists()).toBe(
|
|
78
78
|
false
|
|
79
79
|
)
|
|
80
|
-
expect(
|
|
81
|
-
|
|
82
|
-
)
|
|
80
|
+
expect(
|
|
81
|
+
wrapper.find('[data-test-id="label_right_container"]').exists()
|
|
82
|
+
).toBe(false)
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
it('renders the label on the right by default', () => {
|
|
86
86
|
const wrapper = mountToggle({ label: 'My Label' })
|
|
87
|
-
expect(
|
|
88
|
-
|
|
89
|
-
)
|
|
87
|
+
expect(
|
|
88
|
+
wrapper.find('[data-test-id="label_right_container"]').exists()
|
|
89
|
+
).toBe(true)
|
|
90
90
|
expect(wrapper.find('[data-test-id="label_left_container"]').exists()).toBe(
|
|
91
91
|
false
|
|
92
92
|
)
|
|
@@ -98,9 +98,9 @@ describe('RCToggle', () => {
|
|
|
98
98
|
expect(wrapper.find('[data-test-id="label_left_container"]').exists()).toBe(
|
|
99
99
|
true
|
|
100
100
|
)
|
|
101
|
-
expect(
|
|
102
|
-
|
|
103
|
-
)
|
|
101
|
+
expect(
|
|
102
|
+
wrapper.find('[data-test-id="label_right_container"]').exists()
|
|
103
|
+
).toBe(false)
|
|
104
104
|
})
|
|
105
105
|
|
|
106
106
|
it('renders the info text only when infoTextMessage is provided', () => {
|
|
@@ -120,31 +120,8 @@
|
|
|
120
120
|
v-if="group.children?.length"
|
|
121
121
|
:is-collapsed="isCollapsed"
|
|
122
122
|
>
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
:data-id="`nav_section_${groupKey(group, groupIdx)}`"
|
|
126
|
-
:data-qa-id="`nav_section_${groupKey(group, groupIdx)}`"
|
|
127
|
-
@click="toggleGroup(groupKey(group, groupIdx))"
|
|
128
|
-
>
|
|
129
|
-
<GroupName>{{ group.groupName }}</GroupName>
|
|
130
|
-
<GroupChevron>
|
|
131
|
-
<IconComponent
|
|
132
|
-
:color="theme.semanticColors.grey[700]"
|
|
133
|
-
:hovered-color="theme.semanticColors.purple[500]"
|
|
134
|
-
:name="
|
|
135
|
-
isGroupCollapsed(groupKey(group, groupIdx))
|
|
136
|
-
? 'chevron_down'
|
|
137
|
-
: 'chevron_up'
|
|
138
|
-
"
|
|
139
|
-
size="10px"
|
|
140
|
-
/>
|
|
141
|
-
</GroupChevron>
|
|
142
|
-
</GroupHeader>
|
|
143
|
-
<ItemList
|
|
144
|
-
v-if="
|
|
145
|
-
isCollapsed || !isGroupCollapsed(groupKey(group, groupIdx))
|
|
146
|
-
"
|
|
147
|
-
>
|
|
123
|
+
<GroupName v-if="!isCollapsed">{{ group.groupName }}</GroupName>
|
|
124
|
+
<ItemList>
|
|
148
125
|
<template
|
|
149
126
|
v-for="(item, itemIdx) in group.children"
|
|
150
127
|
:key="item.id ?? itemIdx"
|
|
@@ -160,7 +137,7 @@
|
|
|
160
137
|
:is-disabled="item.isDisabled"
|
|
161
138
|
@click="
|
|
162
139
|
!item.isDisabled &&
|
|
163
|
-
|
|
140
|
+
$emit('on-menu-item-click', { item })
|
|
164
141
|
"
|
|
165
142
|
>
|
|
166
143
|
<IconCell :is-collapsed="isCollapsed">
|
|
@@ -197,7 +174,7 @@
|
|
|
197
174
|
type="tertiary"
|
|
198
175
|
@click="
|
|
199
176
|
!item.isDisabled &&
|
|
200
|
-
|
|
177
|
+
$emit('on-menu-item-click', { item })
|
|
201
178
|
"
|
|
202
179
|
/>
|
|
203
180
|
</template>
|
|
@@ -267,7 +244,7 @@
|
|
|
267
244
|
:is-disabled="sub.isDisabled"
|
|
268
245
|
@click="
|
|
269
246
|
!sub.isDisabled &&
|
|
270
|
-
|
|
247
|
+
$emit('on-menu-item-click', { item: sub })
|
|
271
248
|
"
|
|
272
249
|
>
|
|
273
250
|
<span>{{ sub.name }}</span>
|
|
@@ -330,8 +307,8 @@
|
|
|
330
307
|
p.isCollapsed
|
|
331
308
|
? `${NAV_SIDEBAR_COLLAPSED_OUTER_WIDTH_PX}px`
|
|
332
309
|
: p.expandedWidth
|
|
333
|
-
|
|
334
|
-
|
|
310
|
+
? `${p.expandedWidth}px`
|
|
311
|
+
: 'max-content'};
|
|
335
312
|
min-width: ${(p) =>
|
|
336
313
|
p.isCollapsed ? `${NAV_SIDEBAR_COLLAPSED_OUTER_WIDTH_PX}px` : '0'};
|
|
337
314
|
border-right: 1px solid ${(p) => p.theme.semanticColors.grey[300]};
|
|
@@ -441,18 +418,6 @@
|
|
|
441
418
|
padding: ${(p) => (p.isCollapsed ? '10px 8px' : '10px 16px')};
|
|
442
419
|
`
|
|
443
420
|
|
|
444
|
-
const GroupHeader = styled.div`
|
|
445
|
-
display: flex;
|
|
446
|
-
align-items: center;
|
|
447
|
-
justify-content: space-between;
|
|
448
|
-
gap: 6px;
|
|
449
|
-
cursor: pointer;
|
|
450
|
-
|
|
451
|
-
&:hover > div:first-child {
|
|
452
|
-
color: ${(p) => p.theme.semanticColors.purple[500]};
|
|
453
|
-
}
|
|
454
|
-
`
|
|
455
|
-
|
|
456
421
|
const GroupName = styled.div`
|
|
457
422
|
font-size: 10px;
|
|
458
423
|
font-weight: 400;
|
|
@@ -461,12 +426,6 @@
|
|
|
461
426
|
line-height: 150%;
|
|
462
427
|
`
|
|
463
428
|
|
|
464
|
-
const GroupChevron = styled.div`
|
|
465
|
-
display: flex;
|
|
466
|
-
align-items: center;
|
|
467
|
-
flex-shrink: 0;
|
|
468
|
-
`
|
|
469
|
-
|
|
470
429
|
const ItemList = styled.div`
|
|
471
430
|
display: flex;
|
|
472
431
|
flex-direction: column;
|
|
@@ -799,9 +758,7 @@
|
|
|
799
758
|
ScrollbarThumb,
|
|
800
759
|
GroupsList,
|
|
801
760
|
GroupSection,
|
|
802
|
-
GroupHeader,
|
|
803
761
|
GroupName,
|
|
804
|
-
GroupChevron,
|
|
805
762
|
ItemList,
|
|
806
763
|
MenuItem,
|
|
807
764
|
IconCell,
|
|
@@ -880,7 +837,6 @@
|
|
|
880
837
|
'on-menu-item-click',
|
|
881
838
|
'on-footer-button-click',
|
|
882
839
|
'sidebar-dimensions',
|
|
883
|
-
'section-collapse-toggle',
|
|
884
840
|
],
|
|
885
841
|
data() {
|
|
886
842
|
return {
|
|
@@ -888,7 +844,6 @@
|
|
|
888
844
|
isCollapsed: false,
|
|
889
845
|
responsibleSelectSurfaceOpen: false,
|
|
890
846
|
openDropdownId: null,
|
|
891
|
-
collapsedGroups: {},
|
|
892
847
|
isWrapperHovered: false,
|
|
893
848
|
expandedWidth: null,
|
|
894
849
|
scrollThumbStyle: {},
|
|
@@ -1165,27 +1120,6 @@
|
|
|
1165
1120
|
this.openDropdownId = this.openDropdownId === id ? null : id
|
|
1166
1121
|
}
|
|
1167
1122
|
},
|
|
1168
|
-
groupKey(group, idx) {
|
|
1169
|
-
return group.id ?? group.groupName ?? String(idx)
|
|
1170
|
-
},
|
|
1171
|
-
isGroupCollapsed(key) {
|
|
1172
|
-
return !!this.collapsedGroups[key]
|
|
1173
|
-
},
|
|
1174
|
-
toggleGroup(key) {
|
|
1175
|
-
if (this.collapsedGroups[key]) {
|
|
1176
|
-
delete this.collapsedGroups[key]
|
|
1177
|
-
} else {
|
|
1178
|
-
this.collapsedGroups[key] = true
|
|
1179
|
-
}
|
|
1180
|
-
this.$emit('section-collapse-toggle', {
|
|
1181
|
-
key,
|
|
1182
|
-
collapsed: this.isGroupCollapsed(key),
|
|
1183
|
-
})
|
|
1184
|
-
this.$nextTick(() => {
|
|
1185
|
-
this.updateScrollThumb()
|
|
1186
|
-
this.updateExpandedWidth()
|
|
1187
|
-
})
|
|
1188
|
-
},
|
|
1189
1123
|
},
|
|
1190
1124
|
}
|
|
1191
1125
|
</script>
|
|
@@ -113,7 +113,8 @@
|
|
|
113
113
|
size: {
|
|
114
114
|
type: String,
|
|
115
115
|
default: 'medium',
|
|
116
|
-
validator: (value) =>
|
|
116
|
+
validator: (value) =>
|
|
117
|
+
['tiny', 'small', 'medium', 'large'].includes(value),
|
|
117
118
|
},
|
|
118
119
|
isWhite: {
|
|
119
120
|
required: false,
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils'
|
|
2
|
-
import NavigationSideMenu from '@/components/navigationSideMenu'
|
|
3
|
-
|
|
4
|
-
jest.mock('@/components/icon/iconCache.mjs', () => ({
|
|
5
|
-
// need to mock this due to how jest handles import.meta
|
|
6
|
-
fetchIcon: jest.fn(() => Promise.resolve('mocked-icon-url.svg')),
|
|
7
|
-
}))
|
|
8
|
-
|
|
9
|
-
const menuData = [
|
|
10
|
-
{
|
|
11
|
-
groupName: 'Project',
|
|
12
|
-
children: [
|
|
13
|
-
{ id: 'technologies', name: 'Technologies', dataId: 'nav_technologies' },
|
|
14
|
-
{ id: 'finance', name: 'Finance', dataId: 'nav_finance' },
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
groupName: 'Workflow',
|
|
19
|
-
children: [
|
|
20
|
-
{
|
|
21
|
-
id: 'workflow_template',
|
|
22
|
-
name: 'Workflow template',
|
|
23
|
-
dataId: 'nav_workflow_template',
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
const mountMenu = (props = {}) =>
|
|
30
|
-
mount(NavigationSideMenu, { props: { menuData, ...props } })
|
|
31
|
-
|
|
32
|
-
const item = (wrapper, dataId) => wrapper.find(`[data-id="${dataId}"]`)
|
|
33
|
-
const section = (wrapper, key) => wrapper.find(`[data-id="nav_section_${key}"]`)
|
|
34
|
-
|
|
35
|
-
describe('navigationSideMenu/index.vue', () => {
|
|
36
|
-
describe('default state', () => {
|
|
37
|
-
it('renders a header for each non-empty group', () => {
|
|
38
|
-
const wrapper = mountMenu()
|
|
39
|
-
|
|
40
|
-
expect(section(wrapper, 'Project').exists()).toBe(true)
|
|
41
|
-
expect(section(wrapper, 'Workflow').exists()).toBe(true)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('shows every group item when nothing is collapsed', () => {
|
|
45
|
-
const wrapper = mountMenu()
|
|
46
|
-
|
|
47
|
-
expect(item(wrapper, 'nav_technologies').exists()).toBe(true)
|
|
48
|
-
expect(item(wrapper, 'nav_finance').exists()).toBe(true)
|
|
49
|
-
expect(item(wrapper, 'nav_workflow_template').exists()).toBe(true)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('reports no group as collapsed initially', () => {
|
|
53
|
-
const wrapper = mountMenu()
|
|
54
|
-
|
|
55
|
-
expect(wrapper.vm.isGroupCollapsed('Project')).toBe(false)
|
|
56
|
-
expect(wrapper.vm.isGroupCollapsed('Workflow')).toBe(false)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
describe('toggling a section', () => {
|
|
61
|
-
it("hides that section's items when its header is clicked, and shows them again on a second click", async () => {
|
|
62
|
-
const wrapper = mountMenu()
|
|
63
|
-
|
|
64
|
-
await section(wrapper, 'Project').trigger('click')
|
|
65
|
-
expect(item(wrapper, 'nav_technologies').exists()).toBe(false)
|
|
66
|
-
expect(item(wrapper, 'nav_finance').exists()).toBe(false)
|
|
67
|
-
|
|
68
|
-
await section(wrapper, 'Project').trigger('click')
|
|
69
|
-
expect(item(wrapper, 'nav_technologies').exists()).toBe(true)
|
|
70
|
-
expect(item(wrapper, 'nav_finance').exists()).toBe(true)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('collapses sections independently — collapsing one leaves the others expanded', async () => {
|
|
74
|
-
const wrapper = mountMenu()
|
|
75
|
-
|
|
76
|
-
await section(wrapper, 'Project').trigger('click')
|
|
77
|
-
|
|
78
|
-
expect(item(wrapper, 'nav_technologies').exists()).toBe(false)
|
|
79
|
-
expect(item(wrapper, 'nav_workflow_template').exists()).toBe(true)
|
|
80
|
-
expect(wrapper.vm.isGroupCollapsed('Project')).toBe(true)
|
|
81
|
-
expect(wrapper.vm.isGroupCollapsed('Workflow')).toBe(false)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('emits section-collapse-toggle with the key and post-toggle collapsed state', async () => {
|
|
85
|
-
const wrapper = mountMenu()
|
|
86
|
-
|
|
87
|
-
await section(wrapper, 'Project').trigger('click')
|
|
88
|
-
await section(wrapper, 'Project').trigger('click')
|
|
89
|
-
|
|
90
|
-
const events = wrapper.emitted('section-collapse-toggle')
|
|
91
|
-
expect(events).toHaveLength(2)
|
|
92
|
-
expect(events[0]).toEqual([{ key: 'Project', collapsed: true }])
|
|
93
|
-
expect(events[1]).toEqual([{ key: 'Project', collapsed: false }])
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
describe('groupKey', () => {
|
|
98
|
-
it('prefers an explicit id over the group name', () => {
|
|
99
|
-
const wrapper = mountMenu()
|
|
100
|
-
|
|
101
|
-
expect(wrapper.vm.groupKey({ id: 'a', groupName: 'B' }, 0)).toBe('a')
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('falls back to the group name when there is no id', () => {
|
|
105
|
-
const wrapper = mountMenu()
|
|
106
|
-
|
|
107
|
-
expect(wrapper.vm.groupKey({ groupName: 'B' }, 0)).toBe('B')
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('falls back to the index (as a string) when neither id nor name is present', () => {
|
|
111
|
-
const wrapper = mountMenu()
|
|
112
|
-
|
|
113
|
-
expect(wrapper.vm.groupKey({}, 3)).toBe('3')
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
describe('edge cases', () => {
|
|
118
|
-
it('mounts without error and renders no sections when menuData is empty', () => {
|
|
119
|
-
const wrapper = mount(NavigationSideMenu, { props: { menuData: [] } })
|
|
120
|
-
|
|
121
|
-
expect(wrapper.find('[data-id^="nav_section_"]').exists()).toBe(false)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('treats groups that share a groupName as one section (name is the key)', async () => {
|
|
125
|
-
const dupData = [
|
|
126
|
-
{
|
|
127
|
-
groupName: 'Other',
|
|
128
|
-
children: [{ id: 'a', name: 'A', dataId: 'nav_a' }],
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
groupName: 'Other',
|
|
132
|
-
children: [{ id: 'b', name: 'B', dataId: 'nav_b' }],
|
|
133
|
-
},
|
|
134
|
-
]
|
|
135
|
-
const wrapper = mount(NavigationSideMenu, {
|
|
136
|
-
props: { menuData: dupData },
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
await wrapper.findAll('[data-id="nav_section_Other"]')[0].trigger('click')
|
|
140
|
-
|
|
141
|
-
expect(item(wrapper, 'nav_a').exists()).toBe(false)
|
|
142
|
-
expect(item(wrapper, 'nav_b').exists()).toBe(false)
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
})
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { action } from '@storybook/addon-actions'
|
|
2
|
-
import NavigationSideMenu from './index.vue'
|
|
3
|
-
import theme from '@/assets/theme'
|
|
4
|
-
|
|
5
|
-
// Grouped menu mirroring the beta settings navigation: each top-level entry is a
|
|
6
|
-
// section ({ groupName, children }). Click a section header (e.g. "OFFER") to
|
|
7
|
-
// collapse/expand its items — sections collapse independently.
|
|
8
|
-
const settingsMenu = [
|
|
9
|
-
{
|
|
10
|
-
groupName: 'Project',
|
|
11
|
-
children: [
|
|
12
|
-
{
|
|
13
|
-
id: 'technologies',
|
|
14
|
-
name: 'Technologies',
|
|
15
|
-
dataId: 'nav_technologies',
|
|
16
|
-
icon: 'settings',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
id: 'finance',
|
|
20
|
-
name: 'Finance',
|
|
21
|
-
dataId: 'nav_finance',
|
|
22
|
-
icon: 'documents',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
groupName: 'Workflow',
|
|
28
|
-
children: [
|
|
29
|
-
{
|
|
30
|
-
id: 'workflow_template',
|
|
31
|
-
name: 'Workflow template',
|
|
32
|
-
dataId: 'nav_workflow_template',
|
|
33
|
-
icon: 'settings',
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: 'activity_type',
|
|
37
|
-
name: 'Activity type definition',
|
|
38
|
-
dataId: 'nav_activity_type',
|
|
39
|
-
icon: 'documents',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
groupName: 'Offer',
|
|
45
|
-
children: [
|
|
46
|
-
{
|
|
47
|
-
id: 'branding',
|
|
48
|
-
name: 'Branding',
|
|
49
|
-
dataId: 'nav_branding',
|
|
50
|
-
icon: 'settings',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
id: 'document_templates',
|
|
54
|
-
name: 'Document templates',
|
|
55
|
-
dataId: 'nav_document_templates',
|
|
56
|
-
icon: 'documents',
|
|
57
|
-
// An item-level dropdown (its own children) — orthogonal to section collapse.
|
|
58
|
-
children: [
|
|
59
|
-
{ id: 'quotation', name: 'Quotation', dataId: 'nav_quotation' },
|
|
60
|
-
{ id: 'invoice', name: 'Invoice', dataId: 'nav_invoice' },
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
]
|
|
66
|
-
|
|
67
|
-
const projectManagerOptions = [
|
|
68
|
-
{ id: 1, full_name: 'Firstname Lastname' },
|
|
69
|
-
{ id: 2, full_name: 'Alex Meyer' },
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
export default {
|
|
73
|
-
title: 'Components/Navigation/NavigationSideMenu',
|
|
74
|
-
component: NavigationSideMenu,
|
|
75
|
-
tags: ['autodocs'],
|
|
76
|
-
parameters: {
|
|
77
|
-
layout: 'fullscreen',
|
|
78
|
-
},
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const Template = (args) => ({
|
|
82
|
-
components: { NavigationSideMenu },
|
|
83
|
-
setup() {
|
|
84
|
-
const onSectionToggle = (payload) =>
|
|
85
|
-
action('section-collapse-toggle')(payload)
|
|
86
|
-
const onItemClick = (payload) => action('on-menu-item-click')(payload)
|
|
87
|
-
return { args, onSectionToggle, onItemClick }
|
|
88
|
-
},
|
|
89
|
-
template: `
|
|
90
|
-
<div data-test-id="navigation-side-menu-story" style="display: flex; min-height: 100vh; background: #f5f5f5;">
|
|
91
|
-
<NavigationSideMenu
|
|
92
|
-
v-bind="args"
|
|
93
|
-
@section-collapse-toggle="onSectionToggle"
|
|
94
|
-
@on-menu-item-click="onItemClick"
|
|
95
|
-
/>
|
|
96
|
-
<main style="flex: 1; padding: 24px;">Main content area</main>
|
|
97
|
-
</div>
|
|
98
|
-
`,
|
|
99
|
-
provide: {
|
|
100
|
-
theme,
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
// Default: all sections expanded. Click a section header to collapse/expand it;
|
|
105
|
-
// multiple sections can be collapsed at once (independent, not accordion).
|
|
106
|
-
export const CollapsibleSections = Template.bind({})
|
|
107
|
-
CollapsibleSections.args = {
|
|
108
|
-
menuData: settingsMenu,
|
|
109
|
-
headerTitle: 'Settings',
|
|
110
|
-
activeItemId: 'technologies',
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// An item that has its own children ("Document templates") renders an item-level
|
|
114
|
-
// dropdown, which behaves independently of section collapse.
|
|
115
|
-
export const WithNestedDropdown = Template.bind({})
|
|
116
|
-
WithNestedDropdown.args = {
|
|
117
|
-
menuData: settingsMenu,
|
|
118
|
-
headerTitle: 'Settings',
|
|
119
|
-
activeItemId: 'quotation',
|
|
120
|
-
activeParentId: 'document_templates',
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// The project-view placement of the same component: project-manager select in the
|
|
124
|
-
// header plus a footer button. Section collapse works identically here.
|
|
125
|
-
export const ProjectPlacement = Template.bind({})
|
|
126
|
-
ProjectPlacement.args = {
|
|
127
|
-
menuData: settingsMenu,
|
|
128
|
-
showProjectManagerSelect: true,
|
|
129
|
-
projectManagerOptions,
|
|
130
|
-
projectManagerId: 1,
|
|
131
|
-
footerButtonText: 'Documents',
|
|
132
|
-
activeItemId: 'finance',
|
|
133
|
-
}
|