@stonecrop/aform 0.20.0 → 0.22.0

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,285 +1,149 @@
1
1
  <template>
2
- <div class="adate_time">
3
- <div class="adate_time_fields">
4
- <input
5
- v-model="timeData.hours"
6
- type="text"
7
- inputmode="numeric"
8
- @paste="pasteInput($event, true)"
9
- @focus="focusInput"
10
- @blur="confirmTime"
11
- @keydown.enter.prevent="confirmTime"
12
- @keydown.up.prevent="tick('hours')"
13
- @keydown.down.prevent="tick('hours', -1)" />
14
- <span class="colon">:</span>
15
- <input
16
- v-model="timeData.minutes"
17
- type="text"
18
- inputmode="numeric"
19
- @paste="pasteInput"
20
- @focus="focusInput"
21
- @blur="confirmTime"
22
- @keydown.enter.prevent="confirmTime"
23
- @keydown.up.prevent="tick('minutes')"
24
- @keydown.down.prevent="tick('minutes', -1)" />
25
- <span v-if="useSeconds" class="colon">:</span>
2
+ <div class="aform_form-element">
3
+ <template v-if="mode === 'display'">
4
+ <span class="aform_display-value">{{ displayValue }}</span>
5
+ <label class="aform_field-label">{{ label }}</label>
6
+ </template>
7
+
8
+ <template v-else>
26
9
  <input
27
- v-if="useSeconds"
28
- v-model="timeData.seconds"
10
+ :id="uuid"
11
+ class="aform_input-field"
29
12
  type="text"
30
- inputmode="numeric"
31
- @paste="pasteInput"
32
- @focus="focusInput"
33
- @blur="confirmTime"
34
- @keydown.enter.prevent="confirmTime"
35
- @keydown.up.prevent="tick('seconds')"
36
- @keydown.down.prevent="tick('seconds', -1)" />
37
- <select
38
- v-if="!allowMilitaryTime"
39
- ref="meridiem-selector"
40
- v-model="meridiem"
41
- class="aform-select meridiem-selector"
42
- @change="confirmTime">
43
- <option value="AM">AM</option>
44
- <option value="PM">PM</option>
45
- </select>
46
- </div>
13
+ :value="datetimeDisplay"
14
+ placeholder="Select date and time"
15
+ :disabled="mode === 'read'"
16
+ readonly
17
+ @click="openPicker" />
18
+ <label class="aform_field-label" :for="uuid">{{ label }}</label>
19
+
20
+ <p v-show="errorText" class="aform_error" v-html="errorText"></p>
21
+
22
+ <ADateSelection
23
+ v-if="showPicker"
24
+ ref="pickerRef"
25
+ class="adatetime-picker"
26
+ :select-range="false"
27
+ :show-date="true"
28
+ :show-time="true"
29
+ :default-hours="pickerDefaults.hours"
30
+ :default-minutes="pickerDefaults.minutes"
31
+ :default-seconds="pickerDefaults.seconds"
32
+ :default-meridiem="pickerDefaults.meridiem"
33
+ :allow-military-time="allowMilitaryTime"
34
+ :use-seconds="useSeconds"
35
+ @get-date="handleDate"
36
+ @get-time="handleTime" />
37
+ </template>
47
38
  </div>
48
39
  </template>
49
40
 
50
41
  <script setup lang="ts">
51
- import { ref, reactive, useTemplateRef, watch, onMounted } from 'vue'
42
+ import { ref, computed, watch } from 'vue'
43
+ import { onClickOutside } from '@vueuse/core'
44
+ import ADateSelection from './ADateSelection.vue'
45
+ import type { ComponentProps } from '../../types'
52
46
 
