@kizmann/nano-ui 0.8.21 → 0.8.23

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,447 @@
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
+ boundary: {
92
+ default()
93
+ {
94
+ return null;
95
+ }
96
+ },
97
+
98
+ position: {
99
+ default()
100
+ {
101
+ return 'bottom-start';
102
+ },
103
+ type: [String]
104
+ },
105
+
106
+ disabled: {
107
+ default()
108
+ {
109
+ return false;
110
+ },
111
+ type: [Boolean]
112
+ },
113
+
114
+ clearable: {
115
+ default()
116
+ {
117
+ return false;
118
+ },
119
+ type: [Boolean]
120
+ },
121
+
122
+ days: {
123
+ default()
124
+ {
125
+ return ':count Day|:count Days';
126
+ },
127
+ type: [String]
128
+ },
129
+
130
+ hours: {
131
+ default()
132
+ {
133
+ return ':count Hour|:count Hours';
134
+ },
135
+ type: [String]
136
+ },
137
+
138
+ minutes: {
139
+ default()
140
+ {
141
+ return ':count Minute|:count Minutes';
142
+ },
143
+ type: [String]
144
+ },
145
+
146
+ seconds: {
147
+ default()
148
+ {
149
+ return ':count Second|:count Seconds';
150
+ },
151
+ type: [String]
152
+ }
153
+
154
+ },
155
+
156
+
157
+ watch: {
158
+
159
+ modelValue(value)
160
+ {
161
+ if ( value !== this.tempValue ) {
162
+ this.tempValue = value;
163
+ }
164
+ },
165
+
166
+ },
167
+
168
+ data()
169
+ {
170
+ return {
171
+ focus: false, tempValue: this.modelValue, editValue: null
172
+ };
173
+ },
174
+
175
+ methods: {
176
+
177
+ humanizeValue(value)
178
+ {
179
+ if ( Any.isEmpty(value) ) {
180
+ return '';
181
+ }
182
+
183
+ let seconds = value;
184
+
185
+ // Extract minutes
186
+ let minutes = Math.floor(seconds/60);
187
+ seconds -= minutes * 60;
188
+
189
+ // Extract hours
190
+ let hours = Math.floor(minutes/60);
191
+ minutes -= hours * 60;
192
+
193
+
194
+ // Extract days
195
+ let days = Math.floor(hours/24);
196
+ hours -= days * 24;
197
+
198
+ let text = [];
199
+
200
+ if ( days ) {
201
+ text.push(Locale.choice(this.days, days));
202
+ }
203
+
204
+ if ( hours ) {
205
+ text.push(Locale.choice(this.hours, hours));
206
+ }
207
+
208
+ if ( minutes ) {
209
+ text.push(Locale.choice(this.minutes, minutes));
210
+ }
211
+
212
+ if ( seconds ) {
213
+ text.push(Locale.choice(this.seconds, seconds));
214
+ }
215
+
216
+ return text.join(' ');
217
+ },
218
+
219
+ digitizeValue(text)
220
+ {
221
+ if ( Any.isEmpty(text) ) {
222
+ return this.clearValue;
223
+ }
224
+
225
+ let value = 0;
226
+
227
+ let days = new RegExp(this.days.replaceAll(':count', '([0-9\.\,]+)'), 'i'),
228
+ dmatch = text.match(days);
229
+
230
+ if ( dmatch && dmatch.length === 3 ) {
231
+ value += Any.float(dmatch[1].replace(',', '.')) * 24 * 60 * 60;
232
+ }
233
+
234
+ let hours = new RegExp(this.hours.replaceAll(':count', '([0-9\.\,]+)'), 'i'),
235
+ hmatch = text.match(hours);
236
+
237
+ if ( hmatch && hmatch.length === 3 ) {
238
+ value += Any.float(hmatch[1].replace(',', '.')) * 60 * 60;
239
+ }
240
+
241
+ let minutes = new RegExp(this.minutes.replaceAll(':count', '([0-9\.\,]+)'), 'i'),
242
+ mmatch = text.match(minutes);
243
+
244
+ if ( mmatch && mmatch.length === 3 ) {
245
+ value += Any.float(mmatch[1].replace(',', '.')) * 60;
246
+ }
247
+
248
+ let seconds = new RegExp(this.seconds.replaceAll(':count', '([0-9\.\,]+)'), 'i'),
249
+ smatch = text.match(seconds);
250
+
251
+ if ( smatch && smatch.length === 3 ) {
252
+ value += Any.float(smatch[1].replace(',', '.'));
253
+ }
254
+
255
+ return value;
256
+ },
257
+
258
+ clearDurationpicker()
259
+ {
260
+ this.$emit('update:modelValue', this.tempValue = this.clearValue);
261
+ },
262
+
263
+ onPopoverInput(value)
264
+ {
265
+ this.focus = value;
266
+ },
267
+
268
+ onValueInput(e)
269
+ {
270
+ let value = this.digitizeValue(e.target.value);
271
+
272
+ if ( value === this.tempValue ) {
273
+ return;
274
+ }
275
+
276
+ this.editValue = value;
277
+ },
278
+
279
+ onValueChange(e)
280
+ {
281
+ let value = this.editValue;
282
+
283
+ // Clear edit value
284
+ this.editValue = null;
285
+
286
+ if ( ! value || value === this.tempValue ) {
287
+ return;
288
+ }
289
+
290
+ this.$emit('update:modelValue', this.tempValue = value);
291
+ },
292
+
293
+ onDurationpickerInput(value)
294
+ {
295
+ this.focus = false;
296
+
297
+ // Clear edit value
298
+ this.editValue = null;
299
+
300
+ this.$emit('update:modelValue', this.tempValue = value);
301
+ },
302
+
303
+ },
304
+
305
+ renderLabelClear()
306
+ {
307
+ if ( ! this.clearable || ! this.tempValue ) {
308
+ return null;
309
+ }
310
+
311
+ let props = {};
312
+
313
+ if ( ! this.disabled ) {
314
+ props.onMousedown = this.clearDurationpicker;
315
+ }
316
+
317
+ return (
318
+ <div class="n-durationpicker__clear" {...props}>
319
+ <i class={ nano.Icons.times }></i>
320
+ </div>
321
+ );
322
+ },
323
+
324
+ renderLabelAngle()
325
+ {
326
+ return (
327
+ <div class="n-durationpicker__angle">
328
+ <i class={ nano.Icons.angleDown }></i>
329
+ </div>
330
+ );
331
+ },
332
+
333
+ renderInput()
334
+ {
335
+ let props = {
336
+ value: this.humanizeValue(this.tempValue),
337
+ disabled: this.disabled,
338
+ placeholder: this.placeholder,
339
+ onInput: this.onValueInput,
340
+ onBlur: this.onValueChange,
341
+ onChange: this.onValueChange,
342
+ };
343
+
344
+ return (
345
+ <div class="n-durationpicker__input">
346
+ <input {...props}/>
347
+ </div>
348
+ );
349
+ },
350
+
351
+ renderDisplay()
352
+ {
353
+ let classList = [
354
+ 'n-durationpicker__display'
355
+ ];
356
+
357
+ return (
358
+ <div class={classList}>
359
+ { this.ctor('renderLabelClear')() }
360
+ { this.ctor('renderInput')() }
361
+ { this.ctor('renderLabelAngle')() }
362
+ </div>
363
+ );
364
+ },
365
+
366
+ renderItems()
367
+ {
368
+ return Arr.each(this.options, (value) => {
369
+
370
+ let text = this.humanizeValue(value);
371
+
372
+ let optionProps = {
373
+ //
374
+ };
375
+
376
+ optionProps['onClick'] = () => {
377
+ this.onDurationpickerInput(value);
378
+ }
379
+
380
+ return (<NPopoverOption {...optionProps}>{text}</NPopoverOption>)
381
+ });
382
+ },
383
+
384
+ renderPopover()
385
+ {
386
+ let props = {
387
+ trigger: 'click',
388
+ width: -1,
389
+ size: this.size,
390
+ position: this.position,
391
+ scrollClose: true,
392
+ disabled: this.disabled
393
+ };
394
+
395
+ let slots = {};
396
+
397
+ slots.raw = () => {
398
+
399
+ let scrollProps = {
400
+ relative: true, size: this.size
401
+ }
402
+
403
+ return (
404
+ <NScrollbar ref="scrollbar" class="n-durationpicker__body" {...scrollProps}>
405
+ {this.ctor('renderItems')()}
406
+ </NScrollbar>
407
+ )
408
+ }
409
+
410
+ return (
411
+ <NPopover ref="popover" vModel={this.focus} {...props} v-slots={slots} />
412
+ );
413
+ },
414
+
415
+ render()
416
+ {
417
+ let classList = [
418
+ 'n-durationpicker',
419
+ 'n-durationpicker--' + this.type,
420
+ 'n-durationpicker--' + this.size,
421
+ ];
422
+
423
+ if ( ! this.tempValue ) {
424
+ classList.push('n-empty');
425
+ }
426
+
427
+ if ( this.clearable ) {
428
+ classList.push('n-clearable');
429
+ }
430
+
431
+ if ( this.focus ) {
432
+ classList.push('n-focus');
433
+ }
434
+
435
+ if ( this.disabled ) {
436
+ classList.push('n-disabled');
437
+ }
438
+
439
+ return (
440
+ <div class={classList}>
441
+ { this.ctor('renderDisplay')() }
442
+ { this.ctor('renderPopover')() }
443
+ </div>
444
+ );
445
+ }
446
+
447
+ }
@@ -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";
@@ -1,4 +1,4 @@
1
- import { Arr, Obj, Now, Any } from "@kizmann/pico-js";
1
+ import { Arr, Obj, Now, Any, Locale } from "@kizmann/pico-js";
2
2
 
3
3
  export default {
4
4
 
@@ -79,7 +79,7 @@ export default {
79
79
  displayFormat: {
80
80
  default()
81
81
  {
82
- return 'HH:mm:ss';
82
+ return Locale.trans('HH:mm:ss');
83
83
  },
84
84
  type: [String]
85
85
  },
@@ -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";