From c0e80d75de47d7c3cadb434d80d2cfc1262379e1 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Sun, 23 Feb 2025 13:55:59 +0200 Subject: [PATCH] feat: lock non editable segments --- .../src/useDateTimeField/useDateTimeSegment.ts | 14 ++++++++++---- .../useDateTimeField/useDateTimeSegmentGroup.ts | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/core/src/useDateTimeField/useDateTimeSegment.ts b/packages/core/src/useDateTimeField/useDateTimeSegment.ts index 1e87f19e..ea748d66 100644 --- a/packages/core/src/useDateTimeField/useDateTimeSegment.ts +++ b/packages/core/src/useDateTimeField/useDateTimeSegment.ts @@ -56,7 +56,6 @@ export function useDateTimeSegment(_props: Reactivify) { const segmentEl = shallowRef(); const segmentGroup = inject(DateTimeSegmentGroupKey, null); const isDisabled = createDisabledContext(props.disabled); - const isNonEditable = () => isDisabled.value || !isEditableSegmentType(toValue(props.type)); if (!segmentGroup) { throw new Error('DateTimeSegmentGroup is not provided'); @@ -74,6 +73,7 @@ export function useDateTimeSegment(_props: Reactivify) { isLast, focusNext, isNumeric, + isLockedByRange, } = segmentGroup.useDateSegmentRegistration({ id, getElem: () => segmentEl.value, @@ -82,13 +82,19 @@ export function useDateTimeSegment(_props: Reactivify) { let currentInput = ''; + function isNonEditable() { + return ( + !isEditableSegmentType(toValue(props.type)) || isDisabled.value || toValue(props.readonly) || isLockedByRange() + ); + } + const handlers = { onFocus() { // Reset the current input when the segment is focused currentInput = ''; }, onBeforeinput(evt: InputEvent) { - if (toValue(props.readonly) || isDisabled.value) { + if (isNonEditable()) { blockEvent(evt); return; } @@ -142,7 +148,7 @@ export function useDateTimeSegment(_props: Reactivify) { currentInput = ''; }, onKeydown(evt: KeyboardEvent) { - if (toValue(props.readonly) || isDisabled.value) { + if (isNonEditable()) { return; } @@ -182,7 +188,7 @@ export function useDateTimeSegment(_props: Reactivify) { id, tabindex: isNonEditable() ? -1 : 0, contenteditable: isNonEditable() ? undefined : 'plaintext-only', - 'aria-disabled': isDisabled.value, + 'aria-disabled': isNonEditable(), 'data-segment-type': toValue(props.type), 'aria-label': isNonEditable() ? undefined : toValue(props.type), 'aria-readonly': toValue(props.readonly) ? true : undefined, diff --git a/packages/core/src/useDateTimeField/useDateTimeSegmentGroup.ts b/packages/core/src/useDateTimeField/useDateTimeSegmentGroup.ts index 313bf94e..464c3531 100644 --- a/packages/core/src/useDateTimeField/useDateTimeSegmentGroup.ts +++ b/packages/core/src/useDateTimeField/useDateTimeSegmentGroup.ts @@ -7,6 +7,7 @@ import { useEventListener } from '../helpers/useEventListener'; import { getSegmentTypePlaceholder, isEditableSegmentType, + isEqualPart, isNumericByDefault, isOptionalSegmentType, segmentTypeToDurationLike, @@ -34,6 +35,7 @@ export interface DateTimeSegmentGroupContext { onTouched(): void; isLast(): boolean; focusNext(): void; + isLockedByRange(): boolean; }; } @@ -166,6 +168,18 @@ export function useDateTimeSegmentGroup({ onValueChange(withAllPartsSet(date)); } + function isLockedByRange() { + const type = segment.getType(); + const minDate = toValue(min); + const maxDate = toValue(max); + // Can't be locked when either bound is open. + if (!minDate || !maxDate) { + return false; + } + + return isEqualPart(minDate, maxDate, type); + } + function getMetadata() { const type = segment.getType(); const date = toValue(temporalValue); @@ -252,6 +266,7 @@ export function useDateTimeSegmentGroup({ isLast, focusNext, isNumeric, + isLockedByRange, }; }