From 25cc2d05ff8873930d9e5f8a12d137c85c47c57d Mon Sep 17 00:00:00 2001 From: curt Date: Sun, 12 Oct 2025 22:07:50 -0500 Subject: [PATCH 01/13] added range selection option to ADatePicker --- aform/src/components/form/ADatePicker.vue | 154 ++++++++++++++++-- .../autoinstallers/doc-tools/pnpm-lock.yaml | 16 +- examples/aform/date.story.vue | 3 + 3 files changed, 155 insertions(+), 18 deletions(-) diff --git a/aform/src/components/form/ADatePicker.vue b/aform/src/components/form/ADatePicker.vue index b4659682b..c28fceff6 100644 --- a/aform/src/components/form/ADatePicker.vue +++ b/aform/src/components/form/ADatePicker.vue @@ -7,6 +7,17 @@ {{ monthAndYear }} > + + +
+ +
-
+ + +
+ + + M T @@ -22,15 +33,20 @@ v-for="colNo in numberOfColumns" ref="celldate" :key="getCurrentCell(rowNo, colNo)" + class="date-cell" :contenteditable="false" :spellcheck="false" :tabindex="0" :class="{ todaysDate: isTodaysDate(getCurrentDate(rowNo, colNo)), selectedDate: isSelectedDate(getCurrentDate(rowNo, colNo)), + withinRange: selectRange ? isInDateRange(getCurrentDate(rowNo, colNo)) : false, + startDate: selectRange ? isStartDate(getCurrentDate(rowNo, colNo)) : false, + endDate: selectRange ? isEndDate(getCurrentDate(rowNo, colNo)) : false, }" @click.prevent.stop="selectDate(getCurrentCell(rowNo, colNo))" - @keydown.enter="selectDate(getCurrentCell(rowNo, colNo))"> + @keydown.enter="selectDate(getCurrentCell(rowNo, colNo))" + @mouseover="hoverDate(getCurrentCell(rowNo, colNo))"> {{ new Date(getCurrentDate(rowNo, colNo)).getDate() }} @@ -41,7 +57,7 @@ diff --git a/common/autoinstallers/doc-tools/pnpm-lock.yaml b/common/autoinstallers/doc-tools/pnpm-lock.yaml index a18435250..7ea670c95 100644 --- a/common/autoinstallers/doc-tools/pnpm-lock.yaml +++ b/common/autoinstallers/doc-tools/pnpm-lock.yaml @@ -56,8 +56,8 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fs-extra@11.3.0: - resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} engines: {node: '>=14.14'} function-bind@1.1.2: @@ -84,8 +84,8 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} @@ -150,7 +150,7 @@ snapshots: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) ajv-formats: 3.0.1(ajv@8.13.0) - fs-extra: 11.3.0 + fs-extra: 11.3.2 import-lazy: 4.0.0 jju: 1.4.0 resolve: 1.22.10 @@ -180,10 +180,10 @@ snapshots: fast-deep-equal@3.1.3: {} - fs-extra@11.3.0: + fs-extra@11.3.2: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 function-bind@1.1.2: {} @@ -204,7 +204,7 @@ snapshots: json-schema-traverse@1.0.0: {} - jsonfile@6.1.0: + jsonfile@6.2.0: dependencies: universalify: 2.0.1 optionalDependencies: diff --git a/examples/aform/date.story.vue b/examples/aform/date.story.vue index c11bb11af..854b85c54 100644 --- a/examples/aform/date.story.vue +++ b/examples/aform/date.story.vue @@ -4,6 +4,9 @@

Default Date

+

Date with Range Selection

+ +

Custom Date

