@itfin/components 1.0.62 → 1.0.67
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/scss/components/_selected.scss +1 -1
- package/src/components/checkbox/Checkbox.vue +5 -3
- package/src/components/segmented-control/SegmentedControl.vue +17 -18
- package/src/components/tabs/Tab.vue +39 -0
- package/src/components/tabs/TabContent.vue +24 -0
- package/src/components/tabs/Tabs.vue +66 -0
- package/src/components/tabs/index.stories.js +60 -0
- package/src/components/tabs/tabs.scss +100 -0
- package/src/components/text-field/TextField.vue +19 -1
- package/src/components/text-field/Textarea.vue +12 -0
- package/src/components/wizard/Sidebar.vue +12 -79
- package/src/components/wizard/Wizard.vue +3 -3
- package/src/nuxt-config/componentNormalizer.js +113 -0
- package/src/nuxt-config/config.js +9 -0
package/package.json
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
<div class="itf-checkbox form-check" :class="{ 'form-switch': this.switch, 'itf-checkbox__large': large, 'itf-checkbox__medium': medium }">
|
|
4
4
|
<input class="form-check-input" :id="id" type="checkbox" name="checkbox" v-model="isChecked" :disabled="isDisabled" />
|
|
5
|
-
<label :for="id"
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
<label :for="id" class="form-check-label">
|
|
6
|
+
<slot name="label">
|
|
7
|
+
{{label}}
|
|
8
|
+
<slot name="icon"></slot>
|
|
9
|
+
</slot>
|
|
8
10
|
</label>
|
|
9
11
|
</div>
|
|
10
12
|
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="itf-segmeneted-control">
|
|
3
|
-
<span v-if="!isUndefined" class="selection" :class="{'elevation-1': !disabled}"></span>
|
|
3
|
+
<span v-if="!isUndefined" ref="slider" class="selection" :class="{'elevation-1': !disabled}"></span>
|
|
4
4
|
|
|
5
5
|
<div class="option" v-for="(item, n) in itemsWithNames" :key="n">
|
|
6
6
|
<label>
|
|
7
7
|
<input
|
|
8
|
+
ref="input"
|
|
8
9
|
type="radio"
|
|
9
10
|
:name="name"
|
|
10
11
|
:value="n"
|
|
11
12
|
:checked="isChecked(item)"
|
|
12
13
|
@change="onItemChanged(item)" />
|
|
13
14
|
<span>
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
<slot name="item" :item="item" :itemKey="n">{{item[itemText]}}</slot>
|
|
16
|
+
</span>
|
|
16
17
|
</label>
|
|
17
18
|
</div>
|
|
18
19
|
</div>
|
|
@@ -203,32 +204,30 @@ class itfSegmentedControl extends Vue {
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
init() {
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
this.$el.addEventListener('change', () => updatePillPosition(this));
|
|
208
|
+
//window.addEventListener('resize', () => updatePillPosition(this.$el)); // Prevent pill from detaching from element when window resized. Becuase this is rare I haven't bothered with throttling the event
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
window.addEventListener('resize', () => updatePillPosition(this.$el)); // Prevent pill from detaching from element when window resized. Becuase this is rare I haven't bothered with throttling the event
|
|
210
|
+
updatePillPosition(this);
|
|
211
211
|
|
|
212
|
-
updatePillPosition(
|
|
213
|
-
|
|
214
|
-
function updatePillPosition (el) {
|
|
215
|
-
forEachElement(el, INDIVIDUAL_SEGMENT_SELECTOR, (elem, index) => {
|
|
212
|
+
function updatePillPosition (component) {
|
|
213
|
+
component.$refs.input.forEach((elem, index) => {
|
|
216
214
|
if (elem.checked) {
|
|
217
|
-
moveBackgroundPillToElement(
|
|
215
|
+
component.$nextTick(() => moveBackgroundPillToElement(component, elem, index));
|
|
216
|
+
setTimeout(() => moveBackgroundPillToElement(component, elem, index), 500);
|
|
217
|
+
setTimeout(() => moveBackgroundPillToElement(component, elem, index), 750);
|
|
218
|
+
setTimeout(() => moveBackgroundPillToElement(component, elem, index), 1500);
|
|
219
|
+
setTimeout(() => moveBackgroundPillToElement(component, elem, index), 3000);
|
|
218
220
|
}
|
|
219
221
|
})
|
|
220
222
|
}
|
|
221
223
|
|
|
222
|
-
function moveBackgroundPillToElement (
|
|
223
|
-
const slider =
|
|
224
|
+
function moveBackgroundPillToElement (component, elem, index) {
|
|
225
|
+
const slider = component.$refs.slider;
|
|
226
|
+
console.info('init 2', slider);
|
|
224
227
|
if (slider) {
|
|
225
228
|
slider.style.transform = 'translateX(' + (elem.offsetWidth * index) + 'px)';
|
|
226
229
|
}
|
|
227
230
|
}
|
|
228
|
-
|
|
229
|
-
function forEachElement(el, className, fn) {
|
|
230
|
-
Array.from(el.querySelectorAll(className)).forEach(fn);
|
|
231
|
-
}
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
onItemChanged (item) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="itf-tab" :data-test="`itf-tab-${id}`" @click="setActive" :class="{ active }">
|
|
3
|
+
<span><slot /></span>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
<style lang="scss" scoped>
|
|
7
|
+
.itf-tab {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
<script>
|
|
12
|
+
import { Vue, Component, Prop, Inject } from 'vue-property-decorator';
|
|
13
|
+
|
|
14
|
+
export default @Component({
|
|
15
|
+
name: 'itfTab',
|
|
16
|
+
components: {
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
class itfTab extends Vue {
|
|
20
|
+
@Inject() tabsManager;
|
|
21
|
+
@Prop() id;
|
|
22
|
+
@Prop() to;
|
|
23
|
+
|
|
24
|
+
get active() {
|
|
25
|
+
if (this.to) {
|
|
26
|
+
const route = this.$router.resolve(this.to);
|
|
27
|
+
return this.$route.path === (route && route.href);
|
|
28
|
+
}
|
|
29
|
+
return this.tabsManager && this.tabsManager.getValue() === this.id;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setActive() {
|
|
33
|
+
if (this.to) {
|
|
34
|
+
this.$router.push(this.to);
|
|
35
|
+
}
|
|
36
|
+
this.tabsManager.setValue(id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-show="tabsManager && tabsManager.getValue() === id" :class="{ filled }" class="itf-tab-content" :data-test="`itf-tab-content-${id}`">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
<style lang="scss" scoped>
|
|
7
|
+
.itf-tab-content {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
<script>
|
|
12
|
+
import { Vue, Component, Prop, Inject } from 'vue-property-decorator';
|
|
13
|
+
|
|
14
|
+
export default @Component({
|
|
15
|
+
name: 'itfTabContent',
|
|
16
|
+
components: {
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
class itfTabContent extends Vue {
|
|
20
|
+
@Inject({ default: null }) tabsManager;
|
|
21
|
+
@Prop() id;
|
|
22
|
+
@Prop(Boolean) filled;
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import {
|
|
3
|
+
Vue, Component, Provide, Model, Emit,
|
|
4
|
+
} from 'vue-property-decorator';
|
|
5
|
+
import itfTab from './Tab';
|
|
6
|
+
import './tabs.scss';
|
|
7
|
+
|
|
8
|
+
export default @Component({
|
|
9
|
+
name: 'itfTabs',
|
|
10
|
+
components: {
|
|
11
|
+
itfTab
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
class itfTabs extends Vue {
|
|
15
|
+
@Provide() tabsManager = this;
|
|
16
|
+
|
|
17
|
+
@Model('input') value;
|
|
18
|
+
|
|
19
|
+
tabNodes;
|
|
20
|
+
|
|
21
|
+
render(createElement) {
|
|
22
|
+
const [tabNodes, contents] = parseNodes(this.$slots);
|
|
23
|
+
this.tabNodes = tabNodes;
|
|
24
|
+
|
|
25
|
+
return createElement('div', { staticClass: 'itf-tabs' }, [
|
|
26
|
+
createElement('div', { staticClass: 'itf-tabs-panel' }, tabNodes),
|
|
27
|
+
createElement('div', { staticClass: 'itf-tabs-content' }, contents)
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
function parseNodes(slots) {
|
|
31
|
+
const items = [];
|
|
32
|
+
const contents = [];
|
|
33
|
+
const nodes = (slots.default || []);
|
|
34
|
+
|
|
35
|
+
for (const vnode of nodes) {
|
|
36
|
+
if (!vnode.componentOptions) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (vnode.componentOptions.tag.includes('-tab-content')) {
|
|
40
|
+
contents.push(vnode);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (vnode.componentOptions.tag.includes('-tab')) {
|
|
44
|
+
items.push(vnode);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [items, contents];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Emit('input')
|
|
52
|
+
setValue(value) {
|
|
53
|
+
this.tabNodes = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getValue() {
|
|
57
|
+
return this.value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
scrollToTop() {
|
|
61
|
+
this.$el.scrollIntoView({
|
|
62
|
+
behavior: 'smooth',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
</script>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { storiesOf } from '@storybook/vue';
|
|
2
|
+
import itfApp from '../app/App.vue';
|
|
3
|
+
import itfButton from '../button/Button.vue';
|
|
4
|
+
import itfTab from './Tab.vue';
|
|
5
|
+
import itfTabContent from './TabContent.vue';
|
|
6
|
+
import itfTabs from './Tabs.vue';
|
|
7
|
+
import itfLabel from '../form/Label.vue';
|
|
8
|
+
import itfDatePicker from '../datepicker/DatePicker.vue';
|
|
9
|
+
import itfDateRangePicker from '../datepicker/DateRangePicker.vue';
|
|
10
|
+
|
|
11
|
+
storiesOf('Common', module)
|
|
12
|
+
.add('Tabs', () => ({
|
|
13
|
+
components: {
|
|
14
|
+
itfApp,
|
|
15
|
+
itfTabs,
|
|
16
|
+
itfLabel,
|
|
17
|
+
itfDatePicker,
|
|
18
|
+
itfDateRangePicker,
|
|
19
|
+
itfTab,
|
|
20
|
+
itfTabContent,
|
|
21
|
+
itfButton
|
|
22
|
+
},
|
|
23
|
+
data() {
|
|
24
|
+
return {
|
|
25
|
+
tab: 'Test1'
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
methods: {
|
|
29
|
+
},
|
|
30
|
+
template: `<div>
|
|
31
|
+
<p>You need wrap whole application with this tag</p>
|
|
32
|
+
|
|
33
|
+
<h2>Usage</h2>
|
|
34
|
+
{{tab}}
|
|
35
|
+
<pre>
|
|
36
|
+
<itf-tabs v-model="tab">
|
|
37
|
+
<itf-tab id="Test1">
|
|
38
|
+
asd
|
|
39
|
+
</itf-tab>
|
|
40
|
+
</itf-tabs>
|
|
41
|
+
</pre>
|
|
42
|
+
|
|
43
|
+
<h3>Example</h3>
|
|
44
|
+
|
|
45
|
+
<itf-tabs v-model="tab">
|
|
46
|
+
<itf-tab id="Test1">
|
|
47
|
+
Content 1
|
|
48
|
+
</itf-tab>
|
|
49
|
+
<itf-tab id="Test2">
|
|
50
|
+
Content 2
|
|
51
|
+
</itf-tab>
|
|
52
|
+
<itf-tab-content id="Test1">
|
|
53
|
+
asd
|
|
54
|
+
</itf-tab-content>
|
|
55
|
+
<itf-tab-content id="Test2">
|
|
56
|
+
asd123
|
|
57
|
+
</itf-tab-content>
|
|
58
|
+
</itf-tabs>
|
|
59
|
+
</div>`,
|
|
60
|
+
}));
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
@import '../../assets/scss/variables';
|
|
2
|
+
@import '~bootstrap/scss/grid';
|
|
3
|
+
@import '~bootstrap/scss/containers';
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--itf-tabs-active-bg: #fff;
|
|
7
|
+
--itf-tabs-active-color: #222;
|
|
8
|
+
--itf-tabs-active-border-color: #ffb20fc2;
|
|
9
|
+
--itf-tabs-inactive-bg: #fafafa;
|
|
10
|
+
--itf-tabs-inactive-color: #222;
|
|
11
|
+
--itf-tabs-inactive-border-color: rgba(0, 0, 0, .1);
|
|
12
|
+
--itf-tabs-hover-bg: #F4F7F9;
|
|
13
|
+
--itf-tabs-hover-color: #222;
|
|
14
|
+
--itf-tabs-hover-border-color: rgba(0, 0, 0, .5);
|
|
15
|
+
--itf-tabs-tab-padding: 10px;
|
|
16
|
+
|
|
17
|
+
--itf-tabs-content-bg: #fff;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.itf-tabs {
|
|
21
|
+
.itf-tabs-panel {
|
|
22
|
+
margin: 0px;
|
|
23
|
+
padding: 0px;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
padding-left: calc(var(--itf-tabs-tab-padding) * 2.1);
|
|
26
|
+
list-style-type: none;
|
|
27
|
+
display: flex;
|
|
28
|
+
|
|
29
|
+
.itf-tab {
|
|
30
|
+
display: block;
|
|
31
|
+
//float: right;
|
|
32
|
+
padding: 10px var(--itf-tabs-tab-padding) 8px;
|
|
33
|
+
margin-right: calc(var(--itf-tabs-tab-padding) * 3);
|
|
34
|
+
z-index: 2;
|
|
35
|
+
position: relative;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition: all 250ms ease;
|
|
38
|
+
border-radius: 8px 8px 0 0;
|
|
39
|
+
background-color: var(--itf-tabs-inactive-bg);
|
|
40
|
+
color: var(--itf-tabs-inactive-color);
|
|
41
|
+
border-top: 1px solid var(--itf-tabs-inactive-border-color);
|
|
42
|
+
border-bottom: 1px solid var(--itf-tabs-inactive-border-color);
|
|
43
|
+
|
|
44
|
+
& > span {
|
|
45
|
+
position: relative;
|
|
46
|
+
z-index: 4;
|
|
47
|
+
}
|
|
48
|
+
&:before, &:after {
|
|
49
|
+
display: block;
|
|
50
|
+
content: " ";
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: -1px;
|
|
53
|
+
height: calc(100% + 1px);
|
|
54
|
+
width: calc(var(--itf-tabs-tab-padding) * 5);
|
|
55
|
+
background-color: var(--itf-tabs-inactive-bg);
|
|
56
|
+
color: var(--itf-tabs-inactive-color);
|
|
57
|
+
border-top: 1px solid var(--itf-tabs-inactive-border-color);
|
|
58
|
+
transition: all 250ms ease;
|
|
59
|
+
}
|
|
60
|
+
&:before {
|
|
61
|
+
right: calc(var(--itf-tabs-tab-padding) * -2);
|
|
62
|
+
border-radius: 0 8px 0 0;
|
|
63
|
+
transform: skew(30deg, 0deg);
|
|
64
|
+
box-shadow: rgba(0,0,0,.1) 3px 2px 5px, inset rgba(255,255,255,.09) -1px 0;
|
|
65
|
+
}
|
|
66
|
+
&:after {
|
|
67
|
+
left: calc(var(--itf-tabs-tab-padding) * -2);
|
|
68
|
+
border-radius: 8px 0 0 0;
|
|
69
|
+
//transform: skew(-30deg, 0deg);
|
|
70
|
+
box-shadow: rgba(0,0,0,.1) -3px 2px 5px, inset rgba(255,255,255,.09) 1px 0;
|
|
71
|
+
}
|
|
72
|
+
&:hover, &:hover:before, &:hover:after {
|
|
73
|
+
background-color: var(--itf-tabs-hover-bg);
|
|
74
|
+
color: var(--itf-tabs-hover-color);
|
|
75
|
+
border-top: 1px solid var(--itf-tabs-hover-border-color);
|
|
76
|
+
}
|
|
77
|
+
&.active {
|
|
78
|
+
z-index: 3;
|
|
79
|
+
|
|
80
|
+
&, &:before, &:after {
|
|
81
|
+
background-color: var(--itf-tabs-active-bg);
|
|
82
|
+
color: var(--itf-tabs-active-color);
|
|
83
|
+
border-top: 1px solid var(--itf-tabs-active-border-color);
|
|
84
|
+
border-bottom: 0 none;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
.itf-tabs-content {
|
|
90
|
+
.itf-tab-content {
|
|
91
|
+
&.filled {
|
|
92
|
+
background: var(--itf-tabs-content-bg);
|
|
93
|
+
border: 1px solid var(--itf-tabs-inactive-border-color);
|
|
94
|
+
margin-top: -1px;
|
|
95
|
+
border-bottom-left-radius: $border-radius;
|
|
96
|
+
border-bottom-right-radius: $border-radius;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
<div class="itf-text-field input-group" :class="{ 'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable }">
|
|
4
|
-
<div class="addon" v-if="prependIcon">
|
|
4
|
+
<div class="addon" v-if="prependIcon || $slots.addon">
|
|
5
5
|
<slot name="addon">
|
|
6
6
|
<itf-icon :name="prependIcon"/>
|
|
7
7
|
</slot>
|
|
@@ -19,6 +19,13 @@
|
|
|
19
19
|
:readonly="readonly"
|
|
20
20
|
@input="onInput($event.target.value)"
|
|
21
21
|
@keydown="$emit('keydown', $event)"
|
|
22
|
+
@keyup="$emit('keyup', $event)"
|
|
23
|
+
@keypress="$emit('keypress', $event)"
|
|
24
|
+
@blur="$emit('blur', $event)"
|
|
25
|
+
@focus="$emit('focus', $event)"
|
|
26
|
+
:min="min"
|
|
27
|
+
:max="max"
|
|
28
|
+
:step="step"
|
|
22
29
|
/>
|
|
23
30
|
|
|
24
31
|
<div class="addon-end" v-if="clearable && value">
|
|
@@ -68,6 +75,9 @@ class itfTextField extends Vue {
|
|
|
68
75
|
@Model('input') value;
|
|
69
76
|
@Prop(String) prependIcon;
|
|
70
77
|
@Prop(String) placeholder;
|
|
78
|
+
@Prop() step;
|
|
79
|
+
@Prop() min;
|
|
80
|
+
@Prop() max;
|
|
71
81
|
@Prop(Boolean) clearable;
|
|
72
82
|
@Prop(Boolean) disabled;
|
|
73
83
|
@Prop(Boolean) readonly;
|
|
@@ -95,5 +105,13 @@ class itfTextField extends Vue {
|
|
|
95
105
|
const endText = value.slice(position);
|
|
96
106
|
this.$emit('input', `${startText}${text}${endText}`);
|
|
97
107
|
}
|
|
108
|
+
|
|
109
|
+
focus() {
|
|
110
|
+
this.$refs.input.focus();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
blur() {
|
|
114
|
+
this.$refs.input.blur();
|
|
115
|
+
}
|
|
98
116
|
}
|
|
99
117
|
</script>
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
:value="value"
|
|
19
19
|
@input="onInput($event.target.value)"
|
|
20
20
|
@keydown="$emit('keydown', $event)"
|
|
21
|
+
@keyup="$emit('keyup', $event)"
|
|
22
|
+
@keypress="$emit('keypress', $event)"
|
|
23
|
+
@blur="$emit('blur', $event)"
|
|
24
|
+
@focus="$emit('focus', $event)"
|
|
21
25
|
/>
|
|
22
26
|
</div>
|
|
23
27
|
|
|
@@ -95,5 +99,13 @@ class itfTextarea extends Vue {
|
|
|
95
99
|
const endText = value.slice(position);
|
|
96
100
|
this.$emit('input', `${startText}${text}${endText}`);
|
|
97
101
|
}
|
|
102
|
+
|
|
103
|
+
focus() {
|
|
104
|
+
this.$refs.input.focus();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
blur() {
|
|
108
|
+
this.$refs.input.blur();
|
|
109
|
+
}
|
|
98
110
|
}
|
|
99
111
|
</script>
|
|
@@ -1,54 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
|
-
<div class="
|
|
3
|
+
<div class="py-3 px-2">
|
|
4
4
|
|
|
5
|
-
<ul class="nav nav-pills flex-column mb-auto">
|
|
6
|
-
<li class="nav-item">
|
|
7
|
-
<a href="#" class="nav-link active" aria-current="page">
|
|
8
|
-
<svg class="bi me-2" width="16" height="16"><use xlink:href="#home"></use></svg>
|
|
9
|
-
Home
|
|
10
|
-
</a>
|
|
11
|
-
</li>
|
|
12
|
-
<li>
|
|
13
|
-
<a href="#" class="nav-link link-dark">
|
|
14
|
-
<svg class="bi me-2" width="16" height="16"><use xlink:href="#speedometer2"></use></svg>
|
|
15
|
-
Dashboard
|
|
16
|
-
</a>
|
|
17
|
-
</li>
|
|
18
|
-
<li>
|
|
19
|
-
<a href="#" class="nav-link link-dark">
|
|
20
|
-
<svg class="bi me-2" width="16" height="16"><use xlink:href="#table"></use></svg>
|
|
21
|
-
Orders
|
|
22
|
-
</a>
|
|
23
|
-
</li>
|
|
24
|
-
<li>
|
|
25
|
-
<a href="#" class="nav-link link-dark">
|
|
26
|
-
<svg class="bi me-2" width="16" height="16"><use xlink:href="#grid"></use></svg>
|
|
27
|
-
Products
|
|
28
|
-
</a>
|
|
29
|
-
</li>
|
|
30
|
-
<li>
|
|
31
|
-
<a href="#" class="nav-link link-dark">
|
|
32
|
-
<svg class="bi me-2" width="16" height="16"><use xlink:href="#people-circle"></use></svg>
|
|
33
|
-
Customers
|
|
34
|
-
</a>
|
|
35
|
-
</li>
|
|
36
|
-
</ul>
|
|
37
|
-
|
|
38
|
-
<ul class="nav nav-pills nav-stacked" data-test="step-sidebar">
|
|
5
|
+
<ul class="nav nav-pills flex-column mb-auto ps-0" data-test="step-sidebar">
|
|
39
6
|
|
|
40
7
|
<li v-for="(step, n) in sidebarItems" :class="{ active: selectedId === step.id, disabled: selectedId !== step.id }"
|
|
41
8
|
:data-test="'step-sidebar-' + step.id">
|
|
42
|
-
<strong v-if="selectedId !== step.id && value.
|
|
43
|
-
<
|
|
9
|
+
<strong v-if="selectedId !== step.id && value.includes(step.id)" class="nav-link text-success">
|
|
10
|
+
<itf-icon :name="step['sidebar-icon'] || 'check_circle'"></itf-icon>
|
|
44
11
|
{{step['sidebar-title']}}
|
|
45
12
|
</strong>
|
|
46
|
-
<a href="" v-else @click.prevent="">
|
|
47
|
-
<
|
|
13
|
+
<a href="" v-else @click.prevent="" class="nav-link">
|
|
14
|
+
<itf-icon :name="step['sidebar-icon'] || 'circle'"></itf-icon>
|
|
48
15
|
{{step['sidebar-title']}}
|
|
49
16
|
</a>
|
|
50
|
-
<span aria-hidden="true" class="completed-icon glyphicon air-icon-verified"
|
|
51
|
-
:class="{ 'completed': value.indexOf(step.id) !== -1 }"></span>
|
|
52
17
|
</li>
|
|
53
18
|
</ul>
|
|
54
19
|
|
|
@@ -56,50 +21,18 @@
|
|
|
56
21
|
|
|
57
22
|
</template>
|
|
58
23
|
<style lang="scss">
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.completed-icon {
|
|
62
|
-
position: absolute;
|
|
63
|
-
right: 0;
|
|
64
|
-
top: 0;
|
|
65
|
-
height: 100%;
|
|
66
|
-
display: flex;
|
|
67
|
-
align-items: center;
|
|
68
|
-
//color: $gray-light;
|
|
69
|
-
|
|
70
|
-
&.completed {
|
|
71
|
-
//color: $brand-primary;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
li.active > a {
|
|
76
|
-
//box-shadow: $drop-shadow-darker;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
li > a {
|
|
80
|
-
.glyphicon {
|
|
81
|
-
margin: 0 10px 0 0;
|
|
82
|
-
font-size: 14px;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
li > strong {
|
|
87
|
-
display: block;
|
|
88
|
-
padding: 9px 20px;
|
|
89
|
-
|
|
90
|
-
.glyphicon {
|
|
91
|
-
margin: 0 10px 0 0;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
24
|
+
.itf-wizard-sidebar {
|
|
25
|
+
}
|
|
96
26
|
</style>
|
|
97
27
|
<script>
|
|
98
28
|
import { Vue, Component, Prop } from 'vue-property-decorator';
|
|
29
|
+
import itfIcon from '../icon/Icon';
|
|
99
30
|
|
|
100
31
|
export default @Component({
|
|
101
32
|
name: 'itfWizardSidebar',
|
|
102
|
-
components: {
|
|
33
|
+
components: {
|
|
34
|
+
itfIcon
|
|
35
|
+
},
|
|
103
36
|
})
|
|
104
37
|
class itfWizardSidebar extends Vue {
|
|
105
38
|
@Prop(Array) steps;
|
|
@@ -108,19 +108,19 @@ class itfWizard extends Vue {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
return createElement('div', { staticClass: 'itf-wizard row gx-0' }, [
|
|
111
|
-
isSidebarNeeded ? createElement('div', { staticClass: 'col-md-
|
|
111
|
+
isSidebarNeeded ? createElement('div', { staticClass: 'col-md-3 d-none d-md-flex' }, [
|
|
112
112
|
createSidebar({
|
|
113
113
|
value: (this.value || {}).completed || [],
|
|
114
114
|
steps: this.stepsNodes,
|
|
115
115
|
selectedId: this.currentSidebarId,
|
|
116
116
|
}),
|
|
117
117
|
]) : null,
|
|
118
|
-
createElement('div', { staticClass: isSidebarNeeded ? 'col-md-
|
|
118
|
+
createElement('div', { staticClass: isSidebarNeeded ? 'col-md-9 itf-wizard-step' : 'col-xs-12 itf-wizard-step' }, [node])
|
|
119
119
|
]);
|
|
120
120
|
|
|
121
121
|
function createSidebar(props) {
|
|
122
122
|
return createElement('itf-wizard-sidebar', {
|
|
123
|
-
staticClass: '',
|
|
123
|
+
staticClass: 'itf-wizard-sidebar w-100',
|
|
124
124
|
props,
|
|
125
125
|
});
|
|
126
126
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// modified copy of https://github.com/vuejs/vue-loader/blob/master/lib/runtime/componentNormalizer.js
|
|
2
|
+
// contains code to inject styles from options.injectStyles
|
|
3
|
+
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
/* globals __VUE_SSR_CONTEXT__ */
|
|
6
|
+
|
|
7
|
+
// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
|
|
8
|
+
// This module is a runtime utility for cleaner component module output and will
|
|
9
|
+
// be included in the final webpack user bundle.
|
|
10
|
+
|
|
11
|
+
export default function normalizeComponent (
|
|
12
|
+
scriptExports,
|
|
13
|
+
render,
|
|
14
|
+
staticRenderFns,
|
|
15
|
+
functionalTemplate,
|
|
16
|
+
injectStyles,
|
|
17
|
+
scopeId,
|
|
18
|
+
moduleIdentifier, /* server only */
|
|
19
|
+
shadowMode /* vue-cli only */
|
|
20
|
+
) {
|
|
21
|
+
// Vue.extend constructor export interop
|
|
22
|
+
var options = typeof scriptExports === 'function'
|
|
23
|
+
? scriptExports.options
|
|
24
|
+
: scriptExports
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// render functions
|
|
28
|
+
if (render) {
|
|
29
|
+
options.render = render
|
|
30
|
+
options.staticRenderFns = staticRenderFns
|
|
31
|
+
options._compiled = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// functional template
|
|
35
|
+
if (functionalTemplate) {
|
|
36
|
+
options.functional = true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// scopedId
|
|
40
|
+
if (scopeId) {
|
|
41
|
+
options._scopeId = 'data-v-' + scopeId
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var hook
|
|
45
|
+
if (moduleIdentifier) { // server build
|
|
46
|
+
hook = function (context) {
|
|
47
|
+
// 2.3 injection
|
|
48
|
+
context =
|
|
49
|
+
context || // cached call
|
|
50
|
+
(this.$vnode && this.$vnode.ssrContext) || // stateful
|
|
51
|
+
(this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
|
|
52
|
+
// 2.2 with runInNewContext: true
|
|
53
|
+
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
|
|
54
|
+
context = __VUE_SSR_CONTEXT__
|
|
55
|
+
}
|
|
56
|
+
// modification start
|
|
57
|
+
if (Array.isArray(options.injectStyles)) {
|
|
58
|
+
options.injectStyles.forEach((style) => {
|
|
59
|
+
if (style.__inject__) { // eslint-disable-line no-underscore-dangle
|
|
60
|
+
style.__inject__(context); // eslint-disable-line no-underscore-dangle
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// modification end
|
|
65
|
+
|
|
66
|
+
// inject component styles
|
|
67
|
+
if (injectStyles) {
|
|
68
|
+
injectStyles.call(this, context)
|
|
69
|
+
}
|
|
70
|
+
// register component module identifier for async chunk inferrence
|
|
71
|
+
if (context && context._registeredComponents) {
|
|
72
|
+
context._registeredComponents.add(moduleIdentifier)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// used by ssr in case component is cached and beforeCreate
|
|
76
|
+
// never gets called
|
|
77
|
+
options._ssrRegister = hook
|
|
78
|
+
} else if (injectStyles) {
|
|
79
|
+
hook = shadowMode
|
|
80
|
+
? function () {
|
|
81
|
+
injectStyles.call(
|
|
82
|
+
this,
|
|
83
|
+
(options.functional ? this.parent : this).$root.$options.shadowRoot
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
: injectStyles
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (hook) {
|
|
90
|
+
if (options.functional) {
|
|
91
|
+
// for template-only hot-reload because in that case the render fn doesn't
|
|
92
|
+
// go through the normalizer
|
|
93
|
+
options._injectStyles = hook
|
|
94
|
+
// register for functional component in vue file
|
|
95
|
+
var originalRender = options.render
|
|
96
|
+
options.render = function renderWithStyleInjection (h, context) {
|
|
97
|
+
hook.call(context)
|
|
98
|
+
return originalRender(h, context)
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// inject component registration as beforeCreate hook
|
|
102
|
+
var existing = options.beforeCreate
|
|
103
|
+
options.beforeCreate = existing
|
|
104
|
+
? [].concat(existing, hook)
|
|
105
|
+
: [hook]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
exports: scriptExports,
|
|
111
|
+
options: options
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import webpack from 'webpack';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export default function extend(config) {
|
|
5
|
+
config.plugins.push(new webpack.NormalModuleReplacementPlugin(
|
|
6
|
+
/vue-loader\/lib\/runtime\/componentNormalizer.js/,
|
|
7
|
+
path.join(__dirname, 'componentNormalizer.js'),
|
|
8
|
+
));
|
|
9
|
+
};
|