its_ui_vite 1.0.8 → 1.0.10
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/README.md +16 -0
- package/package.json +2 -1
- package/src/assets/icon/icons-manifest.ts +3 -0
- package/src/assets/icon/svg/calendar-month-outline.svg +3 -0
- package/src/components/CDatepicker.vue +1006 -0
- package/src/components/CSelect.vue +13 -4
- package/src/libIndex.js +2 -0
- package/src/pages/index.vue +36 -0
package/README.md
CHANGED
|
@@ -130,6 +130,22 @@ slots: ['без имени' <!-- есть дефольное значение (p
|
|
|
130
130
|
slots: ['customIcon' <!-- есть дефольное значение -->]
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
* CDatepicker
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
{
|
|
137
|
+
date?: string,
|
|
138
|
+
locale?: 'rus' | 'usa' | 'tur' | 'spa',
|
|
139
|
+
max?: string,
|
|
140
|
+
min?: string,
|
|
141
|
+
width?: string,
|
|
142
|
+
isOpen?: boolean,
|
|
143
|
+
modelValue?: any,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
slots: ['customIcon' <!-- есть дефольное значение -->]
|
|
147
|
+
```
|
|
148
|
+
|
|
133
149
|
* CTooltip
|
|
134
150
|
|
|
135
151
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "its_ui_vite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"main": "./src/libIndex.js",
|
|
5
5
|
"module": "./src/libIndex.js",
|
|
6
6
|
"files": [
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"compression": "^1.7.4",
|
|
24
24
|
"dotenv": "^16.3.1",
|
|
25
25
|
"express": "4.18.2",
|
|
26
|
+
"luxon": "^3.7.2",
|
|
26
27
|
"vue": "^3.3.11",
|
|
27
28
|
"vue3-perfect-scrollbar": "^2.0.0",
|
|
28
29
|
"yargs": "^17.7.2"
|
|
@@ -75,6 +75,8 @@ export type TIcon = {
|
|
|
75
75
|
'bx-volume-mute'?: boolean,
|
|
76
76
|
/**  */
|
|
77
77
|
'bx-wind'?: boolean,
|
|
78
|
+
/**  */
|
|
79
|
+
'calendar-month-outline'?: boolean,
|
|
78
80
|
}
|
|
79
81
|
export const iconContent = {
|
|
80
82
|
'Bar-chart': `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 20V10" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 20V4" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 20V14" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
@@ -115,4 +117,5 @@ export const iconContent = {
|
|
|
115
117
|
'bx-volume-full': `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16 21C19.527 19.453 21.999 16.091 21.999 12C21.999 7.909 19.527 4.547 16 3V5C18.387 6.386 19.999 9.047 19.999 12C19.999 14.953 18.387 17.614 16 19V21Z" fill="white"/><path d="M16 6.99997V17C17.225 15.9 18 13.771 18 12C18 10.229 17.225 8.09997 16 6.99997ZM4 17H6.697L12.445 20.832C12.5958 20.9321 12.7708 20.9896 12.9516 20.9984C13.1324 21.0072 13.3122 20.967 13.472 20.882C13.6316 20.7965 13.765 20.6693 13.858 20.514C13.951 20.3587 14.0001 20.181 14 20V3.99997C13.9999 3.81909 13.9508 3.64162 13.8578 3.48646C13.7648 3.3313 13.6315 3.20427 13.472 3.11889C13.3125 3.03351 13.1329 2.99299 12.9522 3.00163C12.7715 3.01027 12.5966 3.06776 12.446 3.16797L6.697 6.99997H4C2.897 6.99997 2 7.89697 2 8.99997V15C2 16.103 2.897 17 4 17ZM4 8.99997H7C7.033 8.99997 7.061 8.98397 7.093 8.98097C7.22601 8.96741 7.35509 8.928 7.473 8.86497C7.499 8.84997 7.53 8.84797 7.555 8.83197L12 5.86797V18.132L7.555 15.168C7.53 15.151 7.499 15.148 7.473 15.135C7.35491 15.0707 7.22491 15.0312 7.091 15.019C7.059 15.016 7.032 15 7 15H4V8.99997Z" fill="white"/></svg>`,
|
|
116
118
|
'bx-volume-mute': `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21.707 20.293L19.684 18.27C21.1845 16.5263 22.0063 14.3003 21.999 12C21.999 7.90897 19.527 4.54697 16 2.99997V4.99997C18.387 6.38597 19.999 9.04697 19.999 12C19.9946 13.7765 19.4072 15.5025 18.327 16.913L17.042 15.628C17.644 14.536 18 13.19 18 12C18 10.229 17.225 8.09997 16 6.99997V14.586L14 12.586V3.99997C13.9999 3.81908 13.9508 3.64161 13.8578 3.48645C13.7648 3.3313 13.6315 3.20426 13.472 3.11889C13.3125 3.03351 13.1329 2.99298 12.9522 3.00163C12.7715 3.01027 12.5966 3.06776 12.446 3.16797L7.727 6.31297L3.707 2.29297L2.293 3.70697L20.293 21.707L21.707 20.293ZM12 5.86797V10.586L9.169 7.75497L12 5.86797ZM4 17H6.697L12.445 20.832C12.5958 20.9321 12.7708 20.9896 12.9516 20.9984C13.1324 21.0072 13.3122 20.967 13.472 20.882C13.6316 20.7965 13.765 20.6693 13.858 20.514C13.951 20.3587 14.0001 20.181 14 20V18.121L12 16.121V18.132L7.555 15.168C7.53 15.151 7.499 15.148 7.473 15.135C7.35491 15.0707 7.22491 15.0312 7.091 15.019C7.059 15.016 7.032 15 7 15H4V8.99997H4.879L3.102 7.22297C2.77189 7.38821 2.4941 7.6418 2.29954 7.95553C2.10499 8.26926 2.00129 8.63081 2 8.99997V15C2 16.103 2.897 17 4 17Z" fill="white"/></svg>`,
|
|
117
119
|
'bx-wind': `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 5.5C13 3.57 11.43 2 9.5 2C7.466 2 6.25 3.525 6.25 5H8.25C8.25 4.585 8.638 4 9.5 4C10.327 4 11 4.673 11 5.5C11 6.327 10.327 7 9.5 7H2V9H9.5C11.43 9 13 7.43 13 5.5ZM15.5 15H8V17H15.5C16.327 17 17 17.673 17 18.5C17 19.327 16.327 20 15.5 20C14.638 20 14.25 19.415 14.25 19H12.25C12.25 20.475 13.466 22 15.5 22C17.43 22 19 20.43 19 18.5C19 16.57 17.43 15 15.5 15Z" fill="white"/><path d="M18 5C15.794 5 14 6.794 14 9H16C16 7.897 16.897 7 18 7C19.103 7 20 7.897 20 9C20 10.103 19.103 11 18 11H2V13H18C20.206 13 22 11.206 22 9C22 6.794 20.206 5 18 5ZM2 15H6V17H2V15Z" fill="white"/></svg>`,
|
|
120
|
+
'calendar-month-outline': `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 11H9V13H7V11ZM21 5V19C21 20.11 20.11 21 19 21H5C3.89 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H6V1H8V3H16V1H18V3H19C20.11 3 21 3.9 21 5ZM5 7H19V5H5V7ZM19 19V9H5V19H19ZM15 13V11H17V13H15ZM11 13V11H13V13H11ZM7 15H9V17H7V15ZM15 17V15H17V17H15ZM11 17V15H13V17H11Z" fill="white"/></svg>`,
|
|
118
121
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M7 11H9V13H7V11ZM21 5V19C21 20.11 20.11 21 19 21H5C3.89 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H6V1H8V3H16V1H18V3H19C20.11 3 21 3.9 21 5ZM5 7H19V5H5V7ZM19 19V9H5V19H19ZM15 13V11H17V13H15ZM11 13V11H13V13H11ZM7 15H9V17H7V15ZM15 17V15H17V17H15ZM11 17V15H13V17H11Z" fill="white"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,1006 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="root"
|
|
4
|
+
:data-c-datepicker-id="datePickerId"
|
|
5
|
+
class="c-datepicker"
|
|
6
|
+
:style="`--transition: ${transition}ms; --width: ${width}; --picker-content-indent-y: ${pickerContentIndentY}px`"
|
|
7
|
+
>
|
|
8
|
+
<div
|
|
9
|
+
ref="inpWrap"
|
|
10
|
+
:class="['c-datepicker__inp_wrap', { open: isOpenPicker }]"
|
|
11
|
+
@click="setIsOpen(!isOpenPicker)"
|
|
12
|
+
>
|
|
13
|
+
<CInput
|
|
14
|
+
class="c-datepicker__inp"
|
|
15
|
+
size="sm"
|
|
16
|
+
:width="width"
|
|
17
|
+
:placeholder="activeDate.toLocaleString(DateTime.DATE_FULL)"
|
|
18
|
+
:disabled="true"
|
|
19
|
+
>
|
|
20
|
+
<template #customIcon>
|
|
21
|
+
<CIcon :name="{'calendar-month-outline': true}" :size="24" />
|
|
22
|
+
</template>
|
|
23
|
+
</CInput>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
<div
|
|
28
|
+
ref="time"
|
|
29
|
+
:class="['c-datepicker__hours_wrap', { open: isOpenTime }]"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
class="c-datepicker__hours_inps"
|
|
33
|
+
@click="isOpenTime = true"
|
|
34
|
+
>
|
|
35
|
+
<input
|
|
36
|
+
type="text"
|
|
37
|
+
name="hours"
|
|
38
|
+
v-model="modelHour"
|
|
39
|
+
@input="setTime('hour', ($event.target as HTMLInputElement).value)"
|
|
40
|
+
@focus="isOpenTime = true, isOpenPicker = false"
|
|
41
|
+
@blur="dispatchEmit"
|
|
42
|
+
/>
|
|
43
|
+
<span>:</span>
|
|
44
|
+
<input
|
|
45
|
+
type="text"
|
|
46
|
+
name="minute"
|
|
47
|
+
v-model="modelMinute"
|
|
48
|
+
@input="setTime('minute', ($event.target as HTMLInputElement).value)"
|
|
49
|
+
@focus="isOpenTime = true"
|
|
50
|
+
@blur="isOpenTime = false"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
<Teleport to="body">
|
|
54
|
+
<div
|
|
55
|
+
class="c-datepicker__hours_list-wrap"
|
|
56
|
+
ref="timeContent"
|
|
57
|
+
:data-c-datepicker-id="datePickerId"
|
|
58
|
+
:style="timeStyle"
|
|
59
|
+
>
|
|
60
|
+
<div
|
|
61
|
+
:style="`--transition: ${transition}ms; --picker-time-indent-y: ${pickerContentIndentY}px`"
|
|
62
|
+
:class="['c-datepicker__hours_list', pickerContentPosition, {open: isOpenTime}]"
|
|
63
|
+
>
|
|
64
|
+
<div class="c-datepicker__hours_list-content">
|
|
65
|
+
<CScroll class="c-datepicker__hours_list-scroll">
|
|
66
|
+
<button
|
|
67
|
+
v-for="item in hoursOptions"
|
|
68
|
+
:key="item.value"
|
|
69
|
+
:class="['c-datepicker__hours_btn', {active: item.text === modelHour}]"
|
|
70
|
+
@click="setTime('hour', item.text)"
|
|
71
|
+
>
|
|
72
|
+
{{ item.text }}
|
|
73
|
+
</button>
|
|
74
|
+
</CScroll>
|
|
75
|
+
<div class="c-datepicker__hours_list-line"></div>
|
|
76
|
+
<CScroll class="c-datepicker__hours_list-scroll">
|
|
77
|
+
<button
|
|
78
|
+
v-for="item in minuteOptions"
|
|
79
|
+
:key="item.value"
|
|
80
|
+
:class="['c-datepicker__hours_btn', {active: item.text === modelMinute}]"
|
|
81
|
+
@click="setTime('minute', item.text)"
|
|
82
|
+
>
|
|
83
|
+
{{ item.text }}
|
|
84
|
+
</button>
|
|
85
|
+
</CScroll>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</Teleport>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<Teleport to="body">
|
|
93
|
+
<div
|
|
94
|
+
:style="pickerContentStyle"
|
|
95
|
+
:class="['c-datepicker__content_wrap', { open: isOpenPicker }]"
|
|
96
|
+
>
|
|
97
|
+
<div
|
|
98
|
+
ref="pickerContent"
|
|
99
|
+
:data-c-datepicker-id="datePickerId"
|
|
100
|
+
:class="['c-datepicker__content', pickerContentPosition, {open: isOpenPicker}]"
|
|
101
|
+
:style="`--transition: ${transition}ms; --width: ${width}; --picker-content-indent-y: ${pickerContentIndentY}px`"
|
|
102
|
+
>
|
|
103
|
+
<div class="c-datepicker__selects">
|
|
104
|
+
<CSelect
|
|
105
|
+
class="c-datepicker__select"
|
|
106
|
+
ref="monthSelect"
|
|
107
|
+
size="sm"
|
|
108
|
+
:options="monthsOption"
|
|
109
|
+
:transform-val="true"
|
|
110
|
+
:placeholder="monthsOption[activeMonth - 1].text"
|
|
111
|
+
:locale="locale"
|
|
112
|
+
:iconPosition="['right']"
|
|
113
|
+
width="100px"
|
|
114
|
+
:model-value="modelYear"
|
|
115
|
+
@change_cselect="setSelect('month', $event[0])"
|
|
116
|
+
/>
|
|
117
|
+
<CSelect
|
|
118
|
+
class="c-datepicker__select"
|
|
119
|
+
ref="yearSelect"
|
|
120
|
+
size="sm"
|
|
121
|
+
:options="yearOption"
|
|
122
|
+
:transform-val="true"
|
|
123
|
+
:placeholder="String(activeYear)"
|
|
124
|
+
:locale="locale"
|
|
125
|
+
:iconPosition="['right']"
|
|
126
|
+
width="70px"
|
|
127
|
+
:model-value="modelYear"
|
|
128
|
+
@change_cselect="setSelect('year', $event[0])"
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="c-datepicker__table">
|
|
132
|
+
<div v-for="day in text.daysOfWeek" :key="day" class="c-datepicker__table_item c-datepicker__table_name">
|
|
133
|
+
{{ day }}
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<button
|
|
137
|
+
v-for="day in monthDays"
|
|
138
|
+
:key="day.ISO"
|
|
139
|
+
class="c-datepicker__table_item"
|
|
140
|
+
:class="{
|
|
141
|
+
disable: isDisableDay(day.ISO),
|
|
142
|
+
active: isActiveDay(day.ISO),
|
|
143
|
+
}"
|
|
144
|
+
|
|
145
|
+
@click="setActiveDay(day.ISO)"
|
|
146
|
+
>
|
|
147
|
+
<span>{{ day.value }}</span>
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="c-datepicker__action">
|
|
151
|
+
<CButton
|
|
152
|
+
class="c-datepicker__action_btn"
|
|
153
|
+
variant="outlined"
|
|
154
|
+
size="md"
|
|
155
|
+
@click="setIsOpen(false)"
|
|
156
|
+
>
|
|
157
|
+
{{ text.cancel }}
|
|
158
|
+
</CButton>
|
|
159
|
+
<CButton
|
|
160
|
+
class="c-datepicker__action_btn"
|
|
161
|
+
size="md"
|
|
162
|
+
@click="dispatchEmit()"
|
|
163
|
+
>
|
|
164
|
+
{{ text.accept }}
|
|
165
|
+
</CButton>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
</Teleport>
|
|
170
|
+
</div>
|
|
171
|
+
</template>
|
|
172
|
+
|
|
173
|
+
<script setup lang="ts">
|
|
174
|
+
import { DateTime } from 'luxon'
|
|
175
|
+
|
|
176
|
+
import CIcon from './CIcons/CIcon.vue';
|
|
177
|
+
import CSelect from './CSelect.vue';
|
|
178
|
+
import CInput from './CInput.vue';
|
|
179
|
+
import CButton from './CButton.vue';
|
|
180
|
+
import CScroll from './CScroll.vue';
|
|
181
|
+
|
|
182
|
+
import { addTracingElement } from '../assets/js/helpers';
|
|
183
|
+
import { computed, ref, watch, onMounted, onUnmounted, Teleport } from 'vue';
|
|
184
|
+
|
|
185
|
+
type TProps = {
|
|
186
|
+
date?: string,
|
|
187
|
+
locale?: 'rus' | 'usa' | 'tur' | 'spa',
|
|
188
|
+
max?: string,
|
|
189
|
+
min?: string,
|
|
190
|
+
width?: string,
|
|
191
|
+
isOpen?: boolean,
|
|
192
|
+
modelValue?: any,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const props = withDefaults(defineProps<TProps>(), {
|
|
196
|
+
locale: 'rus',
|
|
197
|
+
isOpen: false,
|
|
198
|
+
width: '100%',
|
|
199
|
+
modelValue: () => [],
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const defaultDate = DateTime.now()
|
|
203
|
+
|
|
204
|
+
type TMonthDay = {
|
|
205
|
+
ISO: string
|
|
206
|
+
value: number
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
type TSelectOption = {
|
|
210
|
+
text: string,
|
|
211
|
+
value: number,
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const transition = 200;
|
|
215
|
+
const pickerContentIndentY = 12;
|
|
216
|
+
const datePickerId = Math.random() * 100_000_000
|
|
217
|
+
|
|
218
|
+
let monthDays = ref<TMonthDay[]>([]);
|
|
219
|
+
|
|
220
|
+
let root = ref();
|
|
221
|
+
let inpWrap = ref();
|
|
222
|
+
let pickerContent = ref();
|
|
223
|
+
let monthSelect = ref();
|
|
224
|
+
let yearSelect = ref();
|
|
225
|
+
let time = ref();
|
|
226
|
+
let timeContent = ref();
|
|
227
|
+
|
|
228
|
+
let isOpenTime = ref(false);
|
|
229
|
+
let isOpenPicker = ref(props.isOpen || false);
|
|
230
|
+
let pickerContentPosition = ref<'bottom' | 'top'>('bottom');
|
|
231
|
+
|
|
232
|
+
let oldDateISO = ref<any>(defaultDate.toISO())
|
|
233
|
+
let activeDate = ref<any>(defaultDate);
|
|
234
|
+
let activeMonth = ref<number>(defaultDate.month);
|
|
235
|
+
let activeYear = ref<number>(defaultDate.year);
|
|
236
|
+
|
|
237
|
+
let modelMonth: any = ref([]);
|
|
238
|
+
let modelYear: any = ref([]);
|
|
239
|
+
let modelHour = ref('00');
|
|
240
|
+
let modelMinute = ref('00');
|
|
241
|
+
|
|
242
|
+
let pickerContentStyle = ref({
|
|
243
|
+
left: '0px',
|
|
244
|
+
top: '0px',
|
|
245
|
+
width: '210px',
|
|
246
|
+
height: '38px'
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
let timeStyle = ref({
|
|
250
|
+
left: '0px',
|
|
251
|
+
top: '0px',
|
|
252
|
+
width: '50px',
|
|
253
|
+
height: '34px'
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const TracingElement = addTracingElement(root, handlePicker);
|
|
257
|
+
const TracingTime = addTracingElement(time, handleTime);
|
|
258
|
+
|
|
259
|
+
onMounted(() => {
|
|
260
|
+
if (props.date) {
|
|
261
|
+
if (typeof props.date === 'string') {
|
|
262
|
+
activeDate.value = DateTime.fromISO(props.date)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!activeDate.value?.isValid) {
|
|
266
|
+
activeDate.value = defaultDate
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
oldDateISO.value = activeDate.value;
|
|
271
|
+
|
|
272
|
+
const currentDate = activeDate.value.toISO();
|
|
273
|
+
|
|
274
|
+
activeMonth.value = activeDate.value.month;
|
|
275
|
+
activeYear.value = activeDate.value.year;
|
|
276
|
+
|
|
277
|
+
fillMonthDays(currentDate);
|
|
278
|
+
|
|
279
|
+
modelHour.value = activeDate.value.toFormat('HH');
|
|
280
|
+
modelMinute.value = activeDate.value.toFormat('mm');
|
|
281
|
+
|
|
282
|
+
TracingElement.addListeners();
|
|
283
|
+
TracingTime.addListeners();
|
|
284
|
+
document.body.addEventListener('click', handleClickPicker);
|
|
285
|
+
document.body.addEventListener('click', handleClickTime);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
onUnmounted(() => {
|
|
289
|
+
TracingElement.removeListeners();
|
|
290
|
+
TracingTime.removeListeners();
|
|
291
|
+
document.body.removeEventListener('click', handleClickPicker)
|
|
292
|
+
document.body.removeEventListener('click', handleClickTime);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const emit = defineEmits<{
|
|
296
|
+
(name: 'update:modelValue', value: string),
|
|
297
|
+
(name: 'change_cdatepicker', value: string),
|
|
298
|
+
(name: 'update:isOpen', value: boolean)
|
|
299
|
+
}>();
|
|
300
|
+
|
|
301
|
+
const text = computed(() => {
|
|
302
|
+
const lang = {
|
|
303
|
+
rus: {
|
|
304
|
+
daysOfWeek: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'],
|
|
305
|
+
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
|
|
306
|
+
cancel: 'Отмена',
|
|
307
|
+
accept: 'OK',
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
usa: {
|
|
311
|
+
daysOfWeek: [ 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' ],
|
|
312
|
+
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
313
|
+
cancel: 'Cancel',
|
|
314
|
+
accept: 'OK',
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
tur: {
|
|
318
|
+
daysOfWeek: [ 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' ],
|
|
319
|
+
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
320
|
+
cancel: 'Cancel',
|
|
321
|
+
accept: 'OK',
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
spa: {
|
|
325
|
+
daysOfWeek: [ 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' ],
|
|
326
|
+
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
327
|
+
cancel: 'Cancel',
|
|
328
|
+
accept: 'OK',
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
return lang[props.locale]
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
const monthsOption = computed(() => {
|
|
336
|
+
let options: TSelectOption[] = [];
|
|
337
|
+
|
|
338
|
+
text.value.months.forEach((item, index) => {
|
|
339
|
+
options.push({
|
|
340
|
+
text: item,
|
|
341
|
+
value: index + 1,
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return options;
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const yearOption = computed(() => {
|
|
349
|
+
let options: TSelectOption[] = [];
|
|
350
|
+
|
|
351
|
+
const range = 10;
|
|
352
|
+
const minYear = activeDate.value.year - range;
|
|
353
|
+
const maxYear = activeDate.value.year + range;
|
|
354
|
+
|
|
355
|
+
for(let i = minYear; i < maxYear; i++) {
|
|
356
|
+
options.push({
|
|
357
|
+
text: String(i),
|
|
358
|
+
value: i,
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return options;
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const hoursOptions = computed(() => {
|
|
366
|
+
let options: TSelectOption[] = [];
|
|
367
|
+
|
|
368
|
+
const max = 24;
|
|
369
|
+
|
|
370
|
+
for (let i = 0; i < max; i++) {
|
|
371
|
+
options.push({
|
|
372
|
+
text: getTimeStr(i),
|
|
373
|
+
value: i,
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return options;
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const minuteOptions = computed(() => {
|
|
381
|
+
let options: TSelectOption[] = [];
|
|
382
|
+
|
|
383
|
+
const max = 60;
|
|
384
|
+
|
|
385
|
+
for (let i = 0; i < max; i++) {
|
|
386
|
+
options.push({
|
|
387
|
+
text: getTimeStr(i),
|
|
388
|
+
value: i,
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return options;
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
watch(() => isOpenPicker.value, (newValue) => {
|
|
396
|
+
emit('update:isOpen', newValue);
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
watch(() => activeDate.value, (newValue) => {
|
|
400
|
+
const value = typeof newValue === 'string' ? newValue : newValue.toISO();
|
|
401
|
+
|
|
402
|
+
emit('update:modelValue', value);
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
function handlePicker(positionInfo?: any) {
|
|
406
|
+
pickerContentStyle.value.left = `${positionInfo.position.x}px`;
|
|
407
|
+
pickerContentStyle.value.top = `${positionInfo.position.y}px`;
|
|
408
|
+
pickerContentStyle.value.width = `${positionInfo.position.width}px`;
|
|
409
|
+
pickerContentStyle.value.height = `${positionInfo.position.height}px`;
|
|
410
|
+
setPickerContentPosition();
|
|
411
|
+
|
|
412
|
+
if (positionInfo.isVisible) return;
|
|
413
|
+
|
|
414
|
+
setIsOpen(false);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function handleClickPicker(evt: MouseEvent) {
|
|
418
|
+
const target = (evt.target as HTMLElement);
|
|
419
|
+
const classesArr = [
|
|
420
|
+
'.c-datepicker__inp_wrap',
|
|
421
|
+
'.c-datepicker__content',
|
|
422
|
+
`[data-c-select-id="${monthSelect.value.selectId}"]`,
|
|
423
|
+
`[data-c-select-id="${yearSelect.value.selectId}"]`,
|
|
424
|
+
];
|
|
425
|
+
const classesStr = classesArr.join(',');
|
|
426
|
+
const isTarget: HTMLElement | null = target.closest(classesStr);
|
|
427
|
+
|
|
428
|
+
if (isCurrent(isTarget)) return;
|
|
429
|
+
|
|
430
|
+
setIsOpen(false);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function isCurrent(target: HTMLElement | null) {
|
|
434
|
+
const isMatchMonthSelectId = String(monthSelect.value.selectId) === target?.dataset?.cSelectId;
|
|
435
|
+
const isMatchYearSelectId = String(yearSelect.value.selectId) === target?.dataset?.cSelectId;
|
|
436
|
+
|
|
437
|
+
const isMatchInpWrap = inpWrap.value === target;
|
|
438
|
+
const isMatchPickerContent = pickerContent.value === target;
|
|
439
|
+
|
|
440
|
+
return isMatchMonthSelectId || isMatchYearSelectId || isMatchInpWrap || isMatchPickerContent;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function handleClickTime(evt: MouseEvent) {
|
|
444
|
+
const target = (evt.target as HTMLElement);
|
|
445
|
+
const classesStr = '.c-datepicker__hours_wrap, .c-datepicker__hours_list-wrap';
|
|
446
|
+
const isTimeContent = target.closest(classesStr);
|
|
447
|
+
|
|
448
|
+
const isTarget = isTimeContent === time.value;
|
|
449
|
+
const isContent = isTimeContent === timeContent.value;
|
|
450
|
+
|
|
451
|
+
if (isTarget || isContent) return;
|
|
452
|
+
|
|
453
|
+
isOpenTime.value = false;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function handleTime(positionInfo?: any) {
|
|
457
|
+
timeStyle.value.left = `${positionInfo.position.x}px`;
|
|
458
|
+
timeStyle.value.top = `${positionInfo.position.y}px`;
|
|
459
|
+
timeStyle.value.width = `${positionInfo.position.width}px`;
|
|
460
|
+
timeStyle.value.height = `${positionInfo.position.height}px`;
|
|
461
|
+
|
|
462
|
+
if (positionInfo.isVisible) return;
|
|
463
|
+
|
|
464
|
+
isOpenTime.value = false;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function setPickerContentPosition() {
|
|
468
|
+
const windowHeight = window.innerHeight;
|
|
469
|
+
const inputHeight = root.value.clientHeight;
|
|
470
|
+
const listClientRect = pickerContent.value.getBoundingClientRect()
|
|
471
|
+
const isTop = pickerContentPosition.value === 'top'
|
|
472
|
+
|
|
473
|
+
const indentTop = (listClientRect.height + inputHeight) * (isTop ? 1 : 0) + pickerContentIndentY
|
|
474
|
+
const indent = windowHeight - listClientRect.y - indentTop
|
|
475
|
+
|
|
476
|
+
pickerContentPosition.value = indent > listClientRect.height ? 'bottom' : 'top'
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function fillMonthDays(ISO: string | null) {
|
|
480
|
+
if (typeof ISO !== 'string') return
|
|
481
|
+
|
|
482
|
+
if (monthDays.value.length < 1) {
|
|
483
|
+
const currentDaysDate = DateTime.fromISO(ISO).startOf('month').startOf('week');
|
|
484
|
+
const monthDayObj: TMonthDay = {
|
|
485
|
+
ISO: (currentDaysDate.toISO() as string),
|
|
486
|
+
value: currentDaysDate.day
|
|
487
|
+
};
|
|
488
|
+
monthDays.value.push(monthDayObj);
|
|
489
|
+
|
|
490
|
+
return fillMonthDays(currentDaysDate.toISO());
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const lastWeekDate = DateTime.fromISO(ISO).set({ month: activeMonth.value, year: activeYear.value }).endOf('month', {}).endOf('week', {});
|
|
494
|
+
// добавляем по дню до тех пор пока не дойдем до последней даты
|
|
495
|
+
const currentDate = DateTime.fromISO(ISO).plus({ day: 1 });
|
|
496
|
+
|
|
497
|
+
const monthDayObj: TMonthDay = {
|
|
498
|
+
ISO: (currentDate.toISO() as string),
|
|
499
|
+
value: currentDate.day,
|
|
500
|
+
};
|
|
501
|
+
monthDays.value.push(monthDayObj);
|
|
502
|
+
|
|
503
|
+
const isMismatchYear = lastWeekDate.year !== currentDate.year;
|
|
504
|
+
const isMismatchMonth = lastWeekDate.month !== currentDate.month;
|
|
505
|
+
const isMismatchDay = lastWeekDate.day !== currentDate.day;
|
|
506
|
+
|
|
507
|
+
// проверка на совпадение последней даты
|
|
508
|
+
if (isMismatchYear || isMismatchMonth || isMismatchDay) fillMonthDays(currentDate.toISO());
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function isDisableDay(ISO: string): boolean {
|
|
512
|
+
if (!props.min && !props.max) return false;
|
|
513
|
+
|
|
514
|
+
const currentDate = DateTime.fromISO(ISO);
|
|
515
|
+
const maxDate = DateTime.fromISO(props.max as string);
|
|
516
|
+
const minDate = DateTime.fromISO(props.min as string);
|
|
517
|
+
|
|
518
|
+
const isMoreMax = maxDate.ts < currentDate.ts;
|
|
519
|
+
const isLessMin = minDate.ts > currentDate.ts;
|
|
520
|
+
|
|
521
|
+
return isMoreMax || isLessMin;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function setTime(name: 'hour' | 'minute', value: string) {
|
|
525
|
+
const numValue = value.replace(/[^0-9]/g, '');
|
|
526
|
+
|
|
527
|
+
let min = 0;
|
|
528
|
+
let max = 59;
|
|
529
|
+
|
|
530
|
+
if (name === 'hour') {
|
|
531
|
+
max = 23;
|
|
532
|
+
}
|
|
533
|
+
if (name === 'minute') {
|
|
534
|
+
max = 59;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const validValue = Math.min(Math.max(min, +numValue), max);
|
|
538
|
+
const strValue = getTimeStr(validValue);
|
|
539
|
+
|
|
540
|
+
if (name === 'hour') modelHour.value = strValue
|
|
541
|
+
else modelMinute.value = strValue
|
|
542
|
+
|
|
543
|
+
const currentDate = activeDate.value.toISO();
|
|
544
|
+
|
|
545
|
+
activeDate.value = DateTime.fromISO(currentDate).set({ hour: +modelHour.value, minute: +modelMinute.value });
|
|
546
|
+
|
|
547
|
+
dispatchEmit()
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function getTimeStr(value: number) {
|
|
551
|
+
return `0${value}`.match(/.{2}$/)?.[0] || '00'
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function setIsOpen(value: boolean) {
|
|
555
|
+
isOpenPicker.value = value;
|
|
556
|
+
setOldDate(value);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function setOldDate(value: boolean) {
|
|
560
|
+
if (value) {
|
|
561
|
+
oldDateISO.value = activeDate.value.toISO()
|
|
562
|
+
} else {
|
|
563
|
+
activeDate.value = DateTime.fromISO(oldDateISO.value);
|
|
564
|
+
activeMonth.value = activeDate.value.month;
|
|
565
|
+
activeYear.value = activeDate.value.year;
|
|
566
|
+
|
|
567
|
+
setSelect('month', activeMonth.value);
|
|
568
|
+
setSelect('year', activeYear.value);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function dispatchEmit() {
|
|
573
|
+
const currentDateISO = activeDate.value.toISO();
|
|
574
|
+
setIsOpen(false);
|
|
575
|
+
|
|
576
|
+
oldDateISO.value = currentDateISO;
|
|
577
|
+
activeDate.value = DateTime.fromISO(currentDateISO);
|
|
578
|
+
emit('change_cdatepicker', currentDateISO);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function setActiveDay(ISO: string) {
|
|
582
|
+
if (isDisableDay(ISO)) return;
|
|
583
|
+
|
|
584
|
+
const currentDate = DateTime.fromISO(ISO);
|
|
585
|
+
|
|
586
|
+
const currentActiveDate = DateTime.fromISO(activeDate.value.toISO()).set({
|
|
587
|
+
year: currentDate.year,
|
|
588
|
+
month: currentDate.month,
|
|
589
|
+
day: currentDate.day,
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
activeDate.value = currentActiveDate;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function setSelect(dateName: 'month' | 'year', value: number) {
|
|
596
|
+
if (!value) return;
|
|
597
|
+
|
|
598
|
+
const currentISO = activeDate.value.toISO();
|
|
599
|
+
|
|
600
|
+
if (dateName === 'month') {
|
|
601
|
+
activeMonth.value = value;
|
|
602
|
+
modelMonth.value[0] = monthsOption.value[value - 1]
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (dateName === 'year') {
|
|
606
|
+
activeYear.value = value;
|
|
607
|
+
modelYear.value[0] = {
|
|
608
|
+
value,
|
|
609
|
+
text: String(value)
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
activeDate.value = DateTime.fromISO(currentISO).set({ month: activeMonth.value, year: activeYear.value })
|
|
614
|
+
const currentDate = activeDate.value.toISO();
|
|
615
|
+
|
|
616
|
+
monthDays.value = [];
|
|
617
|
+
fillMonthDays(currentDate);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function isActiveDay(ISO: string): boolean {
|
|
621
|
+
const currentDate = DateTime.fromISO(ISO);
|
|
622
|
+
|
|
623
|
+
return activeDate.value.year === currentDate.year && activeDate.value.month === currentDate.month && activeDate.value.day === currentDate.day
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
defineExpose({
|
|
627
|
+
datePickerId
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
</script>
|
|
631
|
+
|
|
632
|
+
<style lang="scss">
|
|
633
|
+
|
|
634
|
+
$timeWidth: 60px;
|
|
635
|
+
|
|
636
|
+
.c-datepicker {
|
|
637
|
+
display: flex;
|
|
638
|
+
align-items: center;
|
|
639
|
+
|
|
640
|
+
gap: 15px;
|
|
641
|
+
|
|
642
|
+
&__inp {
|
|
643
|
+
&_wrap {
|
|
644
|
+
position: relative;
|
|
645
|
+
|
|
646
|
+
cursor: pointer;
|
|
647
|
+
|
|
648
|
+
&.open,
|
|
649
|
+
&:hover {
|
|
650
|
+
.c-input {
|
|
651
|
+
border: 1px solid var(--green-light);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.c-input__custom-icon svg path {
|
|
655
|
+
fill: var(--green-light);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
&::after {
|
|
660
|
+
content: '';
|
|
661
|
+
|
|
662
|
+
position: absolute;
|
|
663
|
+
left: 0;
|
|
664
|
+
right: 0;
|
|
665
|
+
top: 0;
|
|
666
|
+
bottom: 0;
|
|
667
|
+
|
|
668
|
+
display: flex;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.c-input__wrap {
|
|
672
|
+
opacity: 1;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.c-input__custom-icon {
|
|
677
|
+
opacity: 1;
|
|
678
|
+
|
|
679
|
+
svg path {
|
|
680
|
+
transition: var(--transition);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
&__hours {
|
|
686
|
+
|
|
687
|
+
&_inps {
|
|
688
|
+
display: flex;
|
|
689
|
+
justify-content: center;
|
|
690
|
+
align-items: center;
|
|
691
|
+
|
|
692
|
+
font-size: 14px;
|
|
693
|
+
|
|
694
|
+
color: var(--white);
|
|
695
|
+
|
|
696
|
+
input {
|
|
697
|
+
width: 16px;
|
|
698
|
+
padding: 0;
|
|
699
|
+
|
|
700
|
+
outline: none;
|
|
701
|
+
border: none;
|
|
702
|
+
|
|
703
|
+
color: inherit;
|
|
704
|
+
background: transparent;
|
|
705
|
+
|
|
706
|
+
-moz-appearance: textfield;
|
|
707
|
+
|
|
708
|
+
&::-webkit-outer-spin-button,
|
|
709
|
+
&::-webkit-inner-spin-button {
|
|
710
|
+
-webkit-appearance: none;
|
|
711
|
+
margin: 0;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
&_wrap {
|
|
717
|
+
box-sizing: border-box;
|
|
718
|
+
|
|
719
|
+
display: flex;
|
|
720
|
+
justify-content: center;
|
|
721
|
+
|
|
722
|
+
width: $timeWidth;
|
|
723
|
+
height: 32px;
|
|
724
|
+
|
|
725
|
+
border: 1px solid var(--white);
|
|
726
|
+
border-radius: 5px;
|
|
727
|
+
|
|
728
|
+
background: var(--black-dark);
|
|
729
|
+
|
|
730
|
+
transition: var(--transition);
|
|
731
|
+
|
|
732
|
+
cursor: pointer;
|
|
733
|
+
|
|
734
|
+
&.open,
|
|
735
|
+
&:hover {
|
|
736
|
+
border: 1px solid var(--green-light);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.c-datepicker__hours_list-wrap {
|
|
743
|
+
--max-height: 112px;
|
|
744
|
+
--scroll-height: 100px;
|
|
745
|
+
|
|
746
|
+
position: fixed;
|
|
747
|
+
z-index: 999;
|
|
748
|
+
transition: var(--transition);
|
|
749
|
+
pointer-events: none;
|
|
750
|
+
|
|
751
|
+
.c-datepicker {
|
|
752
|
+
&__hours {
|
|
753
|
+
&_list-content {
|
|
754
|
+
box-sizing: border-box;
|
|
755
|
+
|
|
756
|
+
display: flex;
|
|
757
|
+
|
|
758
|
+
max-height: var(--scroll-height);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
&_list {
|
|
762
|
+
position: absolute;
|
|
763
|
+
left: 0%;
|
|
764
|
+
transform: translate(0px, 0px);
|
|
765
|
+
z-index: 20;
|
|
766
|
+
|
|
767
|
+
box-sizing: border-box;
|
|
768
|
+
|
|
769
|
+
width: $timeWidth;
|
|
770
|
+
max-height: var(--max-height);
|
|
771
|
+
padding: 6px;
|
|
772
|
+
|
|
773
|
+
border: 1px solid var(--green-dark);
|
|
774
|
+
border-radius: 5px;
|
|
775
|
+
|
|
776
|
+
background: var(--black-dark);
|
|
777
|
+
box-shadow: var(--shadow);
|
|
778
|
+
|
|
779
|
+
transition: var(--transition);
|
|
780
|
+
|
|
781
|
+
opacity: 0;
|
|
782
|
+
pointer-events: none;
|
|
783
|
+
|
|
784
|
+
&.bottom {
|
|
785
|
+
--indent-y: var(--picker-time-indent-y);
|
|
786
|
+
|
|
787
|
+
top: 100%;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
&.top {
|
|
791
|
+
--indent-y: calc(var(--picker-time-indent-y) * -1);
|
|
792
|
+
|
|
793
|
+
bottom: 100%;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
&.open {
|
|
797
|
+
transform: translate(0, var(--indent-y));
|
|
798
|
+
|
|
799
|
+
opacity: 1;
|
|
800
|
+
pointer-events: all;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
&_list-scroll {
|
|
805
|
+
.c-scroll__content {
|
|
806
|
+
background: transparent;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.ps__rail-x,
|
|
810
|
+
.ps__rail-y {
|
|
811
|
+
display: none;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
&_list-line {
|
|
816
|
+
display: flex;
|
|
817
|
+
|
|
818
|
+
width: 1px;
|
|
819
|
+
height: var(--scroll-height);
|
|
820
|
+
|
|
821
|
+
margin: 0 3px;
|
|
822
|
+
|
|
823
|
+
background: var(--green-dark);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
&_btn {
|
|
827
|
+
display: flex;
|
|
828
|
+
justify-content: center;
|
|
829
|
+
align-items: center;
|
|
830
|
+
|
|
831
|
+
width: 20px;
|
|
832
|
+
height: 20px;
|
|
833
|
+
|
|
834
|
+
font-size: 14px;
|
|
835
|
+
|
|
836
|
+
border: none;
|
|
837
|
+
outline: none;
|
|
838
|
+
|
|
839
|
+
background: transparent;
|
|
840
|
+
color: var(--white);
|
|
841
|
+
|
|
842
|
+
transition: var(--transition);
|
|
843
|
+
|
|
844
|
+
cursor: pointer;
|
|
845
|
+
|
|
846
|
+
&.active,
|
|
847
|
+
&:hover {
|
|
848
|
+
color: var(--green-light);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
.c-datepicker__content_wrap {
|
|
856
|
+
position: fixed;
|
|
857
|
+
z-index: 999;
|
|
858
|
+
transition: var(--transition);
|
|
859
|
+
pointer-events: none;
|
|
860
|
+
|
|
861
|
+
.c-datepicker {
|
|
862
|
+
&__selects {
|
|
863
|
+
display: flex;
|
|
864
|
+
justify-content: space-between;
|
|
865
|
+
|
|
866
|
+
margin-bottom: 10px;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
&__select {
|
|
870
|
+
.c-input {
|
|
871
|
+
padding: 5px;
|
|
872
|
+
padding-right: 30px !important;
|
|
873
|
+
|
|
874
|
+
border: none !important;
|
|
875
|
+
background: transparent;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.c-input__custom-icon {
|
|
879
|
+
right: 7px !important;
|
|
880
|
+
|
|
881
|
+
.c-select__inp_icon {
|
|
882
|
+
--svg-size: 18px !important;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
&__content {
|
|
888
|
+
box-sizing: border-box;
|
|
889
|
+
|
|
890
|
+
position: absolute;
|
|
891
|
+
left: 50%;
|
|
892
|
+
transform: translate(-50%, 0px);
|
|
893
|
+
z-index: 20;
|
|
894
|
+
|
|
895
|
+
width: 100%;
|
|
896
|
+
min-width: 295px;
|
|
897
|
+
padding: 15px;
|
|
898
|
+
|
|
899
|
+
border: 1px solid var(--green-medium);
|
|
900
|
+
border-radius: 5px;
|
|
901
|
+
|
|
902
|
+
color: var(--white);
|
|
903
|
+
background: var(--black-dark);
|
|
904
|
+
|
|
905
|
+
pointer-events: none;
|
|
906
|
+
opacity: 0;
|
|
907
|
+
|
|
908
|
+
transition: var(--transition);
|
|
909
|
+
|
|
910
|
+
&.bottom {
|
|
911
|
+
--indent-y: var(--picker-content-indent-y);
|
|
912
|
+
|
|
913
|
+
top: 100%;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
&.top {
|
|
917
|
+
--indent-y: calc(var(--picker-content-indent-y) * -1);
|
|
918
|
+
|
|
919
|
+
bottom: 100%;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
&.open {
|
|
923
|
+
transform: translate(-50%, var(--indent-y));
|
|
924
|
+
|
|
925
|
+
opacity: 1;
|
|
926
|
+
pointer-events: all;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.c-input__custom-icon {
|
|
930
|
+
pointer-events: none;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
&__table {
|
|
935
|
+
--item-size: 36px;
|
|
936
|
+
|
|
937
|
+
display: grid;
|
|
938
|
+
grid-template-columns: repeat(7, 36px);
|
|
939
|
+
|
|
940
|
+
gap: 2px;
|
|
941
|
+
|
|
942
|
+
font-size: 14px;
|
|
943
|
+
|
|
944
|
+
&_item {
|
|
945
|
+
width: var(--item-size);
|
|
946
|
+
height: var(--item-size);
|
|
947
|
+
|
|
948
|
+
display: flex;
|
|
949
|
+
align-items: center;
|
|
950
|
+
justify-content: center;
|
|
951
|
+
|
|
952
|
+
padding: 0;
|
|
953
|
+
border: none;
|
|
954
|
+
|
|
955
|
+
background: transparent;
|
|
956
|
+
color: var(--white);
|
|
957
|
+
|
|
958
|
+
cursor: pointer;
|
|
959
|
+
|
|
960
|
+
&.disable {
|
|
961
|
+
opacity: 0.5;
|
|
962
|
+
pointer-events: none;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
&.active span {
|
|
966
|
+
background: var(--green-light);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
span {
|
|
970
|
+
width: 26px;
|
|
971
|
+
height: 26px;
|
|
972
|
+
|
|
973
|
+
display: flex;
|
|
974
|
+
justify-content: center;
|
|
975
|
+
align-items: center;
|
|
976
|
+
|
|
977
|
+
border-radius: 6px;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
&_name {
|
|
982
|
+
display: flex;
|
|
983
|
+
|
|
984
|
+
font-weight: 500;
|
|
985
|
+
|
|
986
|
+
cursor: auto;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
&__action {
|
|
991
|
+
display: flex;
|
|
992
|
+
justify-content: center;
|
|
993
|
+
gap: 12px;
|
|
994
|
+
|
|
995
|
+
margin: 10px auto 0;
|
|
996
|
+
|
|
997
|
+
&_btn {
|
|
998
|
+
width: 84px;
|
|
999
|
+
padding-left: 0;
|
|
1000
|
+
padding-right: 0;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
</style>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
ref="root"
|
|
4
|
+
:data-c-select-id="selectId"
|
|
4
5
|
:style="`--transition: ${transition}ms; --width: ${width}; --list-indent-y: ${listIndentY}px`"
|
|
5
|
-
:class="[classes.root, variant, size, { disabled }]"
|
|
6
|
+
:class="[classes.root, variant, size, { disabled, open: isOpen }]"
|
|
6
7
|
>
|
|
7
8
|
<CInput
|
|
8
9
|
:placeholder="activePlaceholder"
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
</CInput>
|
|
22
23
|
<Teleport to="body">
|
|
23
24
|
<div
|
|
25
|
+
:data-c-select-id="selectId"
|
|
24
26
|
:style="listStyle"
|
|
25
27
|
:class="[classes.fixedContainer, variant, size, { open: isOpen, disabled }]"
|
|
26
28
|
>
|
|
@@ -128,7 +130,8 @@ const emit = defineEmits<{
|
|
|
128
130
|
}>();
|
|
129
131
|
|
|
130
132
|
const transition = 200,
|
|
131
|
-
listIndentY = 12
|
|
133
|
+
listIndentY = 12,
|
|
134
|
+
selectId = Math.random() * 100_000_000
|
|
132
135
|
|
|
133
136
|
let findValue = ref(''),
|
|
134
137
|
isOpen = ref(props.isOpen || false),
|
|
@@ -273,6 +276,7 @@ const handleOption: TDebounceEvent = function(option, evt) {
|
|
|
273
276
|
setOption(option, evt);
|
|
274
277
|
|
|
275
278
|
if (!isMultiple.value) dispatchEmit()
|
|
279
|
+
setActivePlaceholder()
|
|
276
280
|
}
|
|
277
281
|
|
|
278
282
|
const setOption: TDebounceEvent = function(option, evt) {
|
|
@@ -363,14 +367,15 @@ function setListPosition() {
|
|
|
363
367
|
|
|
364
368
|
function handleClick(evt: MouseEvent) {
|
|
365
369
|
const target = (evt.target as HTMLElement);
|
|
366
|
-
const classesStr = `.${classes.input},.c-input__custom-icon${isMultiple.value ? ',.c-input__custom-icon,.c-
|
|
370
|
+
const classesStr = `.${classes.input},.c-input__custom-icon${isMultiple.value ? ',.c-input__custom-icon,.c-select__list' : ''}`
|
|
367
371
|
const currentRoot = target.closest(`.${classes.root}`)
|
|
368
372
|
const domElements = target.closest(classesStr)
|
|
369
373
|
|
|
370
374
|
const isRoot = currentRoot === root.value
|
|
375
|
+
const isList = domElements === list.value.$el
|
|
371
376
|
const isToggle = target.closest('.c-input__custom-icon')
|
|
372
377
|
|
|
373
|
-
if (isRoot && domElements) {
|
|
378
|
+
if ((isRoot || isList) && domElements) {
|
|
374
379
|
setListPosition()
|
|
375
380
|
isOpen.value = isToggle ? !isOpen.value : true
|
|
376
381
|
emit('update:isOpen', isOpen.value)
|
|
@@ -397,6 +402,10 @@ function dispatchEmit() {
|
|
|
397
402
|
}, transition);
|
|
398
403
|
}
|
|
399
404
|
|
|
405
|
+
defineExpose({
|
|
406
|
+
selectId
|
|
407
|
+
})
|
|
408
|
+
|
|
400
409
|
</script>
|
|
401
410
|
|
|
402
411
|
<style lang="scss">
|
package/src/libIndex.js
CHANGED
|
@@ -7,6 +7,7 @@ import CTooltip from './components/CTooltip.vue';
|
|
|
7
7
|
import CPopup from './components/CPopup.vue';
|
|
8
8
|
import CAlert from './components/CAlert.vue';
|
|
9
9
|
import CIcon from './components/CIcons/CIcon.vue';
|
|
10
|
+
import CDatepicker from './components/CDatepicker.vue';
|
|
10
11
|
import CScroll from './components/CScroll.vue';
|
|
11
12
|
|
|
12
13
|
import { CClasses } from './assets/js/helpers';
|
|
@@ -23,6 +24,7 @@ export {
|
|
|
23
24
|
CPopup,
|
|
24
25
|
CAlert,
|
|
25
26
|
CIcon,
|
|
27
|
+
CDatepicker,
|
|
26
28
|
CScroll,
|
|
27
29
|
|
|
28
30
|
CClasses,
|
package/src/pages/index.vue
CHANGED
|
@@ -639,6 +639,40 @@
|
|
|
639
639
|
</div>
|
|
640
640
|
<!-- ./checkboxes -->
|
|
641
641
|
|
|
642
|
+
<!-- CDatepicker -->
|
|
643
|
+
<div class="table content">
|
|
644
|
+
<div class="table__wrap">
|
|
645
|
+
<div class="table__item table__title">
|
|
646
|
+
CDatepicker
|
|
647
|
+
</div>
|
|
648
|
+
<div class="table">
|
|
649
|
+
<!-- col -->
|
|
650
|
+
<div class="table__col checkboxes">
|
|
651
|
+
<div class="table__item">
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
<!-- ./col -->
|
|
655
|
+
|
|
656
|
+
<!-- col -->
|
|
657
|
+
<div class="table__col checkboxes">
|
|
658
|
+
<div class="table__item">
|
|
659
|
+
<CDatepicker @change_cdatepicker="(e) => console.log(e)" />
|
|
660
|
+
</div>
|
|
661
|
+
</div>
|
|
662
|
+
<!-- ./col -->
|
|
663
|
+
|
|
664
|
+
<!-- col -->
|
|
665
|
+
<div class="table__col checkboxes">
|
|
666
|
+
<div class="table__item">
|
|
667
|
+
<CDatepicker @change_cdatepicker="(e) => console.log(e)" />
|
|
668
|
+
</div>
|
|
669
|
+
</div>
|
|
670
|
+
<!-- ./col -->
|
|
671
|
+
</div>
|
|
672
|
+
</div>
|
|
673
|
+
</div>
|
|
674
|
+
<!-- ./CDatepicker -->
|
|
675
|
+
|
|
642
676
|
<!-- select -->
|
|
643
677
|
<div style="min-height: 400px;" class="table content">
|
|
644
678
|
<div class="table__wrap">
|
|
@@ -955,6 +989,7 @@ import CTooltip from '../components/CTooltip.vue';
|
|
|
955
989
|
import CPopup from '../components/CPopup.vue';
|
|
956
990
|
import CAlert from '../components/CAlert.vue';
|
|
957
991
|
import CIcon from '../components/CIcons/CIcon.vue';
|
|
992
|
+
import CDatepicker from '../components/CDatepicker.vue';
|
|
958
993
|
|
|
959
994
|
import { iconContent } from '../assets/icon/icons-manifest';
|
|
960
995
|
|
|
@@ -1089,6 +1124,7 @@ export default {
|
|
|
1089
1124
|
CPopup,
|
|
1090
1125
|
CAlert,
|
|
1091
1126
|
CIcon,
|
|
1127
|
+
CDatepicker,
|
|
1092
1128
|
},
|
|
1093
1129
|
}
|
|
1094
1130
|
</script>
|