its_ui_vite 0.0.1

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.
@@ -0,0 +1,263 @@
1
+ <template>
2
+ <div :style="`--transition: ${transition}ms`" :class="[classes.root, variant]">
3
+ <CInput ref="input" :placeholder="activePlaceholder" v-model.trim="findValue" :class="classes.input">
4
+ <template #customIcon>
5
+ <CIcons class="c-select__inp_icon" :iconId="isMultiple ? 'arrow' : 'lens'" />
6
+ </template>
7
+ </CInput>
8
+
9
+ <CScroll :scrollY="scrollY" :class="['c-select__list', {open: isOpen}]">
10
+ <button
11
+ :class="classes.optionBtn"
12
+ v-for="item in foundOptions"
13
+ :key="item.id"
14
+ @click="debounceEvent(item, $event)"
15
+ >
16
+ <component
17
+ :class="classes.option"
18
+ :is="isMultiple ? 'CCheckbox' : 'div'"
19
+ v-bind.props="{size: 'sm'}"
20
+ >
21
+ {{ item.text }}
22
+ </component>
23
+ </button>
24
+ <div v-if="foundOptions.length < 1" :class="[classes.option, 'not-found']">
25
+ ничего не найдено
26
+ </div>
27
+ </CScroll>
28
+ </div>
29
+ </template>
30
+
31
+ <script>
32
+ import CInput from './CInput.vue'
33
+ import CCheckbox from './CCheckbox.vue'
34
+ import CIcons from './CIcons/index.vue'
35
+ import CScroll from './CScroll.vue';
36
+
37
+ import { getPropValidator, fixDblEvent } from '../assets/js/helpers';
38
+
39
+ export default {
40
+ data() {
41
+ return {
42
+ transition: 200,
43
+ isMultiple: this.variant === 'multiple',
44
+ scrollY: 0,
45
+ activeOptions: new Set(),
46
+ findValue: '',
47
+ activePlaceholder: this.placeholder,
48
+
49
+ debounceEvent: () => {},
50
+
51
+ isOpen: false,
52
+ classes: {
53
+ root: 'c-select',
54
+ input: 'c-select__inp',
55
+ option: 'c-select__list_item',
56
+ optionBtn: 'c-select__list_btn',
57
+ },
58
+ }
59
+ },
60
+
61
+ props: {
62
+ options: {
63
+ type: Array,
64
+
65
+ default: [],
66
+ },
67
+
68
+ variant: {
69
+ type: String,
70
+
71
+ default: 'default',
72
+ validator: getPropValidator('CSelect', 'variant', ['default', 'multiple']),
73
+ },
74
+
75
+ placeholder: {
76
+ type: String,
77
+
78
+ default: 'выберете вариант',
79
+ }
80
+ },
81
+
82
+ methods: {
83
+ handleOption(option, evt) {
84
+ const input = evt.target.closest(`.${this.classes.optionBtn}`).querySelector('input');
85
+ const isAdd = !this.isMultiple || input?.checked
86
+
87
+ if (!this.isMultiple) this.activeOptions.clear()
88
+
89
+ this.activeOptions[isAdd ? 'add' : 'delete'](option)
90
+
91
+ this.setActivePlaceholder()
92
+ this.$emit('change', [...this.activeOptions])
93
+ },
94
+
95
+ setActivePlaceholder() {
96
+ this.findValue = ''
97
+
98
+ const placeholderText = [...this.activeOptions].map(({text}) => text).join('')
99
+ const newPlaceholder = this.activeOptions.size > 1 ? 'несколько' : placeholderText
100
+
101
+ console.log([...this.activeOptions], 'placeholderText');
102
+
103
+ this.activePlaceholder = newPlaceholder || this.placeholder
104
+ },
105
+ },
106
+
107
+ mounted() {
108
+ this.debounceEvent = fixDblEvent(this.handleOption)
109
+ console.log(this.debounceEvent);
110
+
111
+ document.body.addEventListener('click', (evt) => {
112
+ const input = evt.target.closest(`.${this.classes.input}`)
113
+
114
+ if (input === this.$refs.input?.$el) return this.isOpen = true
115
+
116
+ this.isOpen = false
117
+
118
+ setTimeout(() => {
119
+ this.findValue = ''
120
+ }, this.transition);
121
+ })
122
+ },
123
+
124
+ computed: {
125
+ foundOptions() {
126
+ const reg = new RegExp(this.findValue.replace(/\W/g, '\\$&'), 'i')
127
+ this.scrollY = Math.random();
128
+
129
+ return this.options.filter(({text}) => reg.test(text))
130
+ },
131
+ },
132
+
133
+ components: {
134
+ CInput,
135
+ CCheckbox,
136
+ CIcons,
137
+ CScroll,
138
+ }
139
+ }
140
+ </script>
141
+
142
+ <style lang="scss">
143
+ .c-select {
144
+ position: relative;
145
+
146
+ // prop.variant
147
+ &.default {
148
+ .c-select__inp .c-input {
149
+ padding-left: 50px;
150
+ }
151
+
152
+ .c-input__custom-icon {
153
+ left: 15px;
154
+ right: auto;
155
+ }
156
+ }
157
+
158
+ &.multiple {
159
+ .c-input:focus {
160
+ &~ .c-input__custom-icon svg {
161
+ transform: rotate(0deg);
162
+ }
163
+ }
164
+
165
+ .c-input__custom-icon svg {
166
+ transform: rotate(180deg);
167
+ }
168
+ }
169
+ // ./prop.variant
170
+
171
+ &__inp {
172
+ .c-input__custom-icon {
173
+ opacity: 1;
174
+ }
175
+
176
+ .c-input:focus {
177
+ &~ .c-input__custom-icon svg {
178
+ stroke: var(--green-light);
179
+ }
180
+ }
181
+ }
182
+
183
+ &__list {
184
+ position: absolute;
185
+ top: 100%;
186
+ left: 0;
187
+ transform: translate(0px, 0px);
188
+
189
+ width: 100%;
190
+ max-height: 240px;
191
+
192
+ display: flex;
193
+ flex-direction: column;
194
+
195
+ border-radius: 8px;
196
+ border: 1px solid var(--green-medium);
197
+
198
+ transition: var(--transition);
199
+
200
+ opacity: 0;
201
+ pointer-events: none;
202
+
203
+ &.open {
204
+ transform: translate(0, 12px);
205
+
206
+ opacity: 1;
207
+ pointer-events: all;
208
+ }
209
+
210
+ &_item {
211
+ width: 100%;
212
+ height: 100%;
213
+
214
+ padding: 12px 15px;
215
+
216
+ flex-shrink: 0;
217
+ display: flex;
218
+ align-items: center;
219
+
220
+ box-sizing: border-box;
221
+
222
+ color: var(--white);
223
+
224
+ transition: var(--transition);
225
+
226
+ &.not-found {
227
+ background: transparent;
228
+
229
+ cursor: default;
230
+
231
+ justify-content: center;
232
+
233
+ &:hover {
234
+ background: transparent;
235
+ }
236
+ }
237
+
238
+ .c-checkbox__text {
239
+ color: inherit;
240
+ }
241
+ }
242
+
243
+ &_btn {
244
+ height: 48px;
245
+ width: 100%;
246
+
247
+ flex-shrink: 0;
248
+ display: flex;
249
+ align-items: center;
250
+
251
+ border: none;
252
+
253
+ font-size: 16px;
254
+
255
+ background: transparent;
256
+
257
+ &:hover {
258
+ background: var(--green-dark);
259
+ }
260
+ }
261
+ }
262
+ }
263
+ </style>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div class="c-tabs">
3
+ <button :class="['c-tabs__item', {'c-tabs__item-active': item === activeTab}]" v-for="item in tabs" :key="item.id" @click="handleTab(item)">
4
+ <div>
5
+ {{ item.text }}
6
+ </div>
7
+ </button>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ export default {
13
+ data() {
14
+ return {
15
+ activeTab: this.tabs.find(({id}) => id === this.activeId)
16
+ }
17
+ },
18
+ props: {
19
+ tabs: {
20
+ type: Array,
21
+
22
+ required: true,
23
+ default: [],
24
+ },
25
+
26
+ activeId: {
27
+ required: true,
28
+ }
29
+ },
30
+
31
+ computed: {
32
+ activeTab() {
33
+ return this.tabs.find(({id}) => id === (this.activeTab.id || this.activeId))
34
+ }
35
+ },
36
+
37
+ methods: {
38
+ handleTab(activeTab) {
39
+ console.log('handleTab');
40
+ if (this.activeTab === activeTab) return;
41
+
42
+ this.activeTab = activeTab
43
+ this.$emit('tabChange', activeTab)
44
+ }
45
+ },
46
+ }
47
+ </script>
48
+
49
+ <style lang="scss">
50
+ .c-tabs {
51
+ display: flex;
52
+
53
+ max-width: 100%;
54
+
55
+ gap: 40px;
56
+
57
+ &__item {
58
+ display: flex;
59
+ flex-direction: column;
60
+
61
+ font-size: 16px;
62
+
63
+ border: none;
64
+
65
+ color: var(--white);
66
+ background: transparent;
67
+
68
+ cursor: pointer;
69
+
70
+ &::after {
71
+ content: '';
72
+ display: flex;
73
+
74
+ height: 5px;
75
+ width: 100%;
76
+ margin-top: 12px;
77
+
78
+ border-radius: 5px;
79
+
80
+ background: var(--green-light);
81
+ opacity: 0;
82
+ }
83
+
84
+ &-active {
85
+ color: var(--green-light);
86
+
87
+ &::after {
88
+ opacity: 1;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ </style>
@@ -0,0 +1,212 @@
1
+ <template>
2
+ <div :class="['c-tooltip', position, {interactive: interactive}, {open: isOpen.click || isOpen.hover}]">
3
+ <div ref="icon" :class="classes.icon">
4
+ <slot name="icon">
5
+ <CIcons iconId="question" />
6
+ </slot>
7
+ </div>
8
+ <div :class="classes.contentWrap">
9
+ <div :class="classes.content">
10
+ <slot name="content"></slot>
11
+ </div>
12
+ <div class="c-tooltip__arrow"></div>
13
+ </div>
14
+ </div>
15
+ </template>
16
+
17
+ <script>
18
+ import { getPropValidator } from '../assets/js/helpers';
19
+ import CIcons from './CIcons/index.vue'
20
+
21
+ export default {
22
+ data() {
23
+ return {
24
+ isOpen: {
25
+ click: false,
26
+ hover: false,
27
+ },
28
+
29
+ classes: {
30
+ icon: 'c-tooltip__icon',
31
+ content: 'c-tooltip__content',
32
+ contentWrap: 'c-tooltip__content_wrap'
33
+ },
34
+ }
35
+ },
36
+
37
+ props: {
38
+ position: {
39
+ type: String,
40
+
41
+ default: 'top',
42
+ validator: getPropValidator('CTooltip', 'position', ['top', 'bottom']),
43
+ },
44
+
45
+ interactive: {
46
+ type: Boolean,
47
+
48
+ default: true,
49
+ },
50
+ },
51
+
52
+ methods: {
53
+ /**
54
+ * @param {MouseEvent} evt
55
+ */
56
+ handleMouseover(evt){
57
+ const tooltipTarget = evt.target.closest(`.${this.classes.icon}`)
58
+
59
+ if (tooltipTarget !== this.$refs.icon) return
60
+
61
+ this.isOpen.hover = true
62
+ evt.stopPropagation()
63
+ },
64
+
65
+ /**
66
+ * @param {MouseEvent} evt
67
+ */
68
+ handleMouseout(evt) {
69
+ const tooltipTarget = evt.target.closest(`.${this.classes.icon}`)
70
+
71
+ if (tooltipTarget === this.$refs.icon) this.isOpen.hover = false
72
+ },
73
+
74
+ /**
75
+ * @param {MouseEvent} evt
76
+ */
77
+ handleClick(evt) {
78
+ const tooltipTarget = evt.target.closest(`.${this.classes.icon}`)
79
+
80
+ if (tooltipTarget === this.$refs.icon) return this.isOpen.click = true
81
+ this.isOpen.click = false
82
+ },
83
+
84
+ addListener() {
85
+ document.body.addEventListener('mouseover', this.handleMouseover)
86
+ document.body.addEventListener('mouseout', this.handleMouseout)
87
+ document.body.addEventListener('click', this.handleClick)
88
+ },
89
+
90
+ removeListener() {
91
+ document.body.removeEventListener('mouseover', this.handleMouseover)
92
+ document.body.removeEventListener('mouseout', this.handleMouseout)
93
+ document.body.removeEventListener('click', this.handleClick)
94
+ },
95
+ },
96
+
97
+ mounted() {
98
+ this.addListener()
99
+ },
100
+
101
+ beforeDestroy() {
102
+ this.removeListener()
103
+ },
104
+
105
+ components: {
106
+ CIcons,
107
+ },
108
+ }
109
+
110
+ </script>
111
+
112
+ <style lang="scss">
113
+ .c-tooltip {
114
+ --arrow-size: 12px;
115
+
116
+ position: relative;
117
+
118
+ font-size: 12px;
119
+
120
+ // props.position
121
+ &.top {
122
+ .c-tooltip__content_wrap{
123
+ --translate-y: -10px;
124
+ --arrow-translate-y: -6px;
125
+
126
+ bottom: 100%;
127
+ }
128
+
129
+ .c-tooltip__arrow {
130
+ --rotate: 45deg;
131
+
132
+ top: 100%;
133
+ }
134
+ }
135
+
136
+ &.bottom {
137
+ .c-tooltip__content_wrap {
138
+ --translate-y: 10px;
139
+ --arrow-translate-y: 6px;
140
+
141
+ top: 100%;
142
+ }
143
+
144
+ .c-tooltip__arrow {
145
+ --rotate: -135deg;
146
+
147
+ bottom: 100%;
148
+ }
149
+ }
150
+ // ./props.position
151
+
152
+ &.interactive {
153
+ .c-tooltip__content_wrap {
154
+ pointer-events: all;
155
+ }
156
+ }
157
+
158
+ &:not(.open) {
159
+ .c-tooltip__content_wrap {
160
+ --translate-y: 0px;
161
+
162
+ opacity: 0;
163
+ pointer-events: none;
164
+ }
165
+ }
166
+
167
+ &__icon {
168
+ cursor: pointer;
169
+ }
170
+
171
+ &__content {
172
+ position: relative;
173
+ z-index: 10;
174
+
175
+ padding: 7px 10px;
176
+
177
+ border-radius: 6px;
178
+
179
+ background: var(--green-bg);
180
+
181
+ &_wrap {
182
+ position: absolute;
183
+ left: 50%;
184
+ transform: translate(-50%, var(--translate-y));
185
+
186
+ border: 1px solid var(--green-medium);
187
+ border-radius: 6px;
188
+ box-shadow: var(--shadow);
189
+
190
+ color: var(--white);
191
+
192
+ transition: var(--transition);
193
+ pointer-events: none;
194
+ }
195
+ }
196
+
197
+ &__arrow {
198
+ position: absolute;
199
+ left: 50%;
200
+ transform: translate(-50%, var(--arrow-translate-y)) rotate(var(--rotate));
201
+
202
+ width: var(--arrow-size);
203
+ height: var(--arrow-size);
204
+
205
+ box-sizing: border-box;
206
+ border: 1px solid var(--green-medium);
207
+ border-width: 0px 1px 1px 0px;
208
+
209
+ background: var(--green-bg);
210
+ }
211
+ }
212
+ </style>
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { createApp } from 'vue'
2
+
3
+ import './assets/scss/main.scss'
4
+
5
+ import Index from './pages/index.vue'
6
+
7
+ const app = createApp(Index)
8
+ app.mount('#app')
@@ -0,0 +1,21 @@
1
+ import CButton from './src/components/CButton.vue';
2
+ import CTabs from './src/components/CTabs.vue';
3
+ import CInput from './src/components/CInput.vue';
4
+ import CCheckbox from './src/components/CCheckbox.vue';
5
+ import CSelect from './src/components/CSelect.vue';
6
+ import CTooltip from './src/components/CTooltip.vue';
7
+ import CPopup from './src/components/CPopup.vue';
8
+ import CAlert from './src/components/CAlert.vue';
9
+
10
+ import './assets/scss/main.scss'
11
+
12
+ export {
13
+ CButton,
14
+ CTabs,
15
+ CInput,
16
+ CCheckbox,
17
+ CSelect,
18
+ CTooltip,
19
+ CPopup,
20
+ CAlert,
21
+ }