@kizmann/nano-ui 0.8.22 → 0.8.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,463 @@
1
+ import { Any, Obj, Arr, Locale } from "@kizmann/pico-js";
2
+
3
+ export default {
4
+
5
+ name: 'NDurationpicker',
6
+
7
+ props: {
8
+
9
+ modelValue: {
10
+ default()
11
+ {
12
+ return null;
13
+ }
14
+ },
15
+
16
+ clearValue: {
17
+ default()
18
+ {
19
+ return null;
20
+ }
21
+ },
22
+
23
+ options: {
24
+ default()
25
+ {
26
+ return [
27
+ 60 * 5,
28
+ 60 * 10,
29
+ 60 * 15,
30
+ 60 * 30,
31
+ 60 * 45,
32
+ 60 * 60,
33
+ 60 * 90,
34
+ 60 * 120,
35
+ 60 * 150,
36
+ 60 * 60 * 3,
37
+ 60 * 60 * 4,
38
+ 60 * 60 * 5,
39
+ 60 * 60 * 6,
40
+ 60 * 60 * 12,
41
+ 60 * 60 * 24,
42
+ 60 * 60 * 24 * 2,
43
+ 60 * 60 * 24 * 3,
44
+ 60 * 60 * 24 * 4,
45
+ 60 * 60 * 24 * 5,
46
+ 60 * 60 * 24 * 6,
47
+ 60 * 60 * 24 * 7,
48
+ ];
49
+ },
50
+ type: [Array]
51
+ },
52
+
53
+ minDuration: {
54
+ default()
55
+ {
56
+ return null;
57
+ }
58
+ },
59
+
60
+ maxDuration: {
61
+ default()
62
+ {
63
+ return null;
64
+ }
65
+ },
66
+
67
+ size: {
68
+ default()
69
+ {
70
+ return 'md';
71
+ },
72
+ type: [String]
73
+ },
74
+
75
+ type: {
76
+ default()
77
+ {
78
+ return 'primary';
79
+ },
80
+ type: [String]
81
+ },
82
+
83
+ placeholder: {
84
+ default()
85
+ {
86
+ return Locale.trans('Select duration');
87
+ },
88
+ type: [String]
89
+ },
90
+
91
+ negativeText: {
92
+ default()
93
+ {
94
+ return Locale.trans('Negative duration');
95
+ },
96
+ type: [String]
97
+ },
98
+
99
+ boundary: {
100
+ default()
101
+ {
102
+ return null;
103
+ }
104
+ },
105
+
106
+ position: {
107
+ default()
108
+ {
109
+ return 'bottom-start';
110
+ },
111
+ type: [String]
112
+ },
113
+
114
+ disabled: {
115
+ default()
116
+ {
117
+ return false;
118
+ },
119
+ type: [Boolean]
120
+ },
121
+
122
+ clearable: {
123
+ default()
124
+ {
125
+ return false;
126
+ },
127
+ type: [Boolean]
128
+ },
129
+
130
+ days: {
131
+ default()
132
+ {
133
+ return Locale.trans(':count Day|:count Days');
134
+ },
135
+ type: [String]
136
+ },
137
+
138
+ hours: {
139
+ default()
140
+ {
141
+ return Locale.trans(':count Hour|:count Hours');
142
+ },
143
+ type: [String]
144
+ },
145
+
146
+ minutes: {
147
+ default()
148
+ {
149
+ return Locale.trans(':count Minute|:count Minutes');
150
+ },
151
+ type: [String]
152
+ },
153
+
154
+ seconds: {
155
+ default()
156
+ {
157
+ return Locale.trans(':count Second|:count Seconds');
158
+ },
159
+ type: [String]
160
+ }
161
+
162
+ },
163
+
164
+
165
+ watch: {
166
+
167
+ modelValue(value)
168
+ {
169
+ if ( value !== this.tempValue ) {
170
+ this.tempValue = value;
171
+ }
172
+ },
173
+
174
+ },
175
+
176
+ data()
177
+ {
178
+ return {
179
+ focus: false, tempValue: this.modelValue, editValue: null
180
+ };
181
+ },
182
+
183
+ methods: {
184
+
185
+ findPattern(text, pattern)
186
+ {
187
+ pattern = pattern.replaceAll(':count', '([0-9\.\,]+)')
188
+ .replaceAll(' ', '\\s*');
189
+
190
+ return text.match(new RegExp(pattern, 'i'));
191
+ },
192
+
193
+ humanizeValue(value)
194
+ {
195
+ if ( Any.isEmpty(value) ) {
196
+ return '';
197
+ }
198
+
199
+ if ( value < 0 ) {
200
+ return this.negativeText;
201
+ }
202
+
203
+ let seconds = value;
204
+
205
+ // Extract minutes
206
+ let minutes = Math.floor(seconds/60);
207
+ seconds -= minutes * 60;
208
+
209
+ // Extract hours
210
+ let hours = Math.floor(minutes/60);
211
+ minutes -= hours * 60;
212
+
213
+
214
+ // Extract days
215
+ let days = Math.floor(hours/24);
216
+ hours -= days * 24;
217
+
218
+ let text = [];
219
+
220
+ if ( days ) {
221
+ text.push(Locale.choice(this.days, days));
222
+ }
223
+
224
+ if ( hours ) {
225
+ text.push(Locale.choice(this.hours, hours));
226
+ }
227
+
228
+ if ( minutes ) {
229
+ text.push(Locale.choice(this.minutes, minutes));
230
+ }
231
+
232
+ if ( seconds ) {
233
+ text.push(Locale.choice(this.seconds, seconds));
234
+ }
235
+
236
+ return text.join(' ');
237
+ },
238
+
239
+ digitizeValue(text)
240
+ {
241
+ if ( Any.isEmpty(text) ) {
242
+ return this.clearValue;
243
+ }
244
+
245
+ let value = 0;
246
+
247
+ let dmatch = this.findPattern(text, this.days);
248
+
249
+ if ( dmatch && dmatch.length === 3 ) {
250
+ value += Any.float(dmatch[1].replace(',', '.')) * 24 * 60 * 60;
251
+ }
252
+
253
+ let hmatch = this.findPattern(text, this.hours);
254
+
255
+ if ( hmatch && hmatch.length === 3 ) {
256
+ value += Any.float(hmatch[1].replace(',', '.')) * 60 * 60;
257
+ }
258
+
259
+ let mmatch = this.findPattern(text, this.minutes);
260
+
261
+ if ( mmatch && mmatch.length === 3 ) {
262
+ value += Any.float(mmatch[1].replace(',', '.')) * 60;
263
+ }
264
+
265
+ let smatch = this.findPattern(text, this.seconds);
266
+
267
+ if ( smatch && smatch.length === 3 ) {
268
+ value += Any.float(smatch[1].replace(',', '.'));
269
+ }
270
+
271
+ return value;
272
+ },
273
+
274
+ clearDurationpicker()
275
+ {
276
+ this.$emit('update:modelValue', this.tempValue = this.clearValue);
277
+ },
278
+
279
+ onPopoverInput(value)
280
+ {
281
+ this.focus = value;
282
+ },
283
+
284
+ onValueInput(e)
285
+ {
286
+ let value = this.digitizeValue(e.target.value);
287
+
288
+ if ( value === this.tempValue ) {
289
+ return;
290
+ }
291
+
292
+ this.editValue = value;
293
+ },
294
+
295
+ onValueChange(e)
296
+ {
297
+ let value = this.editValue;
298
+
299
+ // Clear edit value
300
+ this.editValue = null;
301
+
302
+ if ( ! value || value === this.tempValue ) {
303
+ return;
304
+ }
305
+
306
+ this.$emit('update:modelValue', this.tempValue = value);
307
+ },
308
+
309
+ onDurationpickerInput(value)
310
+ {
311
+ this.focus = false;
312
+
313
+ // Clear edit value
314
+ this.editValue = null;
315
+
316
+ this.$emit('update:modelValue', this.tempValue = value);
317
+ },
318
+
319
+ },
320
+
321
+ renderLabelClear()
322
+ {
323
+ if ( ! this.clearable || ! this.tempValue ) {
324
+ return null;
325
+ }
326
+
327
+ let props = {};
328
+
329
+ if ( ! this.disabled ) {
330
+ props.onMousedown = this.clearDurationpicker;
331
+ }
332
+
333
+ return (
334
+ <div class="n-durationpicker__clear" {...props}>
335
+ <i class={ nano.Icons.times }></i>
336
+ </div>
337
+ );
338
+ },
339
+
340
+ renderLabelAngle()
341
+ {
342
+ return (
343
+ <div class="n-durationpicker__angle">
344
+ <i class={ nano.Icons.angleDown }></i>
345
+ </div>
346
+ );
347
+ },
348
+
349
+ renderInput()
350
+ {
351
+ let props = {
352
+ value: this.humanizeValue(this.tempValue),
353
+ disabled: this.disabled,
354
+ placeholder: this.placeholder,
355
+ onInput: this.onValueInput,
356
+ onBlur: this.onValueChange,
357
+ onChange: this.onValueChange,
358
+ };
359
+
360
+ return (
361
+ <div class="n-durationpicker__input">
362
+ <input {...props}/>
363
+ </div>
364
+ );
365
+ },
366
+
367
+ renderDisplay()
368
+ {
369
+ let classList = [
370
+ 'n-durationpicker__display'
371
+ ];
372
+
373
+ return (
374
+ <div class={classList}>
375
+ { this.ctor('renderLabelClear')() }
376
+ { this.ctor('renderInput')() }
377
+ { this.ctor('renderLabelAngle')() }
378
+ </div>
379
+ );
380
+ },
381
+
382
+ renderItems()
383
+ {
384
+ return Arr.each(this.options, (value) => {
385
+
386
+ let text = this.humanizeValue(value);
387
+
388
+ let optionProps = {
389
+ //
390
+ };
391
+
392
+ optionProps['onClick'] = () => {
393
+ this.onDurationpickerInput(value);
394
+ }
395
+
396
+ return (<NPopoverOption {...optionProps}>{text}</NPopoverOption>)
397
+ });
398
+ },
399
+
400
+ renderPopover()
401
+ {
402
+ let props = {
403
+ trigger: 'click',
404
+ width: -1,
405
+ size: this.size,
406
+ position: this.position,
407
+ scrollClose: true,
408
+ disabled: this.disabled
409
+ };
410
+
411
+ let slots = {};
412
+
413
+ slots.raw = () => {
414
+
415
+ let scrollProps = {
416
+ relative: true, size: this.size
417
+ }
418
+
419
+ return (
420
+ <NScrollbar ref="scrollbar" class="n-durationpicker__body" {...scrollProps}>
421
+ {this.ctor('renderItems')()}
422
+ </NScrollbar>
423
+ )
424
+ }
425
+
426
+ return (
427
+ <NPopover ref="popover" vModel={this.focus} {...props} v-slots={slots} />
428
+ );
429
+ },
430
+
431
+ render()
432
+ {
433
+ let classList = [
434
+ 'n-durationpicker',
435
+ 'n-durationpicker--' + this.type,
436
+ 'n-durationpicker--' + this.size,
437
+ ];
438
+
439
+ if ( ! this.tempValue ) {
440
+ classList.push('n-empty');
441
+ }
442
+
443
+ if ( this.clearable ) {
444
+ classList.push('n-clearable');
445
+ }
446
+
447
+ if ( this.focus ) {
448
+ classList.push('n-focus');
449
+ }
450
+
451
+ if ( this.disabled ) {
452
+ classList.push('n-disabled');
453
+ }
454
+
455
+ return (
456
+ <div class={classList}>
457
+ { this.ctor('renderDisplay')() }
458
+ { this.ctor('renderPopover')() }
459
+ </div>
460
+ );
461
+ }
462
+
463
+ }
@@ -0,0 +1,162 @@
1
+ @import "../../../root/vars";
2
+
3
+ .n-durationpicker {
4
+ display: flex;
5
+ flex-direction: row;
6
+ align-items: stretch;
7
+ justify-content: stretch;
8
+ width: 100%;
9
+ border: 1px solid transparent;
10
+ }
11
+
12
+ .n-durationpicker.n-disabled {
13
+ cursor: not-allowed;
14
+ opacity: 0.7;
15
+ }
16
+
17
+ .n-durationpicker__display {
18
+ display: flex;
19
+ flex-direction: row;
20
+ align-items: stretch;
21
+ justify-content: stretch;
22
+ width: 100%;
23
+ }
24
+
25
+ .n-durationpicker__input {
26
+ flex: 1 1 auto;
27
+ display: flex;
28
+ flex-direction: row;
29
+ align-items: stretch;
30
+ justify-content: stretch;
31
+ width: 50%;
32
+ }
33
+
34
+ .n-durationpicker__input input {
35
+ cursor: default;
36
+ appearance: none;
37
+ display: block;
38
+ width: 100%;
39
+ white-space: nowrap;
40
+ text-decoration: none;
41
+ line-height: 1.2;
42
+ border: none;
43
+ background: transparent;
44
+ box-shadow: none;
45
+ }
46
+
47
+ .n-disabled .n-durationpicker__input input {
48
+ cursor: not-allowed;
49
+ }
50
+
51
+ .n-durationpicker__clear,
52
+ .n-durationpicker__angle {
53
+ order: 100;
54
+ flex: 0 0 auto;
55
+ display: flex;
56
+ flex-direction: row;
57
+ align-items: center;
58
+ justify-content: center;
59
+ }
60
+
61
+ .n-durationpicker__clear {
62
+ display: none;
63
+ }
64
+
65
+ .n-durationpicker:hover.n-clearable:not(.n-empty) .n-durationpicker__clear,
66
+ .n-durationpicker.n-focus.n-clearable:not(.n-empty) .n-durationpicker__clear {
67
+ display: flex;
68
+ }
69
+
70
+ .n-durationpicker:hover.n-clearable:not(.n-empty) .n-durationpicker__angle,
71
+ .n-durationpicker.n-focus.n-clearable:not(.n-empty) .n-durationpicker__angle {
72
+ display: none;
73
+ }
74
+
75
+ .n-durationpicker__angle {
76
+ transition: transform 0.25s;
77
+ }
78
+
79
+ .n-durationpicker.n-focus .n-durationpicker__angle {
80
+ transform: scaleY(-1);
81
+ }
82
+
83
+ .n-durationpicker__clear i,
84
+ .n-durationpicker__angle i {
85
+ text-align: center;
86
+ }
87
+
88
+ .n-durationpicker__clear i {
89
+ border-radius: 500px;
90
+ }
91
+
92
+ .n-durationpicker__placeholder {
93
+ flex: 1 1 auto;
94
+ display: inline-flex;
95
+ flex-direction: row;
96
+ flex-wrap: wrap;
97
+ align-items: center;
98
+ justify-content: flex-start;
99
+ width: 100%;
100
+ }
101
+
102
+ .n-durationpicker__body,
103
+ .n-durationpicker__empty {
104
+ overflow: hidden;
105
+ margin: 1px 0;
106
+ max-height: 210px;
107
+ }
108
+
109
+ .n-durationpicker__empty {
110
+ text-align: center;
111
+ }
112
+
113
+ @each $suffix, $values in $form {
114
+
115
+ $-duration-font: map-get($values, 'font');
116
+ $-duration-size: map-get($values, 'size');
117
+ $-duration-radius: map-get($values, 'radius');
118
+ $-duration-ratio: map-get($values, 'ratio');
119
+
120
+ .n-durationpicker--#{$suffix} {
121
+ min-height: $-duration-size;
122
+ font-size: $-duration-font;
123
+ border-radius: $-duration-radius;
124
+ }
125
+
126
+ $-duration-padding: $-duration-size * $-duration-ratio * 0.5;
127
+
128
+ .n-durationpicker--#{$suffix} .n-durationpicker__display,
129
+ .n-durationpicker--#{$suffix} .n-durationpicker__input input {
130
+ padding: 0 $-duration-padding;
131
+ }
132
+
133
+ .n-durationpicker--#{$suffix} .n-durationpicker__clear,
134
+ .n-durationpicker--#{$suffix} .n-durationpicker__angle {
135
+ width: $-duration-size;
136
+ margin: 0 -#{$-duration-padding} 0 -#{$-duration-padding};
137
+ }
138
+ .n-durationpicker--#{$suffix} .n-durationpicker__clear i,
139
+ .n-durationpicker--#{$suffix} .n-durationpicker__angle i {
140
+ width: $-duration-size - 14;
141
+ height: $-duration-size - 14;
142
+ line-height: $-duration-size - 14;
143
+ }
144
+
145
+ .n-durationpicker--#{$suffix} .n-durationpicker__angle i {
146
+ font-size: $-duration-font - 2;
147
+ }
148
+
149
+ .n-durationpicker--#{$suffix} .n-durationpicker__clear i {
150
+ font-size: $-duration-font - 4;
151
+ }
152
+
153
+ .n-popover--#{$suffix} .n-durationpicker__body,
154
+ .n-popover--#{$suffix} .n-durationpicker__empty {
155
+ border-radius: $-duration-radius;
156
+ }
157
+
158
+ .n-popover--#{$suffix} .n-durationpicker__empty {
159
+ padding: $-duration-padding;
160
+ }
161
+
162
+ }
package/src/index.js CHANGED
@@ -80,6 +80,7 @@ export function Install(App, Icons = {}, Styles = {})
80
80
  require('./datepicker/index').default(App);
