routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
@@ -0,0 +1,25 @@
@layer vuetify-components {
.v-time-picker.v-picker {
min-width: 328px;
}
.v-time-picker .v-picker__body, .v-time-picker-controls__field-label,
.v-time-picker .v-field {
transition-duration: 0.25s;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-property: transform, max-height, opacity, font-size;
}
@media (prefers-reduced-motion: reduce) {
.v-time-picker .v-picker__body, .v-time-picker-controls__field-label,
.v-time-picker .v-field {
transition: none;
}
}
.v-time-picker .v-picker__body {
transition-behavior: allow-discrete;
max-height: calc-size(max-content, size);
}
.v-time-picker--variant-input .v-picker__body {
transform: scale(0);
max-height: 0;
}
}
@@ -0,0 +1,702 @@
import type { PropType } from 'vue';
import type { Period, VTimePickerViewMode } from './shared.js';
import type { VPickerSlots } from '../../labs/VPicker/VPicker.js';
export type VTimePickerSlots = Omit<VPickerSlots, 'header'>;
type Variant = 'dial' | 'input';
export declare const makeVTimePickerProps: <Defaults extends {
theme?: unknown;
class?: unknown;
style?: unknown;
border?: unknown;
density?: unknown;
elevation?: unknown;
rounded?: unknown;
tile?: unknown;
tag?: unknown;
height?: unknown;
maxHeight?: unknown;
maxWidth?: unknown;
minHeight?: unknown;
minWidth?: unknown;
width?: unknown;
location?: unknown;
position?: unknown;
color?: unknown;
bgColor?: unknown;
divided?: unknown;
title?: unknown;
hideHeader?: unknown;
hideTitle?: unknown;
allowedHours?: unknown;
allowedMinutes?: unknown;
allowedSeconds?: unknown;
max?: unknown;
min?: unknown;
disabled?: unknown;
format?: unknown;
viewMode?: unknown;
period?: unknown;
modelValue?: unknown;
readonly?: unknown;
scrollable?: unknown;
useSeconds?: unknown;
variant?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
theme: unknown extends Defaults["theme"] ? StringConstructor : {
type: PropType<unknown extends Defaults["theme"] ? string : string | Defaults["theme"]>;
default: unknown extends Defaults["theme"] ? string : string | Defaults["theme"];
};
class: unknown extends Defaults["class"] ? PropType<any> : {
type: PropType<unknown extends Defaults["class"] ? any : any>;
default: unknown extends Defaults["class"] ? any : any;
};
style: unknown extends Defaults["style"] ? {
type: PropType<import("vue").StyleValue>;
default: null;
} : Omit<{
type: PropType<import("vue").StyleValue>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | import("vue").StyleValue>;
default: unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | NonNullable<import("vue").StyleValue>;
};
border: unknown extends Defaults["border"] ? (BooleanConstructor | NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["border"] ? string | number | boolean : string | number | boolean | Defaults["border"]>;
default: unknown extends Defaults["border"] ? string | number | boolean : Defaults["border"] | NonNullable<string | number | boolean>;
};
density: unknown extends Defaults["density"] ? {
type: PropType<import("../../composables/density.js").Density>;
default: string;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<import("../../composables/density.js").Density>;
default: string;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["density"] ? import("../../composables/density.js").Density : Defaults["density"] | import("../../composables/density.js").Density>;
default: unknown extends Defaults["density"] ? import("../../composables/density.js").Density : Defaults["density"] | NonNullable<import("../../composables/density.js").Density>;
};
elevation: unknown extends Defaults["elevation"] ? {
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["elevation"] ? string | number : string | number | Defaults["elevation"]>;
default: unknown extends Defaults["elevation"] ? string | number : Defaults["elevation"] | NonNullable<string | number>;
};
rounded: unknown extends Defaults["rounded"] ? {
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
} : Omit<{
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["rounded"] ? string | number | boolean : string | number | boolean | Defaults["rounded"]>;
default: unknown extends Defaults["rounded"] ? string | number | boolean : Defaults["rounded"] | NonNullable<string | number | boolean>;
};
tile: unknown extends Defaults["tile"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["tile"] ? boolean : boolean | Defaults["tile"]>;
default: unknown extends Defaults["tile"] ? boolean : boolean | Defaults["tile"];
};
tag: unknown extends Defaults["tag"] ? {
type: PropType<string | import("../../util/index.js").JSXComponent>;
default: string;
} : Omit<{
type: PropType<string | import("../../util/index.js").JSXComponent>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["tag"] ? string | import("../../util/index.js").JSXComponent : string | Defaults["tag"] | import("../../util/index.js").JSXComponent>;
default: unknown extends Defaults["tag"] ? string | import("../../util/index.js").JSXComponent : Defaults["tag"] | NonNullable<string | import("../../util/index.js").JSXComponent>;
};
height: unknown extends Defaults["height"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["height"] ? string | number : string | number | Defaults["height"]>;
default: unknown extends Defaults["height"] ? string | number : Defaults["height"] | NonNullable<string | number>;
};
maxHeight: unknown extends Defaults["maxHeight"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["maxHeight"] ? string | number : string | number | Defaults["maxHeight"]>;
default: unknown extends Defaults["maxHeight"] ? string | number : Defaults["maxHeight"] | NonNullable<string | number>;
};
maxWidth: unknown extends Defaults["maxWidth"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["maxWidth"] ? string | number : string | number | Defaults["maxWidth"]>;
default: unknown extends Defaults["maxWidth"] ? string | number : Defaults["maxWidth"] | NonNullable<string | number>;
};
minHeight: unknown extends Defaults["minHeight"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["minHeight"] ? string | number : string | number | Defaults["minHeight"]>;
default: unknown extends Defaults["minHeight"] ? string | number : Defaults["minHeight"] | NonNullable<string | number>;
};
minWidth: unknown extends Defaults["minWidth"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["minWidth"] ? string | number : string | number | Defaults["minWidth"]>;
default: unknown extends Defaults["minWidth"] ? string | number : Defaults["minWidth"] | NonNullable<string | number>;
};
width: unknown extends Defaults["width"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["width"] ? string | number : string | number | Defaults["width"]>;
default: unknown extends Defaults["width"] ? string | number : Defaults["width"] | NonNullable<string | number>;
};
location: unknown extends Defaults["location"] ? PropType<import("../../util/index.js").Anchor | null> : {
type: PropType<unknown extends Defaults["location"] ? import("../../util/index.js").Anchor | null : Defaults["location"] | import("../../util/index.js").Anchor | null>;
default: unknown extends Defaults["location"] ? import("../../util/index.js").Anchor | null : Defaults["location"] | NonNullable<import("../../util/index.js").Anchor | null>;
};
position: unknown extends Defaults["position"] ? {
type: PropType<"absolute" | "fixed" | "relative" | "static" | "sticky">;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<"absolute" | "fixed" | "relative" | "static" | "sticky">;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["position"] ? "absolute" | "fixed" | "relative" | "static" | "sticky" : "absolute" | "fixed" | "relative" | "static" | "sticky" | Defaults["position"]>;
default: unknown extends Defaults["position"] ? "absolute" | "fixed" | "relative" | "static" | "sticky" : Defaults["position"] | NonNullable<"absolute" | "fixed" | "relative" | "static" | "sticky">;
};
color: unknown extends Defaults["color"] ? StringConstructor : {
type: PropType<unknown extends Defaults["color"] ? string : string | Defaults["color"]>;
default: unknown extends Defaults["color"] ? string : string | Defaults["color"];
};
bgColor: unknown extends Defaults["bgColor"] ? StringConstructor : {
type: PropType<unknown extends Defaults["bgColor"] ? string : string | Defaults["bgColor"]>;
default: unknown extends Defaults["bgColor"] ? string : string | Defaults["bgColor"];
};
divided: unknown extends Defaults["divided"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["divided"] ? boolean : boolean | Defaults["divided"]>;
default: unknown extends Defaults["divided"] ? boolean : boolean | Defaults["divided"];
};
title: unknown extends Defaults["title"] ? {
type: PropType<string>;
default: string;
} : Omit<{
type: PropType<string>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["title"] ? string : string | Defaults["title"]>;
default: unknown extends Defaults["title"] ? string : string | Defaults["title"];
};
hideHeader: unknown extends Defaults["hideHeader"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["hideHeader"] ? boolean : boolean | Defaults["hideHeader"]>;
default: unknown extends Defaults["hideHeader"] ? boolean : boolean | Defaults["hideHeader"];
};
hideTitle: unknown extends Defaults["hideTitle"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["hideTitle"] ? boolean : boolean | Defaults["hideTitle"]>;
default: unknown extends Defaults["hideTitle"] ? boolean : boolean | Defaults["hideTitle"];
};
allowedHours: unknown extends Defaults["allowedHours"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedHours"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedHours"]>;
default: unknown extends Defaults["allowedHours"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedHours"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
allowedMinutes: unknown extends Defaults["allowedMinutes"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedMinutes"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedMinutes"]>;
default: unknown extends Defaults["allowedMinutes"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedMinutes"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
allowedSeconds: unknown extends Defaults["allowedSeconds"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedSeconds"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedSeconds"]>;
default: unknown extends Defaults["allowedSeconds"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedSeconds"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
max: unknown extends Defaults["max"] ? StringConstructor : {
type: PropType<unknown extends Defaults["max"] ? string : string | Defaults["max"]>;
default: unknown extends Defaults["max"] ? string : string | Defaults["max"];
};
min: unknown extends Defaults["min"] ? StringConstructor : {
type: PropType<unknown extends Defaults["min"] ? string : string | Defaults["min"]>;
default: unknown extends Defaults["min"] ? string : string | Defaults["min"];
};
disabled: unknown extends Defaults["disabled"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"]>;
default: unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"];
};
format: unknown extends Defaults["format"] ? {
type: PropType<'ampm' | '24hr'>;
default: string;
} : Omit<{
type: PropType<'ampm' | '24hr'>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["format"] ? "24hr" | "ampm" : "24hr" | "ampm" | Defaults["format"]>;
default: unknown extends Defaults["format"] ? "24hr" | "ampm" : Defaults["format"] | NonNullable<"24hr" | "ampm">;
};
viewMode: unknown extends Defaults["viewMode"] ? {
type: PropType<VTimePickerViewMode>;
default: string;
} : Omit<{
type: PropType<VTimePickerViewMode>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["viewMode"] ? VTimePickerViewMode : Defaults["viewMode"] | VTimePickerViewMode>;
default: unknown extends Defaults["viewMode"] ? VTimePickerViewMode : Defaults["viewMode"] | NonNullable<VTimePickerViewMode>;
};
period: unknown extends Defaults["period"] ? {
type: PropType<Period>;
default: string;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<Period>;
default: string;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["period"] ? Period : Defaults["period"] | Period>;
default: unknown extends Defaults["period"] ? Period : Defaults["period"] | NonNullable<Period>;
};
modelValue: unknown extends Defaults["modelValue"] ? PropType<any> : {
type: PropType<unknown extends Defaults["modelValue"] ? any : any>;
default: unknown extends Defaults["modelValue"] ? any : any;
};
readonly: unknown extends Defaults["readonly"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"]>;
default: unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"];
};
scrollable: unknown extends Defaults["scrollable"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["scrollable"] ? boolean : boolean | Defaults["scrollable"]>;
default: unknown extends Defaults["scrollable"] ? boolean : boolean | Defaults["scrollable"];
};
useSeconds: unknown extends Defaults["useSeconds"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["useSeconds"] ? boolean : boolean | Defaults["useSeconds"]>;
default: unknown extends Defaults["useSeconds"] ? boolean : boolean | Defaults["useSeconds"];
};
variant: unknown extends Defaults["variant"] ? {
type: PropType<Variant>;
default: string;
} : Omit<{
type: PropType<Variant>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["variant"] ? Variant : Defaults["variant"] | Variant>;
default: unknown extends Defaults["variant"] ? Variant : Defaults["variant"] | NonNullable<Variant>;
};
};
export declare const VTimePicker: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
density: import("../../composables/density.js").Density;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
} & {
theme?: string | undefined;
class?: any;
border?: string | number | boolean | undefined;
elevation?: string | number | undefined;
rounded?: string | number | boolean | undefined;
height?: string | number | undefined;
maxHeight?: string | number | undefined;
maxWidth?: string | number | undefined;
minHeight?: string | number | undefined;
minWidth?: string | number | undefined;
width?: string | number | undefined;
location?: import("../../util/index.js").Anchor | null | undefined;
position?: "absolute" | "fixed" | "relative" | "static" | "sticky" | undefined;
color?: string | undefined;
bgColor?: string | undefined;
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
modelValue?: any;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
actions?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
actions?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:actions"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((val: number) => any) | undefined;
"onUpdate:minute"?: ((val: number) => any) | undefined;
"onUpdate:modelValue"?: ((val: string | null) => any) | undefined;
"onUpdate:period"?: ((val: Period) => any) | undefined;
"onUpdate:second"?: ((val: number) => any) | undefined;
"onUpdate:viewMode"?: ((val: VTimePickerViewMode) => any) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:hour': (val: number) => true;
'update:minute': (val: number) => true;
'update:period': (val: Period) => true;
'update:second': (val: number) => true;
'update:modelValue': (val: string | null) => true;
'update:viewMode': (val: VTimePickerViewMode) => true;
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
style: import("vue").StyleValue;
density: import("../../composables/density.js").Density;
rounded: string | number | boolean;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
}, true, {}, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
actions: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
title: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
density: import("../../composables/density.js").Density;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
} & {
theme?: string | undefined;
class?: any;
border?: string | number | boolean | undefined;
elevation?: string | number | undefined;
rounded?: string | number | boolean | undefined;
height?: string | number | undefined;
maxHeight?: string | number | undefined;
maxWidth?: string | number | undefined;
minHeight?: string | number | undefined;
minWidth?: string | number | undefined;
width?: string | number | undefined;
location?: import("../../util/index.js").Anchor | null | undefined;
position?: "absolute" | "fixed" | "relative" | "static" | "sticky" | undefined;
color?: string | undefined;
bgColor?: string | undefined;
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
modelValue?: any;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
actions?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
actions?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:actions"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((val: number) => any) | undefined;
"onUpdate:minute"?: ((val: number) => any) | undefined;
"onUpdate:modelValue"?: ((val: string | null) => any) | undefined;
"onUpdate:period"?: ((val: Period) => any) | undefined;
"onUpdate:second"?: ((val: number) => any) | undefined;
"onUpdate:viewMode"?: ((val: VTimePickerViewMode) => any) | undefined;
}, {}, {}, {}, {}, {
style: import("vue").StyleValue;
density: import("../../composables/density.js").Density;
rounded: string | number | boolean;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
density: import("../../composables/density.js").Density;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
} & {
theme?: string | undefined;
class?: any;
border?: string | number | boolean | undefined;
elevation?: string | number | undefined;
rounded?: string | number | boolean | undefined;
height?: string | number | undefined;
maxHeight?: string | number | undefined;
maxWidth?: string | number | undefined;
minHeight?: string | number | undefined;
minWidth?: string | number | undefined;
width?: string | number | undefined;
location?: import("../../util/index.js").Anchor | null | undefined;
position?: "absolute" | "fixed" | "relative" | "static" | "sticky" | undefined;
color?: string | undefined;
bgColor?: string | undefined;
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
modelValue?: any;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
actions?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
actions?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:actions"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((val: number) => any) | undefined;
"onUpdate:minute"?: ((val: number) => any) | undefined;
"onUpdate:modelValue"?: ((val: string | null) => any) | undefined;
"onUpdate:period"?: ((val: Period) => any) | undefined;
"onUpdate:second"?: ((val: number) => any) | undefined;
"onUpdate:viewMode"?: ((val: VTimePickerViewMode) => any) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:hour': (val: number) => true;
'update:minute': (val: number) => true;
'update:period': (val: Period) => true;
'update:second': (val: number) => true;
'update:modelValue': (val: string | null) => true;
'update:viewMode': (val: VTimePickerViewMode) => true;
}, string, {
style: import("vue").StyleValue;
density: import("../../composables/density.js").Density;
rounded: string | number | boolean;
tile: boolean;
tag: string | import("../../util/index.js").JSXComponent;
divided: boolean;
title: string;
hideHeader: boolean;
hideTitle: boolean;
disabled: boolean;
format: "24hr" | "ampm";
viewMode: VTimePickerViewMode;
period: Period;
readonly: boolean;
scrollable: boolean;
useSeconds: boolean;
variant: Variant;
}, {}, string, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
actions: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
title: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
theme: StringConstructor;
class: PropType<import("../../composables/component.js").ClassValue>;
style: {
type: PropType<import("vue").StyleValue>;
default: null;
};
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
density: {
type: PropType<import("../../composables/density.js").Density>;
default: string;
validator: (v: any) => boolean;
};
elevation: {
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
};
rounded: {
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
};
tile: BooleanConstructor;
tag: {
type: PropType<string | import("../../util/index.js").JSXComponent>;
default: string;
};
height: (NumberConstructor | StringConstructor)[];
maxHeight: (NumberConstructor | StringConstructor)[];
maxWidth: (NumberConstructor | StringConstructor)[];
minHeight: (NumberConstructor | StringConstructor)[];
minWidth: (NumberConstructor | StringConstructor)[];
width: (NumberConstructor | StringConstructor)[];
location: PropType<import("../../util/index.js").Anchor | null>;
position: {
type: PropType<"absolute" | "fixed" | "relative" | "static" | "sticky">;
validator: (v: any) => boolean;
};
color: StringConstructor;
bgColor: StringConstructor;
divided: BooleanConstructor;
title: {
type: PropType<string>;
default: string;
};
hideHeader: BooleanConstructor;
hideTitle: BooleanConstructor;
allowedHours: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedMinutes: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedSeconds: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
max: StringConstructor;
min: StringConstructor;
disabled: BooleanConstructor;
format: {
type: PropType<'ampm' | '24hr'>;
default: string;
};
viewMode: {
type: PropType<VTimePickerViewMode>;
default: string;
};
period: {
type: PropType<Period>;
default: string;
validator: (v: any) => boolean;
};
modelValue: PropType<any>;
readonly: BooleanConstructor;
scrollable: BooleanConstructor;
useSeconds: BooleanConstructor;
variant: {
type: PropType<Variant>;
default: string;
};
}, import("vue").ExtractPropTypes<{
theme: StringConstructor;
class: PropType<import("../../composables/component.js").ClassValue>;
style: {
type: PropType<import("vue").StyleValue>;
default: null;
};
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
density: {
type: PropType<import("../../composables/density.js").Density>;
default: string;
validator: (v: any) => boolean;
};
elevation: {
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
};
rounded: {
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
};
tile: BooleanConstructor;
tag: {
type: PropType<string | import("../../util/index.js").JSXComponent>;
default: string;
};
height: (NumberConstructor | StringConstructor)[];
maxHeight: (NumberConstructor | StringConstructor)[];
maxWidth: (NumberConstructor | StringConstructor)[];
minHeight: (NumberConstructor | StringConstructor)[];
minWidth: (NumberConstructor | StringConstructor)[];
width: (NumberConstructor | StringConstructor)[];
location: PropType<import("../../util/index.js").Anchor | null>;
position: {
type: PropType<"absolute" | "fixed" | "relative" | "static" | "sticky">;
validator: (v: any) => boolean;
};
color: StringConstructor;
bgColor: StringConstructor;
divided: BooleanConstructor;
title: {
type: PropType<string>;
default: string;
};
hideHeader: BooleanConstructor;
hideTitle: BooleanConstructor;
allowedHours: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedMinutes: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedSeconds: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
max: StringConstructor;
min: StringConstructor;
disabled: BooleanConstructor;
format: {
type: PropType<'ampm' | '24hr'>;
default: string;
};
viewMode: {
type: PropType<VTimePickerViewMode>;
default: string;
};
period: {
type: PropType<Period>;
default: string;
validator: (v: any) => boolean;
};
modelValue: PropType<any>;
readonly: BooleanConstructor;
scrollable: BooleanConstructor;
useSeconds: BooleanConstructor;
variant: {
type: PropType<Variant>;
default: string;
};
}>>;
export type VTimePicker = InstanceType<typeof VTimePicker>;
+226
View File
@@ -0,0 +1,226 @@
import { createElementVNode as _createElementVNode, mergeProps as _mergeProps, createVNode as _createVNode } from "vue";
// Styles
import "./VTimePicker.css";
// Components
import { VTimePickerClock } from "./VTimePickerClock.js";
import { VTimePickerControls } from "./VTimePickerControls.js";
import { makeVPickerProps, VPicker } from "../../labs/VPicker/VPicker.js"; // Composables
import { makeDensityProps, useDensity } from "../../composables/density.js";
import { useLocale } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
import { computed, onMounted, ref, toRef, watch } from 'vue';
import { makeTimeValidationProps, useTimeValidation } from "./useTimeValidation.js";
import { convert12to24, convert24to12, pad } from "./util.js";
import { genericComponent, omit, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVTimePickerProps = propsFactory({
disabled: Boolean,
format: {
type: String,
default: 'ampm'
},
viewMode: {
type: String,
default: 'hour'
},
period: {
type: String,
default: 'am',
validator: v => ['am', 'pm'].includes(v)
},
modelValue: null,
readonly: Boolean,
scrollable: Boolean,
useSeconds: Boolean,
variant: {
type: String,
default: 'dial'
},
...makeTimeValidationProps(),
...omit(makeVPickerProps({
title: '$vuetify.timePicker.title'
}), ['landscape']),
...makeDensityProps()
}, 'VTimePicker');
export const VTimePicker = genericComponent()({
name: 'VTimePicker',
props: makeVTimePickerProps(),
emits: {
'update:hour': val => true,
'update:minute': val => true,
'update:period': val => true,
'update:second': val => true,
'update:modelValue': val => true,
'update:viewMode': val => true
},
setup(props, {
emit,
slots
}) {
const {
t
} = useLocale();
const {
densityClasses
} = useDensity(props);
const inputHour = ref(null);
const inputMinute = ref(null);
const inputSecond = ref(null);
const lazyInputHour = ref(null);
const lazyInputMinute = ref(null);
const lazyInputSecond = ref(null);
const period = useProxiedModel(props, 'period', 'am');
const viewMode = useProxiedModel(props, 'viewMode', 'hour');
const controlsRef = ref(null);
const clockRef = ref(null);
const isAmPm = computed(() => {
return props.format === 'ampm';
});
const {
isAllowedHour,
isAllowedMinute,
isAllowedSecond
} = useTimeValidation(props);
const shouldClear = toRef(() => {
return props.modelValue !== null && inputHour.value === null && inputMinute.value === null && (!props.useSeconds || inputSecond.value === null);
});
function emitValue() {
const value = genValue();
if (value !== null && value !== props.modelValue) {
emit('update:modelValue', value);
}
if (shouldClear.value) {
emit('update:modelValue', null);
}
}
watch(inputHour, emitValue);
watch(inputMinute, emitValue);
watch(inputSecond, emitValue);
watch(period, (newPeriod, oldPeriod) => {
if (inputHour.value == null || newPeriod === oldPeriod) return;
if (newPeriod === 'pm' && inputHour.value < 12) {
inputHour.value = inputHour.value + 12;
} else if (newPeriod === 'am' && inputHour.value >= 12) {
inputHour.value = inputHour.value - 12;
}
});
watch(() => props.modelValue, val => setInputData(val));
watch(() => props.useSeconds, (val, old) => {
if (old && !val && viewMode.value === 'second') {
viewMode.value = 'minute';
}
if (!val && inputSecond.value !== null) {
inputSecond.value = null;
}
});
onMounted(() => {
setInputData(props.modelValue);
});
function genValue() {
if (inputHour.value != null && inputMinute.value != null && (!props.useSeconds || inputSecond.value != null)) {
return `${pad(inputHour.value)}:${pad(inputMinute.value)}` + (props.useSeconds ? `:${pad(inputSecond.value)}` : '');
}
return null;
}
function setInputData(value) {
if (value == null || value === '') {
inputHour.value = null;
inputMinute.value = null;
inputSecond.value = null;
} else if (value instanceof Date) {
inputHour.value = value.getHours();
inputMinute.value = value.getMinutes();
inputSecond.value = value.getSeconds();
} else {
const [hour,, minute,, second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6);
inputHour.value = period ? convert12to24(parseInt(hour, 10), period) : parseInt(hour, 10);
inputMinute.value = parseInt(minute, 10);
inputSecond.value = parseInt(second || 0, 10);
}
period.value = inputHour.value == null || inputHour.value < 12 ? 'am' : 'pm';
}
function onInput(value) {
if (viewMode.value === 'hour') {
inputHour.value = isAmPm.value ? convert12to24(value, period.value) : value;
} else if (viewMode.value === 'minute') {
inputMinute.value = value;
} else {
inputSecond.value = value;
}
}
function onChange(value) {
switch (viewMode.value || 'hour') {
case 'hour':
emit('update:hour', value);
break;
case 'minute':
emit('update:minute', value);
break;
case 'second':
emit('update:second', value);
break;
default:
break;
}
const emitChange = inputHour.value !== null && inputMinute.value !== null && (props.useSeconds ? inputSecond.value !== null : true);
if (viewMode.value === 'hour') {
viewMode.value = 'minute';
} else if (props.useSeconds && viewMode.value === 'minute') {
viewMode.value = 'second';
}
if (inputHour.value === lazyInputHour.value && inputMinute.value === lazyInputMinute.value && (!props.useSeconds || inputSecond.value === lazyInputSecond.value)) return;
const time = genValue();
if (time === null) return;
lazyInputHour.value = inputHour.value;
lazyInputMinute.value = inputMinute.value;
props.useSeconds && (lazyInputSecond.value = inputSecond.value);
emitChange && emitValue();
}
useRender(() => {
const pickerProps = omit(VPicker.filterProps(props), ['hideHeader']);
const timePickerControlsProps = VTimePickerControls.filterProps(props);
const timePickerClockProps = VTimePickerClock.filterProps(omit(props, ['format', 'modelValue', 'min', 'max']));
const clockValidation = viewMode.value === 'hour' ? isAllowedHour.value : viewMode.value === 'minute' ? v => isAllowedMinute.value(inputHour.value, v) : v => isAllowedSecond.value(inputHour.value, inputMinute.value, v);
return _createVNode(VPicker, _mergeProps(pickerProps, {
"color": undefined,
"class": ['v-time-picker', `v-time-picker--variant-${props.variant}`, props.class, densityClasses.value],
"hideHeader": props.hideHeader && props.variant !== 'input',
"style": props.style
}), {
title: () => slots.title?.() ?? _createElementVNode("div", {
"class": "v-time-picker__title"
}, [t(props.title)]),
header: () => _createVNode(VTimePickerControls, _mergeProps(timePickerControlsProps, {
"ampm": isAmPm.value,
"hour": inputHour.value,
"minute": inputMinute.value,
"period": period.value,
"second": inputSecond.value,
"viewMode": viewMode.value,
"inputHints": props.variant === 'input',
"onUpdate:hour": val => inputHour.value = val,
"onUpdate:minute": val => inputMinute.value = val,
"onUpdate:second": val => inputSecond.value = val,
"onUpdate:period": val => period.value = val,
"onUpdate:viewMode": value => viewMode.value = value,
"ref": controlsRef
}), null),
default: () => _createVNode(VTimePickerClock, _mergeProps(timePickerClockProps, {
"allowedValues": clockValidation,
"double": viewMode.value === 'hour' && !isAmPm.value,
"format": viewMode.value === 'hour' ? isAmPm.value ? convert24to12 : val => val : val => pad(val, 2),
"max": viewMode.value === 'hour' ? isAmPm.value && period.value === 'am' ? 11 : 23 : 59,
"min": viewMode.value === 'hour' && isAmPm.value && period.value === 'pm' ? 12 : 0,
"size": 20,
"step": viewMode.value === 'hour' ? 1 : 5,
"modelValue": viewMode.value === 'hour' ? inputHour.value : viewMode.value === 'minute' ? inputMinute.value : inputSecond.value,
"onChange": onChange,
"onInput": onInput,
"ref": clockRef
}), null),
actions: slots.actions
});
});
}
});
//# sourceMappingURL=VTimePicker.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,27 @@
@use '../../styles/tools'
@use '../../styles/settings'
@use './variables' as *
@include tools.layer('components')
.v-time-picker
&.v-picker
min-width: $time-picker-width
.v-picker__body,
&-controls__field-label,
.v-field
transition-duration: .25s
transition-timing-function: settings.$standard-easing
transition-property: transform, max-height, opacity, font-size
@media (prefers-reduced-motion: reduce)
transition: none
.v-picker__body
transition-behavior: allow-discrete
max-height: calc-size(max-content, size)
&--variant-input
.v-picker__body
transform: scale(0)
max-height: 0
@@ -0,0 +1,143 @@
@layer vuetify-components {
.v-time-picker-clock {
background: rgb(var(--v-theme-background));
color: rgb(var(--v-theme-on-background));
}
.v-time-picker-clock:after {
color: rgb(var(--v-theme-primary));
}
.v-time-picker-clock .v-time-picker-clock__item--active {
background-color: rgb(var(--v-theme-surface-variant));
color: rgb(var(--v-theme-on-surface-variant));
}
.v-time-picker-clock {
margin: 24px;
background: rgb(var(--v-theme-surface-light));
border-radius: 50%;
position: relative;
transition: none;
user-select: none;
max-width: 256px;
aspect-ratio: 1;
flex: 100%;
}
.v-time-picker-clock__container {
display: flex;
flex-direction: column;
flex-basis: 290px;
justify-content: center;
padding: 10px;
}
.v-time-picker-clock__hand {
background-color: currentColor;
height: calc(50% - 4px);
width: 2px;
bottom: 50%;
left: calc(50% - 1px);
transform-origin: center bottom;
position: absolute;
will-change: transform;
z-index: 1;
}
.v-time-picker-clock__hand:before {
background: transparent;
border-width: 2px;
border-style: solid;
border-color: currentColor;
border-radius: 100%;
width: 10px;
height: 10px;
content: "";
position: absolute;
top: -4px;
left: 50%;
transform: translate(-50%, -50%);
}
.v-time-picker-clock__hand:after {
content: "";
position: absolute;
height: 8px;
width: 8px;
top: 100%;
left: 50%;
border-radius: 100%;
background-color: currentColor;
transform: translate(-50%, -50%);
}
.v-time-picker-clock__hand--inner:after {
height: 14px;
}
.v-time-picker-clock--readonly {
pointer-events: none;
}
.v-time-picker-clock .v-time-picker-clock__item--disabled {
opacity: var(--v-disabled-opacity);
}
.v-picker--full-width .v-time-picker-clock__container {
max-width: 290px;
}
.v-time-picker-clock__inner {
position: absolute;
bottom: 27px;
left: 27px;
right: 27px;
top: 27px;
}
.v-time-picker-clock__item {
align-items: center;
border-radius: 100%;
cursor: default;
display: flex;
font-size: 16px;
justify-content: center;
height: 40px;
position: absolute;
text-align: center;
width: 40px;
user-select: none;
transform: translate(-50%, -50%);
}
.v-time-picker-clock__item > span {
z-index: 1;
}
.v-time-picker-clock__item:before, .v-time-picker-clock__item:after {
content: "";
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
height: 14px;
width: 14px;
transform: translate(-50%, -50%);
}
.v-time-picker-clock__item:after, .v-time-picker-clock__item:before {
height: 40px;
width: 40px;
}
.v-time-picker-clock__item--active {
cursor: default;
z-index: 2;
}
.v-time-picker-clock__item--disabled {
pointer-events: none;
}
.v-picker--landscape .v-time-picker-clock__container {
flex-direction: row;
}
}
@layer vuetify-final.trumps {
@media (forced-colors: active) {
.v-time-picker-clock__hand {
background-color: highlight;
}
.v-time-picker-clock__hand:before {
border-color: highlight;
}
.v-time-picker-clock__hand:after {
background-color: highlight;
}
.v-time-picker-clock__item--active {
outline: 2px solid highlight;
}
}
}
@@ -0,0 +1,318 @@
import type { PropType } from 'vue';
export declare const makeVTimePickerClockProps: <Defaults extends {
allowedValues?: unknown;
ampm?: unknown;
color?: unknown;
disabled?: unknown;
displayedValue?: unknown;
double?: unknown;
format?: unknown;
max?: unknown;
min?: unknown;
scrollable?: unknown;
readonly?: unknown;
rotate?: unknown;
step?: unknown;
modelValue?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
allowedValues: unknown extends Defaults["allowedValues"] ? PropType<(value: number) => boolean> : {
type: PropType<unknown extends Defaults["allowedValues"] ? (value: number) => boolean : ((value: number) => boolean) | Defaults["allowedValues"]>;
default: unknown extends Defaults["allowedValues"] ? (value: number) => boolean : ((value: number) => boolean) | Defaults["allowedValues"];
};
ampm: unknown extends Defaults["ampm"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["ampm"] ? boolean : boolean | Defaults["ampm"]>;
default: unknown extends Defaults["ampm"] ? boolean : boolean | Defaults["ampm"];
};
color: unknown extends Defaults["color"] ? StringConstructor : {
type: PropType<unknown extends Defaults["color"] ? string : string | Defaults["color"]>;
default: unknown extends Defaults["color"] ? string : string | Defaults["color"];
};
disabled: unknown extends Defaults["disabled"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"]>;
default: unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"];
};
displayedValue: unknown extends Defaults["displayedValue"] ? null : {
type: PropType<unknown extends Defaults["displayedValue"] ? any : any>;
default: unknown extends Defaults["displayedValue"] ? any : any;
};
double: unknown extends Defaults["double"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["double"] ? boolean : boolean | Defaults["double"]>;
default: unknown extends Defaults["double"] ? boolean : boolean | Defaults["double"];
};
format: unknown extends Defaults["format"] ? {
type: FunctionConstructor;
default: (val: string | number) => string | number;
} : Omit<{
type: FunctionConstructor;
default: (val: string | number) => string | number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["format"] ? Function : Function | Defaults["format"]>;
default: unknown extends Defaults["format"] ? Function : Function | Defaults["format"];
};
max: unknown extends Defaults["max"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["max"] ? number : number | Defaults["max"]>;
default: unknown extends Defaults["max"] ? number : number | Defaults["max"];
};
min: unknown extends Defaults["min"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["min"] ? number : number | Defaults["min"]>;
default: unknown extends Defaults["min"] ? number : number | Defaults["min"];
};
scrollable: unknown extends Defaults["scrollable"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["scrollable"] ? boolean : boolean | Defaults["scrollable"]>;
default: unknown extends Defaults["scrollable"] ? boolean : boolean | Defaults["scrollable"];
};
readonly: unknown extends Defaults["readonly"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"]>;
default: unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"];
};
rotate: unknown extends Defaults["rotate"] ? {
type: NumberConstructor;
default: number;
} : Omit<{
type: NumberConstructor;
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["rotate"] ? number : number | Defaults["rotate"]>;
default: unknown extends Defaults["rotate"] ? number : number | Defaults["rotate"];
};
step: unknown extends Defaults["step"] ? {
type: NumberConstructor;
default: number;
} : Omit<{
type: NumberConstructor;
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["step"] ? number : number | Defaults["step"]>;
default: unknown extends Defaults["step"] ? number : number | Defaults["step"];
};
modelValue: unknown extends Defaults["modelValue"] ? {
type: NumberConstructor;
} : Omit<{
type: NumberConstructor;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["modelValue"] ? number : number | Defaults["modelValue"]>;
default: unknown extends Defaults["modelValue"] ? number : number | Defaults["modelValue"];
};
};
export declare const VTimePickerClock: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
max: number;
min: number;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
} & {
allowedValues?: ((value: number) => boolean) | undefined;
color?: string | undefined;
displayedValue?: any;
modelValue?: number | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
onChange?: ((val: number) => any) | undefined;
onInput?: ((val: number) => any) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
change: (val: number) => true;
input: (val: number) => true;
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
}, true, {}, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
max: number;
min: number;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
} & {
allowedValues?: ((value: number) => boolean) | undefined;
color?: string | undefined;
displayedValue?: any;
modelValue?: number | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
onChange?: ((val: number) => any) | undefined;
onInput?: ((val: number) => any) | undefined;
}, {}, {}, {}, {}, {
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
max: number;
min: number;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
} & {
allowedValues?: ((value: number) => boolean) | undefined;
color?: string | undefined;
displayedValue?: any;
modelValue?: number | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
onChange?: ((val: number) => any) | undefined;
onInput?: ((val: number) => any) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
change: (val: number) => true;
input: (val: number) => true;
}, string, {
ampm: boolean;
disabled: boolean;
double: boolean;
format: Function;
scrollable: boolean;
readonly: boolean;
rotate: number;
step: number;
}, {}, string, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
allowedValues: PropType<(value: number) => boolean>;
ampm: BooleanConstructor;
color: StringConstructor;
disabled: BooleanConstructor;
displayedValue: null;
double: BooleanConstructor;
format: {
type: FunctionConstructor;
default: (val: string | number) => string | number;
};
max: {
type: NumberConstructor;
required: true;
};
min: {
type: NumberConstructor;
required: true;
};
scrollable: BooleanConstructor;
readonly: BooleanConstructor;
rotate: {
type: NumberConstructor;
default: number;
};
step: {
type: NumberConstructor;
default: number;
};
modelValue: {
type: NumberConstructor;
};
}, import("vue").ExtractPropTypes<{
allowedValues: PropType<(value: number) => boolean>;
ampm: BooleanConstructor;
color: StringConstructor;
disabled: BooleanConstructor;
displayedValue: null;
double: BooleanConstructor;
format: {
type: FunctionConstructor;
default: (val: string | number) => string | number;
};
max: {
type: NumberConstructor;
required: true;
};
min: {
type: NumberConstructor;
required: true;
};
scrollable: BooleanConstructor;
readonly: BooleanConstructor;
rotate: {
type: NumberConstructor;
default: number;
};
step: {
type: NumberConstructor;
default: number;
};
modelValue: {
type: NumberConstructor;
};
}>>;
export type VTimePickerClock = InstanceType<typeof VTimePickerClock>;
@@ -0,0 +1,252 @@
import { normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode } from "vue";
// Styles
import "./VTimePickerClock.css";
// Composables
import { useBackgroundColor, useTextColor } from "../../composables/color.js"; // Utilities
import { computed, onScopeDispose, ref, watch } from 'vue';
import { debounce, genericComponent, IN_BROWSER, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVTimePickerClockProps = propsFactory({
allowedValues: Function,
ampm: Boolean,
color: String,
disabled: Boolean,
displayedValue: null,
double: Boolean,
format: {
type: Function,
default: val => val
},
max: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
scrollable: Boolean,
readonly: Boolean,
rotate: {
type: Number,
default: 0
},
step: {
type: Number,
default: 1
},
modelValue: {
type: Number
}
}, 'VTimePickerClock');
export const VTimePickerClock = genericComponent()({
name: 'VTimePickerClock',
props: makeVTimePickerClockProps(),
emits: {
change: val => true,
input: val => true
},
setup(props, {
emit
}) {
const clockRef = ref(null);
const innerClockRef = ref(null);
const inputValue = ref(undefined);
const isDragging = ref(false);
const valueOnMouseDown = ref(null);
const valueOnMouseUp = ref(null);
const emitChangeDebounced = debounce(value => emit('change', value), 750);
const {
textColorClasses,
textColorStyles
} = useTextColor(() => props.color);
const {
backgroundColorClasses,
backgroundColorStyles
} = useBackgroundColor(() => props.color);
const count = computed(() => props.max - props.min + 1);
const roundCount = computed(() => props.double ? count.value / 2 : count.value);
const degreesPerUnit = computed(() => 360 / roundCount.value);
const degrees = computed(() => degreesPerUnit.value * Math.PI / 180);
const displayedValue = computed(() => props.modelValue == null ? props.min : props.modelValue);
const innerRadiusScale = computed(() => 0.62);
const genChildren = computed(() => {
const children = [];
for (let value = props.min; value <= props.max; value = value + props.step) {
children.push(value);
}
return children;
});
watch(() => props.modelValue, val => {
inputValue.value = val;
});
function update(value) {
if (inputValue.value !== value) {
inputValue.value = value;
}
emit('input', value);
}
function isAllowed(value) {
return !props.allowedValues || props.allowedValues(value);
}
function wheel(e) {
if (!props.scrollable || props.disabled) return;
e.preventDefault();
const delta = Math.sign(-e.deltaY || 1);
let value = displayedValue.value;
do {
value = value + delta;
value = (value - props.min + count.value) % count.value + props.min;
} while (!isAllowed(value) && value !== displayedValue.value);
if (value !== props.displayedValue) {
update(value);
}
emitChangeDebounced(value);
}
function isInner(value) {
return props.double && value - props.min >= roundCount.value;
}
function handScale(value) {
return isInner(value) ? innerRadiusScale.value : 1;
}
function getPosition(value) {
const rotateRadians = props.rotate * Math.PI / 180;
return {
x: Math.sin((value - props.min) * degrees.value + rotateRadians) * handScale(value),
y: -Math.cos((value - props.min) * degrees.value + rotateRadians) * handScale(value)
};
}
function angleToValue(angle, insideClick) {
const value = (Math.round(angle / degreesPerUnit.value) + (insideClick ? roundCount.value : 0)) % count.value + props.min;
// Necessary to fix edge case when selecting left part of the value(s) at 12 o'clock
if (angle < 360 - degreesPerUnit.value / 2) return value;
return insideClick ? props.max - roundCount.value + 1 : props.min;
}
function getTransform(i) {
const {
x,
y
} = getPosition(i);
return {
left: `${Math.round(50 + x * 50)}%`,
top: `${Math.round(50 + y * 50)}%`
};
}
function euclidean(p0, p1) {
const dx = p1.x - p0.x;
const dy = p1.y - p0.y;
return Math.sqrt(dx * dx + dy * dy);
}
function angle(center, p1) {
const value = 2 * Math.atan2(p1.y - center.y - euclidean(center, p1), p1.x - center.x);
return Math.abs(value * 180 / Math.PI);
}
function setMouseDownValue(value) {
if (valueOnMouseDown.value === null) {
valueOnMouseDown.value = value;
}
valueOnMouseUp.value = value;
update(value);
}
function onDragMove(e) {
e.preventDefault();
if (!isDragging.value && e.type !== 'click' || !clockRef.value) return;
const {
width,
top,
left
} = clockRef.value?.getBoundingClientRect();
const {
width: innerWidth
} = innerClockRef.value?.getBoundingClientRect() ?? {
width: 0
};
const {
clientX,
clientY
} = 'touches' in e ? e.touches[0] : e;
const center = {
x: width / 2,
y: -width / 2
};
const coords = {
x: clientX - left,
y: top - clientY
};
const handAngle = Math.round(angle(center, coords) - props.rotate + 360) % 360;
const insideClick = props.double && euclidean(center, coords) < (innerWidth + innerWidth * innerRadiusScale.value) / 4;
const checksCount = Math.ceil(15 / degreesPerUnit.value);
let value;
for (let i = 0; i < checksCount; i++) {
value = angleToValue(handAngle + i * degreesPerUnit.value, insideClick);
if (isAllowed(value)) return setMouseDownValue(value);
value = angleToValue(handAngle - i * degreesPerUnit.value, insideClick);
if (isAllowed(value)) return setMouseDownValue(value);
}
}
function onMouseDown(e) {
if (props.disabled) return;
e.preventDefault();
window.addEventListener('mousemove', onDragMove);
window.addEventListener('touchmove', onDragMove);
window.addEventListener('mouseup', onMouseUp);
window.addEventListener('touchend', onMouseUp);
valueOnMouseDown.value = null;
valueOnMouseUp.value = null;
isDragging.value = true;
onDragMove(e);
}
function onMouseUp(e) {
e.stopPropagation();
removeListeners();
isDragging.value = false;
if (valueOnMouseUp.value !== null && isAllowed(valueOnMouseUp.value)) {
emit('change', valueOnMouseUp.value);
}
}
function removeListeners() {
if (!IN_BROWSER) return;
window.removeEventListener('mousemove', onDragMove);
window.removeEventListener('touchmove', onDragMove);
window.removeEventListener('mouseup', onMouseUp);
window.removeEventListener('touchend', onMouseUp);
}
onScopeDispose(removeListeners);
useRender(() => {
return _createElementVNode("div", {
"class": _normalizeClass([{
'v-time-picker-clock': true,
'v-time-picker-clock--indeterminate': props.modelValue == null,
'v-time-picker-clock--readonly': props.readonly
}]),
"onMousedown": onMouseDown,
"onTouchstart": onMouseDown,
"onWheel": wheel,
"ref": clockRef
}, [_createElementVNode("div", {
"class": "v-time-picker-clock__inner",
"ref": innerClockRef
}, [_createElementVNode("div", {
"class": _normalizeClass([{
'v-time-picker-clock__hand': true,
'v-time-picker-clock__hand--inner': isInner(props.modelValue)
}, textColorClasses.value]),
"style": _normalizeStyle([{
transform: `rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg) scaleY(${handScale(displayedValue.value)})`
}, textColorStyles.value])
}, null), genChildren.value.map(value => {
const isActive = value === displayedValue.value;
return _createElementVNode("div", {
"class": _normalizeClass([{
'v-time-picker-clock__item': true,
'v-time-picker-clock__item--active': isActive,
'v-time-picker-clock__item--disabled': props.disabled || !isAllowed(value)
}, isActive && backgroundColorClasses.value]),
"style": _normalizeStyle([getTransform(value), isActive && backgroundColorStyles.value])
}, [_createElementVNode("span", null, [props.format(value)])]);
})])]);
});
}
});
//# sourceMappingURL=VTimePickerClock.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,145 @@
@use '../../styles/tools'
@use './variables' as *
@include tools.layer('components')
// Theme
.v-time-picker-clock
background: rgb(var(--v-theme-background))
color: rgb(var(--v-theme-on-background))
&:after
color: rgb(var(--v-theme-primary))
.v-time-picker-clock__item--active
background-color: rgb(var(--v-theme-surface-variant))
color: rgb(var(--v-theme-on-surface-variant))
.v-time-picker-clock
margin: $time-picker-padding
background: rgb(var(--v-theme-surface-light))
border-radius: 50%
position: relative
transition: none
user-select: none
max-width: 256px
aspect-ratio: 1
flex: 100%
&__container
display: flex
flex-direction: column
flex-basis: 290px
justify-content: center
padding: $time-picker-clock-padding
&__hand
background-color: currentColor
height: $time-picker-clock-hand-height
width: $time-picker-clock-hand-width
bottom: 50%
left: $time-picker-clock-hand-left
transform-origin: center bottom
position: absolute
will-change: transform
z-index: 1
&:before
background: transparent
border-width: $time-picker-clock-end-border-width
border-style: $time-picker-clock-end-border-style
border-color: $time-picker-clock-end-border-color
border-radius: 100%
width: $time-picker-clock-end-size
height: $time-picker-clock-end-size
content: ''
position: absolute
top: $time-picker-clock-end-top
left: 50%
transform: translate(-50%, -50%)
&:after
content: ''
position: absolute
height: $time-picker-clock-center-size
width: $time-picker-clock-center-size
top: 100%
left: 50%
border-radius: 100%
background-color: currentColor
transform: translate(-50%, -50%)
&--inner:after
height: $time-picker-clock-inner-hand-height
&--readonly
pointer-events: none
.v-time-picker-clock__item--disabled
opacity: var(--v-disabled-opacity)
.v-picker--full-width
.v-time-picker-clock__container
max-width: $time-picker-clock-max-width
.v-time-picker-clock__inner
position: absolute
bottom: $time-picker-clock-inner-offset
left: $time-picker-clock-inner-offset
right: $time-picker-clock-inner-offset
top: $time-picker-clock-inner-offset
.v-time-picker-clock__item
align-items: center
border-radius: 100%
cursor: default
display: flex
font-size: $time-picker-number-font-size
justify-content: center
height: $time-picker-indicator-size
position: absolute
text-align: center
width: $time-picker-indicator-size
user-select: none
transform: translate(-50%, -50%)
> span
z-index: 1
&:before, &:after
content: ''
border-radius: 100%
position: absolute
top: 50%
left: 50%
height: 14px
width: 14px
transform: translate(-50%, -50%)
&:after, &:before
height: $time-picker-indicator-size
width: $time-picker-indicator-size
&--active
cursor: default
z-index: 2
&--disabled
pointer-events: none
.v-picker--landscape
.v-time-picker-clock
&__container
flex-direction: row
@include tools.layer('trumps')
@media (forced-colors: active)
.v-time-picker-clock
&__hand
background-color: highlight
&:before
border-color: highlight
&:after
background-color: highlight
&__item--active
outline: 2px solid highlight
@@ -0,0 +1,257 @@
@layer vuetify-components {
.v-time-picker-controls {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.875rem;
margin-inline: 24px;
margin-bottom: 12px;
}
.v-time-picker-controls__text {
padding-bottom: 12px;
}
.v-time-picker-controls__time {
display: flex;
white-space: nowrap;
direction: ltr;
justify-content: center;
align-items: start;
}
.v-time-picker-controls__time__separator {
width: 24px;
text-align: center;
}
.v-time-picker--density-compact .v-time-picker-controls__time__separator {
font-weight: bold;
}
.v-time-picker--density-default .v-time-picker-controls__time__separator {
font-size: 56px;
line-height: 74px;
}
.v-time-picker--variant-input .v-time-picker--density-default .v-time-picker-controls__time__separator {
line-height: 64px;
}
.v-time-picker-controls__time--with-seconds .v-time-picker--density-default .v-time-picker-controls__time__separator {
height: 80px;
font-size: 56px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__time__separator {
font-size: 40px;
line-height: 58px;
}
.v-time-picker--variant-input .v-time-picker--density-comfortable .v-time-picker-controls__time__separator {
line-height: 48px;
}
.v-time-picker-controls__time--with-seconds .v-time-picker--density-comfortable .v-time-picker-controls__time__separator {
height: 64px;
font-size: 40px;
}
.v-time-picker--density-compact .v-time-picker-controls__time__separator {
font-size: 32px;
line-height: 50px;
}
.v-time-picker--variant-input .v-time-picker--density-compact .v-time-picker-controls__time__separator {
line-height: 40px;
}
.v-time-picker-controls__time--with-seconds .v-time-picker--density-compact .v-time-picker-controls__time__separator {
height: 56px;
font-size: 32px;
}
.v-time-picker-controls__time__field {
width: 96px;
}
.v-time-picker-controls__time__field .v-field {
width: 96px;
background-color: rgb(var(--v-theme-surface-light));
color: inherit;
transition: color 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.v-time-picker-controls__time__field .v-field > .v-field__overlay {
opacity: 0.04;
}
.v-time-picker-controls__time__field--active .v-field > .v-field__overlay {
opacity: calc((0.04 + var(--v-focus-opacity)) * var(--v-theme-overlay-multiplier));
}
.v-time-picker--variant-input .v-time-picker-controls__time__field {
width: 96px;
}
.v-time-picker--variant-input .v-time-picker-controls__time__field .v-field {
width: 96px;
}
.v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field {
width: 64px;
}
.v-time-picker--variant-input .v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field {
width: 64px;
}
.v-time-picker-controls__time__field .v-field__input {
padding: 0;
font-weight: 500;
text-align: center;
line-height: 1;
align-self: center;
}
.v-time-picker-controls__time__field .v-field__input:focus::placeholder {
opacity: 0;
}
.v-time-picker-controls__time__field.v-input > .v-input__details {
font-size: 12px;
letter-spacing: 0.0333333333em;
padding-inline: 0;
white-space: normal;
}
.v-time-picker-controls__time__field.v-input > .v-input__details > .v-messages {
opacity: 1;
}
.v-time-picker-controls__time__field.v-input--error .v-field__input {
color: rgb(var(--v-theme-error));
}
.v-time-picker-controls__ampm {
margin-left: 12px;
display: flex;
flex-direction: column;
text-transform: uppercase;
}
.v-time-picker-controls__ampm--readonly {
pointer-events: none;
}
.v-time-picker-controls__ampm--readonly .v-picker__title__btn.v-picker__title__btn--active {
opacity: 0.6;
}
.v-time-picker-controls__ampm__btn.v-btn {
min-width: 52px;
padding: 0 8px;
}
.v-time-picker-controls__ampm__btn.v-btn.v-time-picker-controls__ampm__am {
border-radius: 4px 4px 0 0;
border: 1px solid;
}
.v-time-picker-controls__ampm__btn.v-btn.v-time-picker-controls__ampm__pm {
border-radius: 0 0 4px 4px;
border: 1px solid;
border-top: none;
}
.v-time-picker-controls__ampm__btn.v-btn__active {
background: rgb(var(--v-theme-primary));
}
.v-time-picker--density-default .v-time-picker-controls__time__field .v-input__control {
height: 80px;
}
.v-time-picker--density-default .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 56px;
}
.v-time-picker--density-default .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 80px;
}
.v-time-picker--density-default.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control {
height: 72px;
}
.v-time-picker--density-default.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 44px;
}
.v-time-picker--density-default.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 72px;
}
.v-time-picker--density-default .v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field .v-field {
font-size: 40px;
}
.v-time-picker--density-default .v-time-picker-controls__ampm__btn.v-btn {
font-size: 18px;
height: 40px;
}
.v-time-picker--density-default.v-time-picker--variant-input .v-time-picker-controls__ampm__btn.v-btn {
height: 36px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__time__field .v-input__control {
height: 64px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 40px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 64px;
}
.v-time-picker--density-comfortable.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control {
height: 56px;
}
.v-time-picker--density-comfortable.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 32px;
}
.v-time-picker--density-comfortable.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 56px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field .v-field {
font-size: 32px;
}
.v-time-picker--density-comfortable .v-time-picker-controls__ampm__btn.v-btn {
font-size: 14px;
height: 32px;
}
.v-time-picker--density-comfortable.v-time-picker--variant-input .v-time-picker-controls__ampm__btn.v-btn {
height: 28px;
}
.v-time-picker--density-compact .v-time-picker-controls__time__field .v-input__control {
height: 56px;
}
.v-time-picker--density-compact .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 32px;
}
.v-time-picker--density-compact .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 56px;
}
.v-time-picker--density-compact.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control {
height: 48px;
}
.v-time-picker--density-compact.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field {
font-size: 26px;
}
.v-time-picker--density-compact.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control .v-field .v-field__input {
min-height: 48px;
}
.v-time-picker--density-compact .v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field .v-field {
font-size: 28px;
}
.v-time-picker--density-compact .v-time-picker-controls__ampm__btn.v-btn {
font-size: 12px;
height: 28px;
}
.v-time-picker--density-compact.v-time-picker--variant-input .v-time-picker-controls__ampm__btn.v-btn {
height: 24px;
}
.v-picker__title--landscape .v-time-picker-controls {
flex-direction: column;
justify-content: center;
height: 100%;
}
.v-picker__title--landscape .v-time-picker-controls__time {
text-align: right;
}
.v-picker__title--landscape .v-time-picker-controls__time .v-picker__title__btn,
.v-picker__title--landscape .v-time-picker-controls__time span {
height: 55px;
font-size: 55px;
}
.v-picker__title--landscape .v-time-picker-controls__ampm {
margin: 16px 0 0;
align-self: initial;
text-align: center;
}
.v-picker--time .v-picker__title--landscape {
padding: 0;
}
.v-picker--time .v-picker__title--landscape .v-time-picker-controls__time {
text-align: center;
}
}
@layer vuetify-final.trumps {
@media (forced-colors: active) {
.v-time-picker-controls__time__field:has(input:focus-visible) {
outline: 2px solid highlight;
outline-offset: 2px;
}
.v-time-picker-controls__ampm__btn.v-btn--active {
color: highlight;
forced-color-adjust: preserve-parent-color;
}
}
}
@@ -0,0 +1,287 @@
import type { PropType } from 'vue';
import type { Period, VTimePickerViewMode } from './shared.js';
export declare const makeVTimePickerControlsProps: <Defaults extends {
allowedHours?: unknown;
allowedMinutes?: unknown;
allowedSeconds?: unknown;
max?: unknown;
min?: unknown;
ampm?: unknown;
color?: unknown;
disabled?: unknown;
inputHints?: unknown;
hour?: unknown;
minute?: unknown;
second?: unknown;
period?: unknown;
readonly?: unknown;
useSeconds?: unknown;
value?: unknown;
viewMode?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
allowedHours: unknown extends Defaults["allowedHours"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedHours"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedHours"]>;
default: unknown extends Defaults["allowedHours"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedHours"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
allowedMinutes: unknown extends Defaults["allowedMinutes"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedMinutes"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedMinutes"]>;
default: unknown extends Defaults["allowedMinutes"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedMinutes"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
allowedSeconds: unknown extends Defaults["allowedSeconds"] ? PropType<import("./useTimeValidation.js").AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedSeconds"] ? import("./useTimeValidation.js").AllowFunction | number[] : import("./useTimeValidation.js").AllowFunction | number[] | Defaults["allowedSeconds"]>;
default: unknown extends Defaults["allowedSeconds"] ? import("./useTimeValidation.js").AllowFunction | number[] : Defaults["allowedSeconds"] | NonNullable<import("./useTimeValidation.js").AllowFunction | number[]>;
};
max: unknown extends Defaults["max"] ? StringConstructor : {
type: PropType<unknown extends Defaults["max"] ? string : string | Defaults["max"]>;
default: unknown extends Defaults["max"] ? string : string | Defaults["max"];
};
min: unknown extends Defaults["min"] ? StringConstructor : {
type: PropType<unknown extends Defaults["min"] ? string : string | Defaults["min"]>;
default: unknown extends Defaults["min"] ? string : string | Defaults["min"];
};
ampm: unknown extends Defaults["ampm"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["ampm"] ? boolean : boolean | Defaults["ampm"]>;
default: unknown extends Defaults["ampm"] ? boolean : boolean | Defaults["ampm"];
};
color: unknown extends Defaults["color"] ? StringConstructor : {
type: PropType<unknown extends Defaults["color"] ? string : string | Defaults["color"]>;
default: unknown extends Defaults["color"] ? string : string | Defaults["color"];
};
disabled: unknown extends Defaults["disabled"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"]>;
default: unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"];
};
inputHints: unknown extends Defaults["inputHints"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["inputHints"] ? boolean : boolean | Defaults["inputHints"]>;
default: unknown extends Defaults["inputHints"] ? boolean : boolean | Defaults["inputHints"];
};
hour: unknown extends Defaults["hour"] ? PropType<string | number | null> : {
type: PropType<unknown extends Defaults["hour"] ? string | number | null : string | number | Defaults["hour"] | null>;
default: unknown extends Defaults["hour"] ? string | number | null : Defaults["hour"] | NonNullable<string | number | null>;
};
minute: unknown extends Defaults["minute"] ? PropType<string | number | null> : {
type: PropType<unknown extends Defaults["minute"] ? string | number | null : string | number | Defaults["minute"] | null>;
default: unknown extends Defaults["minute"] ? string | number | null : Defaults["minute"] | NonNullable<string | number | null>;
};
second: unknown extends Defaults["second"] ? PropType<string | number | null> : {
type: PropType<unknown extends Defaults["second"] ? string | number | null : string | number | Defaults["second"] | null>;
default: unknown extends Defaults["second"] ? string | number | null : Defaults["second"] | NonNullable<string | number | null>;
};
period: unknown extends Defaults["period"] ? PropType<Period> : {
type: PropType<unknown extends Defaults["period"] ? Period : Defaults["period"] | Period>;
default: unknown extends Defaults["period"] ? Period : Defaults["period"] | NonNullable<Period>;
};
readonly: unknown extends Defaults["readonly"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"]>;
default: unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"];
};
useSeconds: unknown extends Defaults["useSeconds"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["useSeconds"] ? boolean : boolean | Defaults["useSeconds"]>;
default: unknown extends Defaults["useSeconds"] ? boolean : boolean | Defaults["useSeconds"];
};
value: unknown extends Defaults["value"] ? NumberConstructor : {
type: PropType<unknown extends Defaults["value"] ? number : number | Defaults["value"]>;
default: unknown extends Defaults["value"] ? number : number | Defaults["value"];
};
viewMode: unknown extends Defaults["viewMode"] ? PropType<VTimePickerViewMode> : {
type: PropType<unknown extends Defaults["viewMode"] ? VTimePickerViewMode : Defaults["viewMode"] | VTimePickerViewMode>;
default: unknown extends Defaults["viewMode"] ? VTimePickerViewMode : Defaults["viewMode"] | NonNullable<VTimePickerViewMode>;
};
};
export declare const VTimePickerControls: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
} & {
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
color?: string | undefined;
hour?: string | number | null | undefined;
minute?: string | number | null | undefined;
second?: string | number | null | undefined;
period?: Period | undefined;
value?: number | undefined;
viewMode?: VTimePickerViewMode | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((v: number) => any) | undefined;
"onUpdate:minute"?: ((v: number) => any) | undefined;
"onUpdate:period"?: ((data: Period) => any) | undefined;
"onUpdate:second"?: ((v: number) => any) | undefined;
"onUpdate:viewMode"?: ((data: VTimePickerViewMode) => any) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:period': (data: Period) => true;
'update:viewMode': (data: VTimePickerViewMode) => true;
'update:hour': (v: number) => true;
'update:minute': (v: number) => true;
'update:second': (v: number) => true;
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
}, true, {}, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
} & {
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
color?: string | undefined;
hour?: string | number | null | undefined;
minute?: string | number | null | undefined;
second?: string | number | null | undefined;
period?: Period | undefined;
value?: number | undefined;
viewMode?: VTimePickerViewMode | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((v: number) => any) | undefined;
"onUpdate:minute"?: ((v: number) => any) | undefined;
"onUpdate:period"?: ((data: Period) => any) | undefined;
"onUpdate:second"?: ((v: number) => any) | undefined;
"onUpdate:viewMode"?: ((data: VTimePickerViewMode) => any) | undefined;
}, {}, {}, {}, {}, {
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
} & {
allowedHours?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedMinutes?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
allowedSeconds?: import("./useTimeValidation.js").AllowFunction | number[] | undefined;
max?: string | undefined;
min?: string | undefined;
color?: string | undefined;
hour?: string | number | null | undefined;
minute?: string | number | null | undefined;
second?: string | number | null | undefined;
period?: Period | undefined;
value?: number | undefined;
viewMode?: VTimePickerViewMode | undefined;
} & {
$children?: {
default?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | (() => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:default"?: false | (() => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:hour"?: ((v: number) => any) | undefined;
"onUpdate:minute"?: ((v: number) => any) | undefined;
"onUpdate:period"?: ((data: Period) => any) | undefined;
"onUpdate:second"?: ((v: number) => any) | undefined;
"onUpdate:viewMode"?: ((data: VTimePickerViewMode) => any) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:period': (data: Period) => true;
'update:viewMode': (data: VTimePickerViewMode) => true;
'update:hour': (v: number) => true;
'update:minute': (v: number) => true;
'update:second': (v: number) => true;
}, string, {
ampm: boolean;
disabled: boolean;
inputHints: boolean;
readonly: boolean;
useSeconds: boolean;
}, {}, string, import("vue").SlotsType<Partial<{
default: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
allowedHours: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedMinutes: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedSeconds: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
max: StringConstructor;
min: StringConstructor;
ampm: BooleanConstructor;
color: StringConstructor;
disabled: BooleanConstructor;
inputHints: BooleanConstructor;
hour: PropType<number | string | null>;
minute: PropType<number | string | null>;
second: PropType<number | string | null>;
period: PropType<Period>;
readonly: BooleanConstructor;
useSeconds: BooleanConstructor;
value: NumberConstructor;
viewMode: PropType<VTimePickerViewMode>;
}, import("vue").ExtractPropTypes<{
allowedHours: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedMinutes: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
allowedSeconds: PropType<import("./useTimeValidation.js").AllowFunction | number[]>;
max: StringConstructor;
min: StringConstructor;
ampm: BooleanConstructor;
color: StringConstructor;
disabled: BooleanConstructor;
inputHints: BooleanConstructor;
hour: PropType<number | string | null>;
minute: PropType<number | string | null>;
second: PropType<number | string | null>;
period: PropType<Period>;
readonly: BooleanConstructor;
useSeconds: BooleanConstructor;
value: NumberConstructor;
viewMode: PropType<VTimePickerViewMode>;
}>>;
export type VTimePickerControls = InstanceType<typeof VTimePickerControls>;
@@ -0,0 +1,274 @@
import { createVNode as _createVNode, createTextVNode as _createTextVNode, createElementVNode as _createElementVNode, Fragment as _Fragment, normalizeClass as _normalizeClass } from "vue";
// Styles
import "./VTimePickerControls.css";
// Components
import { VTimePickerField } from "./VTimePickerField.js";
import { VBtn } from "../VBtn/index.js"; // Composables
import { useLocale } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
import { computed, nextTick, ref, watch } from 'vue';
import { makeTimeValidationProps, useTimeValidation } from "./useTimeValidation.js";
import { convert12to24, convert24to12, extractInteger, pad } from "./util.js";
import { clamp, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVTimePickerControlsProps = propsFactory({
ampm: Boolean,
color: String,
disabled: Boolean,
inputHints: Boolean,
hour: [Number, String],
minute: [Number, String],
second: [Number, String],
period: String,
readonly: Boolean,
useSeconds: Boolean,
value: Number,
viewMode: String,
...makeTimeValidationProps()
}, 'VTimePickerControls');
export const VTimePickerControls = genericComponent()({
name: 'VTimePickerControls',
props: makeVTimePickerControlsProps(),
emits: {
'update:period': data => true,
'update:viewMode': data => true,
'update:hour': v => true,
'update:minute': v => true,
'update:second': v => true
},
setup(props, {
emit
}) {
const {
t
} = useLocale();
const {
isAllowedHour,
isAllowedMinute,
isAllowedSecond,
findNextAllowed
} = useTimeValidation(props);
const currentHour = computed(() => props.hour !== null ? props.ampm ? convert12to24(Number(props.hour), props.period ?? 'am') : Number(props.hour) : null);
const currentMinute = computed(() => props.minute !== null ? Number(props.minute) : null);
const isHourValid = computed(() => {
if (props.hour === null) return true;
return isAllowedHour.value?.(Number(currentHour.value)) ?? true;
});
const isMinuteValid = computed(() => {
if (props.minute === null) return true;
return isAllowedMinute.value?.(currentHour.value, Number(props.minute)) ?? true;
});
const isSecondValid = computed(() => {
if (props.second === null) return true;
return isAllowedSecond.value?.(currentHour.value, currentMinute.value, Number(props.second)) ?? true;
});
const transformHours = {
in: v => {
if (v == null || isNaN(Number(v))) return null;
const val = Number(v);
return props.ampm ? pad(convert24to12(val)) : pad(val);
},
out: v => {
if (isNaN(Number(v)) || v == null || v === '') return null;
const val = typeof v === 'string' ? extractInteger(v) : Number(v);
if (val === null) return null;
return props.ampm ? convert12to24(val, props.period ?? 'am') : clamp(val, 0, 23);
}
};
const hour = useProxiedModel(props, 'hour', undefined, transformHours.in, transformHours.out);
const transformMinutesOrSeconds = {
in: v => v != null && !isNaN(Number(v)) ? pad(`${v}`) : null,
out: v => {
if (isNaN(Number(v)) || v == null || v === '') return null;
const val = typeof v === 'string' ? extractInteger(v) : Number(v);
return val !== null ? clamp(val, 0, 59) : null;
}
};
const minute = useProxiedModel(props, 'minute', undefined, transformMinutesOrSeconds.in, transformMinutesOrSeconds.out);
const second = useProxiedModel(props, 'second', undefined, transformMinutesOrSeconds.in, transformMinutesOrSeconds.out);
function onHourFieldKeydown(e) {
if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
const isAm = props.period === 'am';
const current = props.ampm ? convert12to24(Number(hour.value ?? 0), isAm ? 'am' : 'pm') : Number(hour.value ?? 0);
const next = findNextAllowed('hour', current, e.key === 'ArrowUp');
const togglePeriod = isAm && next >= 12 || !isAm && next < 12;
if (props.ampm && togglePeriod) {
emit('update:period', props.period === 'am' ? 'pm' : 'am');
nextTick(() => hour.value = pad(next));
} else {
hour.value = pad(next);
}
}
function onMinuteFieldKeydown(e) {
if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
const current = Number(minute.value ?? 0);
const next = findNextAllowed('minute', current, e.key === 'ArrowUp', currentHour.value);
minute.value = pad(next);
}
function onSecondFieldKeydown(e) {
if (!['ArrowUp', 'ArrowDown'].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
const current = Number(second.value ?? 0);
const next = findNextAllowed('second', current, e.key === 'ArrowUp', currentHour.value, currentMinute.value);
second.value = pad(next);
}
function createInputInterceptor(valueTransformOut, compare, apply) {
return e => {
if (!e.data) return;
const inputElement = e.target;
const {
value: existingTxt,
selectionStart,
selectionEnd
} = inputElement ?? {};
if (extractInteger(e.data) === null) {
e.preventDefault();
return;
}
const potentialNewInputVal = existingTxt ? existingTxt.slice(0, selectionStart) + e.data + existingTxt.slice(selectionEnd) : e.data;
if (potentialNewInputVal.length > 2) {
if (selectionStart === selectionEnd && selectionEnd === 0 && e.data.trim().startsWith('0')) {
e.preventDefault();
inputElement.value = potentialNewInputVal.trim().substring(0, 2);
apply(inputElement.value);
if (e.data.trim().length === 1) {
inputElement.setSelectionRange(1, 1);
}
return;
}
if (selectionStart === selectionEnd && selectionEnd === 1 && existingTxt.startsWith('0')) {
e.preventDefault();
inputElement.value = potentialNewInputVal.trim().substring(0, 2);
apply(inputElement.value);
return;
}
const maxValue = props.viewMode === 'hour' ? props.ampm ? 12 : 23 : 59;
const value = extractInteger(potentialNewInputVal);
if (value > maxValue) {
e.preventDefault();
inputElement.value = pad(String(extractInteger(e.data)).substring(0, 2));
apply(inputElement.value);
return;
}
}
const potentialNewNumber = valueTransformOut(potentialNewInputVal);
if (compare(potentialNewNumber)) {
// ignore input when results in the same number
// prevents typing more digits
e.preventDefault();
}
};
}
function setPeriod(val) {
emit('update:period', val);
}
const hourInputRef = ref();
const minuteInputRef = ref();
const secondInputRef = ref();
watch(() => props.viewMode, (_, old) => {
switch (old) {
case 'hour':
hourInputRef.value.blur();
break;
case 'minute':
minuteInputRef.value.blur();
break;
case 'second':
secondInputRef.value.blur();
break;
}
});
const hourInputFilter = createInputInterceptor(transformHours.out, v => transformHours.in(v) === hour.value, v => hour.value = v);
const minuteInputFilter = createInputInterceptor(transformMinutesOrSeconds.out, v => transformMinutesOrSeconds.in(v) === minute.value, v => minute.value = v);
const secondInputFilter = createInputInterceptor(transformMinutesOrSeconds.out, v => transformMinutesOrSeconds.in(v) === second.value, v => second.value = v);
useRender(() => {
return _createElementVNode("div", {
"class": "v-time-picker-controls"
}, [_createElementVNode("div", {
"class": _normalizeClass({
'v-time-picker-controls__time': true,
'v-time-picker-controls__time--with-ampm': props.ampm,
'v-time-picker-controls__time--with-seconds': props.useSeconds
})
}, [_createVNode(VTimePickerField, {
"ref": hourInputRef,
"active": props.viewMode === 'hour',
"color": props.color,
"disabled": props.disabled,
"label": t('$vuetify.timePicker.hour'),
"showHint": props.inputHints,
"error": isHourValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
"modelValue": hour.value,
"onUpdate:modelValue": v => hour.value = v,
"onKeydown": onHourFieldKeydown,
"onBeforeinput": hourInputFilter,
"onFocus": () => emit('update:viewMode', 'hour')
}, null), _createElementVNode("span", {
"class": "v-time-picker-controls__time__separator"
}, [_createTextVNode(":")]), _createVNode(VTimePickerField, {
"ref": minuteInputRef,
"active": props.viewMode === 'minute',
"color": props.color,
"disabled": props.disabled,
"label": t('$vuetify.timePicker.minute'),
"showHint": props.inputHints,
"error": isMinuteValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
"modelValue": minute.value,
"onUpdate:modelValue": v => minute.value = v,
"onKeydown": onMinuteFieldKeydown,
"onBeforeinput": minuteInputFilter,
"onFocus": () => emit('update:viewMode', 'minute')
}, null), props.useSeconds && _createElementVNode("span", {
"key": "secondsDivider",
"class": "v-time-picker-controls__time__separator"
}, [_createTextVNode(":")]), props.useSeconds && _createElementVNode(_Fragment, null, [_createVNode(VTimePickerField, {
"key": "secondsVal",
"ref": secondInputRef,
"active": props.viewMode === 'second',
"color": props.color,
"disabled": props.disabled,
"label": t('$vuetify.timePicker.second'),
"showHint": props.inputHints,
"error": isSecondValid.value ? undefined : t('$vuetify.timePicker.notAllowed'),
"modelValue": second.value,
"onUpdate:modelValue": v => second.value = v,
"onKeydown": onSecondFieldKeydown,
"onBeforeinput": secondInputFilter,
"onFocus": () => emit('update:viewMode', 'second')
}, null)]), props.ampm && _createElementVNode("div", {
"class": "v-time-picker-controls__ampm"
}, [_createVNode(VBtn, {
"active": props.period === 'am',
"color": props.period === 'am' ? props.color : undefined,
"class": _normalizeClass({
'v-time-picker-controls__ampm__am': true,
'v-time-picker-controls__ampm__btn': true,
'v-time-picker-controls__ampm__btn__active': props.period === 'am'
}),
"disabled": props.disabled,
"text": t('$vuetify.timePicker.am'),
"variant": props.disabled && props.period === 'am' ? 'elevated' : 'tonal',
"onClick": () => props.period !== 'am' ? setPeriod('am') : null
}, null), _createVNode(VBtn, {
"active": props.period === 'pm',
"color": props.period === 'pm' ? props.color : undefined,
"class": _normalizeClass({
'v-time-picker-controls__ampm__pm': true,
'v-time-picker-controls__ampm__btn': true,
'v-time-picker-controls__ampm__btn__active': props.period === 'pm'
}),
"disabled": props.disabled,
"text": t('$vuetify.timePicker.pm'),
"variant": props.disabled && props.period === 'pm' ? 'elevated' : 'tonal',
"onClick": () => props.period !== 'pm' ? setPeriod('pm') : null
}, null)])])]);
});
return {};
}
});
//# sourceMappingURL=VTimePickerControls.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,187 @@
@use 'sass:map'
@use '../../styles/tools'
@use '../../styles/settings'
@use './variables' as *
@include tools.layer('components')
.v-time-picker-controls
display: flex
align-items: center
justify-content: center
font-size: .875rem
margin-inline: $time-picker-padding
margin-bottom: 12px
&__text
padding-bottom: 12px
&__time
display: flex
white-space: nowrap
direction: ltr
justify-content: center
align-items: start
.v-time-picker-controls__time__separator
width: $time-picker-controls-separator-width
text-align: center
.v-time-picker--density-compact &
font-weight: bold
@at-root
@include tools.density('v-time-picker', $time-picker-controls-field-density) using ($modifier)
.v-time-picker-controls__time__separator
font-size: $time-picker-controls-btn-font + $modifier
line-height: $time-picker-controls-separator-line-height + $modifier
.v-time-picker--variant-input &
line-height: $time-picker-controls-input-separator-line-height + $modifier
.v-time-picker-controls__time--with-seconds &
height: $time-picker-controls-seconds-btn-height + $modifier
font-size: $time-picker-controls-btn-font + $modifier
.v-time-picker-controls__time__field
width: $time-picker-controls-field-width
.v-field
width: $time-picker-controls-field-width
background-color: $time-picker-controls-field-background
color: inherit
transition: color .25s settings.$standard-easing
> .v-field__overlay
opacity: $time-picker-controls-field-overlay-opacity
&--active .v-field > .v-field__overlay
opacity: calc((#{$time-picker-controls-field-overlay-opacity} + #{map.get(settings.$states, 'focus')}) * var(--v-theme-overlay-multiplier))
.v-time-picker--variant-input &
width: $time-picker-controls-input-field-width
.v-field
width: $time-picker-controls-input-field-width
.v-time-picker-controls__time--with-seconds &
width: $time-picker-controls-seconds-field-width
.v-time-picker--variant-input &
width: $time-picker-controls-input-seconds-field-width
.v-field__input
padding: 0
font-weight: 500
text-align: center
line-height: 1
align-self: center
&:focus::placeholder
opacity: 0
&.v-input > .v-input__details
font-size: $time-picker-field-label-font-size
letter-spacing: $time-picker-field-label-letter-spacing
padding-inline: 0
white-space: normal
> .v-messages
opacity: 1
&.v-input--error .v-field__input
color: rgb(var(--v-theme-error))
.v-time-picker-controls__ampm
margin-left: 12px
display: flex
flex-direction: column
text-transform: uppercase
&--readonly
pointer-events: none
&--readonly
.v-picker__title__btn.v-picker__title__btn--active
opacity: $picker-inactive-btn-opacity
&__btn.v-btn
min-width: 52px
padding: 0 8px
&.v-time-picker-controls__ampm__am
border-radius: $time-picker-controls-ampm-am-border-radius
border: 1px solid
&.v-time-picker-controls__ampm__pm
border-radius: $time-picker-controls-ampm-pm-border-radius
border: 1px solid
border-top: none
&__active
background: rgb(var(--v-theme-primary))
@at-root
@include tools.density('v-time-picker', $time-picker-controls-field-density) using ($modifier)
.v-time-picker-controls__time__field .v-input__control
height: $time-picker-controls-field-height + $modifier
.v-field
font-size: $time-picker-controls-field-font + $modifier
.v-field__input
min-height: $time-picker-controls-field-height + $modifier
&.v-time-picker--variant-input .v-time-picker-controls__time__field .v-input__control
height: $time-picker-controls-input-field-height + $modifier
.v-field
font-size: $time-picker-controls-input-field-font + $modifier * .75
.v-field__input
min-height: $time-picker-controls-input-field-height + $modifier
.v-time-picker-controls__time--with-seconds .v-time-picker-controls__time__field .v-field
font-size: $time-picker-controls-seconds-field-font + $modifier * .5
.v-time-picker-controls__ampm__btn.v-btn
font-size: $time-picker-ampm-title-font-size + $modifier * .25
height: $time-picker-controls-ampm-height + $modifier * .5
&.v-time-picker--variant-input .v-time-picker-controls__ampm__btn.v-btn
height: $time-picker-controls-input-ampm-height + $modifier * .5
.v-picker__title--landscape
.v-time-picker-controls
flex-direction: column
justify-content: center
height: 100%
.v-time-picker-controls__time
text-align: right
.v-picker__title__btn,
span
height: $time-picker-landscape-title-btn-height
font-size: $time-picker-landscape-title-btn-height
.v-time-picker-controls__ampm
margin: $time-picker-landscape-ampm-title-margin
align-self: initial
text-align: center
.v-picker--time .v-picker__title--landscape
padding: 0
.v-time-picker-controls__time
text-align: center
@include tools.layer('trumps')
@media (forced-colors: active)
.v-time-picker-controls
&__time__field:has(input:focus-visible)
outline: 2px solid highlight
outline-offset: 2px
&__ampm__btn.v-btn--active
color: highlight
forced-color-adjust: preserve-parent-color
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
import { normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createVNode as _createVNode } from "vue";
// Components
import { VTextField } from "../VTextField/index.js"; // Composables
import { useTextColor } from "../../composables/color.js";
import { forwardRefs } from "../../composables/forwardRefs.js"; // Utilities
import { ref, shallowRef } from 'vue';
import { genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVTimePickerFieldProps = propsFactory({
active: Boolean,
color: String,
disabled: Boolean,
label: String,
modelValue: String,
error: String,
showHint: Boolean,
readonly: Boolean
}, 'VTimePickerField');
export const VTimePickerField = genericComponent()({
name: 'VTimePickerField',
props: makeVTimePickerFieldProps(),
emits: {
'update:modelValue': v => true
},
setup(props, {
emit
}) {
const {
textColorClasses,
textColorStyles
} = useTextColor(() => props.color);
const vTextInputRef = ref();
const isFocused = shallowRef(false);
function onKeydown(e) {
if (['Backspace', 'Delete'].includes(e.key)) {
e.preventDefault();
const target = e.target;
target.value = '';
emit('update:modelValue', null);
}
}
useRender(() => {
return _createVNode(VTextField, {
"ref": vTextInputRef,
"_as": "VTimePickerField",
"autocomplete": "off",
"class": _normalizeClass(['v-time-picker-controls__time__field', {
'v-time-picker-controls__time__field--active': props.active
}, props.active ? textColorClasses.value : []]),
"style": _normalizeStyle(props.active ? textColorStyles.value : []),
"disabled": props.disabled,
"variant": "solo-filled",
"inputmode": "numeric",
"hideDetails": "auto",
"aria-label": props.label,
"aria-invalid": !!props.error,
"aria-errormessage": props.error,
"error": !!props.error,
"hint": props.showHint ? props.label : undefined,
"persistentHint": true,
"flat": true,
"modelValue": props.modelValue ?? (isFocused.value ? '' : '--'),
"onUpdate:modelValue": v => emit('update:modelValue', v),
"onKeydown": onKeydown,
"onFocus": () => isFocused.value = true,
"onBlur": () => isFocused.value = false
}, null);
});
return forwardRefs({}, vTextInputRef);
}
});
//# sourceMappingURL=VTimePickerField.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,57 @@
@forward '../../labs/VPicker/variables';
$time-picker-padding: 24px !default;
$time-picker-controls-btn-font: 56px !default;
$time-picker-controls-btn-height: 80px !default;
$time-picker-controls-btn-width: 96px !default;
$time-picker-controls-seconds-btn-width: 64px !default;
$time-picker-controls-seconds-btn-height: 80px !default;
$time-picker-controls-seconds-btn-font: 40px !default;
$time-picker-controls-separator-width: 24px !default;
$time-picker-controls-separator-line-height: 74px !default;
$time-picker-controls-ampm-btn-width: 96px !default;
$time-picker-controls-ampm-btn-height: 80px !default;
$time-picker-controls-ampm-height: 40px !default;
$time-picker-controls-field-background: rgb(var(--v-theme-surface-light)) !default;
$time-picker-controls-field-overlay-opacity: 0.04 !default;
$time-picker-controls-field-font: 56px !default;
$time-picker-controls-field-height: 80px !default;
$time-picker-controls-field-width: 96px !default;
$time-picker-controls-seconds-field-width: 64px !default;
$time-picker-controls-seconds-field-font: 40px !default;
$time-picker-controls-field-density: ('default': 0, 'comfortable': -4, 'compact': -6) !default;
$time-picker-controls-input-field-font: 44px !default;
$time-picker-controls-input-field-height: 72px !default;
$time-picker-controls-input-field-width: 96px !default;
$time-picker-controls-input-seconds-field-width: 64px !default;
$time-picker-controls-input-seconds-field-font: 40px !default;
$time-picker-controls-input-separator-line-height: 64px !default;
$time-picker-controls-input-ampm-height: 36px !default;
$time-picker-controls-ampm-am-border-radius: 4px 4px 0 0 !default;
$time-picker-controls-ampm-pm-border-radius: 0 0 4px 4px !default;
$time-picker-ampm-title-font-size: 18px !default;
$time-picker-number-font-size: 16px !default;
$time-picker-field-label-font-size: 12px !default;
$time-picker-field-label-letter-spacing: .0333333333em !default;
$time-picker-indicator-size: 40px !default;
$time-picker-clock-padding: 10px !default;
$time-picker-clock-max-width: 290px !default;
$time-picker-clock-hand-height: calc(50% - 4px) !default;
$time-picker-clock-hand-width: 2px !default;
$time-picker-clock-hand-left: calc(50% - 1px) !default;
$time-picker-clock-center-size: 8px !default;
$time-picker-clock-end-size: 10px !default;
$time-picker-clock-end-top: -4px !default;
$time-picker-clock-inner-hand-height: 14px !default;
$time-picker-clock-inner-offset: 27px !default;
$time-picker-clock-end-border-width: 2px !default;
$time-picker-clock-end-border-style: solid !default;
$time-picker-clock-end-border-color: currentColor !default;
$time-picker-width: 328px !default;
$time-picker-landscape-title-btn-height: 55px !default;
$time-picker-landscape-ampm-title-margin: 16px 0 0 !default;
+3
View File
@@ -0,0 +1,3 @@
export { VTimePicker } from './VTimePicker.js';
export { VTimePickerClock } from './VTimePickerClock.js';
export { VTimePickerControls } from './VTimePickerControls.js';
+4
View File
@@ -0,0 +1,4 @@
export { VTimePicker } from "./VTimePicker.js";
export { VTimePickerClock } from "./VTimePickerClock.js";
export { VTimePickerControls } from "./VTimePickerControls.js";
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["VTimePicker","VTimePickerClock","VTimePickerControls"],"sources":["../../../src/components/VTimePicker/index.ts"],"sourcesContent":["export { VTimePicker } from './VTimePicker'\nexport { VTimePickerClock } from './VTimePickerClock'\nexport { VTimePickerControls } from './VTimePickerControls'\n"],"mappings":"SAASA,WAAW;AAAA,SACXC,gBAAgB;AAAA,SAChBC,mBAAmB","ignoreList":[]}
+2
View File
@@ -0,0 +1,2 @@
export type Period = 'am' | 'pm';
export type VTimePickerViewMode = 'hour' | 'minute' | 'second';
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
{"version":3,"file":"shared.js","names":[],"sources":["../../../src/components/VTimePicker/shared.ts"],"sourcesContent":["export type Period = 'am' | 'pm'\nexport type VTimePickerViewMode = 'hour' | 'minute' | 'second'\n"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,44 @@
import type { PropType } from 'vue';
import type { VTimePickerViewMode } from './shared.js';
export type AllowFunction = (val: number) => boolean;
export declare const makeTimeValidationProps: <Defaults extends {
allowedHours?: unknown;
allowedMinutes?: unknown;
allowedSeconds?: unknown;
max?: unknown;
min?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
allowedHours: unknown extends Defaults["allowedHours"] ? PropType<AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedHours"] ? AllowFunction | number[] : AllowFunction | number[] | Defaults["allowedHours"]>;
default: unknown extends Defaults["allowedHours"] ? AllowFunction | number[] : Defaults["allowedHours"] | NonNullable<AllowFunction | number[]>;
};
allowedMinutes: unknown extends Defaults["allowedMinutes"] ? PropType<AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedMinutes"] ? AllowFunction | number[] : AllowFunction | number[] | Defaults["allowedMinutes"]>;
default: unknown extends Defaults["allowedMinutes"] ? AllowFunction | number[] : Defaults["allowedMinutes"] | NonNullable<AllowFunction | number[]>;
};
allowedSeconds: unknown extends Defaults["allowedSeconds"] ? PropType<AllowFunction | number[]> : {
type: PropType<unknown extends Defaults["allowedSeconds"] ? AllowFunction | number[] : AllowFunction | number[] | Defaults["allowedSeconds"]>;
default: unknown extends Defaults["allowedSeconds"] ? AllowFunction | number[] : Defaults["allowedSeconds"] | NonNullable<AllowFunction | number[]>;
};
max: unknown extends Defaults["max"] ? StringConstructor : {
type: PropType<unknown extends Defaults["max"] ? string : string | Defaults["max"]>;
default: unknown extends Defaults["max"] ? string : string | Defaults["max"];
};
min: unknown extends Defaults["min"] ? StringConstructor : {
type: PropType<unknown extends Defaults["min"] ? string : string | Defaults["min"]>;
default: unknown extends Defaults["min"] ? string : string | Defaults["min"];
};
};
export interface TimeValidationProps {
allowedHours?: AllowFunction | number[];
allowedMinutes?: AllowFunction | number[];
allowedSeconds?: AllowFunction | number[];
min?: string;
max?: string;
}
export declare function useTimeValidation(props: TimeValidationProps): {
isAllowedHour: import("vue").ComputedRef<(val: number) => boolean>;
isAllowedMinute: import("vue").ComputedRef<(hour24hr: number | null, val: number) => boolean>;
isAllowedSecond: import("vue").ComputedRef<(hour24hr: number | null, minute: number | null, val: number) => boolean>;
findNextAllowed: (type: VTimePickerViewMode, value: number, increment: boolean, currentHour?: number | null, currentMinute?: number | null) => number;
};
@@ -0,0 +1,73 @@
// Utilities
import { computed } from 'vue';
import { incrementHour, incrementMinuteOrSecond } from "./util.js";
import { propsFactory } from "../../util/index.js"; // Types
export const makeTimeValidationProps = propsFactory({
allowedHours: [Function, Array],
allowedMinutes: [Function, Array],
allowedSeconds: [Function, Array],
max: String,
min: String
}, 'time-validation');
export function useTimeValidation(props) {
const isAllowedHour = computed(() => {
const minHour = props.min ? Number(props.min.split(':')[0]) : 0;
const maxHour = props.max ? Number(props.max.split(':')[0]) : 23;
return val => {
if (val < minHour) return false;
if (val > maxHour) return false;
if (Array.isArray(props.allowedHours)) return props.allowedHours.includes(val);
if (typeof props.allowedHours === 'function') return props.allowedHours(val);
return true;
};
});
const isAllowedMinute = computed(() => {
const [minHour, minMinute] = props.min ? props.min.split(':').map(Number) : [0, 0];
const [maxHour, maxMinute] = props.max ? props.max.split(':').map(Number) : [23, 59];
const minTime = minHour * 60 + minMinute;
const maxTime = maxHour * 60 + maxMinute;
return (hour24hr, val) => {
if (hour24hr !== null) {
const time = 60 * hour24hr + val;
if (time < minTime) return false;
if (time > maxTime) return false;
}
if (Array.isArray(props.allowedMinutes)) return props.allowedMinutes.includes(val);
if (typeof props.allowedMinutes === 'function') return props.allowedMinutes(val);
return true;
};
});
const isAllowedSecond = computed(() => {
const [minHour, minMinute, minSecond] = props.min ? props.min.split(':').map(Number) : [0, 0, 0];
const [maxHour, maxMinute, maxSecond] = props.max ? props.max.split(':').map(Number) : [23, 59, 59];
const minTime = minHour * 3600 + minMinute * 60 + (minSecond || 0);
const maxTime = maxHour * 3600 + maxMinute * 60 + (maxSecond || 0);
return (hour24hr, minute, val) => {
if (hour24hr !== null && minute !== null) {
const time = 3600 * hour24hr + 60 * minute + val;
if (time < minTime) return false;
if (time > maxTime) return false;
}
if (Array.isArray(props.allowedSeconds)) return props.allowedSeconds.includes(val);
if (typeof props.allowedSeconds === 'function') return props.allowedSeconds(val);
return true;
};
});
function findNextAllowed(type, value, increment, currentHour = null, currentMinute = null) {
const isAllowed = type === 'hour' ? isAllowedHour.value : type === 'minute' ? v => isAllowedMinute.value(currentHour, v) : v => isAllowedSecond.value(currentHour, currentMinute, v);
const nextValue = type === 'hour' ? v => incrementHour(v, increment, null).value : v => incrementMinuteOrSecond(v, increment);
const limit = type === 'hour' ? 24 : 60;
for (let i = 1; i <= limit; i++) {
value = nextValue(value);
if (isAllowed(value)) break;
}
return value;
}
return {
isAllowedHour,
isAllowedMinute,
isAllowedSecond,
findNextAllowed
};
}
//# sourceMappingURL=useTimeValidation.js.map
File diff suppressed because one or more lines are too long
+13
View File
@@ -0,0 +1,13 @@
import type { Period } from './shared.js';
export declare function pad(n: string | number, length?: number): string;
export declare function convert24to12(hour: number): number;
export declare function convert12to24(hour: number, period: Period): number;
export declare function extractInteger(v: string): number | null;
export declare function incrementHour(hour: number, increment: boolean, period: Period | null): {
value: number;
togglePeriod?: undefined;
} | {
value: number;
togglePeriod: boolean;
};
export declare function incrementMinuteOrSecond(val: number, increment: boolean): number;
+61
View File
@@ -0,0 +1,61 @@
// Types
export function pad(n, length = 2) {
return String(n).padStart(length, '0');
}
export function convert24to12(hour) {
return hour ? (hour - 1) % 12 + 1 : 12;
}
export function convert12to24(hour, period) {
return hour % 12 + (period === 'pm' ? 12 : 0);
}
export function extractInteger(v) {
const digits = v.replaceAll(/\D/g, '');
return digits.length > 0 ? Number(digits) : null;
}
export function incrementHour(hour, increment, period) {
if (period) {
if (hour === 12 && increment) {
return {
value: 1
};
}
if (hour === 11 && increment) {
return {
value: 12,
togglePeriod: true
};
}
if (hour === 12 && !increment) {
return {
value: 11,
togglePeriod: true
};
}
if (hour === 1 && !increment) {
return {
value: 12
};
}
} else {
if (hour === 23 && increment) {
return {
value: 0
};
}
if (hour === 0 && !increment) {
return {
value: 23
};
}
}
return {
value: hour + (increment ? 1 : -1)
};
}
export function incrementMinuteOrSecond(val, increment) {
if (val === 59 && increment) return 0;
if (val === 0 && !increment) return 59;
return val + (increment ? 1 : -1);
}
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","names":["pad","n","length","String","padStart","convert24to12","hour","convert12to24","period","extractInteger","v","digits","replaceAll","Number","incrementHour","increment","value","togglePeriod","incrementMinuteOrSecond","val"],"sources":["../../../src/components/VTimePicker/util.ts"],"sourcesContent":["// Types\nimport type { Period } from './shared'\n\nexport function pad (n: string | number, length = 2) {\n return String(n).padStart(length, '0')\n}\n\nexport function convert24to12 (hour: number) {\n return hour ? ((hour - 1) % 12 + 1) : 12\n}\n\nexport function convert12to24 (hour: number, period: Period) {\n return hour % 12 + (period === 'pm' ? 12 : 0)\n}\n\nexport function extractInteger (v: string): number | null {\n const digits = v.replaceAll(/\\D/g, '')\n return digits.length > 0\n ? Number(digits)\n : null\n}\n\nexport function incrementHour (hour: number, increment: boolean, period: Period | null) {\n if (period) {\n if (hour === 12 && increment) { return { value: 1 } }\n if (hour === 11 && increment) { return { value: 12, togglePeriod: true } }\n if (hour === 12 && !increment) { return { value: 11, togglePeriod: true } }\n if (hour === 1 && !increment) { return { value: 12 } }\n } else {\n if (hour === 23 && increment) { return { value: 0 } }\n if (hour === 0 && !increment) { return { value: 23 } }\n }\n return { value: hour + (increment ? 1 : -1) }\n}\n\nexport function incrementMinuteOrSecond (val: number, increment: boolean) {\n if (val === 59 && increment) return 0\n if (val === 0 && !increment) return 59\n return val + (increment ? 1 : -1)\n}\n"],"mappings":"AAAA;;AAGA,OAAO,SAASA,GAAGA,CAAEC,CAAkB,EAAEC,MAAM,GAAG,CAAC,EAAE;EACnD,OAAOC,MAAM,CAACF,CAAC,CAAC,CAACG,QAAQ,CAACF,MAAM,EAAE,GAAG,CAAC;AACxC;AAEA,OAAO,SAASG,aAAaA,CAAEC,IAAY,EAAE;EAC3C,OAAOA,IAAI,GAAI,CAACA,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,GAAI,EAAE;AAC1C;AAEA,OAAO,SAASC,aAAaA,CAAED,IAAY,EAAEE,MAAc,EAAE;EAC3D,OAAOF,IAAI,GAAG,EAAE,IAAIE,MAAM,KAAK,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;AAC/C;AAEA,OAAO,SAASC,cAAcA,CAAEC,CAAS,EAAiB;EACxD,MAAMC,MAAM,GAAGD,CAAC,CAACE,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;EACtC,OAAOD,MAAM,CAACT,MAAM,GAAG,CAAC,GACpBW,MAAM,CAACF,MAAM,CAAC,GACd,IAAI;AACV;AAEA,OAAO,SAASG,aAAaA,CAAER,IAAY,EAAES,SAAkB,EAAEP,MAAqB,EAAE;EACtF,IAAIA,MAAM,EAAE;IACV,IAAIF,IAAI,KAAK,EAAE,IAAIS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE;MAAE,CAAC;IAAC;IACpD,IAAIV,IAAI,KAAK,EAAE,IAAIS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE,EAAE;QAAEC,YAAY,EAAE;MAAK,CAAC;IAAC;IACzE,IAAIX,IAAI,KAAK,EAAE,IAAI,CAACS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE,EAAE;QAAEC,YAAY,EAAE;MAAK,CAAC;IAAC;IAC1E,IAAIX,IAAI,KAAK,CAAC,IAAI,CAACS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE;MAAG,CAAC;IAAC;EACvD,CAAC,MAAM;IACL,IAAIV,IAAI,KAAK,EAAE,IAAIS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE;MAAE,CAAC;IAAC;IACpD,IAAIV,IAAI,KAAK,CAAC,IAAI,CAACS,SAAS,EAAE;MAAE,OAAO;QAAEC,KAAK,EAAE;MAAG,CAAC;IAAC;EACvD;EACA,OAAO;IAAEA,KAAK,EAAEV,IAAI,IAAIS,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;EAAE,CAAC;AAC/C;AAEA,OAAO,SAASG,uBAAuBA,CAAEC,GAAW,EAAEJ,SAAkB,EAAE;EACxE,IAAII,GAAG,KAAK,EAAE,IAAIJ,SAAS,EAAE,OAAO,CAAC;EACrC,IAAII,GAAG,KAAK,CAAC,IAAI,CAACJ,SAAS,EAAE,OAAO,EAAE;EACtC,OAAOI,GAAG,IAAIJ,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC","ignoreList":[]}