53
47
  const {
48
+ label = 'Date & Time',
49
+ mode,
50
+ uuid,
51
+ errors,
52
+ validation = { errorMessage: '' },
54
53
  allowMilitaryTime = false,
55
- defaultHours = 12,
56
- defaultMinutes = 0,
57
- defaultSeconds = 0,
58
- defaultMeridiem = 'AM',
59
54
  useSeconds = true,
60
- } = defineProps<{
61
- allowMilitaryTime?: boolean
62
- defaultHours?: number
63
- defaultMinutes?: number
64
- defaultSeconds?: number
65
- defaultMeridiem?: string
66
- useSeconds?: boolean
67
- }>()
68
-
69
- const emit = defineEmits<{
70
- 'get-time': [{ hours: number; minutes: number; seconds: number; meridiem: string; militaryTime: number }]
71
- }>()
72
-
73
- const meridiemSelector = useTemplateRef<HTMLSelectElement>('meridiem-selector')
74
-
75
- const timeData = reactive({
76
- hours: String(defaultHours).padStart(2, '0'),
77
- minutes: String(defaultMinutes).padStart(2, '0'),
78
- seconds: String(defaultSeconds).padStart(2, '0'),
79
- })
80
-
81
- const meridiem = ref(defaultMeridiem == 'AM' ? 'AM' : 'PM')
82
-
83
- onMounted(() => {
84
- emitTime()
85
- })
86
-
87
- const confirmTime = () => {
88
- const maxHours = allowMilitaryTime ? 23 : 12
89
- const minHours = allowMilitaryTime ? 0 : 1
90
- let hours = Number(timeData.hours)
91
- let minutes = Number(timeData.minutes)
92
- let seconds = Number(timeData.seconds)
55
+ } = defineProps<
56
+ ComponentProps & {
57
+ allowMilitaryTime?: boolean
58
+ useSeconds?: boolean
59
+ }
60
+ >()
93
61
 
94
- if (isNaN(hours) || timeData.hours === '' || hours > maxHours) hours = maxHours
95
- if (!allowMilitaryTime && hours < minHours) hours = minHours
96
- if (isNaN(minutes) || timeData.minutes === '' || minutes > 59) minutes = 59
97
- if (isNaN(seconds) || timeData.seconds === '' || seconds > 59) seconds = 59
62
+ const errorText = computed(() => (errors?.length ? errors.join('; ') : (validation.errorMessage ?? '')))
98
63
 
99
- timeData.hours = String(hours).padStart(2, '0')
100
- timeData.minutes = String(minutes).padStart(2, '0')
101
- timeData.seconds = String(seconds).padStart(2, '0')
64
+ const modelValue = defineModel<string | Date>()
102
65
 
103
- emitTime()
104
- }
66
+ const currentDateTime = ref<Date>(modelValue.value ? new Date(modelValue.value) : new Date())
105
67
 
106
- const emitTime = () => {
107
- const hours = Number(timeData.hours)
108
- const minutes = Number(timeData.minutes)
109
- const seconds = Number(timeData.seconds)
110
- emit('get-time', {
111
- hours,
112
- minutes,
113
- seconds,
114
- meridiem: meridiem.value,
115
- militaryTime: allowMilitaryTime ? hours : meridiem.value === 'PM' ? (hours === 12 ? 12 : hours + 12) : hours % 12,
116
- })
117
- }
68
+ const showPicker = ref(false)
69
+ const pickerRef = ref(null)
70
+ onClickOutside(pickerRef, () => (showPicker.value = false))
118
71
 
