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
+65
View File
@@ -0,0 +1,65 @@
@layer vuetify-components {
.v-overlay-container {
contain: layout;
left: 0;
pointer-events: none;
position: absolute;
top: 0;
display: contents;
}
.v-overlay {
--v-overlay-opacity: 0.32;
border-radius: inherit;
display: flex;
left: 0;
pointer-events: none;
position: fixed;
top: 0;
bottom: 0;
right: 0;
}
.v-overlay__content {
outline: none;
position: absolute;
pointer-events: auto;
contain: layout;
}
.v-overlay__scrim {
pointer-events: auto;
background: #000;
border-radius: inherit;
bottom: 0;
left: 0;
opacity: var(--v-overlay-opacity);
position: fixed;
right: 0;
top: 0;
}
.v-overlay--absolute {
position: absolute;
}
.v-overlay--contained .v-overlay__scrim {
position: absolute;
}
.v-overlay--scroll-blocked {
padding-inline-end: var(--v-scrollbar-offset);
}
}
@layer vuetify-final.trumps {
.v-overlay-scroll-blocked {
padding-inline-end: var(--v-scrollbar-offset);
}
.v-overlay-scroll-blocked:not(html) {
overflow-y: hidden;
}
html.v-overlay-scroll-blocked {
position: fixed;
top: var(--v-body-scroll-y);
left: var(--v-body-scroll-x);
width: 100%;
height: 100%;
}
.v-overlay-scroll-blocked .v-navigation-drawer--right.v-navigation-drawer--active {
margin-right: var(--v-scrollbar-offset);
}
}
+906
View File
@@ -0,0 +1,906 @@
import type { PropType, Ref } from 'vue';
import type { TemplateRef } from '../../util/index.js';
export type OverlaySlots = {
default: {
isActive: Ref<boolean>;
};
activator: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
};
};
export declare const makeVOverlayProps: <Defaults extends {
theme?: unknown;
class?: unknown;
style?: unknown;
locationStrategy?: unknown;
location?: unknown;
origin?: unknown;
offset?: unknown;
stickToTarget?: unknown;
viewportMargin?: unknown;
scrollStrategy?: unknown;
height?: unknown;
maxHeight?: unknown;
maxWidth?: unknown;
minHeight?: unknown;
minWidth?: unknown;
width?: unknown;
transition?: unknown;
closeDelay?: unknown;
openDelay?: unknown;
target?: unknown;
activator?: unknown;
activatorProps?: unknown;
openOnClick?: unknown;
openOnHover?: unknown;
openOnFocus?: unknown;
closeOnContentClick?: unknown;
retainFocus?: unknown;
captureFocus?: unknown;
disableInitialFocus?: unknown;
eager?: unknown;
absolute?: unknown;
attach?: unknown;
closeOnBack?: unknown;
contained?: unknown;
contentClass?: unknown;
contentProps?: unknown;
disabled?: unknown;
opacity?: unknown;
noClickAnimation?: unknown;
modelValue?: unknown;
persistent?: unknown;
scrim?: unknown;
zIndex?: 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>;
};
locationStrategy: unknown extends Defaults["locationStrategy"] ? {
type: PropType<import("./locationStrategies.js").StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
} : Omit<{
type: PropType<import("./locationStrategies.js").StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["locationStrategy"] ? "connected" | "static" | import("../../types.js").LocationStrategyFunction : "connected" | "static" | import("../../types.js").LocationStrategyFunction | Defaults["locationStrategy"]>;
default: unknown extends Defaults["locationStrategy"] ? "connected" | "static" | import("../../types.js").LocationStrategyFunction : Defaults["locationStrategy"] | NonNullable<"connected" | "static" | import("../../types.js").LocationStrategyFunction>;
};
location: unknown extends Defaults["location"] ? {
type: PropType<import("./locationStrategies.js").StrategyProps['location']>;
default: string;
} : Omit<{
type: PropType<import("./locationStrategies.js").StrategyProps['location']>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["location"] ? import("../../util/index.js").Anchor : Defaults["location"] | import("../../util/index.js").Anchor>;
default: unknown extends Defaults["location"] ? import("../../util/index.js").Anchor : Defaults["location"] | NonNullable<import("../../util/index.js").Anchor>;
};
origin: unknown extends Defaults["origin"] ? {
type: PropType<import("./locationStrategies.js").StrategyProps['origin']>;
default: string;
} : Omit<{
type: PropType<import("./locationStrategies.js").StrategyProps['origin']>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["origin"] ? "auto" | "overlap" | import("../../util/index.js").Anchor : "auto" | "overlap" | Defaults["origin"] | import("../../util/index.js").Anchor>;
default: unknown extends Defaults["origin"] ? "auto" | "overlap" | import("../../util/index.js").Anchor : Defaults["origin"] | NonNullable<"auto" | "overlap" | import("../../util/index.js").Anchor>;
};
offset: unknown extends Defaults["offset"] ? PropType<string | number | number[] | undefined> : {
type: PropType<unknown extends Defaults["offset"] ? string | number | number[] | undefined : string | number | number[] | Defaults["offset"] | undefined>;
default: unknown extends Defaults["offset"] ? string | number | number[] | undefined : Defaults["offset"] | NonNullable<string | number | number[] | undefined>;
};
stickToTarget: unknown extends Defaults["stickToTarget"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["stickToTarget"] ? boolean : boolean | Defaults["stickToTarget"]>;
default: unknown extends Defaults["stickToTarget"] ? boolean : boolean | Defaults["stickToTarget"];
};
viewportMargin: unknown extends Defaults["viewportMargin"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["viewportMargin"] ? string | number : string | number | Defaults["viewportMargin"]>;
default: unknown extends Defaults["viewportMargin"] ? string | number : Defaults["viewportMargin"] | NonNullable<string | number>;
};
scrollStrategy: unknown extends Defaults["scrollStrategy"] ? {
type: PropType<import("./scrollStrategies.js").StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
} : Omit<{
type: PropType<import("./scrollStrategies.js").StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["scrollStrategy"] ? "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction : "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction | Defaults["scrollStrategy"]>;
default: unknown extends Defaults["scrollStrategy"] ? "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction : Defaults["scrollStrategy"] | NonNullable<"block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction>;
};
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>;
};
transition: unknown extends Defaults["transition"] ? import("vue").Prop<string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null> : {
type: PropType<unknown extends Defaults["transition"] ? string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null : string | boolean | Defaults["transition"] | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null>;
default: unknown extends Defaults["transition"] ? string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null : Defaults["transition"] | NonNullable<string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null>;
};
closeDelay: unknown extends Defaults["closeDelay"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["closeDelay"] ? string | number : string | number | Defaults["closeDelay"]>;
default: unknown extends Defaults["closeDelay"] ? string | number : Defaults["closeDelay"] | NonNullable<string | number>;
};
openDelay: unknown extends Defaults["openDelay"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["openDelay"] ? string | number : string | number | Defaults["openDelay"]>;
default: unknown extends Defaults["openDelay"] ? string | number : Defaults["openDelay"] | NonNullable<string | number>;
};
target: unknown extends Defaults["target"] ? PropType<"cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined> : {
type: PropType<unknown extends Defaults["target"] ? "cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined : "cursor" | "parent" | Element | [x: number, y: number] | Defaults["target"] | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
default: unknown extends Defaults["target"] ? "cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined : Defaults["target"] | NonNullable<"cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
};
activator: unknown extends Defaults["activator"] ? PropType<"parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined> : {
type: PropType<unknown extends Defaults["activator"] ? "parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined : "parent" | Element | Defaults["activator"] | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
default: unknown extends Defaults["activator"] ? "parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined : Defaults["activator"] | NonNullable<"parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
};
activatorProps: unknown extends Defaults["activatorProps"] ? {
type: PropType<Record<string, any>>;
default: () => {};
} : Omit<{
type: PropType<Record<string, any>>;
default: () => {};
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["activatorProps"] ? Record<string, any> : Record<string, any> | Defaults["activatorProps"]>;
default: unknown extends Defaults["activatorProps"] ? Record<string, any> : Record<string, any> | Defaults["activatorProps"];
};
openOnClick: unknown extends Defaults["openOnClick"] ? {
type: BooleanConstructor;
default: undefined;
} : Omit<{
type: BooleanConstructor;
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["openOnClick"] ? boolean : boolean | Defaults["openOnClick"]>;
default: unknown extends Defaults["openOnClick"] ? boolean : boolean | Defaults["openOnClick"];
};
openOnHover: unknown extends Defaults["openOnHover"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["openOnHover"] ? boolean : boolean | Defaults["openOnHover"]>;
default: unknown extends Defaults["openOnHover"] ? boolean : boolean | Defaults["openOnHover"];
};
openOnFocus: unknown extends Defaults["openOnFocus"] ? {
type: BooleanConstructor;
default: undefined;
} : Omit<{
type: BooleanConstructor;
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["openOnFocus"] ? boolean : boolean | Defaults["openOnFocus"]>;
default: unknown extends Defaults["openOnFocus"] ? boolean : boolean | Defaults["openOnFocus"];
};
closeOnContentClick: unknown extends Defaults["closeOnContentClick"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["closeOnContentClick"] ? boolean : boolean | Defaults["closeOnContentClick"]>;
default: unknown extends Defaults["closeOnContentClick"] ? boolean : boolean | Defaults["closeOnContentClick"];
};
retainFocus: unknown extends Defaults["retainFocus"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["retainFocus"] ? boolean : boolean | Defaults["retainFocus"]>;
default: unknown extends Defaults["retainFocus"] ? boolean : boolean | Defaults["retainFocus"];
};
captureFocus: unknown extends Defaults["captureFocus"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["captureFocus"] ? boolean : boolean | Defaults["captureFocus"]>;
default: unknown extends Defaults["captureFocus"] ? boolean : boolean | Defaults["captureFocus"];
};
disableInitialFocus: unknown extends Defaults["disableInitialFocus"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["disableInitialFocus"] ? boolean : boolean | Defaults["disableInitialFocus"]>;
default: unknown extends Defaults["disableInitialFocus"] ? boolean : boolean | Defaults["disableInitialFocus"];
};
eager: unknown extends Defaults["eager"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["eager"] ? boolean : boolean | Defaults["eager"]>;
default: unknown extends Defaults["eager"] ? boolean : boolean | Defaults["eager"];
};
absolute: unknown extends Defaults["absolute"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["absolute"] ? boolean : boolean | Defaults["absolute"]>;
default: unknown extends Defaults["absolute"] ? boolean : boolean | Defaults["absolute"];
};
attach: unknown extends Defaults["attach"] ? PropType<string | boolean | Element> : {
type: PropType<unknown extends Defaults["attach"] ? string | boolean | Element : string | boolean | Element | Defaults["attach"]>;
default: unknown extends Defaults["attach"] ? string | boolean | Element : Defaults["attach"] | NonNullable<string | boolean | Element>;
};
closeOnBack: unknown extends Defaults["closeOnBack"] ? {
type: BooleanConstructor;
default: boolean;
} : Omit<{
type: BooleanConstructor;
default: boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["closeOnBack"] ? boolean : boolean | Defaults["closeOnBack"]>;
default: unknown extends Defaults["closeOnBack"] ? boolean : boolean | Defaults["closeOnBack"];
};
contained: unknown extends Defaults["contained"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["contained"] ? boolean : boolean | Defaults["contained"]>;
default: unknown extends Defaults["contained"] ? boolean : boolean | Defaults["contained"];
};
contentClass: unknown extends Defaults["contentClass"] ? null : {
type: PropType<unknown extends Defaults["contentClass"] ? any : any>;
default: unknown extends Defaults["contentClass"] ? any : any;
};
contentProps: unknown extends Defaults["contentProps"] ? null : {
type: PropType<unknown extends Defaults["contentProps"] ? any : any>;
default: unknown extends Defaults["contentProps"] ? any : any;
};
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"];
};
opacity: unknown extends Defaults["opacity"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["opacity"] ? string | number : string | number | Defaults["opacity"]>;
default: unknown extends Defaults["opacity"] ? string | number : Defaults["opacity"] | NonNullable<string | number>;
};
noClickAnimation: unknown extends Defaults["noClickAnimation"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["noClickAnimation"] ? boolean : boolean | Defaults["noClickAnimation"]>;
default: unknown extends Defaults["noClickAnimation"] ? boolean : boolean | Defaults["noClickAnimation"];
};
modelValue: unknown extends Defaults["modelValue"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["modelValue"] ? boolean : boolean | Defaults["modelValue"]>;
default: unknown extends Defaults["modelValue"] ? boolean : boolean | Defaults["modelValue"];
};
persistent: unknown extends Defaults["persistent"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["persistent"] ? boolean : boolean | Defaults["persistent"]>;
default: unknown extends Defaults["persistent"] ? boolean : boolean | Defaults["persistent"];
};
scrim: unknown extends Defaults["scrim"] ? {
type: (BooleanConstructor | StringConstructor)[];
default: boolean;
} : Omit<{
type: (BooleanConstructor | StringConstructor)[];
default: boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["scrim"] ? string | boolean : string | boolean | Defaults["scrim"]>;
default: unknown extends Defaults["scrim"] ? string | boolean : Defaults["scrim"] | NonNullable<string | boolean>;
};
zIndex: unknown extends Defaults["zIndex"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["zIndex"] ? string | number : string | number | Defaults["zIndex"]>;
default: unknown extends Defaults["zIndex"] ? string | number : Defaults["zIndex"] | NonNullable<string | number>;
};
};
export declare const VOverlay: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnHover: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
} & {
theme?: string | undefined;
class?: any;
offset?: string | number | number[] | 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;
transition?: string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null | undefined;
closeDelay?: string | number | undefined;
openDelay?: string | number | undefined;
target?: "cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined;
activator?: "parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined;
openOnClick?: boolean | undefined;
openOnFocus?: boolean | undefined;
attach?: string | boolean | Element | undefined;
contentClass?: any;
contentProps?: any;
opacity?: string | number | undefined;
} & {
$children?: {
default?: ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:activator"?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
} & {
onAfterEnter?: (() => any) | undefined;
onAfterLeave?: (() => any) | undefined;
"onClick:outside"?: ((e: MouseEvent) => any) | undefined;
onKeydown?: ((e: KeyboardEvent) => any) | undefined;
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
}, {
activatorEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
scrimEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
target: import("vue").ComputedRef<HTMLElement | [x: number, y: number] | undefined>;
animateClick: () => void;
contentEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
rootEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
globalTop: Readonly<Ref<boolean, boolean>>;
localTop: Readonly<Ref<boolean, boolean>>;
updateLocation: Ref<((e: Event) => void) | undefined, ((e: Event) => void) | undefined>;
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'click:outside': (e: MouseEvent) => true;
'update:modelValue': (value: boolean) => true;
keydown: (e: KeyboardEvent) => true;
afterEnter: () => true;
afterLeave: () => true;
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
style: import("vue").StyleValue;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnClick: boolean;
openOnHover: boolean;
openOnFocus: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
}, true, {}, import("vue").SlotsType<Partial<{
default: (arg: {
isActive: Ref<boolean>;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
activator: (arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => 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;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnHover: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
} & {
theme?: string | undefined;
class?: any;
offset?: string | number | number[] | 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;
transition?: string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null | undefined;
closeDelay?: string | number | undefined;
openDelay?: string | number | undefined;
target?: "cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined;
activator?: "parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined;
openOnClick?: boolean | undefined;
openOnFocus?: boolean | undefined;
attach?: string | boolean | Element | undefined;
contentClass?: any;
contentProps?: any;
opacity?: string | number | undefined;
} & {
$children?: {
default?: ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:activator"?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
} & {
onAfterEnter?: (() => any) | undefined;
onAfterLeave?: (() => any) | undefined;
"onClick:outside"?: ((e: MouseEvent) => any) | undefined;
onKeydown?: ((e: KeyboardEvent) => any) | undefined;
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
}, {
activatorEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
scrimEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
target: import("vue").ComputedRef<HTMLElement | [x: number, y: number] | undefined>;
animateClick: () => void;
contentEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
rootEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
globalTop: Readonly<Ref<boolean, boolean>>;
localTop: Readonly<Ref<boolean, boolean>>;
updateLocation: Ref<((e: Event) => void) | undefined, ((e: Event) => void) | undefined>;
}, {}, {}, {}, {
style: import("vue").StyleValue;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnClick: boolean;
openOnHover: boolean;
openOnFocus: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnHover: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
} & {
theme?: string | undefined;
class?: any;
offset?: string | number | number[] | 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;
transition?: string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null | undefined;
closeDelay?: string | number | undefined;
openDelay?: string | number | undefined;
target?: "cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined;
activator?: "parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined;
openOnClick?: boolean | undefined;
openOnFocus?: boolean | undefined;
attach?: string | boolean | Element | undefined;
contentClass?: any;
contentProps?: any;
opacity?: string | number | undefined;
} & {
$children?: {
default?: ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
'v-slots'?: {
default?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
activator?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:activator"?: false | ((arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => import("vue").VNodeChild) | undefined;
"v-slot:default"?: false | ((arg: {
isActive: Ref<boolean>;
}) => import("vue").VNodeChild) | undefined;
} & {
onAfterEnter?: (() => any) | undefined;
onAfterLeave?: (() => any) | undefined;
"onClick:outside"?: ((e: MouseEvent) => any) | undefined;
onKeydown?: ((e: KeyboardEvent) => any) | undefined;
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
}, {
activatorEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
scrimEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
target: import("vue").ComputedRef<HTMLElement | [x: number, y: number] | undefined>;
animateClick: () => void;
contentEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
rootEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
globalTop: Readonly<Ref<boolean, boolean>>;
localTop: Readonly<Ref<boolean, boolean>>;
updateLocation: Ref<((e: Event) => void) | undefined, ((e: Event) => void) | undefined>;
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'click:outside': (e: MouseEvent) => true;
'update:modelValue': (value: boolean) => true;
keydown: (e: KeyboardEvent) => true;
afterEnter: () => true;
afterLeave: () => true;
}, string, {
style: import("vue").StyleValue;
locationStrategy: "connected" | "static" | import("../../types.js").LocationStrategyFunction;
location: import("../../util/index.js").Anchor;
origin: "auto" | "overlap" | import("../../util/index.js").Anchor;
stickToTarget: boolean;
viewportMargin: string | number;
scrollStrategy: "block" | "close" | "none" | "reposition" | import("../../types.js").ScrollStrategyFunction;
activatorProps: Record<string, any>;
openOnClick: boolean;
openOnHover: boolean;
openOnFocus: boolean;
closeOnContentClick: boolean;
retainFocus: boolean;
captureFocus: boolean;
eager: boolean;
absolute: boolean;
closeOnBack: boolean;
contained: boolean;
disabled: boolean;
noClickAnimation: boolean;
modelValue: boolean;
persistent: boolean;
scrim: string | boolean;
zIndex: string | number;
_disableGlobalStack: boolean;
}, {}, string, import("vue").SlotsType<Partial<{
default: (arg: {
isActive: Ref<boolean>;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
activator: (arg: {
isActive: boolean;
props: Record<string, any>;
targetRef: TemplateRef;
}) => 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;
};
locationStrategy: {
type: PropType<import("./locationStrategies.js").StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
};
location: {
type: PropType<import("./locationStrategies.js").StrategyProps['location']>;
default: string;
};
origin: {
type: PropType<import("./locationStrategies.js").StrategyProps['origin']>;
default: string;
};
offset: PropType<import("./locationStrategies.js").StrategyProps['offset']>;
stickToTarget: BooleanConstructor;
viewportMargin: {
type: (NumberConstructor | StringConstructor)[];
default: number;
};
scrollStrategy: {
type: PropType<import("./scrollStrategies.js").StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
};
height: (NumberConstructor | StringConstructor)[];
maxHeight: (NumberConstructor | StringConstructor)[];
maxWidth: (NumberConstructor | StringConstructor)[];
minHeight: (NumberConstructor | StringConstructor)[];
minWidth: (NumberConstructor | StringConstructor)[];
width: (NumberConstructor | StringConstructor)[];
transition: import("vue").Prop<string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null>;
closeDelay: (NumberConstructor | StringConstructor)[];
openDelay: (NumberConstructor | StringConstructor)[];
target: PropType<"cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
activator: PropType<"parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
activatorProps: {
type: PropType<Record<string, any>>;
default: () => {};
};
openOnClick: {
type: BooleanConstructor;
default: undefined;
};
openOnHover: BooleanConstructor;
openOnFocus: {
type: BooleanConstructor;
default: undefined;
};
closeOnContentClick: BooleanConstructor;
retainFocus: BooleanConstructor;
captureFocus: BooleanConstructor;
eager: BooleanConstructor;
absolute: BooleanConstructor;
attach: PropType<boolean | string | Element>;
closeOnBack: {
type: BooleanConstructor;
default: boolean;
};
contained: BooleanConstructor;
contentClass: null;
contentProps: null;
disabled: BooleanConstructor;
opacity: (NumberConstructor | StringConstructor)[];
noClickAnimation: BooleanConstructor;
modelValue: BooleanConstructor;
persistent: BooleanConstructor;
scrim: {
type: (BooleanConstructor | StringConstructor)[];
default: boolean;
};
zIndex: {
type: (NumberConstructor | StringConstructor)[];
default: number;
};
_disableGlobalStack: BooleanConstructor;
}, import("vue").ExtractPropTypes<{
theme: StringConstructor;
class: PropType<import("../../composables/component.js").ClassValue>;
style: {
type: PropType<import("vue").StyleValue>;
default: null;
};
locationStrategy: {
type: PropType<import("./locationStrategies.js").StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
};
location: {
type: PropType<import("./locationStrategies.js").StrategyProps['location']>;
default: string;
};
origin: {
type: PropType<import("./locationStrategies.js").StrategyProps['origin']>;
default: string;
};
offset: PropType<import("./locationStrategies.js").StrategyProps['offset']>;
stickToTarget: BooleanConstructor;
viewportMargin: {
type: (NumberConstructor | StringConstructor)[];
default: number;
};
scrollStrategy: {
type: PropType<import("./scrollStrategies.js").StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
};
height: (NumberConstructor | StringConstructor)[];
maxHeight: (NumberConstructor | StringConstructor)[];
maxWidth: (NumberConstructor | StringConstructor)[];
minHeight: (NumberConstructor | StringConstructor)[];
minWidth: (NumberConstructor | StringConstructor)[];
width: (NumberConstructor | StringConstructor)[];
transition: import("vue").Prop<string | boolean | (import("vue").TransitionProps & {
component?: import("vue").Component;
}) | null>;
closeDelay: (NumberConstructor | StringConstructor)[];
openDelay: (NumberConstructor | StringConstructor)[];
target: PropType<"cursor" | "parent" | Element | [x: number, y: number] | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
activator: PropType<"parent" | Element | import("vue").ComponentPublicInstance | (string & {}) | undefined>;
activatorProps: {
type: PropType<Record<string, any>>;
default: () => {};
};
openOnClick: {
type: BooleanConstructor;
default: undefined;
};
openOnHover: BooleanConstructor;
openOnFocus: {
type: BooleanConstructor;
default: undefined;
};
closeOnContentClick: BooleanConstructor;
retainFocus: BooleanConstructor;
captureFocus: BooleanConstructor;
eager: BooleanConstructor;
absolute: BooleanConstructor;
attach: PropType<boolean | string | Element>;
closeOnBack: {
type: BooleanConstructor;
default: boolean;
};
contained: BooleanConstructor;
contentClass: null;
contentProps: null;
disabled: BooleanConstructor;
opacity: (NumberConstructor | StringConstructor)[];
noClickAnimation: BooleanConstructor;
modelValue: BooleanConstructor;
persistent: BooleanConstructor;
scrim: {
type: (BooleanConstructor | StringConstructor)[];
default: boolean;
};
zIndex: {
type: (NumberConstructor | StringConstructor)[];
default: number;
};
_disableGlobalStack: BooleanConstructor;
}>>;
export type VOverlay = InstanceType<typeof VOverlay>;
+324
View File
@@ -0,0 +1,324 @@
import { mergeProps as _mergeProps, createElementVNode as _createElementVNode, createVNode as _createVNode, Fragment as _Fragment, vShow as _vShow, withDirectives as _withDirectives } from "vue";
// Styles
import "./VOverlay.css";
// Composables
import { makeLocationStrategyProps, useLocationStrategies } from "./locationStrategies.js";
import { makeScrollStrategyProps, useScrollStrategies } from "./scrollStrategies.js";
import { makeActivatorProps, useActivator } from "./useActivator.js";
import { useBackgroundColor } from "../../composables/color.js";
import { makeComponentProps } from "../../composables/component.js";
import { makeDimensionProps, useDimension } from "../../composables/dimensions.js";
import { makeFocusTrapProps, useFocusTrap } from "../../composables/focusTrap.js";
import { useHydration } from "../../composables/hydration.js";
import { makeLazyProps, useLazy } from "../../composables/lazy.js";
import { useRtl } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js";
import { useBackButton, useRouter } from "../../composables/router.js";
import { useScopeId } from "../../composables/scopeId.js";
import { useStack } from "../../composables/stack.js";
import { useTeleport } from "../../composables/teleport.js";
import { makeThemeProps, provideTheme } from "../../composables/theme.js";
import { useToggleScope } from "../../composables/toggleScope.js";
import { makeTransitionProps, MaybeTransition } from "../../composables/transition.js"; // Directives
import vClickOutside from "../../directives/click-outside/index.js"; // Utilities
import { computed, mergeProps, onBeforeUnmount, ref, Teleport, Transition, watch } from 'vue';
import { animate, convertToUnit, genericComponent, getCurrentInstance, getScrollParent, IN_BROWSER, omit, propsFactory, standardEasing, useRender } from "../../util/index.js"; // Types
function Scrim(props) {
const {
modelValue,
color,
...rest
} = props;
return _createVNode(Transition, {
"name": "fade-transition",
"appear": true
}, {
default: () => [props.modelValue && _createElementVNode("div", _mergeProps({
"class": ['v-overlay__scrim', props.color.backgroundColorClasses.value],
"style": props.color.backgroundColorStyles.value
}, rest), null)]
});
}
export const makeVOverlayProps = propsFactory({
absolute: Boolean,
attach: [Boolean, String, Object],
closeOnBack: {
type: Boolean,
default: true
},
contained: Boolean,
contentClass: null,
contentProps: null,
disabled: Boolean,
opacity: [Number, String],
noClickAnimation: Boolean,
modelValue: Boolean,
persistent: Boolean,
scrim: {
type: [Boolean, String],
default: true
},
zIndex: {
type: [Number, String],
default: 2000
},
...makeActivatorProps(),
...makeComponentProps(),
...makeDimensionProps(),
...makeLazyProps(),
...makeLocationStrategyProps(),
...makeScrollStrategyProps(),
...makeFocusTrapProps(),
...makeThemeProps(),
...makeTransitionProps()
}, 'VOverlay');
export const VOverlay = genericComponent()({
name: 'VOverlay',
directives: {
vClickOutside
},
inheritAttrs: false,
props: {
_disableGlobalStack: Boolean,
...omit(makeVOverlayProps(), ['disableInitialFocus'])
},
emits: {
'click:outside': e => true,
'update:modelValue': value => true,
keydown: e => true,
afterEnter: () => true,
afterLeave: () => true
},
setup(props, {
slots,
attrs,
emit
}) {
const vm = getCurrentInstance('VOverlay');
const root = ref();
const scrimEl = ref();
const contentEl = ref();
const model = useProxiedModel(props, 'modelValue');
const isActive = computed({
get: () => model.value,
set: v => {
if (!(v && props.disabled)) model.value = v;
}
});
const {
themeClasses
} = provideTheme(props);
const {
rtlClasses,
isRtl
} = useRtl();
const {
hasContent,
onAfterLeave: _onAfterLeave
} = useLazy(props, isActive);
const scrimColor = useBackgroundColor(() => {
return typeof props.scrim === 'string' ? props.scrim : null;
});
const {
globalTop,
localTop,
stackStyles
} = useStack(isActive, () => props.zIndex, props._disableGlobalStack);
const {
activatorEl,
activatorRef,
target,
targetEl,
targetRef,
activatorEvents,
contentEvents,
scrimEvents
} = useActivator(props, {
isActive,
isTop: localTop,
contentEl
});
const {
teleportTarget
} = useTeleport(() => {
const target = props.attach || props.contained;
if (target) return target;
const rootNode = activatorEl?.value?.getRootNode() || vm.proxy?.$el?.getRootNode();
if (rootNode instanceof ShadowRoot) return rootNode;
return false;
});
const {
dimensionStyles
} = useDimension(props);
const isMounted = useHydration();
const {
scopeId
} = useScopeId();
watch(() => props.disabled, v => {
if (v) isActive.value = false;
});
const {
contentStyles,
updateLocation
} = useLocationStrategies(props, {
isRtl,
contentEl,
target,
isActive
});
useScrollStrategies(props, {
root,
contentEl,
targetEl,
target,
isActive,
updateLocation
});
function onClickOutside(e) {
emit('click:outside', e);
if (!props.persistent) isActive.value = false;else animateClick();
}
function closeConditional(e) {
return isActive.value && localTop.value && (
// If using scrim, only close if clicking on it rather than anything opened on top
!props.scrim || e.target === scrimEl.value || e instanceof MouseEvent && e.shadowTarget === scrimEl.value);
}
useFocusTrap(props, {
isActive,
localTop,
contentEl,
activatorEl
});
IN_BROWSER && watch(isActive, val => {
if (val) {
window.addEventListener('keydown', onKeydown);
} else {
window.removeEventListener('keydown', onKeydown);
}
}, {
immediate: true
});
onBeforeUnmount(() => {
if (!IN_BROWSER) return;
window.removeEventListener('keydown', onKeydown);
});
function onKeydown(e) {
if (e.key === 'Escape' && globalTop.value) {
if (!contentEl.value?.contains(document.activeElement)) {
emit('keydown', e);
}
if (!props.persistent) {
isActive.value = false;
if (contentEl.value?.contains(document.activeElement)) {
activatorEl.value?.focus();
}
} else animateClick();
}
}
function onKeydownSelf(e) {
if (e.key === 'Escape' && !globalTop.value) return;
emit('keydown', e);
}
const router = useRouter();
useToggleScope(() => props.closeOnBack, () => {
useBackButton(router, () => {
if (globalTop.value && isActive.value) {
if (!props.persistent) isActive.value = false;else animateClick();
return false;
}
return undefined;
});
});
const top = ref();
watch(() => isActive.value && (props.absolute || props.contained) && teleportTarget.value == null, val => {
if (val) {
const scrollParent = getScrollParent(root.value);
if (scrollParent && scrollParent !== document.scrollingElement) {
top.value = scrollParent.scrollTop;
}
}
});
// Add a quick "bounce" animation to the content
function animateClick() {
if (props.noClickAnimation) return;
contentEl.value && animate(contentEl.value, [{
transformOrigin: 'center'
}, {
transform: 'scale(1.03)'
}, {
transformOrigin: 'center'
}], {
duration: 150,
easing: standardEasing
});
}
function onAfterEnter() {
emit('afterEnter');
}
function onAfterLeave() {
_onAfterLeave();
emit('afterLeave');
}
useRender(() => _createElementVNode(_Fragment, null, [slots.activator?.({
isActive: isActive.value,
targetRef,
props: mergeProps({
ref: activatorRef
}, activatorEvents.value, props.activatorProps)
}), isMounted.value && hasContent.value && _createVNode(Teleport, {
"disabled": !teleportTarget.value,
"to": teleportTarget.value
}, {
default: () => [_createElementVNode("div", _mergeProps({
"class": ['v-overlay', {
'v-overlay--absolute': props.absolute || props.contained,
'v-overlay--active': isActive.value,
'v-overlay--contained': props.contained
}, themeClasses.value, rtlClasses.value, props.class],
"style": [stackStyles.value, {
'--v-overlay-opacity': props.opacity,
top: convertToUnit(top.value)
}, props.style],
"ref": root,
"onKeydown": onKeydownSelf
}, scopeId, attrs), [_createVNode(Scrim, _mergeProps({
"color": scrimColor,
"modelValue": isActive.value && !!props.scrim,
"ref": scrimEl
}, scrimEvents.value), null), _createVNode(MaybeTransition, {
"appear": true,
"persisted": true,
"transition": props.transition,
"target": target.value,
"onAfterEnter": onAfterEnter,
"onAfterLeave": onAfterLeave
}, {
default: () => [_withDirectives(_createElementVNode("div", _mergeProps({
"ref": contentEl,
"class": ['v-overlay__content', props.contentClass],
"style": [dimensionStyles.value, contentStyles.value]
}, contentEvents.value, props.contentProps), [slots.default?.({
isActive
})]), [[_vShow, isActive.value], [vClickOutside, {
handler: onClickOutside,
closeConditional,
include: () => [activatorEl.value]
}]])]
})])]
})]));
return {
activatorEl,
scrimEl,
target,
animateClick,
contentEl,
rootEl: root,
globalTop,
localTop,
updateLocation
};
}
});
//# sourceMappingURL=VOverlay.js.map
File diff suppressed because one or more lines are too long
+69
View File
@@ -0,0 +1,69 @@
@use 'sass:selector'
@use '../../styles/tools'
@use './variables' as *
@include tools.layer('components')
// Block
.v-overlay-container
contain: layout
left: 0
pointer-events: none
position: absolute
top: 0
display: contents
.v-overlay
--v-overlay-opacity: #{$overlay-opacity}
border-radius: inherit
display: flex
left: 0
pointer-events: none
position: fixed
top: 0
bottom: 0
right: 0
// Element
.v-overlay__content
outline: none
position: absolute
pointer-events: auto
contain: layout
.v-overlay__scrim
pointer-events: auto
background: $overlay-scrim-background
border-radius: inherit
bottom: 0
left: 0
opacity: var(--v-overlay-opacity)
position: fixed
right: 0
top: 0
// Modifier
.v-overlay--absolute
position: absolute
.v-overlay--contained .v-overlay__scrim
position: absolute
.v-overlay--scroll-blocked
padding-inline-end: var(--v-scrollbar-offset)
@include tools.layer('trumps')
.v-overlay-scroll-blocked
padding-inline-end: var(--v-scrollbar-offset)
&:not(html)
overflow-y: hidden
@at-root #{selector.append(html, &)}
position: fixed
top: var(--v-body-scroll-y)
left: var(--v-body-scroll-x)
width: 100%
height: 100%
.v-navigation-drawer--right.v-navigation-drawer--active
margin-right: var(--v-scrollbar-offset)
@@ -0,0 +1,3 @@
// Defaults
$overlay-opacity: 0.32 !default;
$overlay-scrim-background: #000 !default;
+1
View File
@@ -0,0 +1 @@
export { VOverlay } from './VOverlay.js';
+2
View File
@@ -0,0 +1,2 @@
export { VOverlay } from "./VOverlay.js";
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["VOverlay"],"sources":["../../../src/components/VOverlay/index.ts"],"sourcesContent":["export { VOverlay } from './VOverlay'\n"],"mappings":"SAASA,QAAQ","ignoreList":[]}
@@ -0,0 +1,106 @@
import { Box } from '../../util/box.js';
import type { PropType, Ref } from 'vue';
import type { Anchor } from '../../util/index.js';
export interface LocationStrategyData {
contentEl: Ref<HTMLElement | undefined>;
target: Ref<HTMLElement | [x: number, y: number] | undefined>;
isActive: Ref<boolean>;
isRtl: Ref<boolean>;
}
export type LocationStrategyFunction = (data: LocationStrategyData, props: StrategyProps, contentStyles: Ref<Record<string, string>>) => undefined | {
updateLocation: (e?: Event) => void;
};
declare const locationStrategies: {
static: typeof staticLocationStrategy;
connected: typeof connectedLocationStrategy;
};
export interface StrategyProps {
locationStrategy: keyof typeof locationStrategies | LocationStrategyFunction;
location: Anchor;
origin: Anchor | 'auto' | 'overlap';
offset?: number | string | number[];
stickToTarget?: boolean;
viewportMargin?: number | string;
maxHeight?: number | string;
maxWidth?: number | string;
minHeight?: number | string;
minWidth?: number | string;
}
export declare const makeLocationStrategyProps: <Defaults extends {
locationStrategy?: unknown;
location?: unknown;
origin?: unknown;
offset?: unknown;
stickToTarget?: unknown;
viewportMargin?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
locationStrategy: unknown extends Defaults["locationStrategy"] ? {
type: PropType<StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
} : Omit<{
type: PropType<StrategyProps['locationStrategy']>;
default: string;
validator: (val: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["locationStrategy"] ? "connected" | "static" | LocationStrategyFunction : "connected" | "static" | LocationStrategyFunction | Defaults["locationStrategy"]>;
default: unknown extends Defaults["locationStrategy"] ? "connected" | "static" | LocationStrategyFunction : Defaults["locationStrategy"] | NonNullable<"connected" | "static" | LocationStrategyFunction>;
};
location: unknown extends Defaults["location"] ? {
type: PropType<StrategyProps['location']>;
default: string;
} : Omit<{
type: PropType<StrategyProps['location']>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["location"] ? Anchor : Defaults["location"] | Anchor>;
default: unknown extends Defaults["location"] ? Anchor : Defaults["location"] | NonNullable<Anchor>;
};
origin: unknown extends Defaults["origin"] ? {
type: PropType<StrategyProps['origin']>;
default: string;
} : Omit<{
type: PropType<StrategyProps['origin']>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["origin"] ? "auto" | "overlap" | Anchor : "auto" | "overlap" | Defaults["origin"] | Anchor>;
default: unknown extends Defaults["origin"] ? "auto" | "overlap" | Anchor : Defaults["origin"] | NonNullable<"auto" | "overlap" | Anchor>;
};
offset: unknown extends Defaults["offset"] ? PropType<string | number | number[] | undefined> : {
type: PropType<unknown extends Defaults["offset"] ? string | number | number[] | undefined : string | number | number[] | Defaults["offset"] | undefined>;
default: unknown extends Defaults["offset"] ? string | number | number[] | undefined : Defaults["offset"] | NonNullable<string | number | number[] | undefined>;
};
stickToTarget: unknown extends Defaults["stickToTarget"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["stickToTarget"] ? boolean : boolean | Defaults["stickToTarget"]>;
default: unknown extends Defaults["stickToTarget"] ? boolean : boolean | Defaults["stickToTarget"];
};
viewportMargin: unknown extends Defaults["viewportMargin"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["viewportMargin"] ? string | number : string | number | Defaults["viewportMargin"]>;
default: unknown extends Defaults["viewportMargin"] ? string | number : Defaults["viewportMargin"] | NonNullable<string | number>;
};
};
export declare function useLocationStrategies(props: StrategyProps, data: LocationStrategyData): {
contentStyles: Ref<{}, {}>;
updateLocation: Ref<((e: Event) => void) | undefined, ((e: Event) => void) | undefined>;
};
declare function staticLocationStrategy(): void;
declare function connectedLocationStrategy(data: LocationStrategyData, props: StrategyProps, contentStyles: Ref<Record<string, string>>): {
updateLocation: () => {
available: {
x: number;
y: number;
};
contentBox: Box;
flipped: {
x: boolean;
y: boolean;
};
} | undefined;
};
@@ -0,0 +1,435 @@
// Composables
import { useToggleScope } from "../../composables/toggleScope.js"; // Utilities
import { computed, nextTick, onScopeDispose, ref, watch } from 'vue';
import { anchorToPoint, getOffset } from "./util/point.js";
import { CircularBuffer, clamp, consoleError, convertToUnit, deepEqual, destructComputed, flipAlign, flipCorner, flipSide, getAxis, getScrollParents, IN_BROWSER, isFixedPosition, nullifyTransforms, parseAnchor, propsFactory } from "../../util/index.js";
import { Box, getElementBox, getOverflow, getTargetBox } from "../../util/box.js"; // Types
const locationStrategies = {
static: staticLocationStrategy,
// specific viewport position, usually centered
connected: connectedLocationStrategy // connected to a certain element
};
export const makeLocationStrategyProps = propsFactory({
locationStrategy: {
type: [String, Function],
default: 'static',
validator: val => typeof val === 'function' || val in locationStrategies
},
location: {
type: String,
default: 'bottom'
},
origin: {
type: String,
default: 'auto'
},
offset: [Number, String, Array],
stickToTarget: Boolean,
viewportMargin: {
type: [Number, String],
default: 12
}
}, 'VOverlay-location-strategies');
export function useLocationStrategies(props, data) {
const contentStyles = ref({});
const updateLocation = ref();
if (IN_BROWSER) {
useToggleScope(() => !!(data.isActive.value && props.locationStrategy), reset => {
watch(() => props.locationStrategy, reset);
onScopeDispose(() => {
window.removeEventListener('resize', onResize);
visualViewport?.removeEventListener('resize', onVisualResize);
visualViewport?.removeEventListener('scroll', onVisualScroll);
updateLocation.value = undefined;
});
window.addEventListener('resize', onResize, {
passive: true
});
visualViewport?.addEventListener('resize', onVisualResize, {
passive: true
});
visualViewport?.addEventListener('scroll', onVisualScroll, {
passive: true
});
if (typeof props.locationStrategy === 'function') {
updateLocation.value = props.locationStrategy(data, props, contentStyles)?.updateLocation;
} else {
updateLocation.value = locationStrategies[props.locationStrategy](data, props, contentStyles)?.updateLocation;
}
});
}
function onResize(e) {
updateLocation.value?.(e);
}
function onVisualResize(e) {
updateLocation.value?.(e);
}
function onVisualScroll(e) {
updateLocation.value?.(e);
}
return {
contentStyles,
updateLocation
};
}
function staticLocationStrategy() {
// TODO
}
/** Get size of element ignoring max-width/max-height */
function getIntrinsicSize(el, isRtl) {
// const scrollables = new Map<Element, [number, number]>()
// el.querySelectorAll('*').forEach(el => {
// const x = el.scrollLeft
// const y = el.scrollTop
// if (x || y) {
// scrollables.set(el, [x, y])
// }
// })
// const initialMaxWidth = el.style.maxWidth
// const initialMaxHeight = el.style.maxHeight
// el.style.removeProperty('max-width')
// el.style.removeProperty('max-height')
/* eslint-disable-next-line sonarjs/prefer-immediate-return */
const contentBox = nullifyTransforms(el);
if (isRtl) {
contentBox.x += parseFloat(el.style.right || 0);
} else {
contentBox.x -= parseFloat(el.style.left || 0);
}
contentBox.y -= parseFloat(el.style.top || 0);
// el.style.maxWidth = initialMaxWidth
// el.style.maxHeight = initialMaxHeight
// scrollables.forEach((position, el) => {
// el.scrollTo(...position)
// })
return contentBox;
}
function connectedLocationStrategy(data, props, contentStyles) {
const activatorFixed = Array.isArray(data.target.value) || isFixedPosition(data.target.value);
if (activatorFixed) {
Object.assign(contentStyles.value, {
position: 'fixed',
top: 0,
[data.isRtl.value ? 'right' : 'left']: 0
});
}
const {
preferredAnchor,
preferredOrigin
} = destructComputed(() => {
const parsedAnchor = parseAnchor(props.location, data.isRtl.value);
const parsedOrigin = props.origin === 'overlap' ? parsedAnchor : props.origin === 'auto' ? flipSide(parsedAnchor) : parseAnchor(props.origin, data.isRtl.value);
// Some combinations of props may produce an invalid origin
if (parsedAnchor.side === parsedOrigin.side && parsedAnchor.align === flipAlign(parsedOrigin).align) {
return {
preferredAnchor: flipCorner(parsedAnchor),
preferredOrigin: flipCorner(parsedOrigin)
};
} else {
return {
preferredAnchor: parsedAnchor,
preferredOrigin: parsedOrigin
};
}
});
const [minWidth, minHeight, maxWidth, maxHeight] = ['minWidth', 'minHeight', 'maxWidth', 'maxHeight'].map(key => {
return computed(() => {
const val = parseFloat(props[key]);
return isNaN(val) ? Infinity : val;
});
});
const offset = computed(() => {
if (Array.isArray(props.offset)) {
return props.offset;
}
if (typeof props.offset === 'string') {
const offset = props.offset.split(' ').map(parseFloat);
if (offset.length < 2) offset.push(0);
return offset;
}
return typeof props.offset === 'number' ? [props.offset, 0] : [0, 0];
});
let observe = false;
let lastFrame = -1;
const flipped = new CircularBuffer(4);
const observer = new ResizeObserver(() => {
if (!observe) return;
// Detect consecutive frames
requestAnimationFrame(newTime => {
if (newTime !== lastFrame) flipped.clear();
requestAnimationFrame(newNewTime => {
lastFrame = newNewTime;
});
});
if (flipped.isFull) {
const values = flipped.values();
if (deepEqual(values.at(-1), values.at(-3)) && !deepEqual(values.at(-1), values.at(-2))) {
// Flipping is causing a container resize loop
return;
}
}
const result = updateLocation();
if (result) flipped.push(result.flipped);
});
let targetBox = new Box({
x: 0,
y: 0,
width: 0,
height: 0
});
watch(data.target, (newTarget, oldTarget) => {
if (oldTarget && !Array.isArray(oldTarget)) observer.unobserve(oldTarget);
if (!Array.isArray(newTarget)) {
if (newTarget) observer.observe(newTarget);
} else if (!deepEqual(newTarget, oldTarget)) {
updateLocation();
}
}, {
immediate: true
});
watch(data.contentEl, (newContentEl, oldContentEl) => {
if (oldContentEl) observer.unobserve(oldContentEl);
if (newContentEl) observer.observe(newContentEl);
}, {
immediate: true
});
onScopeDispose(() => {
observer.disconnect();
});
// eslint-disable-next-line max-statements
function updateLocation() {
observe = false;
requestAnimationFrame(() => observe = true);
if (!data.target.value || !data.contentEl.value) return;
if (Array.isArray(data.target.value) || data.target.value.offsetParent || data.target.value.getClientRects().length) {
targetBox = getTargetBox(data.target.value);
} // Otherwise target element is hidden, use last known value
const contentBox = getIntrinsicSize(data.contentEl.value, data.isRtl.value);
const scrollParents = getScrollParents(data.contentEl.value);
const viewportMargin = Number(props.viewportMargin);
if (!scrollParents.length) {
scrollParents.push(document.documentElement);
if (!(data.contentEl.value.style.top && data.contentEl.value.style.left)) {
contentBox.x -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-x') || 0);
contentBox.y -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-y') || 0);
}
}
const viewport = scrollParents.reduce((box, el) => {
const scrollBox = getElementBox(el);
if (box) {
return new Box({
x: Math.max(box.left, scrollBox.left),
y: Math.max(box.top, scrollBox.top),
width: Math.min(box.right, scrollBox.right) - Math.max(box.left, scrollBox.left),
height: Math.min(box.bottom, scrollBox.bottom) - Math.max(box.top, scrollBox.top)
});
}
return scrollBox;
}, undefined);
if (props.stickToTarget) {
viewport.x += Math.min(viewportMargin, targetBox.x);
viewport.y += Math.min(viewportMargin, targetBox.y);
viewport.width = Math.max(viewport.width - viewportMargin * 2, targetBox.x + targetBox.width - viewportMargin);
viewport.height = Math.max(viewport.height - viewportMargin * 2, targetBox.y + targetBox.height - viewportMargin);
} else {
viewport.x += viewportMargin;
viewport.y += viewportMargin;
viewport.width -= viewportMargin * 2;
viewport.height -= viewportMargin * 2;
}
let placement = {
anchor: preferredAnchor.value,
origin: preferredOrigin.value
};
function checkOverflow(_placement) {
const box = new Box(contentBox);
const targetPoint = anchorToPoint(_placement.anchor, targetBox);
const contentPoint = anchorToPoint(_placement.origin, box);
let {
x,
y
} = getOffset(targetPoint, contentPoint);
switch (_placement.anchor.side) {
case 'top':
y -= offset.value[0];
break;
case 'bottom':
y += offset.value[0];
break;
case 'left':
x -= offset.value[0];
break;
case 'right':
x += offset.value[0];
break;
}
switch (_placement.anchor.align) {
case 'top':
y -= offset.value[1];
break;
case 'bottom':
y += offset.value[1];
break;
case 'left':
x -= offset.value[1];
break;
case 'right':
x += offset.value[1];
break;
}
box.x += x;
box.y += y;
box.width = Math.min(box.width, maxWidth.value);
box.height = Math.min(box.height, maxHeight.value);
const overflows = getOverflow(box, viewport);
return {
overflows,
x,
y
};
}
let x = 0;
let y = 0;
const available = {
x: 0,
y: 0
};
const flipped = {
x: false,
y: false
};
let resets = -1;
while (true) {
if (resets++ > 10) {
consoleError('Infinite loop detected in connectedLocationStrategy');
break;
}
const {
x: _x,
y: _y,
overflows
} = checkOverflow(placement);
x += _x;
y += _y;
contentBox.x += _x;
contentBox.y += _y;
// flip
{
const axis = getAxis(placement.anchor);
const hasOverflowX = overflows.x.before || overflows.x.after;
const hasOverflowY = overflows.y.before || overflows.y.after;
let reset = false;
['x', 'y'].forEach(key => {
if (key === 'x' && hasOverflowX && !flipped.x || key === 'y' && hasOverflowY && !flipped.y) {
const newPlacement = {
anchor: {
...placement.anchor
},
origin: {
...placement.origin
}
};
const flip = key === 'x' ? axis === 'y' ? flipAlign : flipSide : axis === 'y' ? flipSide : flipAlign;
newPlacement.anchor = flip(newPlacement.anchor);
newPlacement.origin = flip(newPlacement.origin);
const {
overflows: newOverflows
} = checkOverflow(newPlacement);
if (newOverflows[key].before <= overflows[key].before && newOverflows[key].after <= overflows[key].after || newOverflows[key].before + newOverflows[key].after < (overflows[key].before + overflows[key].after) / 2) {
placement = newPlacement;
reset = flipped[key] = true;
}
}
});
if (reset) continue;
}
// shift
if (overflows.x.before) {
x += overflows.x.before;
contentBox.x += overflows.x.before;
}
if (overflows.x.after) {
x -= overflows.x.after;
contentBox.x -= overflows.x.after;
}
if (overflows.y.before) {
y += overflows.y.before;
contentBox.y += overflows.y.before;
}
if (overflows.y.after) {
y -= overflows.y.after;
contentBox.y -= overflows.y.after;
}
// size
{
const overflows = getOverflow(contentBox, viewport);
available.x = viewport.width - overflows.x.before - overflows.x.after;
available.y = viewport.height - overflows.y.before - overflows.y.after;
x += overflows.x.before;
contentBox.x += overflows.x.before;
y += overflows.y.before;
contentBox.y += overflows.y.before;
}
break;
}
const axis = getAxis(placement.anchor);
Object.assign(contentStyles.value, {
'--v-overlay-anchor-origin': `${placement.anchor.side} ${placement.anchor.align}`,
transformOrigin: `${placement.origin.side} ${placement.origin.align}`,
// transform: `translate(${pixelRound(x)}px, ${pixelRound(y)}px)`,
top: convertToUnit(pixelRound(y)),
left: data.isRtl.value ? undefined : convertToUnit(pixelRound(x)),
right: data.isRtl.value ? convertToUnit(pixelRound(-x)) : undefined,
minWidth: convertToUnit(axis === 'y' ? Math.min(minWidth.value, targetBox.width) : minWidth.value),
maxWidth: convertToUnit(pixelCeil(clamp(available.x, minWidth.value === Infinity ? 0 : minWidth.value, maxWidth.value))),
maxHeight: convertToUnit(pixelCeil(clamp(available.y, minHeight.value === Infinity ? 0 : minHeight.value, maxHeight.value)))
});
return {
available,
contentBox,
flipped
};
}
watch(() => [preferredAnchor.value, preferredOrigin.value, props.offset, props.minWidth, props.minHeight, props.maxWidth, props.maxHeight], () => updateLocation());
nextTick(() => {
const result = updateLocation();
// TODO: overflowing content should only require a single updateLocation call
// Icky hack to make sure the content is positioned consistently
if (!result) return;
const {
available,
contentBox
} = result;
if (contentBox.height > available.y) {
requestAnimationFrame(() => {
updateLocation();
requestAnimationFrame(() => {
updateLocation();
});
});
}
});
return {
updateLocation
};
}
function pixelRound(val) {
return Math.round(val * devicePixelRatio) / devicePixelRatio;
}
function pixelCeil(val) {
return Math.ceil(val * devicePixelRatio) / devicePixelRatio;
}
//# sourceMappingURL=locationStrategies.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
/**
* Schedule a task to run in an animation frame on its own
* This is useful for heavy tasks that may cause jank if all ran together
*/
export declare function requestNewFrame(cb: () => void): void;
@@ -0,0 +1,27 @@
let clean = true;
const frames = [];
/**
* Schedule a task to run in an animation frame on its own
* This is useful for heavy tasks that may cause jank if all ran together
*/
export function requestNewFrame(cb) {
if (!clean || frames.length) {
frames.push(cb);
run();
} else {
clean = false;
cb();
run();
}
}
let raf = -1;
function run() {
cancelAnimationFrame(raf);
raf = requestAnimationFrame(() => {
const frame = frames.shift();
if (frame) frame();
if (frames.length) run();else clean = true;
});
}
//# sourceMappingURL=requestNewFrame.js.map
@@ -0,0 +1 @@
{"version":3,"file":"requestNewFrame.js","names":["clean","frames","requestNewFrame","cb","length","push","run","raf","cancelAnimationFrame","requestAnimationFrame","frame","shift"],"sources":["../../../src/components/VOverlay/requestNewFrame.ts"],"sourcesContent":["let clean = true\nconst frames = [] as any[]\n\n/**\n * Schedule a task to run in an animation frame on its own\n * This is useful for heavy tasks that may cause jank if all ran together\n */\nexport function requestNewFrame (cb: () => void) {\n if (!clean || frames.length) {\n frames.push(cb)\n run()\n } else {\n clean = false\n cb()\n run()\n }\n}\n\nlet raf = -1\nfunction run () {\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n const frame = frames.shift()\n if (frame) frame()\n\n if (frames.length) run()\n else clean = true\n })\n}\n"],"mappings":"AAAA,IAAIA,KAAK,GAAG,IAAI;AAChB,MAAMC,MAAM,GAAG,EAAW;;AAE1B;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAAEC,EAAc,EAAE;EAC/C,IAAI,CAACH,KAAK,IAAIC,MAAM,CAACG,MAAM,EAAE;IAC3BH,MAAM,CAACI,IAAI,CAACF,EAAE,CAAC;IACfG,GAAG,CAAC,CAAC;EACP,CAAC,MAAM;IACLN,KAAK,GAAG,KAAK;IACbG,EAAE,CAAC,CAAC;IACJG,GAAG,CAAC,CAAC;EACP;AACF;AAEA,IAAIC,GAAG,GAAG,CAAC,CAAC;AACZ,SAASD,GAAGA,CAAA,EAAI;EACdE,oBAAoB,CAACD,GAAG,CAAC;EACzBA,GAAG,GAAGE,qBAAqB,CAAC,MAAM;IAChC,MAAMC,KAAK,GAAGT,MAAM,CAACU,KAAK,CAAC,CAAC;IAC5B,IAAID,KAAK,EAAEA,KAAK,CAAC,CAAC;IAElB,IAAIT,MAAM,CAACG,MAAM,EAAEE,GAAG,CAAC,CAAC,MACnBN,KAAK,GAAG,IAAI;EACnB,CAAC,CAAC;AACJ","ignoreList":[]}
@@ -0,0 +1,41 @@
import type { EffectScope, PropType, Ref } from 'vue';
export interface ScrollStrategyData {
root: Ref<HTMLElement | undefined>;
contentEl: Ref<HTMLElement | undefined>;
targetEl: Ref<HTMLElement | undefined>;
target: Ref<HTMLElement | [x: number, y: number] | undefined>;
isActive: Ref<boolean>;
updateLocation: Ref<((e: Event) => void) | undefined>;
}
export type ScrollStrategyFunction = (data: ScrollStrategyData, props: StrategyProps, scope: EffectScope) => void;
declare const scrollStrategies: {
none: null;
close: typeof closeScrollStrategy;
block: typeof blockScrollStrategy;
reposition: typeof repositionScrollStrategy;
};
export interface StrategyProps {
scrollStrategy: keyof typeof scrollStrategies | ScrollStrategyFunction;
contained: boolean | undefined;
}
export declare const makeScrollStrategyProps: <Defaults extends {
scrollStrategy?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
scrollStrategy: unknown extends Defaults["scrollStrategy"] ? {
type: PropType<StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
} : Omit<{
type: PropType<StrategyProps['scrollStrategy']>;
default: string;
validator: (val: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["scrollStrategy"] ? "block" | "close" | "none" | "reposition" | ScrollStrategyFunction : "block" | "close" | "none" | "reposition" | ScrollStrategyFunction | Defaults["scrollStrategy"]>;
default: unknown extends Defaults["scrollStrategy"] ? "block" | "close" | "none" | "reposition" | ScrollStrategyFunction : Defaults["scrollStrategy"] | NonNullable<"block" | "close" | "none" | "reposition" | ScrollStrategyFunction>;
};
};
export declare function useScrollStrategies(props: StrategyProps, data: ScrollStrategyData): void;
declare function closeScrollStrategy(data: ScrollStrategyData): void;
declare function blockScrollStrategy(data: ScrollStrategyData, props: StrategyProps): void;
declare function repositionScrollStrategy(data: ScrollStrategyData, props: StrategyProps, scope: EffectScope): void;
@@ -0,0 +1,133 @@
// Utilities
import { effectScope, onScopeDispose, watchEffect } from 'vue';
import { requestNewFrame } from "./requestNewFrame.js";
import { convertToUnit, getScrollParents, hasScrollbar, IN_BROWSER, propsFactory } from "../../util/index.js"; // Types
const scrollStrategies = {
none: null,
close: closeScrollStrategy,
block: blockScrollStrategy,
reposition: repositionScrollStrategy
};
export const makeScrollStrategyProps = propsFactory({
scrollStrategy: {
type: [String, Function],
default: 'block',
validator: val => typeof val === 'function' || val in scrollStrategies
}
}, 'VOverlay-scroll-strategies');
export function useScrollStrategies(props, data) {
if (!IN_BROWSER) return;
let scope;
watchEffect(async () => {
scope?.stop();
if (!(data.isActive.value && props.scrollStrategy)) return;
scope = effectScope();
await new Promise(resolve => setTimeout(resolve));
scope.active && scope.run(() => {
if (typeof props.scrollStrategy === 'function') {
props.scrollStrategy(data, props, scope);
} else {
scrollStrategies[props.scrollStrategy]?.(data, props, scope);
}
});
});
onScopeDispose(() => {
scope?.stop();
});
}
function closeScrollStrategy(data) {
function onScroll(e) {
data.isActive.value = false;
}
bindScroll(getTargetEl(data.target.value, data.contentEl.value), onScroll);
}
function blockScrollStrategy(data, props) {
const offsetParent = data.root.value?.offsetParent;
const target = getTargetEl(data.target.value, data.contentEl.value);
const scrollElements = [...new Set([...getScrollParents(target, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
const scrollbarWidth = window.innerWidth - document.documentElement.offsetWidth;
const scrollableParent = (el => hasScrollbar(el) && el)(offsetParent || document.documentElement);
if (scrollableParent) {
data.root.value.classList.add('v-overlay--scroll-blocked');
}
scrollElements.forEach((el, i) => {
el.style.setProperty('--v-body-scroll-x', convertToUnit(-el.scrollLeft));
el.style.setProperty('--v-body-scroll-y', convertToUnit(-el.scrollTop));
if (el !== document.documentElement || getComputedStyle(el).overflowY !== 'scroll') {
el.style.setProperty('--v-scrollbar-offset', convertToUnit(scrollbarWidth));
}
el.classList.add('v-overlay-scroll-blocked');
});
onScopeDispose(() => {
scrollElements.forEach((el, i) => {
const x = parseFloat(el.style.getPropertyValue('--v-body-scroll-x'));
const y = parseFloat(el.style.getPropertyValue('--v-body-scroll-y'));
const scrollBehavior = el.style.scrollBehavior;
el.style.scrollBehavior = 'auto';
el.style.removeProperty('--v-body-scroll-x');
el.style.removeProperty('--v-body-scroll-y');
el.style.removeProperty('--v-scrollbar-offset');
el.classList.remove('v-overlay-scroll-blocked');
el.scrollLeft = -x;
el.scrollTop = -y;
el.style.scrollBehavior = scrollBehavior;
});
if (scrollableParent) {
data.root.value.classList.remove('v-overlay--scroll-blocked');
}
});
}
function repositionScrollStrategy(data, props, scope) {
let slow = false;
let raf = -1;
let ric = -1;
function update(e) {
requestNewFrame(() => {
const start = performance.now();
data.updateLocation.value?.(e);
const time = performance.now() - start;
slow = time / (1000 / 60) > 2;
});
}
ric = (typeof requestIdleCallback === 'undefined' ? cb => cb() : requestIdleCallback)(() => {
scope.run(() => {
bindScroll(getTargetEl(data.target.value, data.contentEl.value), e => {
if (slow) {
// If the position calculation is slow,
// defer updates until scrolling is finished.
// Browsers usually fire one scroll event per frame so
// we just wait until we've got two frames without an event
cancelAnimationFrame(raf);
raf = requestAnimationFrame(() => {
raf = requestAnimationFrame(() => {
update(e);
});
});
} else {
update(e);
}
});
});
});
onScopeDispose(() => {
typeof cancelIdleCallback !== 'undefined' && cancelIdleCallback(ric);
cancelAnimationFrame(raf);
});
}
function getTargetEl(target, contentEl) {
return Array.isArray(target) ? document.elementsFromPoint(...target).find(el => !contentEl?.contains(el)) : target ?? contentEl;
}
function bindScroll(el, onScroll) {
const scrollElements = [document, ...getScrollParents(el)];
scrollElements.forEach(el => {
el.addEventListener('scroll', onScroll, {
passive: true
});
});
onScopeDispose(() => {
scrollElements.forEach(el => {
el.removeEventListener('scroll', onScroll);
});
});
}
//# sourceMappingURL=scrollStrategies.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,98 @@
import type { ComponentPublicInstance, PropType, Ref } from 'vue';
import type { DelayProps } from '../../composables/delay.js';
interface ActivatorProps extends DelayProps {
target: 'parent' | 'cursor' | (string & {}) | Element | ComponentPublicInstance | [x: number, y: number] | undefined;
activator: 'parent' | (string & {}) | Element | ComponentPublicInstance | undefined;
activatorProps: Record<string, any>;
openOnClick: boolean | undefined;
openOnHover: boolean;
openOnFocus: boolean | undefined;
closeOnContentClick: boolean;
}
export declare const makeActivatorProps: <Defaults extends {
closeDelay?: unknown;
openDelay?: unknown;
target?: unknown;
activator?: unknown;
activatorProps?: unknown;
openOnClick?: unknown;
openOnHover?: unknown;
openOnFocus?: unknown;
closeOnContentClick?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
closeDelay: unknown extends Defaults["closeDelay"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["closeDelay"] ? string | number : string | number | Defaults["closeDelay"]>;
default: unknown extends Defaults["closeDelay"] ? string | number : Defaults["closeDelay"] | NonNullable<string | number>;
};
openDelay: unknown extends Defaults["openDelay"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["openDelay"] ? string | number : string | number | Defaults["openDelay"]>;
default: unknown extends Defaults["openDelay"] ? string | number : Defaults["openDelay"] | NonNullable<string | number>;
};
target: unknown extends Defaults["target"] ? PropType<"cursor" | "parent" | Element | [x: number, y: number] | ComponentPublicInstance | (string & {}) | undefined> : {
type: PropType<unknown extends Defaults["target"] ? "cursor" | "parent" | Element | [x: number, y: number] | ComponentPublicInstance | (string & {}) | undefined : "cursor" | "parent" | Element | [x: number, y: number] | Defaults["target"] | ComponentPublicInstance | (string & {}) | undefined>;
default: unknown extends Defaults["target"] ? "cursor" | "parent" | Element | [x: number, y: number] | ComponentPublicInstance | (string & {}) | undefined : Defaults["target"] | NonNullable<"cursor" | "parent" | Element | [x: number, y: number] | ComponentPublicInstance | (string & {}) | undefined>;
};
activator: unknown extends Defaults["activator"] ? PropType<"parent" | Element | ComponentPublicInstance | (string & {}) | undefined> : {
type: PropType<unknown extends Defaults["activator"] ? "parent" | Element | ComponentPublicInstance | (string & {}) | undefined : "parent" | Element | Defaults["activator"] | ComponentPublicInstance | (string & {}) | undefined>;
default: unknown extends Defaults["activator"] ? "parent" | Element | ComponentPublicInstance | (string & {}) | undefined : Defaults["activator"] | NonNullable<"parent" | Element | ComponentPublicInstance | (string & {}) | undefined>;
};
activatorProps: unknown extends Defaults["activatorProps"] ? {
type: PropType<ActivatorProps['activatorProps']>;
default: () => {};
} : Omit<{
type: PropType<ActivatorProps['activatorProps']>;
default: () => {};
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["activatorProps"] ? Record<string, any> : Record<string, any> | Defaults["activatorProps"]>;
default: unknown extends Defaults["activatorProps"] ? Record<string, any> : Record<string, any> | Defaults["activatorProps"];
};
openOnClick: unknown extends Defaults["openOnClick"] ? {
type: BooleanConstructor;
default: undefined;
} : Omit<{
type: BooleanConstructor;
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["openOnClick"] ? boolean : boolean | Defaults["openOnClick"]>;
default: unknown extends Defaults["openOnClick"] ? boolean : boolean | Defaults["openOnClick"];
};
openOnHover: unknown extends Defaults["openOnHover"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["openOnHover"] ? boolean : boolean | Defaults["openOnHover"]>;
default: unknown extends Defaults["openOnHover"] ? boolean : boolean | Defaults["openOnHover"];
};
openOnFocus: unknown extends Defaults["openOnFocus"] ? {
type: BooleanConstructor;
default: undefined;
} : Omit<{
type: BooleanConstructor;
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["openOnFocus"] ? boolean : boolean | Defaults["openOnFocus"]>;
default: unknown extends Defaults["openOnFocus"] ? boolean : boolean | Defaults["openOnFocus"];
};
closeOnContentClick: unknown extends Defaults["closeOnContentClick"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["closeOnContentClick"] ? boolean : boolean | Defaults["closeOnContentClick"]>;
default: unknown extends Defaults["closeOnContentClick"] ? boolean : boolean | Defaults["closeOnContentClick"];
};
};
export declare function useActivator(props: ActivatorProps, { isActive, isTop, contentEl }: {
isActive: Ref<boolean>;
isTop: Ref<boolean>;
contentEl: Ref<HTMLElement | undefined>;
}): {
activatorEl: Ref<HTMLElement | undefined, HTMLElement | undefined>;
activatorRef: import("../../util/index.js").TemplateRef;
target: import("vue").ComputedRef<HTMLElement | [x: number, y: number] | undefined>;
targetEl: import("vue").ComputedRef<HTMLElement | undefined>;
targetRef: import("../../util/index.js").TemplateRef;
activatorEvents: import("vue").ComputedRef<Partial<{
onClick: (e: MouseEvent) => void;
onMouseenter: (e: MouseEvent) => void;
onMouseleave: (e: MouseEvent) => void;
onFocus: (e: FocusEvent) => void;
onBlur: (e: FocusEvent) => void;
}>>;
contentEvents: import("vue").ComputedRef<Record<string, EventListener>>;
scrimEvents: import("vue").ComputedRef<Record<string, EventListener>>;
};
+267
View File
@@ -0,0 +1,267 @@
// Components
import { VMenuSymbol } from "../VMenu/shared.js"; // Composables
import { makeDelayProps, useDelay } from "../../composables/delay.js"; // Utilities
import { computed, effectScope, inject, mergeProps, nextTick, onScopeDispose, ref, watch, watchEffect } from 'vue';
import { bindProps, getCurrentInstance, IN_BROWSER, matchesSelector, propsFactory, templateRef, unbindProps } from "../../util/index.js"; // Types
export const makeActivatorProps = propsFactory({
target: [String, Object],
activator: [String, Object],
activatorProps: {
type: Object,
default: () => ({})
},
openOnClick: {
type: Boolean,
default: undefined
},
openOnHover: Boolean,
openOnFocus: {
type: Boolean,
default: undefined
},
closeOnContentClick: Boolean,
...makeDelayProps()
}, 'VOverlay-activator');
export function useActivator(props, {
isActive,
isTop,
contentEl
}) {
const vm = getCurrentInstance('useActivator');
const activatorEl = ref();
let isHovered = false;
let isFocused = false;
let firstEnter = true;
const openOnFocus = computed(() => props.openOnFocus || props.openOnFocus == null && props.openOnHover);
const openOnClick = computed(() => props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value);
const {
runOpenDelay,
runCloseDelay
} = useDelay(props, value => {
if (value === (props.openOnHover && isHovered || openOnFocus.value && isFocused) && !(props.openOnHover && isActive.value && !isTop.value)) {
if (isActive.value !== value) {
firstEnter = true;
}
isActive.value = value;
}
});
const cursorTarget = ref();
const availableEvents = {
onClick: e => {
e.stopPropagation();
activatorEl.value = e.currentTarget || e.target;
if (!isActive.value) {
cursorTarget.value = [e.clientX, e.clientY];
}
isActive.value = !isActive.value;
},
onMouseenter: e => {
isHovered = true;
activatorEl.value = e.currentTarget || e.target;
runOpenDelay();
},
onMouseleave: e => {
isHovered = false;
runCloseDelay();
},
onFocus: e => {
if (matchesSelector(e.target, ':focus-visible') === false) return;
isFocused = true;
e.stopPropagation();
activatorEl.value = e.currentTarget || e.target;
runOpenDelay();
},
onBlur: e => {
isFocused = false;
e.stopPropagation();
runCloseDelay({
minDelay: 1
});
}
};
const activatorEvents = computed(() => {
const events = {};
if (openOnClick.value) {
events.onClick = availableEvents.onClick;
}
if (props.openOnHover) {
events.onMouseenter = availableEvents.onMouseenter;
events.onMouseleave = availableEvents.onMouseleave;
}
if (openOnFocus.value) {
events.onFocus = availableEvents.onFocus;
events.onBlur = availableEvents.onBlur;
}
return events;
});
const contentEvents = computed(() => {
const events = {};
if (props.openOnHover) {
events.onMouseenter = () => {
isHovered = true;
runOpenDelay();
};
events.onMouseleave = () => {
isHovered = false;
runCloseDelay();
};
}
if (openOnFocus.value) {
events.onFocusin = e => {
if (!e.target.matches(':focus-visible')) return;
isFocused = true;
runOpenDelay();
};
events.onFocusout = () => {
isFocused = false;
runCloseDelay({
minDelay: 1
});
};
}
if (props.closeOnContentClick) {
const menu = inject(VMenuSymbol, null);
events.onClick = () => {
isActive.value = false;
menu?.closeParents();
};
}
return events;
});
const scrimEvents = computed(() => {
const events = {};
if (props.openOnHover) {
events.onMouseenter = () => {
if (firstEnter) {
isHovered = true;
firstEnter = false;
runOpenDelay();
}
};
events.onMouseleave = () => {
isHovered = false;
runCloseDelay();
};
}
return events;
});
watch(isTop, val => {
if (val && (props.openOnHover && !isHovered && (!openOnFocus.value || !isFocused) || openOnFocus.value && !isFocused && (!props.openOnHover || !isHovered)) && !contentEl.value?.contains(document.activeElement)) {
runCloseDelay();
}
});
watch(isActive, val => {
if (!val) {
setTimeout(() => {
cursorTarget.value = undefined;
});
}
}, {
flush: 'post'
});
const activatorRef = templateRef();
watchEffect(() => {
if (!activatorRef.value) return;
nextTick(() => {
activatorEl.value = activatorRef.el;
});
});
const targetRef = templateRef();
const target = computed(() => {
if (props.target === 'cursor' && cursorTarget.value) return cursorTarget.value;
if (targetRef.value) return targetRef.el;
return getTarget(props.target, vm) || activatorEl.value;
});
const targetEl = computed(() => {
return Array.isArray(target.value) ? undefined : target.value;
});
let scope;
watch(() => !!props.activator, val => {
if (val && IN_BROWSER) {
scope = effectScope();
scope.run(() => {
_useActivator(props, vm, {
activatorEl,
activatorEvents
});
});
} else if (scope) {
scope.stop();
}
}, {
flush: 'post',
immediate: true
});
onScopeDispose(() => {
scope?.stop();
});
return {
activatorEl,
activatorRef,
target,
targetEl,
targetRef,
activatorEvents,
contentEvents,
scrimEvents
};
}
function _useActivator(props, vm, {
activatorEl,
activatorEvents
}) {
watch(() => props.activator, (val, oldVal) => {
if (oldVal && val !== oldVal) {
const activator = getActivator(oldVal);
activator && unbindActivatorProps(activator);
}
if (val) {
nextTick(() => bindActivatorProps());
}
}, {
immediate: true
});
watch(() => props.activatorProps, () => {
bindActivatorProps();
});
onScopeDispose(() => {
unbindActivatorProps();
});
function bindActivatorProps(el = getActivator(), _props = props.activatorProps) {
if (!el) return;
bindProps(el, mergeProps(activatorEvents.value, _props));
}
function unbindActivatorProps(el = getActivator(), _props = props.activatorProps) {
if (!el) return;
unbindProps(el, mergeProps(activatorEvents.value, _props));
}
function getActivator(selector = props.activator) {
const activator = getTarget(selector, vm);
// The activator should only be a valid element (Ignore comments and text nodes)
activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : undefined;
return activatorEl.value;
}
}
function getTarget(selector, vm) {
if (!selector) return;
let target;
if (selector === 'parent') {
let el = vm?.proxy?.$el?.parentNode;
while (el?.hasAttribute('data-no-activator')) {
el = el.parentNode;
}
target = el;
} else if (typeof selector === 'string') {
// Selector
target = document.querySelector(selector);
} else if ('$el' in selector) {
// Component (ref)
target = selector.$el;
} else {
// HTMLElement | Element | [x, y]
target = selector;
}
return target;
}
//# sourceMappingURL=useActivator.js.map
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
import type { ParsedAnchor } from '../../../util/index.js';
import type { Box } from '../../../util/box.js';
type Point = {
x: number;
y: number;
};
declare class As<T extends string> {
private as;
}
type ElementPoint = Point & As<'element'>;
type ViewportPoint = Point & As<'viewport'>;
type Offset = Point & As<'offset'>;
/** Convert a point in local space to viewport space */
export declare function elementToViewport(point: ElementPoint, offset: Offset | Box): ViewportPoint;
/** Convert a point in viewport space to local space */
export declare function viewportToElement(point: ViewportPoint, offset: Offset | Box): ElementPoint;
/** Get the difference between two points */
export declare function getOffset<T extends Point>(a: T, b: T): Offset;
/** Convert an anchor object to a point in local space */
export declare function anchorToPoint(anchor: ParsedAnchor, box: Box): ViewportPoint;
+57
View File
@@ -0,0 +1,57 @@
// Types
/** Convert a point in local space to viewport space */
export function elementToViewport(point, offset) {
return {
x: point.x + offset.x,
y: point.y + offset.y
};
}
/** Convert a point in viewport space to local space */
export function viewportToElement(point, offset) {
return {
x: point.x - offset.x,
y: point.y - offset.y
};
}
/** Get the difference between two points */
export function getOffset(a, b) {
return {
x: a.x - b.x,
y: a.y - b.y
};
}
/** Convert an anchor object to a point in local space */
export function anchorToPoint(anchor, box) {
if (anchor.side === 'top' || anchor.side === 'bottom') {
const {
side,
align
} = anchor;
const x = align === 'left' ? 0 : align === 'center' ? box.width / 2 : align === 'right' ? box.width : align;
const y = side === 'top' ? 0 : side === 'bottom' ? box.height : side;
return elementToViewport({
x,
y
}, box);
} else if (anchor.side === 'left' || anchor.side === 'right') {
const {
side,
align
} = anchor;
const x = side === 'left' ? 0 : side === 'right' ? box.width : side;
const y = align === 'top' ? 0 : align === 'center' ? box.height / 2 : align === 'bottom' ? box.height : align;
return elementToViewport({
x,
y
}, box);
}
return elementToViewport({
x: box.width / 2,
y: box.height / 2
}, box);
}
//# sourceMappingURL=point.js.map
@@ -0,0 +1 @@
{"version":3,"file":"point.js","names":["elementToViewport","point","offset","x","y","viewportToElement","getOffset","a","b","anchorToPoint","anchor","box","side","align","width","height"],"sources":["../../../../src/components/VOverlay/util/point.ts"],"sourcesContent":["// Types\nimport type { ParsedAnchor } from '@/util'\nimport type { Box } from '@/util/box'\n\ntype Point = { x: number, y: number }\ndeclare class As<T extends string> {\n private as: T\n}\ntype ElementPoint = Point & As<'element'>\ntype ViewportPoint = Point & As<'viewport'>\ntype Offset = Point & As<'offset'>\n\n/** Convert a point in local space to viewport space */\nexport function elementToViewport (point: ElementPoint, offset: Offset | Box) {\n return {\n x: point.x + offset.x,\n y: point.y + offset.y,\n } as ViewportPoint\n}\n\n/** Convert a point in viewport space to local space */\nexport function viewportToElement (point: ViewportPoint, offset: Offset | Box) {\n return {\n x: point.x - offset.x,\n y: point.y - offset.y,\n } as ElementPoint\n}\n\n/** Get the difference between two points */\nexport function getOffset<T extends Point> (a: T, b: T) {\n return {\n x: a.x - b.x,\n y: a.y - b.y,\n } as Offset\n}\n\n/** Convert an anchor object to a point in local space */\nexport function anchorToPoint (anchor: ParsedAnchor, box: Box): ViewportPoint {\n if (anchor.side === 'top' || anchor.side === 'bottom') {\n const { side, align } = anchor\n\n const x: number =\n align === 'left' ? 0\n : align === 'center' ? box.width / 2\n : align === 'right' ? box.width\n : align\n const y: number =\n side === 'top' ? 0\n : side === 'bottom' ? box.height\n : side\n\n return elementToViewport({ x, y } as ElementPoint, box)\n } else if (anchor.side === 'left' || anchor.side === 'right') {\n const { side, align } = anchor\n\n const x: number =\n side === 'left' ? 0\n : side === 'right' ? box.width\n : side\n const y: number =\n align === 'top' ? 0\n : align === 'center' ? box.height / 2\n : align === 'bottom' ? box.height\n : align\n\n return elementToViewport({ x, y } as ElementPoint, box)\n }\n\n return elementToViewport({\n x: box.width / 2,\n y: box.height / 2,\n } as ElementPoint, box)\n}\n"],"mappings":"AAAA;;AAYA;AACA,OAAO,SAASA,iBAAiBA,CAAEC,KAAmB,EAAEC,MAAoB,EAAE;EAC5E,OAAO;IACLC,CAAC,EAAEF,KAAK,CAACE,CAAC,GAAGD,MAAM,CAACC,CAAC;IACrBC,CAAC,EAAEH,KAAK,CAACG,CAAC,GAAGF,MAAM,CAACE;EACtB,CAAC;AACH;;AAEA;AACA,OAAO,SAASC,iBAAiBA,CAAEJ,KAAoB,EAAEC,MAAoB,EAAE;EAC7E,OAAO;IACLC,CAAC,EAAEF,KAAK,CAACE,CAAC,GAAGD,MAAM,CAACC,CAAC;IACrBC,CAAC,EAAEH,KAAK,CAACG,CAAC,GAAGF,MAAM,CAACE;EACtB,CAAC;AACH;;AAEA;AACA,OAAO,SAASE,SAASA,CAAmBC,CAAI,EAAEC,CAAI,EAAE;EACtD,OAAO;IACLL,CAAC,EAAEI,CAAC,CAACJ,CAAC,GAAGK,CAAC,CAACL,CAAC;IACZC,CAAC,EAAEG,CAAC,CAACH,CAAC,GAAGI,CAAC,CAACJ;EACb,CAAC;AACH;;AAEA;AACA,OAAO,SAASK,aAAaA,CAAEC,MAAoB,EAAEC,GAAQ,EAAiB;EAC5E,IAAID,MAAM,CAACE,IAAI,KAAK,KAAK,IAAIF,MAAM,CAACE,IAAI,KAAK,QAAQ,EAAE;IACrD,MAAM;MAAEA,IAAI;MAAEC;IAAM,CAAC,GAAGH,MAAM;IAE9B,MAAMP,CAAS,GACbU,KAAK,KAAK,MAAM,GAAG,CAAC,GAClBA,KAAK,KAAK,QAAQ,GAAGF,GAAG,CAACG,KAAK,GAAG,CAAC,GAClCD,KAAK,KAAK,OAAO,GAAGF,GAAG,CAACG,KAAK,GAC7BD,KAAK;IACT,MAAMT,CAAS,GACbQ,IAAI,KAAK,KAAK,GAAG,CAAC,GAChBA,IAAI,KAAK,QAAQ,GAAGD,GAAG,CAACI,MAAM,GAC9BH,IAAI;IAER,OAAOZ,iBAAiB,CAAC;MAAEG,CAAC;MAAEC;IAAE,CAAC,EAAkBO,GAAG,CAAC;EACzD,CAAC,MAAM,IAAID,MAAM,CAACE,IAAI,KAAK,MAAM,IAAIF,MAAM,CAACE,IAAI,KAAK,OAAO,EAAE;IAC5D,MAAM;MAAEA,IAAI;MAAEC;IAAM,CAAC,GAAGH,MAAM;IAE9B,MAAMP,CAAS,GACbS,IAAI,KAAK,MAAM,GAAG,CAAC,GACjBA,IAAI,KAAK,OAAO,GAAGD,GAAG,CAACG,KAAK,GAC5BF,IAAI;IACR,MAAMR,CAAS,GACbS,KAAK,KAAK,KAAK,GAAG,CAAC,GACjBA,KAAK,KAAK,QAAQ,GAAGF,GAAG,CAACI,MAAM,GAAG,CAAC,GACnCF,KAAK,KAAK,QAAQ,GAAGF,GAAG,CAACI,MAAM,GAC/BF,KAAK;IAET,OAAOb,iBAAiB,CAAC;MAAEG,CAAC;MAAEC;IAAE,CAAC,EAAkBO,GAAG,CAAC;EACzD;EAEA,OAAOX,iBAAiB,CAAC;IACvBG,CAAC,EAAEQ,GAAG,CAACG,KAAK,GAAG,CAAC;IAChBV,CAAC,EAAEO,GAAG,CAACI,MAAM,GAAG;EAClB,CAAC,EAAkBJ,GAAG,CAAC;AACzB","ignoreList":[]}