From 3765a94b3cfdf444f2bc8984134d73b98e8e1c35 Mon Sep 17 00:00:00 2001 From: curt Date: Tue, 21 Oct 2025 13:34:15 -0500 Subject: [PATCH 02/13] updated picker range to swap dates when picking earlier date when clicking --- aform/src/components/form/ADatePicker.vue | 54 ++++++++++++++--------- examples/aform/date.story.vue | 6 +-- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/aform/src/components/form/ADatePicker.vue b/aform/src/components/form/ADatePicker.vue index c28fceff6..c92d44f10 100644 --- a/aform/src/components/form/ADatePicker.vue +++ b/aform/src/components/form/ADatePicker.vue @@ -10,10 +10,20 @@
- +
-
- - + +
@@ -187,15 +197,13 @@ const getCurrentCell = (rowNo: number, colNo: number) => { const isInDateRange = (day: string | number | Date) => { //apply the withinRange class to all days within the selected range - const this_date = new Date(day) - const start_date = new Date(selectedDateRange.start_date) - const end_date = - selectedDateRange.end_date != null ? new Date(selectedDateRange.end_date) : new Date(hoveredDate.value) + let start_date = new Date(selectedDateRange.start_date) + let end_date = selectedDateRange.end_date != null ? new Date(selectedDateRange.end_date) : new Date(hoveredDate.value) + + if (start_date.getTime() > end_date.getTime()) [start_date, end_date] = [end_date, start_date] - if (selectedDateRange.start_date != null) - return this_date.getTime() > start_date.getTime() && this_date.getTime() < end_date.getTime() - return false + return this_date.getTime() > start_date.getTime() && this_date.getTime() < end_date.getTime() } const getCurrentDate = (rowNo: number, colNo: number) => { @@ -207,27 +215,26 @@ const hoverDate = (currentIndex: number) => { const selectDate = (currentIndex: number) => { date.value = selectedDate.value = new Date(currentDates.value[currentIndex]) - //If selectRange prop is set to true, set range start and end points on selection - if (props.selectRange) { - if ( - selectedDateRange.start_date == null || - selectedDateRange.end_date != null || - selectedDate.value.getTime() < selectedDateRange.start_date.getTime() - ) { + if (selectedDateRange.start_date == null || selectedDateRange.end_date != null) { selectedDateRange.start_date = date.value selectedDateRange.end_date = null - startDateInput.value = parseDateToString(date.value) + } else if (selectedDate.value.getTime() < selectedDateRange.start_date.getTime()) { + //set it as the start date and swap them + selectedDateRange.end_date = selectedDateRange.start_date + selectedDateRange.start_date = date.value } else { selectedDateRange.end_date = date.value - endDateInput.value = parseDateToString(date.value) } } + + startDateInput.value = parseDateToString(selectedDateRange.start_date) + endDateInput.value = parseDateToString(selectedDateRange.end_date) } const parseDateToString = (date: Date) => { let date_string = '' - if (!date.getTime()) { + if (date == null || !date.getTime()) { return '' } date_string += date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear() @@ -240,6 +247,9 @@ const monthAndYear = computed(() => { month: 'long', }) }) +const enterDate = event => { + if (event.key === 'Enter') applyDates() +} // setup keyboard navigation useKeyboardNav([ @@ -340,8 +350,12 @@ defineExpose({ currentMonth, currentYear, selectedDate, selectedDateRange }) display: flex; width: 100%; gap: 5px; + align-items: center; } .adatepicker .date-input > input { width: 50%; + padding: 2px; +} +.date-input-button { } diff --git a/examples/aform/date.story.vue b/examples/aform/date.story.vue index 854b85c54..42d377c56 100644 --- a/examples/aform/date.story.vue +++ b/examples/aform/date.story.vue @@ -1,12 +1,12 @@ From 1d58d0150360b4b0ff8b29ec5fb7f48962c8f982 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Thu, 23 Apr 2026 16:25:20 +0530 Subject: [PATCH 13/13] fix: replace adatetime input from number to text for accessibiity --- aform/src/components/form/ADateTime.vue | 122 ++++++++++-------------- aform/tests/date.spec.ts | 27 +++++- aform/tests/datetime.spec.ts | 68 ++++++------- 3 files changed, 110 insertions(+), 107 deletions(-) diff --git a/aform/src/components/form/ADateTime.vue b/aform/src/components/form/ADateTime.vue index 93c2fc2c3..a0a7b6ed1 100644 --- a/aform/src/components/form/ADateTime.vue +++ b/aform/src/components/form/ADateTime.vue @@ -2,8 +2,9 @@
: : () /* Template Refs */ const meridiemSelector = useTemplateRef('meridiem-selector') -/* Actual time values held for each time unit */ +/* Display values held as formatted strings */ const time_data = reactive({ - hours: defaultHours, - minutes: defaultMinutes, - seconds: defaultSeconds, + hours: String(defaultHours).padStart(2, '0'), + minutes: String(defaultMinutes).padStart(2, '0'), + seconds: String(defaultSeconds).padStart(2, '0'), }) const meridiem = ref(defaultMeridiem == 'AM' ? 'AM' : 'PM') onMounted(() => { - // emit default values on mount emitTime() }) -/* Sets the time_data to match the input fields, called on blur or Enter, can set sendEmit to false to prevent emiting the time data */ -const confirmTime = (sendEmit = true) => { +/* Called on blur, Enter, or change — validates, re-pads display strings, and emits */ +const confirmTime = () => { const maxHours = allowMilitaryTime ? 23 : 12 - if (time_data.hours > maxHours || time_data.hours === '') time_data.hours = maxHours - if (time_data.minutes > 59 || time_data.minutes === '') time_data.minutes = 59 - if (time_data.seconds > 59 || time_data.seconds === '') time_data.seconds = 59 - padString() - if (sendEmit) emitTime() + let hours = Number(time_data.hours) + let minutes = Number(time_data.minutes) + let seconds = Number(time_data.seconds) + + if (isNaN(hours) || time_data.hours === '' || hours > maxHours) hours = maxHours + if (isNaN(minutes) || time_data.minutes === '' || minutes > 59) minutes = 59 + if (isNaN(seconds) || time_data.seconds === '' || seconds > 59) seconds = 59 + + time_data.hours = String(hours).padStart(2, '0') + time_data.minutes = String(minutes).padStart(2, '0') + time_data.seconds = String(seconds).padStart(2, '0') + + emitTime() } -/* on emit, format the time_data to a generic object */ +/* Emit numeric time data */ const emitTime = () => { const hours = Number(time_data.hours) const minutes = Number(time_data.minutes) @@ -110,13 +120,6 @@ const emitTime = () => { }) } -/* pad the time strings with leading 0's if they are less than 10 */ -const padString = () => { - for (const str of ['hours', 'minutes', 'seconds'] as const) { - time_data[str] = String(time_data[str]).padStart(2, '0') - } -} - const focusInput = (event: FocusEvent) => { const target = event.target if (target instanceof HTMLInputElement) { @@ -130,40 +133,44 @@ const tick = (target: 'hours' | 'minutes' | 'seconds', amount = 1) => { if (target == 'hours') { const oldHours = Number(time_data.hours) - time_data.hours = oldHours + amount - if ((oldHours == 11 && time_data.hours == 12) || (oldHours == 12 && time_data.hours == 11)) changeMeridiem() - } else if (target == 'minutes') time_data.minutes = Number(time_data.minutes) + amount - else if (target == 'seconds') time_data.seconds = Number(time_data.seconds) + amount + time_data.hours = String(oldHours + amount) + if ((oldHours == 11 && Number(time_data.hours) == 12) || (oldHours == 12 && Number(time_data.hours) == 11)) { + changeMeridiem() + } + } else if (target == 'minutes') { + time_data.minutes = String(Number(time_data.minutes) + amount) + } else if (target == 'seconds') { + time_data.seconds = String(Number(time_data.seconds) + amount) + } - if (time_data.seconds < 0) time_data.minutes-- - else if (time_data.seconds > 59) time_data.minutes++ - if (time_data.minutes < 0) time_data.hours-- - else if (time_data.minutes > 59) time_data.hours++ + if (Number(time_data.seconds) < 0) time_data.minutes = String(Number(time_data.minutes) - 1) + else if (Number(time_data.seconds) > 59) time_data.minutes = String(Number(time_data.minutes) + 1) - time_data.hours = formatTime(Number(time_data.hours), minHours, maxHours) - time_data.minutes = formatTime(Number(time_data.minutes), 0, 59) - time_data.seconds = formatTime(Number(time_data.seconds), 0, 59) + if (Number(time_data.minutes) < 0) time_data.hours = String(Number(time_data.hours) - 1) + else if (Number(time_data.minutes) > 59) time_data.hours = String(Number(time_data.hours) + 1) - padString() + time_data.hours = String(formatTime(Number(time_data.hours), minHours, maxHours)).padStart(2, '0') + time_data.minutes = String(formatTime(Number(time_data.minutes), 0, 59)).padStart(2, '0') + time_data.seconds = String(formatTime(Number(time_data.seconds), 0, 59)).padStart(2, '0') } -/* Watchers */ +/* Watchers — prevent more than two digits while typing */ watch( () => time_data.hours, (newVal, oldVal) => { - time_data.hours = newVal > 99 ? oldVal : newVal + time_data.hours = Number(newVal) > 99 ? oldVal : newVal } ) watch( () => time_data.minutes, (newVal, oldVal) => { - time_data.minutes = newVal > 99 ? oldVal : newVal + time_data.minutes = Number(newVal) > 99 ? oldVal : newVal } ) watch( () => time_data.seconds, (newVal, oldVal) => { - time_data.seconds = newVal > 99 ? oldVal : newVal + time_data.seconds = Number(newVal) > 99 ? oldVal : newVal } ) @@ -179,8 +186,6 @@ const changeMeridiem = () => { } const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { - //pasteAllFields will apply the paste effect to all input fields, should only be used on the first field/hour - event.stopPropagation() event.preventDefault() @@ -199,9 +204,9 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { const time_units = pastedData.match(/(..?)/g) if (!time_units) return - time_data.seconds = Number(time_units[2]) - time_data.minutes = Number(time_units[1]) - time_data.hours = Number(time_units[0]) + time_data.seconds = time_units[2] + time_data.minutes = time_units[1] + time_data.hours = time_units[0] confirmTime() if (!allowMilitaryTime) meridiemSelector.value?.focus() } else { @@ -209,7 +214,6 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { const target = event.target if (target instanceof HTMLInputElement) { target.value = pastedData - //manually call the input event to force v-model update target.dispatchEvent(new Event('input')) } } @@ -224,14 +228,12 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { font-size: 1rem; background: var(--sc-gray-10); } - .adate_time_fields { display: flex; align-items: stretch; gap: 5px; justify-content: flex-start; } - .adate_time_fields > input { min-width: 30px; padding: 2px; @@ -239,7 +241,6 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { display: inline-block; flex-basis: 0; } - .meridiem-selector { cursor: pointer; display: inline-block; @@ -247,27 +248,22 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { padding: 5px; user-select: none; } - .meridiem-selector:focus { outline: 2px solid black; outline-offset: -2px; } - .adate_time_segment { display: flex; flex-direction: column; width: 40px; } - .colon { display: flex; align-items: normal; } - .aform_form-btn { cursor: pointer; } - .aform-select { border-radius: 0px; border: 1px solid rgb(118, 118, 118); @@ -280,19 +276,7 @@ const pasteInput = (event: ClipboardEvent, pasteAllFields = false) => { position: relative; color: var(--sc-cell-text-color); } - .meridiem-selector { margin-left: 6px; } - -input[type='number']::-webkit-outer-spin-button, -input[type='number']::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -input[type='number'] { - -moz-appearance: textfield; - appearance: textfield; -} diff --git a/aform/tests/date.spec.ts b/aform/tests/date.spec.ts index 9509605bb..72092fb0b 100644 --- a/aform/tests/date.spec.ts +++ b/aform/tests/date.spec.ts @@ -2,10 +2,23 @@ import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import ADate from '../src/components/form/ADate.vue' +import ADateSelection from '../src/components/form/ADateSelection.vue' +import ADatePicker from '../src/components/form/ADatePicker.vue' +import ADateTime from '../src/components/form/ADateTime.vue' + +const globalComponents = { + global: { + components: { + ADateSelection, + ADatePicker, + ADateTime, + }, + }, +} describe('date component', () => { it('date input is rendered', async () => { - const wrapper = mount(ADate) + const wrapper = mount(ADate, globalComponents) const $input = wrapper.find('input') expect($input.exists()).toBe(true) expect($input.attributes('type')).toBe('date') @@ -13,6 +26,7 @@ describe('date component', () => { it('date input is rendered with value', async () => { const wrapper = mount(ADate, { + ...globalComponents, props: { modelValue: '2021-01-01', }, @@ -24,6 +38,7 @@ describe('date component', () => { it('date input is disabled by default', async () => { const wrapper = mount(ADate, { + ...globalComponents, props: { mode: 'read', }, @@ -34,7 +49,7 @@ describe('date component', () => { }) it('date input is required', async () => { - const wrapper = mount(ADate) + const wrapper = mount(ADate, globalComponents) const $input = wrapper.find('input') // TODO: setup environment to test spawning the datepicker @@ -43,7 +58,7 @@ describe('date component', () => { }) it('formats date value on input change', async () => { - const wrapper = mount(ADate) + const wrapper = mount(ADate, globalComponents) const $input = wrapper.find('input') await $input.setValue('2023-06-15') await wrapper.vm.$nextTick() @@ -52,6 +67,7 @@ describe('date component', () => { it('renders in display mode with formatted date', () => { const wrapper = mount(ADate, { + ...globalComponents, props: { modelValue: '2021-01-01', mode: 'display' }, }) expect(wrapper.find('input').exists()).toBe(false) @@ -59,7 +75,10 @@ describe('date component', () => { }) it('renders in display mode with empty span when no value', () => { - const wrapper = mount(ADate, { props: { mode: 'display' } }) + const wrapper = mount(ADate, { + ...globalComponents, + props: { mode: 'display' }, + }) expect(wrapper.find('input').exists()).toBe(false) expect(wrapper.find('.aform_display-value').text()).toBe('') }) diff --git a/aform/tests/datetime.spec.ts b/aform/tests/datetime.spec.ts index 4330be519..5273f4726 100644 --- a/aform/tests/datetime.spec.ts +++ b/aform/tests/datetime.spec.ts @@ -6,11 +6,11 @@ import ADateTime from '../src/components/form/ADateTime.vue' describe('datetime component', () => { it('renders time inputs with default values', () => { const wrapper = mount(ADateTime) - const inputs = wrapper.findAll('input[type="number"]') + const inputs = wrapper.findAll('input[type="text"]') expect(inputs.length).toBe(3) // hours, minutes, seconds expect(inputs[0].element.value).toBe('12') - expect(inputs[1].element.value).toBe('0') - expect(inputs[2].element.value).toBe('0') + expect(inputs[1].element.value).toBe('00') + expect(inputs[2].element.value).toBe('00') }) it('emits get-time on mount', () => { @@ -43,13 +43,13 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { useSeconds: false }, }) - const inputs = wrapper.findAll('input[type="number"]') + const inputs = wrapper.findAll('input[type="text"]') expect(inputs.length).toBe(2) }) it('updates hours and emits on blur', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(3) await hoursInput.trigger('blur') const emitted = wrapper.emitted('get-time') @@ -59,7 +59,7 @@ describe('datetime component', () => { it('updates minutes and emits on enter key', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] await minutesInput.setValue(45) await minutesInput.trigger('keydown.enter') const emitted = wrapper.emitted('get-time') @@ -79,35 +79,35 @@ describe('datetime component', () => { it('increments hours with up arrow', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.trigger('keydown.up') expect(hoursInput.element.value).toBe('01') }) it('decrements hours with down arrow', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.trigger('keydown.down') expect(hoursInput.element.value).toBe('11') }) it('increments minutes with up arrow', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] await minutesInput.trigger('keydown.up') expect(minutesInput.element.value).toBe('01') }) it('decrements seconds with down arrow', async () => { const wrapper = mount(ADateTime) - const secondsInput = wrapper.findAll('input[type="number"]')[2] + const secondsInput = wrapper.findAll('input[type="text"]')[2] await secondsInput.trigger('keydown.down') expect(secondsInput.element.value).toBe('59') }) it('wraps hours from 12 to 1 in non-military mode', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(12) await hoursInput.trigger('keydown.up') expect(hoursInput.element.value).toBe('01') @@ -115,7 +115,7 @@ describe('datetime component', () => { it('wraps hours from 1 to 12 in non-military mode', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(1) await hoursInput.trigger('keydown.down') expect(hoursInput.element.value).toBe('12') @@ -125,7 +125,7 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { allowMilitaryTime: true }, }) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(23) await hoursInput.trigger('blur') expect(hoursInput.element.value).toBe('23') @@ -135,7 +135,7 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { allowMilitaryTime: true }, }) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(23) await hoursInput.trigger('keydown.up') expect(hoursInput.element.value).toBe('00') @@ -145,14 +145,14 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { allowMilitaryTime: true, defaultHours: 0 }, }) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.trigger('keydown.down') expect(hoursInput.element.value).toBe('23') }) it('clamps hours to max on blur', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(99) await hoursInput.trigger('blur') expect(hoursInput.element.value).toBe('12') @@ -160,7 +160,7 @@ describe('datetime component', () => { it('clamps minutes to 59 on blur', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] await minutesInput.setValue(99) await minutesInput.trigger('blur') expect(minutesInput.element.value).toBe('59') @@ -168,7 +168,7 @@ describe('datetime component', () => { it('clamps seconds to 59 on blur', async () => { const wrapper = mount(ADateTime) - const secondsInput = wrapper.findAll('input[type="number"]')[2] + const secondsInput = wrapper.findAll('input[type="text"]')[2] await secondsInput.setValue(99) await secondsInput.trigger('blur') expect(secondsInput.element.value).toBe('59') @@ -176,7 +176,7 @@ describe('datetime component', () => { it('changes meridiem when crossing 11-12 boundary upward', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(11) await hoursInput.trigger('keydown.up') const select = wrapper.find('select') @@ -187,7 +187,7 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { defaultMeridiem: 'PM' }, }) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(12) await hoursInput.trigger('keydown.down') const select = wrapper.find('select') @@ -198,7 +198,7 @@ describe('datetime component', () => { const wrapper = mount(ADateTime, { props: { defaultMeridiem: 'PM' }, }) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(3) await hoursInput.trigger('blur') const emitted = wrapper.emitted('get-time') @@ -208,7 +208,7 @@ describe('datetime component', () => { it('emits correct militaryTime for AM hours', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(3) await hoursInput.trigger('blur') const emitted = wrapper.emitted('get-time') @@ -236,7 +236,7 @@ describe('datetime component', () => { it('selects input text on focus', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] const selectMock = vi.fn() Object.defineProperty(hoursInput.element, 'select', { value: selectMock }) await hoursInput.trigger('focus') @@ -245,7 +245,7 @@ describe('datetime component', () => { it('handles paste on hours field', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] const clipboardData = { getData: vi.fn().mockReturnValue('143045') } const event = new Event('paste', { bubbles: true, cancelable: true }) Object.defineProperty(event, 'clipboardData', { value: clipboardData }) @@ -259,7 +259,7 @@ describe('datetime component', () => { it('handles single field paste', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] const clipboardData = { getData: vi.fn().mockReturnValue('55') } const event = new Event('paste', { bubbles: true, cancelable: true }) Object.defineProperty(event, 'clipboardData', { value: clipboardData }) @@ -270,7 +270,7 @@ describe('datetime component', () => { it('pads single digit values on confirm', async () => { const wrapper = mount(ADateTime) - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] await hoursInput.setValue(3) await hoursInput.trigger('blur') expect(hoursInput.element.value).toBe('03') @@ -278,37 +278,37 @@ describe('datetime component', () => { it('increments minutes when seconds roll over', async () => { const wrapper = mount(ADateTime) - const secondsInput = wrapper.findAll('input[type="number"]')[2] + const secondsInput = wrapper.findAll('input[type="text"]')[2] await secondsInput.setValue(59) await secondsInput.trigger('keydown.up') - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] expect(minutesInput.element.value).toBe('01') }) it('decrements minutes when seconds roll under', async () => { const wrapper = mount(ADateTime) - const secondsInput = wrapper.findAll('input[type="number"]')[2] + const secondsInput = wrapper.findAll('input[type="text"]')[2] await secondsInput.setValue(0) await secondsInput.trigger('keydown.down') - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] expect(minutesInput.element.value).toBe('59') }) it('increments hours when minutes roll over', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] await minutesInput.setValue(59) await minutesInput.trigger('keydown.up') - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] expect(hoursInput.element.value).toBe('01') }) it('decrements hours when minutes roll under', async () => { const wrapper = mount(ADateTime) - const minutesInput = wrapper.findAll('input[type="number"]')[1] + const minutesInput = wrapper.findAll('input[type="text"]')[1] await minutesInput.setValue(0) await minutesInput.trigger('keydown.down') - const hoursInput = wrapper.findAll('input[type="number"]')[0] + const hoursInput = wrapper.findAll('input[type="text"]')[0] expect(hoursInput.element.value).toBe('11') }) })