Skip to content

Commit

Permalink
feat: auto focus the next segment if the current one is done
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Jan 26, 2025
1 parent 861c0ea commit 77eb41e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 20 deletions.
25 changes: 18 additions & 7 deletions packages/core/src/useDateTimeField/useDateTimeSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function useDateTimeSegment(_props: Reactivify<DateTimeSegmentProps>) {
throw new Error('DateTimeSegmentGroup is not provided');
}

const { increment, decrement, setValue, maxValue, minValue, parser } = segmentGroup.useDateSegmentRegistration({
const { increment, decrement, setValue, getMetadata, onDone, parser } = segmentGroup.useDateSegmentRegistration({
id,
getElem: () => segmentEl.value,
getType: () => toValue(props.type),
Expand Down Expand Up @@ -74,23 +74,34 @@ export function useDateTimeSegment(_props: Reactivify<DateTimeSegmentProps>) {
currentInput = nextValue;

const parsed = parser.parse(nextValue);
const min = minValue();
const max = maxValue();
if (isNullOrUndefined(min) || isNullOrUndefined(max)) {
const { min, max, maxLength } = getMetadata();
if (isNullOrUndefined(min) || isNullOrUndefined(max) || isNullOrUndefined(maxLength)) {
return;
}

if (Number.isNaN(parsed) || parsed < min || parsed > max) {
if (Number.isNaN(parsed) || parsed > max) {
return;
}

if (segmentEl.value) {
segmentEl.value.textContent = parsed.toString();
segmentEl.value.textContent = currentInput;
}

// If the current input length is greater than or equal to the max length, or the parsed value is greater than the max value,
// then we should signal the segment group that this segment is done and it can move to the next segment
if (currentInput.length >= maxLength || parsed * 10 > max) {
onDone();
}
},
onBlur() {
const { min, max } = getMetadata();

if (isNullOrUndefined(min) || isNullOrUndefined(max)) {
return;
}

const parsed = parser.parse(segmentEl.value?.textContent || '');
if (!Number.isNaN(parsed)) {
if (!Number.isNaN(parsed) && parsed >= min && parsed <= max) {
setValue(parsed);
}

Expand Down
36 changes: 24 additions & 12 deletions packages/core/src/useDateTimeField/useDateTimeSegmentGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ export interface DateTimeSegmentGroupContext {
increment(): void;
decrement(): void;
setValue(value: number): void;

maxValue(): number | null;
minValue(): number | null;
getMetadata(): { min: number | null; max: number | null; maxLength: number | null };
onDone(): void;
};
}

Expand Down Expand Up @@ -63,6 +62,10 @@ export function useDateTimeSegmentGroup({
return formatter.value.formatToParts(date.toPlainDateTime()) as { type: DateTimeSegmentType; value: string }[];
});

function onSegmentDone() {
focusNextSegment();
}

function useDateSegmentRegistration(segment: DateTimeSegmentRegistration) {
renderedSegments.value.push(segment);
onBeforeUnmount(() => {
Expand Down Expand Up @@ -90,7 +93,7 @@ export function useDateTimeSegmentGroup({
onValueChange(date);
}

function maxValue() {
function getMetadata() {
const type = segment.getType();
const date = toValue(temporalValue);
const maxPartsRecord: Partial<Record<DateTimeSegmentType, number>> = {
Expand All @@ -102,11 +105,6 @@ export function useDateTimeSegmentGroup({
second: 59,
};

return maxPartsRecord[type] ?? null;
}

function minValue() {
const type = segment.getType();
const minPartsRecord: Partial<Record<DateTimeSegmentType, number>> = {
day: 1,
month: 1,
Expand All @@ -116,16 +114,30 @@ export function useDateTimeSegmentGroup({
second: 0,
};

return minPartsRecord[type] ?? null;
const maxLengths: Partial<Record<DateTimeSegmentType, number>> = {
day: 2,
month: 2,
year: 4,
hour: 2,
minute: 2,
second: 2,
};

return {
min: minPartsRecord[type] ?? null,
max: maxPartsRecord[type] ?? null,
maxLength: maxLengths[type] ?? null,
};
}

return {
increment,
decrement,
setValue,
parser,
maxValue,
minValue,
onSegmentDone,
getMetadata,
onDone: onSegmentDone,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import DateField from '@/components/DateField.vue';
label="Date"
:format-options="{
day: '2-digit',
month: 'long',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
hour12: true,
Expand Down

0 comments on commit 77eb41e

Please sign in to comment.