@afeefa/vue-app 0.0.352 → 0.0.353

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.
@@ -1 +1 @@
1
- 0.0.352
1
+ 0.0.353
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.352",
3
+ "version": "0.0.353",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="timePicker">
2
+ <div :class="['timePicker', {nullable}]">
3
3
  <div :class="['timeInput inputField', {focus: focusHour}]">
4
4
  <div
5
5
  class="up iconButton"
@@ -15,6 +15,7 @@
15
15
  dense
16
16
  outlined
17
17
  hide-details
18
+ placeholder="HH"
18
19
  :error-messages="error ? ['error'] : []"
19
20
  @wheel.prevent="onWheelHour"
20
21
  @focus="focusHour = true"
@@ -50,6 +51,7 @@
50
51
  dense
51
52
  outlined
52
53
  hide-details
54
+ placeholder="MM"
53
55
  :error-messages="error ? ['error'] : []"
54
56
  @wheel.prevent="onWheelMinute"
55
57
  @focus="focusMinute = true"
@@ -65,6 +67,20 @@
65
67
  </a-icon>
66
68
  </div>
67
69
  </div>
70
+
71
+ <div
72
+ v-if="nullable && currentDate"
73
+ class="clear"
74
+ >
75
+ <a-icon
76
+ color="primary"
77
+ class="iconButton"
78
+ title="Zeit löschen"
79
+ @click="clear"
80
+ >
81
+ $closeCircleIcon
82
+ </a-icon>
83
+ </div>
68
84
  </div>
69
85
  </template>
70
86
 
@@ -75,7 +91,7 @@ import formatHour from '@a-vue/utils/format-hour'
75
91
  import formatMinutes from '@a-vue/utils/format-minutes'
76
92
 
77
93
  @Component({
78
- props: ['value', {error: false}]
94
+ props: ['value', {error: false}, {nullable: false}]
79
95
  })
80
96
  export default class ATimePicker extends Vue {
81
97
  currentDate = null
@@ -86,23 +102,48 @@ export default class ATimePicker extends Vue {
86
102
  focusMinute = false
87
103
 
88
104
  created () {
89
- this.currentDate = new Date(this.value)
105
+ this.currentDate = this.toDate(this.value)
90
106
 
91
107
  this.initHourAndMinutes()
92
108
  }
93
109
 
94
110
  @Watch('value')
95
111
  valueChanged () {
112
+ const value = this.toDate(this.value)
113
+
96
114
  // filter out inner changes loop
97
- if (this.value.getTime() === this.currentDate.getTime()) {
115
+ if (value?.getTime() === this.currentDate?.getTime()) {
98
116
  return
99
117
  }
100
118
 
101
- this.currentDate = this.value
119
+ this.currentDate = value
102
120
 
103
121
  this.initHourAndMinutes()
104
122
  }
105
123
 
124
+ // an empty value must not become a date: new Date(null) is the epoch,
125
+ // which renders as 01:00 in any timezone east of UTC
126
+ toDate (value) {
127
+ return value ? new Date(value) : null
128
+ }
129
+
130
+ clear () {
131
+ const hadValue = !!this.currentDate
132
+
133
+ this.currentDate = null
134
+
135
+ this.initHourAndMinutes()
136
+
137
+ if (hadValue) {
138
+ this.$emit('input', null)
139
+ }
140
+ }
141
+
142
+ // a picker without a value starts counting/typing at midnight
143
+ get dateOrMidnight () {
144
+ return this.currentDate || moment().startOf('day').toDate()
145
+ }
146
+
106
147
  onWheelHour (wheelEvent) {
107
148
  if (!this.focusHour) {
108
149
  return
@@ -125,11 +166,18 @@ export default class ATimePicker extends Vue {
125
166
  }
126
167
  }
127
168
 
169
+ // a nullable picker shows its placeholder instead of a made up 00:00
128
170
  get formattedHour () {
171
+ if (!this.currentDate) {
172
+ return this.nullable ? '' : '00'
173
+ }
129
174
  return formatHour(this.currentDate)
130
175
  }
131
176
 
132
177
  get formattedMinutes () {
178
+ if (!this.currentDate) {
179
+ return this.nullable ? '' : '00'
180
+ }
133
181
  return formatMinutes(this.currentDate)
134
182
  }
135
183
 
@@ -159,37 +207,55 @@ export default class ATimePicker extends Vue {
159
207
  }
160
208
 
161
209
  updateHoursAndMinute () {
210
+ this.focusMinute = false
211
+ this.focusHour = false
212
+
213
+ const nothingEntered = !this.currentHour && !this.currentMinutes
214
+
215
+ // clearing both fields is the way back to no time at all
216
+ if (this.nullable) {
217
+ if (nothingEntered) {
218
+ this.clear()
219
+ return
220
+ }
221
+ } else if (!this.currentDate && !Number(this.currentHour) && !Number(this.currentMinutes)) {
222
+ // without a value, mere focussing must not produce a 00:00
223
+ this.initHourAndMinutes()
224
+ return
225
+ }
226
+
227
+ let date = this.dateOrMidnight
228
+
162
229
  if (this.hourValid) {
163
- this.currentDate = moment(this.currentDate).hours(this.currentHour).toDate()
230
+ date = moment(date).hours(this.currentHour).toDate()
164
231
  }
165
232
 
166
233
  if (this.minutesValid) {
167
- this.currentDate = moment(this.currentDate).minutes(this.currentMinutes).toDate()
234
+ date = moment(date).minutes(this.currentMinutes).toDate()
168
235
  }
169
236
 
170
- this.focusMinute = false
171
- this.focusHour = false
237
+ this.currentDate = date
172
238
 
173
239
  this.dispatchDate()
174
240
  }
175
241
 
176
242
  hourUp () {
177
- this.currentDate = moment(this.currentDate).add(1, 'hours').toDate()
243
+ this.currentDate = moment(this.dateOrMidnight).add(1, 'hours').toDate()
178
244
  this.dispatchDate()
179
245
  }
180
246
 
181
247
  hourDown () {
182
- this.currentDate = moment(this.currentDate).subtract(1, 'hours').toDate()
248
+ this.currentDate = moment(this.dateOrMidnight).subtract(1, 'hours').toDate()
183
249
  this.dispatchDate()
184
250
  }
185
251
 
186
252
  minutesUp () {
187
- this.currentDate = moment(this.currentDate).add(15, 'minutes').toDate()
253
+ this.currentDate = moment(this.dateOrMidnight).add(15, 'minutes').toDate()
188
254
  this.dispatchDate()
189
255
  }
190
256
 
191
257
  minutesDown () {
192
- this.currentDate = moment(this.currentDate).subtract(15, 'minutes').toDate()
258
+ this.currentDate = moment(this.dateOrMidnight).subtract(15, 'minutes').toDate()
193
259
  this.dispatchDate()
194
260
  }
195
261
 
@@ -232,6 +298,24 @@ export default class ATimePicker extends Vue {
232
298
  .hourMinutesSeparator {
233
299
  padding: 0 .4em;
234
300
  }
301
+
302
+ // the HH/MM placeholder needs a bit more room than two digits
303
+
304
+ &.nullable .v-input ::v-deep(input) {
305
+ width: 30px;
306
+ }
307
+
308
+ // only present along with a value, so it takes no room while empty
309
+
310
+ .clear {
311
+ display: flex;
312
+ padding-left: .3em;
313
+
314
+ ::v-deep() svg {
315
+ width: 24px;
316
+ height: 24px;
317
+ }
318
+ }
235
319
  }
236
320
 
237
321
  .v-input ::v-deep(input) {