ropav 0.13.0 → 0.15.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.
- package/dist/components/accordion/index.d.ts +1 -0
- package/dist/components/alert-dialog/alert-dialog-backdrop.js +3 -1
- package/dist/components/autocomplete/index.d.ts +1 -0
- package/dist/components/calendar/index.d.ts +1 -0
- package/dist/components/checkbox-group/index.d.ts +1 -0
- package/dist/components/color-slider/index.d.ts +1 -0
- package/dist/components/combo-box/index.d.ts +2 -0
- package/dist/components/date-field/index.d.ts +1 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/use-date-range-picker.js +1 -1
- package/dist/components/disclosure-group/index.d.ts +1 -0
- package/dist/components/drawer/drawer-backdrop.js +3 -1
- package/dist/components/dropdown/dropdown-menu.js +7 -3
- package/dist/components/dropdown/dropdown-root.js +1 -1
- package/dist/components/dropdown/dropdown-submenu-trigger.js +1 -1
- package/dist/components/dropdown/dropdown.context.d.ts +1 -1
- package/dist/components/dropdown/index.d.ts +1 -0
- package/dist/components/field-error/field-error-root.js +1 -1
- package/dist/components/form/form-root.js +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/meter/meter-root.js +1 -1
- package/dist/components/modal/modal-backdrop.js +3 -1
- package/dist/components/number-field/index.d.ts +1 -0
- package/dist/components/overlay/overlay-popover.js +15 -6
- package/dist/components/portal-provider/index.d.ts +3 -0
- package/dist/components/portal-provider/index.js +2 -0
- package/dist/components/portal-provider/portal-provider.d.ts +21 -0
- package/dist/components/portal-provider/portal-provider.js +20 -0
- package/dist/components/portal-provider/portal-provider.types.d.ts +22 -0
- package/dist/components/radio-group/index.d.ts +1 -0
- package/dist/components/range-calendar/index.d.ts +1 -0
- package/dist/components/segmented-control/index.d.ts +1 -0
- package/dist/components/select/index.d.ts +1 -0
- package/dist/components/slider/index.d.ts +1 -0
- package/dist/components/table/table-drag-handle.js +1 -1
- package/dist/components/tabs/index.d.ts +1 -0
- package/dist/components/tabs/tabs-root.js +5 -0
- package/dist/components/tabs/tabs.types.d.ts +8 -0
- package/dist/components/time-field/index.d.ts +2 -0
- package/dist/components/toast/toast-provider.js +3 -1
- package/dist/components/toggle-button/index.d.ts +1 -0
- package/dist/components/toggle-button-group/index.d.ts +1 -0
- package/dist/components/tooltip/index.d.ts +1 -0
- package/dist/components/tooltip/tooltip-content.js +4 -1
- package/dist/composables/drag-manager.js +1 -1
- package/dist/composables/drag-modality.js +2 -1
- package/dist/composables/focus-scope-registry.d.ts +27 -0
- package/dist/composables/focus-scope-registry.js +45 -0
- package/dist/composables/form-context.d.ts +25 -0
- package/dist/composables/form-context.js +17 -0
- package/dist/composables/index.d.ts +1 -24
- package/dist/composables/interaction-modality.d.ts +42 -0
- package/dist/composables/interaction-modality.js +91 -0
- package/dist/composables/use-calendar-cell.js +1 -1
- package/dist/composables/use-checkbox-group-state.js +2 -1
- package/dist/composables/use-combo-box-state.d.ts +2 -1
- package/dist/composables/use-combo-box-state.js +3 -2
- package/dist/composables/use-combo-box.js +6 -3
- package/dist/composables/use-css-variable.js +1 -5
- package/dist/composables/use-default-locale.d.ts +9 -0
- package/dist/composables/use-default-locale.js +39 -0
- package/dist/composables/use-dismissable.d.ts +6 -0
- package/dist/composables/use-dismissable.js +9 -11
- package/dist/composables/use-display-names.js +1 -1
- package/dist/composables/use-drag.js +1 -1
- package/dist/composables/use-droppable-collection.js +1 -1
- package/dist/composables/use-focus-scope.d.ts +6 -12
- package/dist/composables/use-focus-scope.js +14 -33
- package/dist/composables/use-form-validation-state.d.ts +1 -60
- package/dist/composables/use-form-validation-state.js +3 -134
- package/dist/composables/use-form-validation.d.ts +2 -1
- package/dist/composables/use-form-validation.js +2 -2
- package/dist/composables/use-interaction-states.d.ts +0 -36
- package/dist/composables/use-interaction-states.js +8 -91
- package/dist/composables/use-locale.d.ts +0 -14
- package/dist/composables/use-locale.js +4 -37
- package/dist/composables/use-localized-string-dictionary.d.ts +10 -0
- package/dist/composables/use-localized-string-dictionary.js +26 -0
- package/dist/composables/use-localized-string-formatter.d.ts +0 -9
- package/dist/composables/use-localized-string-formatter.js +3 -24
- package/dist/composables/use-long-press.d.ts +0 -2
- package/dist/composables/use-long-press.js +2 -2
- package/dist/composables/use-menu-trigger-state.d.ts +64 -0
- package/dist/composables/use-menu-trigger-state.js +90 -0
- package/dist/composables/use-menu-trigger.d.ts +2 -1
- package/dist/composables/use-modal-overlay.d.ts +2 -1
- package/dist/composables/use-modal-overlay.js +17 -4
- package/dist/composables/use-overlay-trigger-state.d.ts +0 -62
- package/dist/composables/use-overlay-trigger-state.js +2 -87
- package/dist/composables/use-page-size.d.ts +14 -0
- package/dist/composables/use-page-size.js +42 -0
- package/dist/composables/use-portal.d.ts +35 -0
- package/dist/composables/use-portal.js +47 -0
- package/dist/composables/use-press.d.ts +0 -20
- package/dist/composables/use-press.js +3 -26
- package/dist/composables/use-range-calendar.js +1 -1
- package/dist/composables/use-select-state.d.ts +1 -1
- package/dist/composables/use-select-state.js +1 -1
- package/dist/composables/use-slider.js +1 -1
- package/dist/composables/use-toast-region.js +2 -1
- package/dist/composables/use-tooltip-trigger-state.js +1 -15
- package/dist/composables/use-tooltip-trigger.js +1 -1
- package/dist/composables/use-viewport-size.d.ts +0 -13
- package/dist/composables/use-viewport-size.js +1 -38
- package/dist/composables/validation-result.d.ts +37 -0
- package/dist/composables/validation-result.js +122 -0
- package/dist/composables/virtual-event.d.ts +20 -0
- package/dist/composables/virtual-event.js +28 -0
- package/dist/index.js +13 -35
- package/dist/ropav.min.css +1 -1
- package/dist/utils/aria-hide-outside.d.ts +4 -1
- package/dist/utils/aria-hide-outside.js +17 -5
- package/dist/utils/date-validation.js +1 -1
- package/dist/utils/region.d.ts +10 -0
- package/dist/utils/region.js +13 -0
- package/dist/version.js +1 -1
- package/package.json +6 -2
|
@@ -1,31 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isMac } from "../utils/platform.js";
|
|
2
|
+
import { isVirtualClick, isVirtualPointerEvent } from "./virtual-event.js";
|
|
2
3
|
import { computed, onScopeDispose, shallowRef, toValue, watch } from "vue";
|
|
3
4
|
//#region src/composables/use-press.ts
|
|
4
5
|
/**
|
|
5
|
-
* Whether a click came from something other than a pointer.
|
|
6
|
-
*
|
|
7
|
-
* Ported from React Aria's `isVirtualClick`. A screen reader and `element.click()` both
|
|
8
|
-
* produce a click with no pointer data behind it, which is the only way to tell them apart
|
|
9
|
-
* from a real one.
|
|
10
|
-
*/
|
|
11
|
-
var isVirtualClick = (event) => {
|
|
12
|
-
if (event.pointerType === "" && event.isTrusted) return true;
|
|
13
|
-
if (isAndroid() && event.pointerType) return event.type === "click" && event.buttons === 1;
|
|
14
|
-
return event.detail === 0 && !event.pointerType;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Whether a pointer event was synthesised by assistive technology.
|
|
18
|
-
*
|
|
19
|
-
* A screen reader activating an element reports a zero-sized pointer. Safari on iOS gives
|
|
20
|
-
* such events the wrong coordinates and target, so they have to be left to the click handler.
|
|
21
|
-
*
|
|
22
|
-
* Android needs a shape of its own, and the zero-size test is turned off there rather than left
|
|
23
|
-
* to miss: TalkBack's double tap reports a one-by-one pointer claiming to be a mouse. Every part
|
|
24
|
-
* of that is load-bearing — pressure alone would catch real presses in Safari, which reports zero
|
|
25
|
-
* for those too, and the mouse claim is what separates the double tap from a touch screen press.
|
|
26
|
-
*/
|
|
27
|
-
var isVirtualPointerEvent = (event) => !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === "mouse";
|
|
28
|
-
/**
|
|
29
6
|
* Whether an enter or a leave came from a pointer with no hover to report.
|
|
30
7
|
*
|
|
31
8
|
* A touch pointer is created where the finger lands and destroyed where it lifts, and the browser
|
|
@@ -385,4 +362,4 @@ var usePress = (options = {}) => {
|
|
|
385
362
|
};
|
|
386
363
|
};
|
|
387
364
|
//#endregion
|
|
388
|
-
export {
|
|
365
|
+
export { usePress };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isVirtualPointerEvent } from "./
|
|
1
|
+
import { isVirtualPointerEvent } from "./virtual-event.js";
|
|
2
2
|
import { useCalendar } from "./use-calendar.js";
|
|
3
3
|
import { onScopeDispose, toValue, watch } from "vue";
|
|
4
4
|
//#region src/composables/use-range-calendar.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CollectionKey, UseCollectionReturn } from "./use-collection.js";
|
|
2
2
|
import type { FormValidationState, ValidationBehavior, ValidationFunction } from "./use-form-validation-state.js";
|
|
3
|
-
import type { MenuTriggerState } from "./use-
|
|
3
|
+
import type { MenuTriggerState } from "./use-menu-trigger-state.js";
|
|
4
4
|
import type { DisabledBehavior, UseSelectionManagerReturn } from "./use-selection-manager.js";
|
|
5
5
|
import type { ComputedRef, MaybeRefOrGetter } from "vue";
|
|
6
6
|
/** Whether one or several options can be chosen. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useControllableState } from "./use-controllable-state.js";
|
|
2
|
-
import { useMenuTriggerState } from "./use-overlay-trigger-state.js";
|
|
3
2
|
import { useCollection } from "./use-collection.js";
|
|
4
3
|
import { createListCollection } from "../utils/virtualizer-collection.js";
|
|
5
4
|
import { useFormValidationState } from "./use-form-validation-state.js";
|
|
5
|
+
import { useMenuTriggerState } from "./use-menu-trigger-state.js";
|
|
6
6
|
import { useSelectionManager } from "./use-selection-manager.js";
|
|
7
7
|
import { computed, shallowRef, toValue } from "vue";
|
|
8
8
|
//#region src/composables/use-select-state.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setInteractionModality } from "./
|
|
1
|
+
import { setInteractionModality } from "./interaction-modality.js";
|
|
2
2
|
import { useMove } from "./use-move.js";
|
|
3
3
|
import { clamp } from "../utils/number.js";
|
|
4
4
|
import { computed, onScopeDispose, toValue } from "vue";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getInteractionModality, retainInteractionModality
|
|
1
|
+
import { getInteractionModality, retainInteractionModality } from "./interaction-modality.js";
|
|
2
|
+
import { useInteractionStates } from "./use-interaction-states.js";
|
|
2
3
|
import { TOP_LAYER_ATTRIBUTE } from "../utils/top-layer.js";
|
|
3
4
|
import { willOpenKeyboard } from "../utils/platform.js";
|
|
4
5
|
import { useLocalizedStringFormatter } from "./use-localized-string-formatter.js";
|
|
@@ -27,20 +27,6 @@ var clearCooldownTimeout = () => {
|
|
|
27
27
|
globalCooldownTimeout = null;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
* Forget the shared warmup state.
|
|
31
|
-
*
|
|
32
|
-
* For a test: the registry and both timers outlive any one component, so a case that leaves a
|
|
33
|
-
* tooltip warm would make the next one open with no delay and read as a bug in that test instead.
|
|
34
|
-
*/
|
|
35
|
-
var resetTooltipWarmup = () => {
|
|
36
|
-
tooltips.clear();
|
|
37
|
-
clearWarmUpTimeout();
|
|
38
|
-
clearCooldownTimeout();
|
|
39
|
-
globalWarmedUp = false;
|
|
40
|
-
};
|
|
41
|
-
/** How many tooltips are registered. For a test proving a disposed trigger left nothing behind. */
|
|
42
|
-
var getRegisteredTooltipCount = () => tooltips.size;
|
|
43
|
-
/**
|
|
44
30
|
* Open state for a tooltip trigger, ported from React Stately's `useTooltipTriggerState`.
|
|
45
31
|
*
|
|
46
32
|
* Two things beyond a plain overlay trigger, and both are about time rather than state. A tooltip
|
|
@@ -138,4 +124,4 @@ var useTooltipTriggerState = (options = {}) => {
|
|
|
138
124
|
};
|
|
139
125
|
};
|
|
140
126
|
//#endregion
|
|
141
|
-
export {
|
|
127
|
+
export { useTooltipTriggerState };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useId as useId$1 } from "./use-id.js";
|
|
2
|
-
import { getInteractionModality, isFocusVisible, retainInteractionModality } from "./
|
|
2
|
+
import { getInteractionModality, isFocusVisible, retainInteractionModality } from "./interaction-modality.js";
|
|
3
3
|
import { computed, onScopeDispose, shallowRef, toValue, watch } from "vue";
|
|
4
4
|
//#region src/composables/use-tooltip-trigger.ts
|
|
5
5
|
/**
|
|
@@ -3,11 +3,6 @@ export interface ViewportSize {
|
|
|
3
3
|
width: number;
|
|
4
4
|
height: number;
|
|
5
5
|
}
|
|
6
|
-
export interface PageSize {
|
|
7
|
-
/** Absent on the server, and while there is no document to measure. */
|
|
8
|
-
width: number | undefined;
|
|
9
|
-
height: number | undefined;
|
|
10
|
-
}
|
|
11
6
|
/**
|
|
12
7
|
* Track the visual viewport, ported from React Aria's `useViewportSize`.
|
|
13
8
|
*
|
|
@@ -21,11 +16,3 @@ export interface PageSize {
|
|
|
21
16
|
* ```
|
|
22
17
|
*/
|
|
23
18
|
export declare const useViewportSize: () => ShallowRef<ViewportSize>;
|
|
24
|
-
/**
|
|
25
|
-
* Track the size of the whole scrollable page.
|
|
26
|
-
*
|
|
27
|
-
* Ported from the block React Aria computes inline in `ModalOverlayInner`. Published as
|
|
28
|
-
* `--page-width` / `--page-height` for a backdrop that has to cover a page taller than the
|
|
29
|
-
* viewport rather than only the part currently on screen.
|
|
30
|
-
*/
|
|
31
|
-
export declare const usePageSize: () => ShallowRef<PageSize>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isScrollable } from "../utils/focus.js";
|
|
2
1
|
import { isIOS, isWebKit, willOpenKeyboard } from "../utils/platform.js";
|
|
3
2
|
import { onScopeDispose, shallowRef } from "vue";
|
|
4
3
|
//#region src/composables/use-viewport-size.ts
|
|
@@ -81,41 +80,5 @@ var useViewportSize = () => {
|
|
|
81
80
|
}, true);
|
|
82
81
|
return size;
|
|
83
82
|
};
|
|
84
|
-
var measurePage = () => {
|
|
85
|
-
if (typeof document === "undefined") return {
|
|
86
|
-
height: void 0,
|
|
87
|
-
width: void 0
|
|
88
|
-
};
|
|
89
|
-
const scrolling = isScrollable(document.body) ? document.body : document.scrollingElement ?? document.documentElement;
|
|
90
|
-
const rect = scrolling.getBoundingClientRect();
|
|
91
|
-
return {
|
|
92
|
-
height: scrolling.scrollHeight - rect.height % 1,
|
|
93
|
-
width: scrolling.scrollWidth - rect.width % 1
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Track the size of the whole scrollable page.
|
|
98
|
-
*
|
|
99
|
-
* Ported from the block React Aria computes inline in `ModalOverlayInner`. Published as
|
|
100
|
-
* `--page-width` / `--page-height` for a backdrop that has to cover a page taller than the
|
|
101
|
-
* viewport rather than only the part currently on screen.
|
|
102
|
-
*/
|
|
103
|
-
var usePageSize = () => {
|
|
104
|
-
const size = shallowRef(measurePage());
|
|
105
|
-
if (typeof document === "undefined") return size;
|
|
106
|
-
const onResize = () => {
|
|
107
|
-
const next = measurePage();
|
|
108
|
-
if (next.width === size.value.width && next.height === size.value.height) return;
|
|
109
|
-
size.value = next;
|
|
110
|
-
};
|
|
111
|
-
const viewport = getVisualViewport();
|
|
112
|
-
window.addEventListener("resize", onResize);
|
|
113
|
-
viewport?.addEventListener("resize", onResize);
|
|
114
|
-
onScopeDispose(() => {
|
|
115
|
-
window.removeEventListener("resize", onResize);
|
|
116
|
-
viewport?.removeEventListener("resize", onResize);
|
|
117
|
-
}, true);
|
|
118
|
-
return size;
|
|
119
|
-
};
|
|
120
83
|
//#endregion
|
|
121
|
-
export {
|
|
84
|
+
export { useViewportSize };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ValidationDetails, ValidationResult, RequiredControl } from "./use-form-validation-state.js";
|
|
2
|
+
export declare const VALID_VALIDITY_STATE: ValidationDetails;
|
|
3
|
+
/** Failure that came from a prop, a `validate` function or the server rather than the browser. */
|
|
4
|
+
export declare const CUSTOM_VALIDITY_STATE: ValidationDetails;
|
|
5
|
+
/** A required field with nothing in it. What the browser reports under `"native"`. */
|
|
6
|
+
export declare const MISSING_VALIDITY_STATE: ValidationDetails;
|
|
7
|
+
export declare const DEFAULT_VALIDATION_RESULT: ValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* One verdict out of several, for a control whose value has more than one part.
|
|
10
|
+
*
|
|
11
|
+
* Invalid if any part is, with the messages collected in order and deduplicated — two ends of a
|
|
12
|
+
* range that are both out of bounds say the same thing, and saying it twice is not more helpful.
|
|
13
|
+
*/
|
|
14
|
+
export declare const mergeValidation: (...results: ValidationResult[]) => ValidationResult;
|
|
15
|
+
/** Form controls that take part in constraint validation. */
|
|
16
|
+
export type ValidatableElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
17
|
+
/** Freeze an element's live validity into a result the state layer can hold. */
|
|
18
|
+
export declare const getNativeValidation: (element: ValidatableElement) => ValidationResult;
|
|
19
|
+
/**
|
|
20
|
+
* What the browser would say about an empty control of this kind.
|
|
21
|
+
*
|
|
22
|
+
* Read off a detached probe rather than translated here. The platform already holds the sentence,
|
|
23
|
+
* in the *browser's* locale — which is the locale a validation message belongs in, since it sits
|
|
24
|
+
* beside the browser's own — and it is the one the same field would report under `"native"`.
|
|
25
|
+
*
|
|
26
|
+
* Empty on a server, where the field cannot have been revealed yet and so has nothing to say.
|
|
27
|
+
*/
|
|
28
|
+
export declare const missingValueMessage: (kind: RequiredControl) => string;
|
|
29
|
+
/** Whether a value counts as nothing. Covers every shape a field holds when it is empty. */
|
|
30
|
+
export declare const isValueMissing: (value: unknown) => boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Whether two results say the same thing.
|
|
33
|
+
*
|
|
34
|
+
* Not an optimisation: the results live in `shallowRef`s, and assigning an equal-but-new
|
|
35
|
+
* object still retriggers every computed reading them.
|
|
36
|
+
*/
|
|
37
|
+
export declare const isEqualValidation: (a: ValidationResult | null, b: ValidationResult | null) => boolean;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
//#region src/composables/validation-result.ts
|
|
2
|
+
var VALID_VALIDITY_STATE = Object.freeze({
|
|
3
|
+
badInput: false,
|
|
4
|
+
customError: false,
|
|
5
|
+
patternMismatch: false,
|
|
6
|
+
rangeOverflow: false,
|
|
7
|
+
rangeUnderflow: false,
|
|
8
|
+
stepMismatch: false,
|
|
9
|
+
tooLong: false,
|
|
10
|
+
tooShort: false,
|
|
11
|
+
typeMismatch: false,
|
|
12
|
+
valid: true,
|
|
13
|
+
valueMissing: false
|
|
14
|
+
});
|
|
15
|
+
/** Failure that came from a prop, a `validate` function or the server rather than the browser. */
|
|
16
|
+
var CUSTOM_VALIDITY_STATE = Object.freeze({
|
|
17
|
+
...VALID_VALIDITY_STATE,
|
|
18
|
+
customError: true,
|
|
19
|
+
valid: false
|
|
20
|
+
});
|
|
21
|
+
/** A required field with nothing in it. What the browser reports under `"native"`. */
|
|
22
|
+
var MISSING_VALIDITY_STATE = Object.freeze({
|
|
23
|
+
...VALID_VALIDITY_STATE,
|
|
24
|
+
valid: false,
|
|
25
|
+
valueMissing: true
|
|
26
|
+
});
|
|
27
|
+
var DEFAULT_VALIDATION_RESULT = Object.freeze({
|
|
28
|
+
isInvalid: false,
|
|
29
|
+
validationDetails: VALID_VALIDITY_STATE,
|
|
30
|
+
validationErrors: []
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* One verdict out of several, for a control whose value has more than one part.
|
|
34
|
+
*
|
|
35
|
+
* Invalid if any part is, with the messages collected in order and deduplicated — two ends of a
|
|
36
|
+
* range that are both out of bounds say the same thing, and saying it twice is not more helpful.
|
|
37
|
+
*/
|
|
38
|
+
var mergeValidation = (...results) => {
|
|
39
|
+
const errors = /* @__PURE__ */ new Set();
|
|
40
|
+
const details = { ...VALID_VALIDITY_STATE };
|
|
41
|
+
let isInvalid = false;
|
|
42
|
+
for (const result of results) {
|
|
43
|
+
for (const error of result.validationErrors) errors.add(error);
|
|
44
|
+
isInvalid ||= result.isInvalid;
|
|
45
|
+
for (const key of Object.keys(details)) details[key] ||= result.validationDetails[key];
|
|
46
|
+
}
|
|
47
|
+
details.valid = !isInvalid;
|
|
48
|
+
return {
|
|
49
|
+
isInvalid,
|
|
50
|
+
validationDetails: details,
|
|
51
|
+
validationErrors: [...errors]
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/** Freeze an element's live validity into a result the state layer can hold. */
|
|
55
|
+
var getNativeValidation = (element) => {
|
|
56
|
+
const validity = element.validity;
|
|
57
|
+
return {
|
|
58
|
+
isInvalid: !validity.valid,
|
|
59
|
+
validationDetails: {
|
|
60
|
+
badInput: validity.badInput,
|
|
61
|
+
customError: validity.customError,
|
|
62
|
+
patternMismatch: validity.patternMismatch,
|
|
63
|
+
rangeOverflow: validity.rangeOverflow,
|
|
64
|
+
rangeUnderflow: validity.rangeUnderflow,
|
|
65
|
+
stepMismatch: validity.stepMismatch,
|
|
66
|
+
tooLong: validity.tooLong,
|
|
67
|
+
tooShort: validity.tooShort,
|
|
68
|
+
typeMismatch: validity.typeMismatch,
|
|
69
|
+
valid: validity.valid,
|
|
70
|
+
valueMissing: validity.valueMissing
|
|
71
|
+
},
|
|
72
|
+
validationErrors: element.validationMessage ? [element.validationMessage] : []
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
var missingValueMessages = /* @__PURE__ */ new Map();
|
|
76
|
+
/**
|
|
77
|
+
* What the browser would say about an empty control of this kind.
|
|
78
|
+
*
|
|
79
|
+
* Read off a detached probe rather than translated here. The platform already holds the sentence,
|
|
80
|
+
* in the *browser's* locale — which is the locale a validation message belongs in, since it sits
|
|
81
|
+
* beside the browser's own — and it is the one the same field would report under `"native"`.
|
|
82
|
+
*
|
|
83
|
+
* Empty on a server, where the field cannot have been revealed yet and so has nothing to say.
|
|
84
|
+
*/
|
|
85
|
+
var missingValueMessage = (kind) => {
|
|
86
|
+
const cached = missingValueMessages.get(kind);
|
|
87
|
+
if (cached !== void 0) return cached;
|
|
88
|
+
if (typeof document === "undefined") return "";
|
|
89
|
+
let probe;
|
|
90
|
+
if (kind === "select") probe = document.createElement("select");
|
|
91
|
+
else {
|
|
92
|
+
const input = document.createElement("input");
|
|
93
|
+
if (kind !== "text") {
|
|
94
|
+
input.type = kind;
|
|
95
|
+
input.name = "probe";
|
|
96
|
+
}
|
|
97
|
+
probe = input;
|
|
98
|
+
}
|
|
99
|
+
probe.required = true;
|
|
100
|
+
const message = probe.validationMessage;
|
|
101
|
+
missingValueMessages.set(kind, message);
|
|
102
|
+
return message;
|
|
103
|
+
};
|
|
104
|
+
/** Whether a value counts as nothing. Covers every shape a field holds when it is empty. */
|
|
105
|
+
var isValueMissing = (value) => {
|
|
106
|
+
if (value == null || value === "" || value === false) return true;
|
|
107
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
108
|
+
return typeof value === "number" && Number.isNaN(value);
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Whether two results say the same thing.
|
|
112
|
+
*
|
|
113
|
+
* Not an optimisation: the results live in `shallowRef`s, and assigning an equal-but-new
|
|
114
|
+
* object still retriggers every computed reading them.
|
|
115
|
+
*/
|
|
116
|
+
var isEqualValidation = (a, b) => {
|
|
117
|
+
if (a === b) return true;
|
|
118
|
+
if (!a || !b) return false;
|
|
119
|
+
return a.isInvalid === b.isInvalid && a.validationErrors.length === b.validationErrors.length && a.validationErrors.every((error, index) => error === b.validationErrors[index]) && Object.keys(a.validationDetails).every((key) => a.validationDetails[key] === b.validationDetails[key]);
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
export { CUSTOM_VALIDITY_STATE, DEFAULT_VALIDATION_RESULT, MISSING_VALIDITY_STATE, VALID_VALIDITY_STATE, getNativeValidation, isEqualValidation, isValueMissing, mergeValidation, missingValueMessage };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a click came from something other than a pointer.
|
|
3
|
+
*
|
|
4
|
+
* Ported from React Aria's `isVirtualClick`. A screen reader and `element.click()` both
|
|
5
|
+
* produce a click with no pointer data behind it, which is the only way to tell them apart
|
|
6
|
+
* from a real one.
|
|
7
|
+
*/
|
|
8
|
+
export declare const isVirtualClick: (event: MouseEvent) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether a pointer event was synthesised by assistive technology.
|
|
11
|
+
*
|
|
12
|
+
* A screen reader activating an element reports a zero-sized pointer. Safari on iOS gives
|
|
13
|
+
* such events the wrong coordinates and target, so they have to be left to the click handler.
|
|
14
|
+
*
|
|
15
|
+
* Android needs a shape of its own, and the zero-size test is turned off there rather than left
|
|
16
|
+
* to miss: TalkBack's double tap reports a one-by-one pointer claiming to be a mouse. Every part
|
|
17
|
+
* of that is load-bearing — pressure alone would catch real presses in Safari, which reports zero
|
|
18
|
+
* for those too, and the mouse claim is what separates the double tap from a touch screen press.
|
|
19
|
+
*/
|
|
20
|
+
export declare const isVirtualPointerEvent: (event: PointerEvent) => boolean;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isAndroid } from "../utils/platform.js";
|
|
2
|
+
//#region src/composables/virtual-event.ts
|
|
3
|
+
/**
|
|
4
|
+
* Whether a click came from something other than a pointer.
|
|
5
|
+
*
|
|
6
|
+
* Ported from React Aria's `isVirtualClick`. A screen reader and `element.click()` both
|
|
7
|
+
* produce a click with no pointer data behind it, which is the only way to tell them apart
|
|
8
|
+
* from a real one.
|
|
9
|
+
*/
|
|
10
|
+
var isVirtualClick = (event) => {
|
|
11
|
+
if (event.pointerType === "" && event.isTrusted) return true;
|
|
12
|
+
if (isAndroid() && event.pointerType) return event.type === "click" && event.buttons === 1;
|
|
13
|
+
return event.detail === 0 && !event.pointerType;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Whether a pointer event was synthesised by assistive technology.
|
|
17
|
+
*
|
|
18
|
+
* A screen reader activating an element reports a zero-sized pointer. Safari on iOS gives
|
|
19
|
+
* such events the wrong coordinates and target, so they have to be left to the click handler.
|
|
20
|
+
*
|
|
21
|
+
* Android needs a shape of its own, and the zero-size test is turned off there rather than left
|
|
22
|
+
* to miss: TalkBack's double tap reports a one-by-one pointer claiming to be a mouse. Every part
|
|
23
|
+
* of that is load-bearing — pressure alone would catch real presses in Safari, which reports zero
|
|
24
|
+
* for those too, and the mouse claim is what separates the double tap from a touch screen press.
|
|
25
|
+
*/
|
|
26
|
+
var isVirtualPointerEvent = (event) => !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === "mouse";
|
|
27
|
+
//#endregion
|
|
28
|
+
export { isVirtualClick, isVirtualPointerEvent };
|