119
- const focusInput = (event: FocusEvent) => {
120
- const target = event.target
121
- if (target instanceof HTMLInputElement) {
122
- target.select()
123
- }
72
+ const openPicker = () => {
73
+ if (mode !== 'read') showPicker.value = true
124
74
  }
125
75
 
126
- const tick = (target: 'hours' | 'minutes' | 'seconds', amount = 1) => {
127
- const maxHours = allowMilitaryTime ? 23 : 12
128
- const minHours = allowMilitaryTime ? 0 : 1
129
-
130
- if (target == 'hours') {
131
- const oldHours = Number(timeData.hours)
132
- timeData.hours = String(oldHours + amount)
133
- if ((oldHours == 11 && Number(timeData.hours) == 12) || (oldHours == 12 && Number(timeData.hours) == 11)) {
134
- changeMeridiem()
135
- }
136
- } else if (target == 'minutes') {
137
- timeData.minutes = String(Number(timeData.minutes) + amount)
138
- } else if (target == 'seconds') {
139
- timeData.seconds = String(Number(timeData.seconds) + amount)
140
- }
141
-
142
- const prevHours = Number(timeData.hours)
143
-
144
- if (Number(timeData.seconds) < 0) timeData.minutes = String(Number(timeData.minutes) - 1)
145
- else if (Number(timeData.seconds) > 59) timeData.minutes = String(Number(timeData.minutes) + 1)
146
-
147
- if (Number(timeData.minutes) < 0) timeData.hours = String(prevHours - 1)
148
- else if (Number(timeData.minutes) > 59) timeData.hours = String(prevHours + 1)
76
+ const displayValue = computed(() => {
77
+ if (!modelValue.value) return ''
78
+ return currentDateTime.value.toLocaleString()
79
+ })
149
80
 
150
- const newRawHours = Number(timeData.hours)
151
- if (!allowMilitaryTime && newRawHours !== prevHours) {
152
- if ((prevHours === 11 && newRawHours === 12) || (prevHours === 12 && newRawHours === 11)) {
153
- changeMeridiem()
154
- }
81
+ const datetimeDisplay = computed(() => displayValue.value)
82
+
83
+ const pickerDefaults = computed(() => {
84
+ const d = currentDateTime.value
85
+ const hours24 = d.getHours()
86
+ const meridiem = hours24 >= 12 ? 'PM' : 'AM'
87
+ const hours12 = hours24 % 12 || 12
88
+ return {
89
+ hours: allowMilitaryTime ? hours24 : hours12,
90
+ minutes: d.getMinutes(),
91
+ seconds: d.getSeconds(),
92
+ meridiem,
155
93
  }
94
+ })
156
95
 
157
- timeData.hours = String(formatTime(Number(timeData.hours), minHours, maxHours)).padStart(2, '0')
158
- timeData.minutes = String(formatTime(Number(timeData.minutes), 0, 59)).padStart(2, '0')
159
- timeData.seconds = String(formatTime(Number(timeData.seconds), 0, 59)).padStart(2, '0')
96
+ const emitModel = () => {
97
+ modelValue.value = currentDateTime.value.toISOString()
98
+ }
99
+
100
+ const handleDate = (data: { selected: Date }) => {
101
+ const next = new Date(currentDateTime.value)
102
+ next.setFullYear(data.selected.getFullYear(), data.selected.getMonth(), data.selected.getDate())
103
+ currentDateTime.value = next
104
+ emitModel()
105
+ }
106
+
107
+ const handleTime = (data: {
108
+ hours: number
109
+ minutes: number
110
+ seconds: number
111
+ meridiem: string
112
+ militaryTime?: number
113
+ source?: 'init' | 'user'
114
+ }) => {
115
+ // The widget announces its own starting value as it mounts, and those defaults come from
116
+ // `pickerDefaults` — i.e. straight back out of this component. Writing that echo to the model
117
+ // meant one click on an empty field silently filled it with the current date and time.
118
+ if (data.source === 'init') return
119
+
120
+ const next = new Date(currentDateTime.value)
121
+ const hours = data.militaryTime ?? data.hours
122
+ next.setHours(hours, data.minutes, useSeconds ? data.seconds : 0, 0)
123
+ currentDateTime.value = next
124
+ emitModel()
125
+ // Deliberately does NOT close the picker. `get-time` is the widget's current value, not a
126
+ // commit — it fires on every blur, arrow key and meridiem change — so closing here shut the
127
+ // picker as soon as the user tabbed out of the hours field. Dismissal is the click-outside
128
+ // handler above; closing on `get-date` instead would strand the time half of a datetime.
160
129
  }
161
130
 
162
131
  watch(
163
- () => timeData.hours,
164
- (newVal, oldVal) => {
165
- timeData.hours = Number(newVal) > 99 ? oldVal : newVal
166
- }
167
- )
168
- watch(
169
- () => timeData.minutes,
170
- (newVal, oldVal) => {
171
- timeData.minutes = Number(newVal) > 99 ? oldVal : newVal
172
- }
173
- )
174
- watch(
175
- () => timeData.seconds,
176
- (newVal, oldVal) => {
177
- timeData.seconds = Number(newVal) > 99 ? oldVal : newVal
178
- }
179
- )
180
-
181
- const formatTime = (target: number, min: number, max: number): number => {
182
- if (target > max) return min
183
- else if (target < min) return max
184
- return target
185
- }
186
-
187
- const changeMeridiem = () => {
188
- meridiem.value = meridiem.value == 'PM' ? 'AM' : 'PM'
189
- emitTime()
190
- }
191
-
192
- const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => {
193
- event.stopPropagation()
194
- event.preventDefault()
195
-
196
- const clipboardData = event.clipboardData
197
- if (!clipboardData) return
198
- let pastedData: string = clipboardData.getData('Text')
199
-
200
- pastedData = pastedData.replace(/[^0-9]/g, '')
201
-
202
- if (pasteAllFields) {
203
- if (pastedData.length % 2 != 0) pastedData = '0' + pastedData
204
- if (pastedData.length < 3) pastedData += '00'
205
- if (pastedData.length < 5) pastedData += '00'
206
-
207
- const timeUnits = pastedData.match(/(..?)/g)
208
- if (!timeUnits || timeUnits.length < 3) return
209
-
210
- timeData.seconds = timeUnits[2]
211
- timeData.minutes = timeUnits[1]
212
- timeData.hours = timeUnits[0]
213
- confirmTime()
214
- if (!allowMilitaryTime) meridiemSelector.value?.focus()
215
- } else {
216
- if (pastedData.length > 2) pastedData = pastedData.slice(0, 2)
217
- const target = event.target
218
- if (target instanceof HTMLInputElement) {
219
- target.value = pastedData
220
- target.dispatchEvent(new Event('input'))
132
+ () => modelValue.value,
133
+ newValue => {
134
+ if (newValue) {
135
+ currentDateTime.value = new Date(newValue)
221
136
  }
222
137
  }
223
- }
138
+ )
224
139
  </script>
225
140
 
226
141
  <style scoped>
227
- .adate_time {
228
- width: auto;
229
- padding: 10px;
230
- box-sizing: border-box;
231
- font-size: 1rem;
232
- background: var(--sc-gray-10);
233
- }
234
- .adate_time_fields {
235
- display: flex;
236
- align-items: stretch;
237
- gap: 5px;
238
- justify-content: flex-start;
239
- }
240
- .adate_time_fields > input {
241
- min-width: 30px;
242
- padding: 2px;
243
- text-align: center;
244
- display: inline-block;
245
- flex-basis: 0;
246
- }
247
- .meridiem-selector {
248
- cursor: pointer;
249
- display: inline-block;
250
- flex-basis: 0;
251
- padding: 5px;
252
- user-select: none;
253
- }
254
- .meridiem-selector:focus {
255
- outline: 2px solid black;
256
- outline-offset: -2px;
257
- }
258
- .adate_time_segment {
259
- display: flex;
260
- flex-direction: column;
261
- width: 40px;
262
- }
263
- .colon {
264
- display: flex;
265
- align-items: normal;
266
- }
267
- .aform_form-btn {
268
- cursor: pointer;
269
- }
270
- .aform-select {
271
- border-radius: 0px;
272
- border: 1px solid rgb(118, 118, 118);
273
- font-size: 1rem;
274
- padding: 0rem;
275
- margin: 0;
276
- border-radius: 0;
277
- box-sizing: border-box;
278
- min-height: auto;
279
- position: relative;
280
- color: var(--sc-cell-text-color);
281
- }
282
- .meridiem-selector {
283
- margin-left: 6px;
142
+ .adatetime-picker {
143
+ position: absolute;
144
+ top: 100%;
145
+ left: 0;
146
+ z-index: 1000;
147
+ margin-top: 0.25rem;
284
148
  }
285
149
  </style>
@@ -0,0 +1,299 @@
1
+ <template>
2
+ <div class="adate_time">
3
+ <div class="adate_time_fields">
4
+ <input
5
+ v-model="timeData.hours"
6
+ type="text"
7
+ inputmode="numeric"
8
+ @paste="pasteInput($event, true)"
9
+ @focus="focusInput"
10
+ @blur="confirmTime"
11
+ @keydown.enter.prevent="confirmTime"
12
+ @keydown.up.prevent="tick('hours')"
13
+ @keydown.down.prevent="tick('hours', -1)" />
14
+ <span class="colon">:</span>
15
+ <input
16
+ v-model="timeData.minutes"
17
+ type="text"
18
+ inputmode="numeric"
19
+ @paste="pasteInput"
20
+ @focus="focusInput"
21
+ @blur="confirmTime"
22
+ @keydown.enter.prevent="confirmTime"
23
+ @keydown.up.prevent="tick('minutes')"
24
+ @keydown.down.prevent="tick('minutes', -1)" />
25
+ <span v-if="useSeconds" class="colon">:</span>
26
+ <input
27
+ v-if="useSeconds"
28
+ v-model="timeData.seconds"
29
+ type="text"
30
+ inputmode="numeric"
31
+ @paste="pasteInput"
32
+ @focus="focusInput"
33
+ @blur="confirmTime"
34
+ @keydown.enter.prevent="confirmTime"
35
+ @keydown.up.prevent="tick('seconds')"
36
+ @keydown.down.prevent="tick('seconds', -1)" />
37
+ <select
38
+ v-if="!allowMilitaryTime"
39
+ ref="meridiem-selector"
40
+ v-model="meridiem"
41
+ class="aform-select meridiem-selector"
42
+ @change="confirmTime">
43
+ <option value="AM">AM</option>
44
+ <option value="PM">PM</option>
45
+ </select>
46
+ </div>
47
+ </div>
48
+ </template>
49
+
50
+ <script setup lang="ts">
51
+ import { ref, reactive, useTemplateRef, watch, onMounted } from 'vue'
52
+
53
+ const {
54
+ allowMilitaryTime = false,
55
+ defaultHours = 12,
56
+ defaultMinutes = 0,
57
+ defaultSeconds = 0,
58
+ defaultMeridiem = 'AM',
59
+ useSeconds = true,
60
+ } = defineProps<{
61
+ allowMilitaryTime?: boolean
62
+ defaultHours?: number
63
+ defaultMinutes?: number
64
+ defaultSeconds?: number
65
+ defaultMeridiem?: string
66
+ useSeconds?: boolean
67
+ }>()
68
+
69
+ // `get-time` carries the widget's CURRENT VALUE, not a commit: it fires once as the widget
70
+ // mounts and again on every blur, Enter, arrow key and meridiem change — five times during one
71
+ // ordinary edit. `source` is what lets a parent tell the start-up announcement apart from a real
72
+ // user edit; without it a parent has nothing to key on and must guess from the value alone.
73
+ const emit = defineEmits<{
74
+ 'get-time': [
75
+ {
76
+ hours: number
77
+ minutes: number
78
+ seconds: number
79
+ meridiem: string
80
+ militaryTime: number
81
+ source: 'init' | 'user'
82
+ },
83
+ ]
84
+ }>()
85
+
86
+ const meridiemSelector = useTemplateRef<HTMLSelectElement>('meridiem-selector')
87
+
88
+ const timeData = reactive({
89
+ hours: String(defaultHours).padStart(2, '0'),
90
+ minutes: String(defaultMinutes).padStart(2, '0'),
91
+ seconds: String(defaultSeconds).padStart(2, '0'),
92
+ })
93
+
94
+ const meridiem = ref(defaultMeridiem == 'AM' ? 'AM' : 'PM')
95
+
96
+ onMounted(() => {
97
+ emitTime('init')
98
+ })
99
+
100
+ const confirmTime = () => {
101
+ const maxHours = allowMilitaryTime ? 23 : 12
102
+ const minHours = allowMilitaryTime ? 0 : 1
103
+ let hours = Number(timeData.hours)
104
+ let minutes = Number(timeData.minutes)
105
+ let seconds = Number(timeData.seconds)
106
+
107
+ if (isNaN(hours) || timeData.hours === '' || hours > maxHours) hours = maxHours
108
+ if (!allowMilitaryTime && hours < minHours) hours = minHours
109
+ if (isNaN(minutes) || timeData.minutes === '' || minutes > 59) minutes = 59
110
+ if (isNaN(seconds) || timeData.seconds === '' || seconds > 59) seconds = 59
111
+
112
+ timeData.hours = String(hours).padStart(2, '0')
113
+ timeData.minutes = String(minutes).padStart(2, '0')
114
+ timeData.seconds = String(seconds).padStart(2, '0')
115
+
116
+ emitTime('user')
117
+ }
118
+
119
+ const emitTime = (source: 'init' | 'user') => {
120
+ const hours = Number(timeData.hours)
121
+ const minutes = Number(timeData.minutes)
122
+ const seconds = Number(timeData.seconds)
123
+ emit('get-time', {
124
+ hours,
125
+ minutes,
126
+ seconds,
127
+ source,
128
+ meridiem: meridiem.value,
129
+ militaryTime: allowMilitaryTime ? hours : meridiem.value === 'PM' ? (hours === 12 ? 12 : hours + 12) : hours % 12,
130
+ })
131
+ }
132
+
133
+ const focusInput = (event: FocusEvent) => {
134
+ const target = event.target
135
+ if (target instanceof HTMLInputElement) {
136
+ target.select()
137
+ }
138
+ }
139
+
140
+ const tick = (target: 'hours' | 'minutes' | 'seconds', amount = 1) => {
141
+ const maxHours = allowMilitaryTime ? 23 : 12
142
+ const minHours = allowMilitaryTime ? 0 : 1
143
+
144
+ if (target == 'hours') {
145
+ const oldHours = Number(timeData.hours)
146
+ timeData.hours = String(oldHours + amount)
147
+ if ((oldHours == 11 && Number(timeData.hours) == 12) || (oldHours == 12 && Number(timeData.hours) == 11)) {
148
+ changeMeridiem()
149
+ }
150
+ } else if (target == 'minutes') {
151
+ timeData.minutes = String(Number(timeData.minutes) + amount)
152
+ } else if (target == 'seconds') {
153
+ timeData.seconds = String(Number(timeData.seconds) + amount)
154
+ }
155
+
156
+ const prevHours = Number(timeData.hours)
157
+
158
+ if (Number(timeData.seconds) < 0) timeData.minutes = String(Number(timeData.minutes) - 1)
159
+ else if (Number(timeData.seconds) > 59) timeData.minutes = String(Number(timeData.minutes) + 1)
160
+
161
+ if (Number(timeData.minutes) < 0) timeData.hours = String(prevHours - 1)
162
+ else if (Number(timeData.minutes) > 59) timeData.hours = String(prevHours + 1)
163
+
164
+ const newRawHours = Number(timeData.hours)
165
+ if (!allowMilitaryTime && newRawHours !== prevHours) {
166
+ if ((prevHours === 11 && newRawHours === 12) || (prevHours === 12 && newRawHours === 11)) {
167
+ changeMeridiem()
168
+ }
169
+ }
170
+
171
+ timeData.hours = String(formatTime(Number(timeData.hours), minHours, maxHours)).padStart(2, '0')
172
+ timeData.minutes = String(formatTime(Number(timeData.minutes), 0, 59)).padStart(2, '0')
173
+ timeData.seconds = String(formatTime(Number(timeData.seconds), 0, 59)).padStart(2, '0')
174
+ }
175
+
176
+ watch(
177
+ () => timeData.hours,
178
+ (newVal, oldVal) => {
179
+ timeData.hours = Number(newVal) > 99 ? oldVal : newVal
180
+ }
181
+ )
182
+ watch(
183
+ () => timeData.minutes,
184
+ (newVal, oldVal) => {
185
+ timeData.minutes = Number(newVal) > 99 ? oldVal : newVal
186
+ }
187
+ )
188
+ watch(
189
+ () => timeData.seconds,
190
+ (newVal, oldVal) => {
191
+ timeData.seconds = Number(newVal) > 99 ? oldVal : newVal
192
+ }
193
+ )
194
+
195
+ const formatTime = (target: number, min: number, max: number): number => {
196
+ if (target > max) return min
197
+ else if (target < min) return max
198
+ return target
199
+ }
200
+
201
+ const changeMeridiem = () => {
202
+ meridiem.value = meridiem.value == 'PM' ? 'AM' : 'PM'
203
+ emitTime('user')
204
+ }
205
+
206
+ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => {
207
+ event.stopPropagation()
208
+ event.preventDefault()
209
+
210
+ const clipboardData = event.clipboardData
211
+ if (!clipboardData) return
212
+ let pastedData: string = clipboardData.getData('Text')
213
+
214
+ pastedData = pastedData.replace(/[^0-9]/g, '')
215
+
216
+ if (pasteAllFields) {
217
+ if (pastedData.length % 2 != 0) pastedData = '0' + pastedData
218
+ if (pastedData.length < 3) pastedData += '00'
219
+ if (pastedData.length < 5) pastedData += '00'
220
+
221
+ const timeUnits = pastedData.match(/(..?)/g)
222
+ if (!timeUnits || timeUnits.length < 3) return
223
+
224
+ timeData.seconds = timeUnits[2]
225
+ timeData.minutes = timeUnits[1]
226
+ timeData.hours = timeUnits[0]
227
+ confirmTime()
228
+ if (!allowMilitaryTime) meridiemSelector.value?.focus()
229
+ } else {
230
+ if (pastedData.length > 2) pastedData = pastedData.slice(0, 2)
231
+ const target = event.target
232
+ if (target instanceof HTMLInputElement) {
233
+ target.value = pastedData
234
+ target.dispatchEvent(new Event('input'))
235
+ }
236
+ }
237
+ }
238
+ </script>
239
+
240
+ <style scoped>
241
+ .adate_time {
242
+ width: auto;
243
+ padding: 10px;
244
+ box-sizing: border-box;
245
+ font-size: 1rem;
246
+ background: var(--sc-gray-10);
247
+ }
248
+ .adate_time_fields {
249
+ display: flex;
250
+ align-items: stretch;
251
+ gap: 5px;
252
+ justify-content: flex-start;
253
+ }
254
+ .adate_time_fields > input {
255
+ min-width: 30px;
256
+ padding: 2px;
257
+ text-align: center;
258
+ display: inline-block;
259
+ flex-basis: 0;
260
+ }
261
+ .meridiem-selector {
262
+ cursor: pointer;
263
+ display: inline-block;
264
+ flex-basis: 0;
265
+ padding: 5px;
266
+ user-select: none;
267
+ }
268
+ .meridiem-selector:focus {
269
+ outline: 2px solid black;
270
+ outline-offset: -2px;
271
+ }
272
+ .adate_time_segment {
273
+ display: flex;
274
+ flex-direction: column;
275
+ width: 40px;
276
+ }
277
+ .colon {
278
+ display: flex;
279
+ align-items: normal;
280
+ }
281
+ .aform_form-btn {
282
+ cursor: pointer;
283
+ }
284
+ .aform-select {
285
+ border-radius: 0px;
286
+ border: 1px solid rgb(118, 118, 118);
287
+ font-size: 1rem;
288
+ padding: 0rem;
289
+ margin: 0;
290
+ border-radius: 0;
291
+ box-sizing: border-box;
292
+ min-height: auto;
293
+ position: relative;
294
+ color: var(--sc-cell-text-color);
295
+ }
296
+ .meridiem-selector {
297
+ margin-left: 6px;
298
+ }
299
+ </style>