81
81
  require('./timepicker/index').default(App);
82
82
  require('./datetimepicker/index').default(App);
83
+ require('./durationpicker/index').default(App);
83
84
  require('./transfer/index').default(App);
84
85
  require('./form/index').default(App); // check
85
86
  require('./tabs/index').default(App);
package/src/index.scss CHANGED
@@ -20,6 +20,7 @@
20
20
  @import "./datepicker/index";
21
21
  @import "./timepicker/index";
22
22
  @import "./datetimepicker/index";
23
+ @import "./durationpicker/index";
23
24
  @import "./transfer/index";
24
25
  @import "./file/index";
25
26
  @import "./popover/index";
@@ -0,0 +1 @@
1
+ @import "./src/durationpicker/durationpicker";
@@ -0,0 +1,49 @@
1
+ @import "../../../root/vars";
2
+
3
+ .n-durationpicker {
4
+ border: 1px solid $color-gray-15;
5
+ }
6
+
7
+ .n-durationpicker.n-disabled {
8
+ background: rgba($color-gray-15, 0.3);
9
+ }
10
+
11
+ .n-durationpicker__seperator {
12
+ color: $color-gray-60;
13
+ }
14
+
15
+ .n-durationpicker__clear,
16
+ .n-durationpicker__angle {
17
+ color: $color-gray-60;
18
+ }
19
+
20
+ .n-durationpicker__clear i {
21
+ background: rgba($color-gray-15, 0.6);
22
+ }
23
+
24
+ .n-durationpicker__placeholder {
25
+ color: rgba($color-black, 0.5);
26
+ }
27
+
28
+ .n-durationpicker__body,
29
+ .n-durationpicker__empty {
30
+ background: $color-white;
31
+ box-shadow: 0 1px 3px 1px rgba($color-shadow, 0.15);
32
+ }
33
+
34
+ .n-durationpicker__empty {
35
+ color: $color-gray-60;
36
+ }
37
+
38
+ @each $color, $values in $colors {
39
+
40
+ $-color-base: map_get($values, 'base');
41
+ $-color-light: map_get($values, 'light');
42
+ $-color-dark: map_get($values, 'dark');
43
+
44
+ .n-durationpicker--#{$color}:not(.n-disabled):hover,
45
+ .n-durationpicker--#{$color}:not(.n-disabled).n-focus {
46
+ border-color: $-color-base;
47
+ }
48
+
49
+ }
@@ -20,6 +20,7 @@
20
20
  @import "./datepicker/index";
21
21
  @import "./timepicker/index";
22
22
  @import "./datetimepicker/index";
23
+ @import "./durationpicker/index";
23
24
  @import "./transfer/index";
24
25
  @import "./popover/index";
25
26
  @import "./modal/index";