routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
import type { PropType } from 'vue';
|
||||
export interface InputAutocompleteProps {
|
||||
autocomplete: 'suppress' | string | undefined;
|
||||
name?: string;
|
||||
}
|
||||
export declare const makeAutocompleteProps: <Defaults extends {
|
||||
autocomplete?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
autocomplete: unknown extends Defaults["autocomplete"] ? PropType<string> : {
|
||||
type: PropType<unknown extends Defaults["autocomplete"] ? string : string | Defaults["autocomplete"]>;
|
||||
default: unknown extends Defaults["autocomplete"] ? string : string | Defaults["autocomplete"];
|
||||
};
|
||||
};
|
||||
export declare function useAutocomplete(props: InputAutocompleteProps): {
|
||||
isSuppressing: Readonly<import("vue").Ref<boolean, boolean>>;
|
||||
fieldAutocomplete: Readonly<import("vue").Ref<string | undefined, string | undefined>>;
|
||||
fieldName: Readonly<import("vue").Ref<string | undefined, string | undefined>>;
|
||||
update: () => number;
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Utilities
|
||||
import { shallowRef, toRef, useId } from 'vue';
|
||||
import { propsFactory } from "../util/index.js"; // Types
|
||||
// Types
|
||||
// Composables
|
||||
export const makeAutocompleteProps = propsFactory({
|
||||
autocomplete: String
|
||||
}, 'autocomplete');
|
||||
export function useAutocomplete(props) {
|
||||
const uniqueId = useId();
|
||||
const reloadTrigger = shallowRef(0);
|
||||
const isSuppressing = toRef(() => props.autocomplete === 'suppress');
|
||||
const fieldName = toRef(() => {
|
||||
if (!props.name) return undefined;
|
||||
return isSuppressing.value ? `${props.name}-${uniqueId}-${reloadTrigger.value}` : props.name;
|
||||
});
|
||||
const fieldAutocomplete = toRef(() => {
|
||||
return isSuppressing.value ? 'off' : props.autocomplete;
|
||||
});
|
||||
return {
|
||||
isSuppressing,
|
||||
fieldAutocomplete,
|
||||
fieldName,
|
||||
update: () => reloadTrigger.value = new Date().getTime()
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=autocomplete.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"autocomplete.js","names":["shallowRef","toRef","useId","propsFactory","makeAutocompleteProps","autocomplete","String","useAutocomplete","props","uniqueId","reloadTrigger","isSuppressing","fieldName","name","undefined","value","fieldAutocomplete","update","Date","getTime"],"sources":["../../src/composables/autocomplete.ts"],"sourcesContent":["// Utilities\nimport { shallowRef, toRef, useId } from 'vue'\nimport { propsFactory } from '@/util'\n\n// Types\nimport type { PropType } from 'vue'\n\n// Types\nexport interface InputAutocompleteProps {\n autocomplete: 'suppress' | string | undefined\n name?: string\n}\n\n// Composables\nexport const makeAutocompleteProps = propsFactory({\n autocomplete: String as PropType<'suppress' | string>,\n}, 'autocomplete')\n\nexport function useAutocomplete (props: InputAutocompleteProps) {\n const uniqueId = useId()\n const reloadTrigger = shallowRef(0)\n\n const isSuppressing = toRef(() => props.autocomplete === 'suppress')\n\n const fieldName = toRef(() => {\n if (!props.name) return undefined\n\n return isSuppressing.value\n ? `${props.name}-${uniqueId}-${reloadTrigger.value}`\n : props.name\n })\n\n const fieldAutocomplete = toRef(() => {\n return isSuppressing.value\n ? 'off'\n : props.autocomplete\n })\n\n return {\n isSuppressing,\n fieldAutocomplete,\n fieldName,\n update: () => reloadTrigger.value = new Date().getTime(),\n }\n}\n"],"mappings":"AAAA;AACA,SAASA,UAAU,EAAEC,KAAK,EAAEC,KAAK,QAAQ,KAAK;AAAA,SACrCC,YAAY,4BAErB;AAGA;AAMA;AACA,OAAO,MAAMC,qBAAqB,GAAGD,YAAY,CAAC;EAChDE,YAAY,EAAEC;AAChB,CAAC,EAAE,cAAc,CAAC;AAElB,OAAO,SAASC,eAAeA,CAAEC,KAA6B,EAAE;EAC9D,MAAMC,QAAQ,GAAGP,KAAK,CAAC,CAAC;EACxB,MAAMQ,aAAa,GAAGV,UAAU,CAAC,CAAC,CAAC;EAEnC,MAAMW,aAAa,GAAGV,KAAK,CAAC,MAAMO,KAAK,CAACH,YAAY,KAAK,UAAU,CAAC;EAEpE,MAAMO,SAAS,GAAGX,KAAK,CAAC,MAAM;IAC5B,IAAI,CAACO,KAAK,CAACK,IAAI,EAAE,OAAOC,SAAS;IAEjC,OAAOH,aAAa,CAACI,KAAK,GACtB,GAAGP,KAAK,CAACK,IAAI,IAAIJ,QAAQ,IAAIC,aAAa,CAACK,KAAK,EAAE,GAClDP,KAAK,CAACK,IAAI;EAChB,CAAC,CAAC;EAEF,MAAMG,iBAAiB,GAAGf,KAAK,CAAC,MAAM;IACpC,OAAOU,aAAa,CAACI,KAAK,GACtB,KAAK,GACLP,KAAK,CAACH,YAAY;EACxB,CAAC,CAAC;EAEF,OAAO;IACLM,aAAa;IACbK,iBAAiB;IACjBJ,SAAS;IACTK,MAAM,EAAEA,CAAA,KAAMP,aAAa,CAACK,KAAK,GAAG,IAAIG,IAAI,CAAC,CAAC,CAACC,OAAO,CAAC;EACzD,CAAC;AACH","ignoreList":[]}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
interface AutofocusProps {
|
||||
autofocus: boolean;
|
||||
}
|
||||
export declare function useAutofocus(props: AutofocusProps): {
|
||||
onIntersect: (isIntersecting: boolean, entries: IntersectionObserverEntry[]) => void;
|
||||
};
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
export function useAutofocus(props) {
|
||||
function onIntersect(isIntersecting, entries) {
|
||||
if (!props.autofocus || !isIntersecting) return;
|
||||
const el = entries[0].target;
|
||||
const target = el.matches('input,textarea') ? el : el.querySelector('input,textarea');
|
||||
target?.focus();
|
||||
}
|
||||
return {
|
||||
onIntersect
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=autofocus.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"autofocus.js","names":["useAutofocus","props","onIntersect","isIntersecting","entries","autofocus","el","target","matches","querySelector","focus"],"sources":["../../src/composables/autofocus.ts"],"sourcesContent":["interface AutofocusProps {\n autofocus: boolean\n}\n\nexport function useAutofocus (props: AutofocusProps) {\n function onIntersect (\n isIntersecting: boolean,\n entries: IntersectionObserverEntry[]\n ) {\n if (!props.autofocus || !isIntersecting) return\n\n const el = entries[0].target\n const target = (el.matches('input,textarea') ? el : el.querySelector('input,textarea')) as HTMLElement | null\n target?.focus()\n }\n\n return {\n onIntersect,\n }\n}\n"],"mappings":"AAIA,OAAO,SAASA,YAAYA,CAAEC,KAAqB,EAAE;EACnD,SAASC,WAAWA,CAClBC,cAAuB,EACvBC,OAAoC,EACpC;IACA,IAAI,CAACH,KAAK,CAACI,SAAS,IAAI,CAACF,cAAc,EAAE;IAEzC,MAAMG,EAAE,GAAGF,OAAO,CAAC,CAAC,CAAC,CAACG,MAAM;IAC5B,MAAMA,MAAM,GAAID,EAAE,CAACE,OAAO,CAAC,gBAAgB,CAAC,GAAGF,EAAE,GAAGA,EAAE,CAACG,aAAa,CAAC,gBAAgB,CAAwB;IAC7GF,MAAM,EAAEG,KAAK,CAAC,CAAC;EACjB;EAEA,OAAO;IACLR;EACF,CAAC;AACH","ignoreList":[]}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export interface BorderProps {
|
||||
border?: boolean | number | string;
|
||||
}
|
||||
export declare const makeBorderProps: <Defaults extends {
|
||||
border?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
border: unknown extends Defaults["border"] ? (BooleanConstructor | NumberConstructor | StringConstructor)[] : {
|
||||
type: import("vue").PropType<unknown extends Defaults["border"] ? string | number | boolean : string | number | boolean | Defaults["border"]>;
|
||||
default: unknown extends Defaults["border"] ? string | number | boolean : Defaults["border"] | NonNullable<string | number | boolean>;
|
||||
};
|
||||
};
|
||||
export declare function useBorder(props: BorderProps, name?: string): {
|
||||
borderClasses: import("vue").ComputedRef<string | string[]>;
|
||||
};
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Utilities
|
||||
import { computed } from 'vue';
|
||||
import { getCurrentInstanceName, propsFactory } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export const makeBorderProps = propsFactory({
|
||||
border: [Boolean, Number, String]
|
||||
}, 'border');
|
||||
export function useBorder(props, name = getCurrentInstanceName()) {
|
||||
const borderClasses = computed(() => {
|
||||
const border = props.border;
|
||||
if (border === true || border === '') {
|
||||
return `${name}--border`;
|
||||
} else if (typeof border === 'string' || border === 0) {
|
||||
return String(border).split(' ').map(v => `border-${v}`);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
return {
|
||||
borderClasses
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=border.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"border.js","names":["computed","getCurrentInstanceName","propsFactory","makeBorderProps","border","Boolean","Number","String","useBorder","props","name","borderClasses","split","map","v"],"sources":["../../src/composables/border.ts"],"sourcesContent":["// Utilities\nimport { computed } from 'vue'\nimport { getCurrentInstanceName, propsFactory } from '@/util'\n\n// Types\nexport interface BorderProps {\n border?: boolean | number | string\n}\n\n// Composables\nexport const makeBorderProps = propsFactory({\n border: [Boolean, Number, String],\n}, 'border')\n\nexport function useBorder (\n props: BorderProps,\n name = getCurrentInstanceName(),\n) {\n const borderClasses = computed(() => {\n const border = props.border\n\n if (border === true || border === '') {\n return `${name}--border`\n } else if (\n typeof border === 'string' ||\n border === 0\n ) {\n return String(border).split(' ').map(v => `border-${v}`)\n }\n\n return []\n })\n\n return { borderClasses }\n}\n"],"mappings":"AAAA;AACA,SAASA,QAAQ,QAAQ,KAAK;AAAA,SACrBC,sBAAsB,EAAEC,YAAY,4BAE7C;AAKA;AACA,OAAO,MAAMC,eAAe,GAAGD,YAAY,CAAC;EAC1CE,MAAM,EAAE,CAACC,OAAO,EAAEC,MAAM,EAAEC,MAAM;AAClC,CAAC,EAAE,QAAQ,CAAC;AAEZ,OAAO,SAASC,SAASA,CACvBC,KAAkB,EAClBC,IAAI,GAAGT,sBAAsB,CAAC,CAAC,EAC/B;EACA,MAAMU,aAAa,GAAGX,QAAQ,CAAC,MAAM;IACnC,MAAMI,MAAM,GAAGK,KAAK,CAACL,MAAM;IAE3B,IAAIA,MAAM,KAAK,IAAI,IAAIA,MAAM,KAAK,EAAE,EAAE;MACpC,OAAO,GAAGM,IAAI,UAAU;IAC1B,CAAC,MAAM,IACL,OAAON,MAAM,KAAK,QAAQ,IAC1BA,MAAM,KAAK,CAAC,EACZ;MACA,OAAOG,MAAM,CAACH,MAAM,CAAC,CAACQ,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CAACC,CAAC,IAAI,UAAUA,CAAC,EAAE,CAAC;IAC1D;IAEA,OAAO,EAAE;EACX,CAAC,CAAC;EAEF,OAAO;IAAEH;EAAc,CAAC;AAC1B","ignoreList":[]}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
import type { PropType } from 'vue';
|
||||
export interface CalendarProps {
|
||||
allowedDates: unknown[] | ((date: unknown) => boolean) | undefined;
|
||||
disabled: boolean;
|
||||
displayValue?: unknown;
|
||||
modelValue: unknown[] | undefined;
|
||||
max: unknown;
|
||||
min: unknown;
|
||||
showAdjacentMonths: boolean;
|
||||
month: number | string | undefined;
|
||||
weekdays: number[];
|
||||
year: number | string | undefined;
|
||||
weeksInMonth: 'dynamic' | 'static';
|
||||
firstDayOfWeek: number | string | undefined;
|
||||
firstDayOfYear: number | string | undefined;
|
||||
weekdayFormat: 'long' | 'short' | 'narrow' | undefined;
|
||||
'onUpdate:modelValue': ((value: unknown[]) => void) | undefined;
|
||||
'onUpdate:month': ((value: number) => void) | undefined;
|
||||
'onUpdate:year': ((value: number) => void) | undefined;
|
||||
}
|
||||
export type CalendarDay = {
|
||||
date: Date;
|
||||
formatted: string;
|
||||
isAdjacent: boolean;
|
||||
isDisabled: boolean;
|
||||
isEnd: boolean;
|
||||
isHidden: boolean;
|
||||
isSame: boolean;
|
||||
isSelected: boolean;
|
||||
isStart: boolean;
|
||||
isToday: boolean;
|
||||
isWeekEnd: boolean;
|
||||
isWeekStart: boolean;
|
||||
isoDate: string;
|
||||
localized: string;
|
||||
month: number;
|
||||
year: number;
|
||||
};
|
||||
export type CalendarWeekdays = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
||||
export declare const makeCalendarProps: <Defaults extends {
|
||||
allowedDates?: unknown;
|
||||
disabled?: unknown;
|
||||
displayValue?: unknown;
|
||||
modelValue?: unknown;
|
||||
month?: unknown;
|
||||
max?: unknown;
|
||||
min?: unknown;
|
||||
showAdjacentMonths?: unknown;
|
||||
year?: unknown;
|
||||
weekdays?: unknown;
|
||||
weeksInMonth?: unknown;
|
||||
firstDayOfWeek?: unknown;
|
||||
firstDayOfYear?: unknown;
|
||||
weekdayFormat?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
allowedDates: unknown extends Defaults["allowedDates"] ? PropType<unknown[] | ((date: unknown) => boolean)> : {
|
||||
type: PropType<unknown extends Defaults["allowedDates"] ? unknown[] | ((date: unknown) => boolean) : unknown[] | ((date: unknown) => boolean) | Defaults["allowedDates"]>;
|
||||
default: unknown extends Defaults["allowedDates"] ? unknown[] | ((date: unknown) => boolean) : Defaults["allowedDates"] | NonNullable<unknown[] | ((date: unknown) => boolean)>;
|
||||
};
|
||||
disabled: unknown extends Defaults["disabled"] ? {
|
||||
type: BooleanConstructor;
|
||||
default: null;
|
||||
} : Omit<{
|
||||
type: BooleanConstructor;
|
||||
default: null;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"]>;
|
||||
default: unknown extends Defaults["disabled"] ? boolean : boolean | Defaults["disabled"];
|
||||
};
|
||||
displayValue: unknown extends Defaults["displayValue"] ? PropType<unknown> : {
|
||||
type: PropType<unknown extends Defaults["displayValue"] ? unknown : unknown>;
|
||||
default: unknown extends Defaults["displayValue"] ? unknown : {} | Defaults["displayValue"];
|
||||
};
|
||||
modelValue: unknown extends Defaults["modelValue"] ? PropType<unknown[]> : {
|
||||
type: PropType<unknown extends Defaults["modelValue"] ? unknown[] : unknown[] | Defaults["modelValue"]>;
|
||||
default: unknown extends Defaults["modelValue"] ? unknown[] : unknown[] | Defaults["modelValue"];
|
||||
};
|
||||
month: unknown extends Defaults["month"] ? (NumberConstructor | StringConstructor)[] : {
|
||||
type: PropType<unknown extends Defaults["month"] ? string | number : string | number | Defaults["month"]>;
|
||||
default: unknown extends Defaults["month"] ? string | number : Defaults["month"] | NonNullable<string | number>;
|
||||
};
|
||||
max: unknown extends Defaults["max"] ? PropType<unknown> : {
|
||||
type: PropType<unknown extends Defaults["max"] ? unknown : unknown>;
|
||||
default: unknown extends Defaults["max"] ? unknown : {} | Defaults["max"];
|
||||
};
|
||||
min: unknown extends Defaults["min"] ? PropType<unknown> : {
|
||||
type: PropType<unknown extends Defaults["min"] ? unknown : unknown>;
|
||||
default: unknown extends Defaults["min"] ? unknown : {} | Defaults["min"];
|
||||
};
|
||||
showAdjacentMonths: unknown extends Defaults["showAdjacentMonths"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["showAdjacentMonths"] ? boolean : boolean | Defaults["showAdjacentMonths"]>;
|
||||
default: unknown extends Defaults["showAdjacentMonths"] ? boolean : boolean | Defaults["showAdjacentMonths"];
|
||||
};
|
||||
year: unknown extends Defaults["year"] ? (NumberConstructor | StringConstructor)[] : {
|
||||
type: PropType<unknown extends Defaults["year"] ? string | number : string | number | Defaults["year"]>;
|
||||
default: unknown extends Defaults["year"] ? string | number : Defaults["year"] | NonNullable<string | number>;
|
||||
};
|
||||
weekdays: unknown extends Defaults["weekdays"] ? {
|
||||
type: PropType<CalendarWeekdays[]>;
|
||||
default: () => number[];
|
||||
} : Omit<{
|
||||
type: PropType<CalendarWeekdays[]>;
|
||||
default: () => number[];
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["weekdays"] ? CalendarWeekdays[] : CalendarWeekdays[] | Defaults["weekdays"]>;
|
||||
default: unknown extends Defaults["weekdays"] ? CalendarWeekdays[] : CalendarWeekdays[] | Defaults["weekdays"];
|
||||
};
|
||||
weeksInMonth: unknown extends Defaults["weeksInMonth"] ? {
|
||||
type: PropType<'dynamic' | 'static'>;
|
||||
default: string;
|
||||
} : Omit<{
|
||||
type: PropType<'dynamic' | 'static'>;
|
||||
default: string;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["weeksInMonth"] ? "dynamic" | "static" : "dynamic" | "static" | Defaults["weeksInMonth"]>;
|
||||
default: unknown extends Defaults["weeksInMonth"] ? "dynamic" | "static" : Defaults["weeksInMonth"] | NonNullable<"dynamic" | "static">;
|
||||
};
|
||||
firstDayOfWeek: unknown extends Defaults["firstDayOfWeek"] ? {
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
default: undefined;
|
||||
} : Omit<{
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
default: undefined;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["firstDayOfWeek"] ? string | number : string | number | Defaults["firstDayOfWeek"]>;
|
||||
default: unknown extends Defaults["firstDayOfWeek"] ? string | number : Defaults["firstDayOfWeek"] | NonNullable<string | number>;
|
||||
};
|
||||
firstDayOfYear: unknown extends Defaults["firstDayOfYear"] ? {
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
default: undefined;
|
||||
} : Omit<{
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
default: undefined;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["firstDayOfYear"] ? string | number : string | number | Defaults["firstDayOfYear"]>;
|
||||
default: unknown extends Defaults["firstDayOfYear"] ? string | number : Defaults["firstDayOfYear"] | NonNullable<string | number>;
|
||||
};
|
||||
weekdayFormat: unknown extends Defaults["weekdayFormat"] ? PropType<"long" | "narrow" | "short" | undefined> : {
|
||||
type: PropType<unknown extends Defaults["weekdayFormat"] ? "long" | "narrow" | "short" | undefined : "long" | "narrow" | "short" | Defaults["weekdayFormat"] | undefined>;
|
||||
default: unknown extends Defaults["weekdayFormat"] ? "long" | "narrow" | "short" | undefined : Defaults["weekdayFormat"] | NonNullable<"long" | "narrow" | "short" | undefined>;
|
||||
};
|
||||
};
|
||||
export declare function useCalendar(props: CalendarProps): {
|
||||
displayValue: import("vue").ComputedRef<unknown>;
|
||||
daysInMonth: import("vue").ComputedRef<CalendarDay[]>;
|
||||
daysInWeek: import("vue").ComputedRef<CalendarDay[]>;
|
||||
genDays: (days: Date[], today: Date) => CalendarDay[];
|
||||
model: import("vue").Ref<readonly unknown[], readonly unknown[]> & {
|
||||
readonly externalValue: unknown[] | undefined;
|
||||
};
|
||||
weeksInMonth: import("vue").ComputedRef<unknown[][]>;
|
||||
weekdayLabels: import("vue").ComputedRef<string[]>;
|
||||
weekNumbers: import("vue").ComputedRef<(number | null)[]>;
|
||||
};
|
||||
export declare function useCalendarRange(props: Pick<CalendarProps, 'min' | 'max'>): {
|
||||
minDate: import("vue").ComputedRef<unknown>;
|
||||
maxDate: import("vue").ComputedRef<unknown>;
|
||||
clampDate: (date: unknown) => unknown;
|
||||
isInAllowedRange: (date: unknown) => boolean;
|
||||
};
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
// Composables
|
||||
import { useDate } from "./date/date.js";
|
||||
import { useProxiedModel } from "./proxiedModel.js"; // Utilities
|
||||
import { computed } from 'vue';
|
||||
import { propsFactory, wrapInArray } from "../util/index.js"; // Types
|
||||
// Types
|
||||
// Composables
|
||||
export const makeCalendarProps = propsFactory({
|
||||
allowedDates: [Array, Function],
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
},
|
||||
displayValue: null,
|
||||
modelValue: Array,
|
||||
month: [Number, String],
|
||||
max: null,
|
||||
min: null,
|
||||
showAdjacentMonths: Boolean,
|
||||
year: [Number, String],
|
||||
weekdays: {
|
||||
type: Array,
|
||||
default: () => [0, 1, 2, 3, 4, 5, 6]
|
||||
},
|
||||
weeksInMonth: {
|
||||
type: String,
|
||||
default: 'dynamic'
|
||||
},
|
||||
firstDayOfWeek: {
|
||||
type: [Number, String],
|
||||
default: undefined
|
||||
},
|
||||
firstDayOfYear: {
|
||||
type: [Number, String],
|
||||
default: undefined
|
||||
},
|
||||
weekdayFormat: String
|
||||
}, 'calendar');
|
||||
export function useCalendar(props) {
|
||||
const adapter = useDate();
|
||||
const model = useProxiedModel(props, 'modelValue', [], v => wrapInArray(v).map(i => adapter.date(i)));
|
||||
const displayValue = computed(() => {
|
||||
if (props.displayValue) return adapter.date(props.displayValue);
|
||||
if (model.value.length > 0) return adapter.date(model.value[0]);
|
||||
if (props.min) return adapter.date(props.min);
|
||||
if (Array.isArray(props.allowedDates)) return adapter.date(props.allowedDates[0]);
|
||||
return adapter.date();
|
||||
});
|
||||
const year = useProxiedModel(props, 'year', undefined, v => {
|
||||
const value = v != null ? Number(v) : adapter.getYear(displayValue.value);
|
||||
return adapter.startOfYear(adapter.setYear(adapter.date(), value));
|
||||
}, v => adapter.getYear(v));
|
||||
const month = useProxiedModel(props, 'month', undefined, v => {
|
||||
const value = v != null ? Number(v) : adapter.getMonth(displayValue.value);
|
||||
const date = adapter.setYear(adapter.startOfMonth(adapter.date()), adapter.getYear(year.value));
|
||||
return adapter.setMonth(date, value);
|
||||
}, v => adapter.getMonth(v));
|
||||
const weekdayLabels = computed(() => {
|
||||
const firstDayOfWeek = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
|
||||
return adapter.getWeekdays(props.firstDayOfWeek, props.weekdayFormat).filter((_, i) => props.weekdays.includes((i + firstDayOfWeek) % 7));
|
||||
});
|
||||
const weeksInMonth = computed(() => {
|
||||
const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek);
|
||||
const days = weeks.flat();
|
||||
|
||||
// Make sure there's always 6 weeks in month (6 * 7 days)
|
||||
// if weeksInMonth is 'static'
|
||||
const daysInMonth = 6 * 7;
|
||||
if (props.weeksInMonth === 'static' && days.length < daysInMonth) {
|
||||
const lastDay = days[days.length - 1];
|
||||
let week = [];
|
||||
for (let day = 1; day <= daysInMonth - days.length; day++) {
|
||||
week.push(adapter.addDays(lastDay, day));
|
||||
if (day % 7 === 0) {
|
||||
weeks.push(week);
|
||||
week = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
return weeks;
|
||||
});
|
||||
function genDays(days, today) {
|
||||
return days.filter(date => {
|
||||
return props.weekdays.includes(adapter.toJsDate(date).getDay());
|
||||
}).map((date, index) => {
|
||||
const isoDate = adapter.toISO(date);
|
||||
const isAdjacent = !adapter.isSameMonth(date, month.value);
|
||||
const isStart = adapter.isSameDay(date, adapter.startOfMonth(month.value));
|
||||
const isEnd = adapter.isSameDay(date, adapter.endOfMonth(month.value));
|
||||
const isSame = adapter.isSameDay(date, month.value);
|
||||
const weekdaysCount = props.weekdays.length;
|
||||
return {
|
||||
date,
|
||||
formatted: adapter.format(date, 'keyboardDate'),
|
||||
isAdjacent,
|
||||
isDisabled: isDisabled(date),
|
||||
isEnd,
|
||||
isHidden: isAdjacent && !props.showAdjacentMonths,
|
||||
isSame,
|
||||
isSelected: model.value.some(value => adapter.isSameDay(date, value)),
|
||||
isStart,
|
||||
isToday: adapter.isSameDay(date, today),
|
||||
isWeekEnd: index % weekdaysCount === weekdaysCount - 1,
|
||||
isWeekStart: index % weekdaysCount === 0,
|
||||
isoDate,
|
||||
localized: adapter.format(date, 'dayOfMonth'),
|
||||
month: adapter.getMonth(date),
|
||||
year: adapter.getYear(date)
|
||||
};
|
||||
});
|
||||
}
|
||||
const daysInWeek = computed(() => {
|
||||
const lastDay = adapter.startOfWeek(displayValue.value, props.firstDayOfWeek);
|
||||
const week = [];
|
||||
for (let day = 0; day <= 6; day++) {
|
||||
week.push(adapter.addDays(lastDay, day));
|
||||
}
|
||||
const today = adapter.date();
|
||||
return genDays(week, today);
|
||||
});
|
||||
const daysInMonth = computed(() => {
|
||||
const days = weeksInMonth.value.flat();
|
||||
const today = adapter.date();
|
||||
return genDays(days, today);
|
||||
});
|
||||
const weekNumbers = computed(() => {
|
||||
return weeksInMonth.value.map(week => {
|
||||
return week.length ? adapter.getWeek(week[0], props.firstDayOfWeek, props.firstDayOfYear) : null;
|
||||
});
|
||||
});
|
||||
const {
|
||||
minDate,
|
||||
maxDate
|
||||
} = useCalendarRange(props);
|
||||
function isDisabled(value) {
|
||||
if (props.disabled) return true;
|
||||
const date = adapter.date(value);
|
||||
if (minDate.value && adapter.isBefore(adapter.endOfDay(date), minDate.value)) return true;
|
||||
if (maxDate.value && adapter.isAfter(date, maxDate.value)) return true;
|
||||
if (Array.isArray(props.allowedDates) && props.allowedDates.length > 0) {
|
||||
return !props.allowedDates.some(d => adapter.isSameDay(adapter.date(d), date));
|
||||
}
|
||||
if (typeof props.allowedDates === 'function') {
|
||||
return !props.allowedDates(date);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
displayValue,
|
||||
daysInMonth,
|
||||
daysInWeek,
|
||||
genDays,
|
||||
model,
|
||||
weeksInMonth,
|
||||
weekdayLabels,
|
||||
weekNumbers
|
||||
};
|
||||
}
|
||||
export function useCalendarRange(props) {
|
||||
const adapter = useDate();
|
||||
const minDate = computed(() => {
|
||||
if (!props.min) return null;
|
||||
const date = adapter.date(props.min);
|
||||
return adapter.isValid(date) ? date : null;
|
||||
});
|
||||
const maxDate = computed(() => {
|
||||
if (!props.max) return null;
|
||||
const date = adapter.date(props.max);
|
||||
return adapter.isValid(date) ? date : null;
|
||||
});
|
||||
function clampDate(date) {
|
||||
if (minDate.value && adapter.isBefore(date, minDate.value)) {
|
||||
return minDate.value;
|
||||
}
|
||||
if (maxDate.value && adapter.isAfter(date, maxDate.value)) {
|
||||
return maxDate.value;
|
||||
}
|
||||
return date;
|
||||
}
|
||||
function isInAllowedRange(date) {
|
||||
return (!minDate.value || adapter.isAfter(date, minDate.value)) && (!maxDate.value || adapter.isBefore(date, maxDate.value));
|
||||
}
|
||||
return {
|
||||
minDate,
|
||||
maxDate,
|
||||
clampDate,
|
||||
isInAllowedRange
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=calendar.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+26
@@ -0,0 +1,26 @@
|
||||
import type { CSSProperties, MaybeRefOrGetter, Ref } from 'vue';
|
||||
export type ColorValue = string | false | null | undefined;
|
||||
export interface TextColorData {
|
||||
textColorClasses: Ref<string[]>;
|
||||
textColorStyles: Ref<CSSProperties>;
|
||||
}
|
||||
export interface BackgroundColorData {
|
||||
backgroundColorClasses: Ref<string[]>;
|
||||
backgroundColorStyles: Ref<CSSProperties>;
|
||||
}
|
||||
export declare function useColor(colors: MaybeRefOrGetter<{
|
||||
background?: ColorValue;
|
||||
text?: ColorValue;
|
||||
}>): {
|
||||
colorClasses: Readonly<Ref<string[], string[]>>;
|
||||
colorStyles: Readonly<Ref<CSSProperties, CSSProperties>>;
|
||||
};
|
||||
export declare function useTextColor(color: MaybeRefOrGetter<ColorValue>): TextColorData;
|
||||
export declare function useBackgroundColor(color: MaybeRefOrGetter<ColorValue>): BackgroundColorData;
|
||||
export declare function computeColor(colors: MaybeRefOrGetter<{
|
||||
background?: ColorValue;
|
||||
text?: ColorValue;
|
||||
}>): {
|
||||
class: string[];
|
||||
style: CSSProperties;
|
||||
};
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// Utilities
|
||||
import { toValue } from 'vue';
|
||||
import { destructComputed, hasLightForeground, isCssColor, isParsableColor, parseColor } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export function useColor(colors) {
|
||||
return destructComputed(() => {
|
||||
const {
|
||||
class: colorClasses,
|
||||
style: colorStyles
|
||||
} = computeColor(colors);
|
||||
return {
|
||||
colorClasses,
|
||||
colorStyles
|
||||
};
|
||||
});
|
||||
}
|
||||
export function useTextColor(color) {
|
||||
const {
|
||||
colorClasses: textColorClasses,
|
||||
colorStyles: textColorStyles
|
||||
} = useColor(() => ({
|
||||
text: toValue(color)
|
||||
}));
|
||||
return {
|
||||
textColorClasses,
|
||||
textColorStyles
|
||||
};
|
||||
}
|
||||
export function useBackgroundColor(color) {
|
||||
const {
|
||||
colorClasses: backgroundColorClasses,
|
||||
colorStyles: backgroundColorStyles
|
||||
} = useColor(() => ({
|
||||
background: toValue(color)
|
||||
}));
|
||||
return {
|
||||
backgroundColorClasses,
|
||||
backgroundColorStyles
|
||||
};
|
||||
}
|
||||
function normalizeColors(colors) {
|
||||
return {
|
||||
text: typeof colors.text === 'string' ? colors.text.replace(/^text-/, '') : colors.text,
|
||||
background: typeof colors.background === 'string' ? colors.background.replace(/^bg-/, '') : colors.background
|
||||
};
|
||||
}
|
||||
export function computeColor(colors) {
|
||||
const _colors = normalizeColors(toValue(colors));
|
||||
const classes = [];
|
||||
const styles = {};
|
||||
if (_colors.background) {
|
||||
if (isCssColor(_colors.background)) {
|
||||
styles.backgroundColor = _colors.background;
|
||||
if (!_colors.text && isParsableColor(_colors.background)) {
|
||||
const backgroundColor = parseColor(_colors.background);
|
||||
if (backgroundColor.a == null || backgroundColor.a === 1) {
|
||||
classes.push(hasLightForeground(backgroundColor) ? 'v-theme-on-dark' : 'v-theme-on-light');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
classes.push(`bg-${_colors.background}`);
|
||||
}
|
||||
}
|
||||
if (_colors.text) {
|
||||
if (isCssColor(_colors.text)) {
|
||||
styles.color = _colors.text;
|
||||
styles.caretColor = _colors.text;
|
||||
} else {
|
||||
classes.push(`text-${_colors.text}`);
|
||||
}
|
||||
}
|
||||
return {
|
||||
class: classes,
|
||||
style: styles
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=color.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+25
@@ -0,0 +1,25 @@
|
||||
import type { PropType, StyleValue } from 'vue';
|
||||
export type ClassValue = any;
|
||||
export interface ComponentProps {
|
||||
class: ClassValue;
|
||||
style: StyleValue | undefined;
|
||||
}
|
||||
export declare const makeComponentProps: <Defaults extends {
|
||||
class?: unknown;
|
||||
style?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
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<StyleValue>;
|
||||
default: null;
|
||||
} : Omit<{
|
||||
type: PropType<StyleValue>;
|
||||
default: null;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["style"] ? StyleValue : Defaults["style"] | StyleValue>;
|
||||
default: unknown extends Defaults["style"] ? StyleValue : Defaults["style"] | NonNullable<StyleValue>;
|
||||
};
|
||||
};
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Utilities
|
||||
import { propsFactory } from "../util/propsFactory.js"; // Types
|
||||
// TODO: import from vue once upstream PR is merged
|
||||
// https://github.com/vuejs/core/pull/14441
|
||||
// Composables
|
||||
export const makeComponentProps = propsFactory({
|
||||
class: [String, Array, Object],
|
||||
style: {
|
||||
type: [String, Array, Object],
|
||||
default: null
|
||||
}
|
||||
}, 'component');
|
||||
//# sourceMappingURL=component.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"component.js","names":["propsFactory","makeComponentProps","class","String","Array","Object","style","type","default"],"sources":["../../src/composables/component.ts"],"sourcesContent":["// Utilities\nimport { propsFactory } from '@/util/propsFactory'\n\n// Types\nimport type { PropType, StyleValue } from 'vue'\n\n// TODO: import from vue once upstream PR is merged\n// https://github.com/vuejs/core/pull/14441\nexport type ClassValue = any\n\nexport interface ComponentProps {\n class: ClassValue\n style: StyleValue | undefined\n}\n\n// Composables\nexport const makeComponentProps = propsFactory({\n class: [String, Array, Object] as PropType<ClassValue>,\n style: {\n type: [String, Array, Object] as PropType<StyleValue>,\n default: null,\n },\n}, 'component')\n"],"mappings":"AAAA;AAAA,SACSA,YAAY,mCAErB;AAGA;AACA;AAQA;AACA,OAAO,MAAMC,kBAAkB,GAAGD,YAAY,CAAC;EAC7CE,KAAK,EAAE,CAACC,MAAM,EAAEC,KAAK,EAAEC,MAAM,CAAyB;EACtDC,KAAK,EAAE;IACLC,IAAI,EAAE,CAACJ,MAAM,EAAEC,KAAK,EAAEC,MAAM,CAAyB;IACrDG,OAAO,EAAE;EACX;AACF,CAAC,EAAE,WAAW,CAAC","ignoreList":[]}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
export interface DateAdapter<T = unknown> {
|
||||
date(value?: any): T | null;
|
||||
format(date: T, formatString: string): string;
|
||||
toJsDate(value: T): Date;
|
||||
parseISO(date: string): T;
|
||||
toISO(date: T): string;
|
||||
startOfDay(date: T): T;
|
||||
endOfDay(date: T): T;
|
||||
startOfWeek(date: T, firstDayOfWeek?: number | string): T;
|
||||
endOfWeek(date: T): T;
|
||||
startOfMonth(date: T): T;
|
||||
endOfMonth(date: T): T;
|
||||
startOfYear(date: T): T;
|
||||
endOfYear(date: T): T;
|
||||
isAfter(date: T, comparing: T): boolean;
|
||||
isAfterDay(date: T, comparing: T): boolean;
|
||||
isSameDay(date: T, comparing: T): boolean;
|
||||
isSameMonth(date: T, comparing: T): boolean;
|
||||
isSameYear(date: T, comparing: T): boolean;
|
||||
isBefore(date: T, comparing: T): boolean;
|
||||
isEqual(date: T, comparing: T): boolean;
|
||||
isValid(date: any): boolean;
|
||||
isWithinRange(date: T, range: [T, T]): boolean;
|
||||
addMinutes(date: T, amount: number): T;
|
||||
addHours(date: T, amount: number): T;
|
||||
addDays(date: T, amount: number): T;
|
||||
addWeeks(date: T, amount: number): T;
|
||||
addMonths(date: T, amount: number): T;
|
||||
getYear(date: T): number;
|
||||
setYear(date: T, year: number): T;
|
||||
getDiff(date: T, comparing: T | string, unit?: string): number;
|
||||
getWeekArray(date: T, firstDayOfWeek?: number | string): T[][];
|
||||
getWeekdays(firstDayOfWeek?: number | string, weekdayFormat?: 'long' | 'short' | 'narrow'): string[];
|
||||
getWeek(date: T, firstDayOfWeek?: number | string, firstDayOfYear?: number | string): number;
|
||||
getMonth(date: T): number;
|
||||
setMonth(date: T, month: number): T;
|
||||
getDate(date: T): number;
|
||||
setDate(date: T, day: number): T;
|
||||
getNextMonth(date: T): T;
|
||||
getPreviousMonth(date: T): T;
|
||||
getHours(date: T): number;
|
||||
setHours(date: T, hours: number): T;
|
||||
getMinutes(date: T): number;
|
||||
setMinutes(date: T, minutes: number): T;
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=DateAdapter.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"DateAdapter.js","names":[],"sources":["../../../src/composables/date/DateAdapter.ts"],"sourcesContent":["export interface DateAdapter<T = unknown> {\n date (value?: any): T | null\n format (date: T, formatString: string): string\n toJsDate (value: T): Date\n parseISO (date: string): T\n toISO (date: T): string\n\n startOfDay (date: T): T\n endOfDay (date: T): T\n startOfWeek (date: T, firstDayOfWeek?: number | string): T\n endOfWeek (date: T): T\n startOfMonth (date: T): T\n endOfMonth (date: T): T\n startOfYear (date: T): T\n endOfYear (date: T): T\n\n isAfter (date: T, comparing: T): boolean\n isAfterDay(date: T, comparing: T): boolean\n\n isSameDay (date: T, comparing: T): boolean\n isSameMonth (date: T, comparing: T): boolean\n isSameYear(date: T, comparing: T): boolean\n\n isBefore (date: T, comparing: T): boolean\n isEqual (date: T, comparing: T): boolean\n isValid (date: any): boolean\n isWithinRange (date: T, range: [T, T]): boolean\n\n addMinutes (date: T, amount: number): T\n addHours (date: T, amount: number): T\n addDays (date: T, amount: number): T\n addWeeks (date: T, amount: number): T\n addMonths (date: T, amount: number): T\n\n getYear (date: T): number\n setYear (date: T, year: number): T\n getDiff (date: T, comparing: T | string, unit?: string): number\n getWeekArray (date: T, firstDayOfWeek?: number | string): T[][]\n getWeekdays (firstDayOfWeek?: number | string, weekdayFormat?: 'long' | 'short' | 'narrow'): string[]\n getWeek (date: T, firstDayOfWeek?: number | string, firstDayOfYear?: number | string): number\n getMonth (date: T): number\n setMonth (date: T, month: number): T\n getDate (date: T): number\n setDate (date: T, day: number): T\n getNextMonth (date: T): T\n getPreviousMonth(date: T): T\n\n getHours (date: T): number\n setHours (date: T, hours: number): T\n getMinutes (date: T): number\n setMinutes (date: T, minutes: number): T\n}\n"],"mappings":"","ignoreList":[]}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { VuetifyDateAdapter } from './vuetify.js';
|
||||
import type { DateAdapter } from '../index.js';
|
||||
type CustomDateFormat = Intl.DateTimeFormatOptions | ((date: string, formatString: string, locale: string) => string);
|
||||
export declare class StringDateAdapter implements DateAdapter<string> {
|
||||
base: VuetifyDateAdapter;
|
||||
constructor(options: {
|
||||
locale: string;
|
||||
formats?: Record<string, CustomDateFormat>;
|
||||
});
|
||||
addDays(date: string, amount: number): string;
|
||||
addHours(date: string, amount: number): string;
|
||||
addMinutes(date: string, amount: number): string;
|
||||
addMonths(date: string, amount: number): string;
|
||||
addWeeks(date: string, amount: number): string;
|
||||
date(value?: any): string | null;
|
||||
endOfDay(date: string): string;
|
||||
endOfMonth(date: string): string;
|
||||
endOfWeek(date: string): string;
|
||||
endOfYear(date: string): string;
|
||||
format(date: string, formatString: string): string;
|
||||
getDate(date: string): number;
|
||||
getDiff(date: string, comparing: string, unit?: string): number;
|
||||
getHours(date: string): number;
|
||||
getMinutes(date: string): number;
|
||||
getMonth(date: string): number;
|
||||
getWeek(date: string, firstDayOfWeek?: number | string, firstDayOfYear?: number | string): number;
|
||||
getNextMonth(date: string): string;
|
||||
getPreviousMonth(date: string): string;
|
||||
getWeekArray(date: string, firstDayOfWeek?: number | string): string[][];
|
||||
getWeekdays(firstDayOfWeek?: number | string, weekdayFormat?: 'long' | 'short' | 'narrow'): string[];
|
||||
getYear(date: string): number;
|
||||
isAfter(date: string, comparing: string): boolean;
|
||||
isAfterDay(date: string, comparing: string): boolean;
|
||||
isBefore(date: string, comparing: string): boolean;
|
||||
isEqual(date: string, comparing: string): boolean;
|
||||
isSameDay(date: string, comparing: string): boolean;
|
||||
isSameMonth(date: string, comparing: string): boolean;
|
||||
isSameYear(date: string, comparing: string): boolean;
|
||||
isValid(date: any): boolean;
|
||||
isWithinRange(date: string, range: [string, string]): boolean;
|
||||
parseISO(date: string): string;
|
||||
setDate(date: string, day: number): string;
|
||||
setHours(date: string, hours: number): string;
|
||||
setMinutes(date: string, minutes: number): string;
|
||||
setMonth(date: string, month: number): string;
|
||||
setYear(date: string, year: number): string;
|
||||
startOfDay(date: string): string;
|
||||
startOfMonth(date: string): string;
|
||||
startOfWeek(date: string, firstDayOfWeek?: number | string): string;
|
||||
startOfYear(date: string): string;
|
||||
toISO(date: string): string;
|
||||
toJsDate(value: string): Date;
|
||||
}
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
// Composables
|
||||
import { VuetifyDateAdapter } from "./vuetify.js"; // Types
|
||||
export class StringDateAdapter {
|
||||
constructor(options) {
|
||||
this.base = new VuetifyDateAdapter({
|
||||
locale: options.locale,
|
||||
formats: options.formats && Object.fromEntries(Object.entries(options.formats).map(([k, v]) => {
|
||||
return [k, typeof v === 'function' ? (date, ...args) => v(this.base.toISO(date), ...args) : v];
|
||||
}))
|
||||
});
|
||||
}
|
||||
addDays(date, amount) {
|
||||
return this.base.toISO(this.base.addDays(this.base.date(date), amount));
|
||||
}
|
||||
addHours(date, amount) {
|
||||
return this.base.toISO(this.base.addHours(this.base.date(date), amount));
|
||||
}
|
||||
addMinutes(date, amount) {
|
||||
return this.base.toISO(this.base.addMinutes(this.base.date(date), amount));
|
||||
}
|
||||
addMonths(date, amount) {
|
||||
return this.base.toISO(this.base.addMonths(this.base.date(date), amount));
|
||||
}
|
||||
addWeeks(date, amount) {
|
||||
return this.base.toISO(this.base.addWeeks(this.base.date(date), amount));
|
||||
}
|
||||
date(value) {
|
||||
return this.base.toISO(this.base.date(value));
|
||||
}
|
||||
endOfDay(date) {
|
||||
return this.base.toISO(this.base.endOfDay(this.base.date(date)));
|
||||
}
|
||||
endOfMonth(date) {
|
||||
return this.base.toISO(this.base.endOfMonth(this.base.date(date)));
|
||||
}
|
||||
endOfWeek(date) {
|
||||
return this.base.toISO(this.base.endOfWeek(this.base.date(date)));
|
||||
}
|
||||
endOfYear(date) {
|
||||
return this.base.toISO(this.base.endOfYear(this.base.date(date)));
|
||||
}
|
||||
format(date, formatString) {
|
||||
return this.base.format(this.base.date(date), formatString);
|
||||
}
|
||||
getDate(date) {
|
||||
return this.base.getDate(this.base.date(date));
|
||||
}
|
||||
getDiff(date, comparing, unit) {
|
||||
return this.base.getDiff(this.base.date(date), comparing, unit);
|
||||
}
|
||||
getHours(date) {
|
||||
return this.base.getHours(this.base.date(date));
|
||||
}
|
||||
getMinutes(date) {
|
||||
return this.base.getMinutes(this.base.date(date));
|
||||
}
|
||||
getMonth(date) {
|
||||
return this.base.getMonth(this.base.date(date));
|
||||
}
|
||||
getWeek(date, firstDayOfWeek, firstDayOfYear) {
|
||||
return this.base.getWeek(this.base.date(date), firstDayOfWeek, firstDayOfYear);
|
||||
}
|
||||
getNextMonth(date) {
|
||||
return this.base.toISO(this.base.getNextMonth(this.base.date(date)));
|
||||
}
|
||||
getPreviousMonth(date) {
|
||||
return this.base.toISO(this.base.getPreviousMonth(this.base.date(date)));
|
||||
}
|
||||
getWeekArray(date, firstDayOfWeek) {
|
||||
return this.base.getWeekArray(this.base.date(date), firstDayOfWeek).map(week => {
|
||||
return week.map(day => {
|
||||
return this.base.toISO(day);
|
||||
});
|
||||
});
|
||||
}
|
||||
getWeekdays(firstDayOfWeek, weekdayFormat) {
|
||||
return this.base.getWeekdays(firstDayOfWeek, weekdayFormat);
|
||||
}
|
||||
getYear(date) {
|
||||
return this.base.getYear(this.base.date(date));
|
||||
}
|
||||
isAfter(date, comparing) {
|
||||
return this.base.isAfter(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isAfterDay(date, comparing) {
|
||||
return this.base.isAfterDay(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isBefore(date, comparing) {
|
||||
return this.base.isBefore(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isEqual(date, comparing) {
|
||||
return this.base.isEqual(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isSameDay(date, comparing) {
|
||||
return this.base.isSameDay(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isSameMonth(date, comparing) {
|
||||
return this.base.isSameMonth(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isSameYear(date, comparing) {
|
||||
return this.base.isSameYear(this.base.date(date), this.base.date(comparing));
|
||||
}
|
||||
isValid(date) {
|
||||
return this.base.isValid(date);
|
||||
}
|
||||
isWithinRange(date, range) {
|
||||
return this.base.isWithinRange(this.base.date(date), [this.base.date(range[0]), this.base.date(range[1])]);
|
||||
}
|
||||
parseISO(date) {
|
||||
return this.base.toISO(this.base.parseISO(date));
|
||||
}
|
||||
setDate(date, day) {
|
||||
return this.base.toISO(this.base.setDate(this.base.date(date), day));
|
||||
}
|
||||
setHours(date, hours) {
|
||||
return this.base.toISO(this.base.setHours(this.base.date(date), hours));
|
||||
}
|
||||
setMinutes(date, minutes) {
|
||||
return this.base.toISO(this.base.setMinutes(this.base.date(date), minutes));
|
||||
}
|
||||
setMonth(date, month) {
|
||||
return this.base.toISO(this.base.setMonth(this.base.date(date), month));
|
||||
}
|
||||
setYear(date, year) {
|
||||
return this.base.toISO(this.base.setYear(this.base.date(date), year));
|
||||
}
|
||||
startOfDay(date) {
|
||||
return this.base.toISO(this.base.startOfDay(this.base.date(date)));
|
||||
}
|
||||
startOfMonth(date) {
|
||||
return this.base.toISO(this.base.startOfMonth(this.base.date(date)));
|
||||
}
|
||||
startOfWeek(date, firstDayOfWeek) {
|
||||
return this.base.toISO(this.base.startOfWeek(this.base.date(date), firstDayOfWeek));
|
||||
}
|
||||
startOfYear(date) {
|
||||
return this.base.toISO(this.base.startOfYear(this.base.date(date)));
|
||||
}
|
||||
toISO(date) {
|
||||
return this.base.toISO(this.base.date(date));
|
||||
}
|
||||
toJsDate(value) {
|
||||
return this.base.date(value);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=string.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+54
@@ -0,0 +1,54 @@
|
||||
import type { DateAdapter } from '../DateAdapter.js';
|
||||
type CustomDateFormat = Intl.DateTimeFormatOptions | ((date: Date, formatString: string, locale: string) => string);
|
||||
export declare class VuetifyDateAdapter implements DateAdapter<Date> {
|
||||
locale: string;
|
||||
formats?: Record<string, CustomDateFormat>;
|
||||
constructor(options: {
|
||||
locale: string;
|
||||
formats?: Record<string, CustomDateFormat>;
|
||||
});
|
||||
date(value?: any): Date | null;
|
||||
toJsDate(date: Date): Date;
|
||||
toISO(date: Date): string;
|
||||
parseISO(date: string): Date;
|
||||
addMinutes(date: Date, amount: number): Date;
|
||||
addHours(date: Date, amount: number): Date;
|
||||
addDays(date: Date, amount: number): Date;
|
||||
addWeeks(date: Date, amount: number): Date;
|
||||
addMonths(date: Date, amount: number): Date;
|
||||
getWeekArray(date: Date, firstDayOfWeek?: number | string): Date[][];
|
||||
startOfWeek(date: Date, firstDayOfWeek?: number | string): Date;
|
||||
endOfWeek(date: Date): Date;
|
||||
startOfMonth(date: Date): Date;
|
||||
endOfMonth(date: Date): Date;
|
||||
format(date: Date, formatString: string): string;
|
||||
isEqual(date: Date, comparing: Date): boolean;
|
||||
isValid(date: any): boolean;
|
||||
isWithinRange(date: Date, range: [Date, Date]): boolean;
|
||||
isAfter(date: Date, comparing: Date): boolean;
|
||||
isAfterDay(date: Date, comparing: Date): boolean;
|
||||
isBefore(date: Date, comparing: Date): boolean;
|
||||
isSameDay(date: Date, comparing: Date): boolean;
|
||||
isSameMonth(date: Date, comparing: Date): boolean;
|
||||
isSameYear(date: Date, comparing: Date): boolean;
|
||||
setMinutes(date: Date, count: number): Date;
|
||||
setHours(date: Date, count: number): Date;
|
||||
setMonth(date: Date, count: number): Date;
|
||||
setDate(date: Date, day: number): Date;
|
||||
setYear(date: Date, year: number): Date;
|
||||
getDiff(date: Date, comparing: Date | string, unit?: string): number;
|
||||
getWeekdays(firstDayOfWeek?: number | string, weekdayFormat?: 'long' | 'short' | 'narrow'): string[];
|
||||
getYear(date: Date): number;
|
||||
getMonth(date: Date): number;
|
||||
getWeek(date: Date, firstDayOfWeek?: number | string, firstDayOfYear?: number | string): number;
|
||||
getDate(date: Date): number;
|
||||
getNextMonth(date: Date): Date;
|
||||
getPreviousMonth(date: Date): Date;
|
||||
getHours(date: Date): number;
|
||||
getMinutes(date: Date): number;
|
||||
startOfDay(date: Date): Date;
|
||||
endOfDay(date: Date): Date;
|
||||
startOfYear(date: Date): Date;
|
||||
endOfYear(date: Date): Date;
|
||||
}
|
||||
|
||||
+690
@@ -0,0 +1,690 @@
|
||||
// Utilities
|
||||
import { consoleWarn, createRange, padStart } from "../../../util/index.js"; // Types
|
||||
function weekInfo(locale) {
|
||||
// https://simplelocalize.io/data/locales/
|
||||
// then `new Intl.Locale(...).getWeekInfo()`
|
||||
const code = locale.slice(-2).toUpperCase();
|
||||
switch (true) {
|
||||
case locale === 'GB-alt-variant':
|
||||
{
|
||||
return {
|
||||
firstDay: 0,
|
||||
firstWeekSize: 4
|
||||
};
|
||||
}
|
||||
case locale === '001':
|
||||
{
|
||||
return {
|
||||
firstDay: 1,
|
||||
firstWeekSize: 1
|
||||
};
|
||||
}
|
||||
case `AG AS BD BR BS BT BW BZ CA CO DM DO ET GT GU HK HN ID IL IN JM JP KE
|
||||
KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PY SA SG SV TH TT TW UM US
|
||||
VE VI WS YE ZA ZW`.includes(code):
|
||||
{
|
||||
return {
|
||||
firstDay: 0,
|
||||
firstWeekSize: 1
|
||||
};
|
||||
}
|
||||
case `AI AL AM AR AU AZ BA BM BN BY CL CM CN CR CY EC GE HR KG KZ LB LK LV
|
||||
MD ME MK MN MY NZ RO RS SI TJ TM TR UA UY UZ VN XK`.includes(code):
|
||||
{
|
||||
return {
|
||||
firstDay: 1,
|
||||
firstWeekSize: 1
|
||||
};
|
||||
}
|
||||
case `AD AN AT AX BE BG CH CZ DE DK EE ES FI FJ FO FR GB GF GP GR HU IE IS
|
||||
IT LI LT LU MC MQ NL NO PL RE RU SE SK SM VA`.includes(code):
|
||||
{
|
||||
return {
|
||||
firstDay: 1,
|
||||
firstWeekSize: 4
|
||||
};
|
||||
}
|
||||
case `AE AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY`.includes(code):
|
||||
{
|
||||
return {
|
||||
firstDay: 6,
|
||||
firstWeekSize: 1
|
||||
};
|
||||
}
|
||||
case code === 'MV':
|
||||
{
|
||||
return {
|
||||
firstDay: 5,
|
||||
firstWeekSize: 1
|
||||
};
|
||||
}
|
||||
case code === 'PT':
|
||||
{
|
||||
return {
|
||||
firstDay: 0,
|
||||
firstWeekSize: 4
|
||||
};
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function getWeekArray(date, locale, firstDayOfWeek) {
|
||||
const weeks = [];
|
||||
let currentWeek = [];
|
||||
const firstDayOfMonth = startOfMonth(date);
|
||||
const lastDayOfMonth = endOfMonth(date);
|
||||
const first = firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0;
|
||||
const firstDayWeekIndex = (firstDayOfMonth.getDay() - first + 7) % 7;
|
||||
const lastDayWeekIndex = (lastDayOfMonth.getDay() - first + 7) % 7;
|
||||
for (let i = 0; i < firstDayWeekIndex; i++) {
|
||||
const adjacentDay = new Date(firstDayOfMonth);
|
||||
adjacentDay.setDate(adjacentDay.getDate() - (firstDayWeekIndex - i));
|
||||
currentWeek.push(adjacentDay);
|
||||
}
|
||||
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
|
||||
const day = new Date(date.getFullYear(), date.getMonth(), i);
|
||||
|
||||
// Add the day to the current week
|
||||
currentWeek.push(day);
|
||||
|
||||
// If the current week has 7 days, add it to the weeks array and start a new week
|
||||
if (currentWeek.length === 7) {
|
||||
weeks.push(currentWeek);
|
||||
currentWeek = [];
|
||||
}
|
||||
}
|
||||
for (let i = 1; i < 7 - lastDayWeekIndex; i++) {
|
||||
const adjacentDay = new Date(lastDayOfMonth);
|
||||
adjacentDay.setDate(adjacentDay.getDate() + i);
|
||||
currentWeek.push(adjacentDay);
|
||||
}
|
||||
if (currentWeek.length > 0) {
|
||||
weeks.push(currentWeek);
|
||||
}
|
||||
return weeks;
|
||||
}
|
||||
function startOfWeek(date, locale, firstDayOfWeek) {
|
||||
let day = (firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0) % 7;
|
||||
|
||||
// prevent infinite loop
|
||||
if (![0, 1, 2, 3, 4, 5, 6].includes(day)) {
|
||||
consoleWarn('Invalid firstDayOfWeek, expected discrete number in range [0-6]');
|
||||
day = 0;
|
||||
}
|
||||
const d = new Date(date);
|
||||
while (d.getDay() !== day) {
|
||||
d.setDate(d.getDate() - 1);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
function endOfWeek(date, locale) {
|
||||
const d = new Date(date);
|
||||
const lastDay = ((weekInfo(locale)?.firstDay ?? 0) + 6) % 7;
|
||||
while (d.getDay() !== lastDay) {
|
||||
d.setDate(d.getDate() + 1);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
function startOfMonth(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), 1);
|
||||
}
|
||||
function endOfMonth(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
||||
}
|
||||
function parseLocalDate(value) {
|
||||
const parts = value.split('-').map(Number);
|
||||
|
||||
// new Date() uses local time zone when passing individual date component values
|
||||
return new Date(parts[0], parts[1] - 1, parts[2]);
|
||||
}
|
||||
const _YYYMMDD = /^([12]\d{3}-([1-9]|0[1-9]|1[0-2])-([1-9]|0[1-9]|[12]\d|3[01]))$/;
|
||||
function date(value) {
|
||||
if (value == null) return new Date();
|
||||
if (value instanceof Date) return value;
|
||||
if (typeof value === 'string') {
|
||||
let parsed;
|
||||
if (_YYYMMDD.test(value)) {
|
||||
return parseLocalDate(value);
|
||||
} else {
|
||||
parsed = Date.parse(value);
|
||||
}
|
||||
if (!isNaN(parsed)) return new Date(parsed);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const sundayJanuarySecond2000 = new Date(2000, 0, 2);
|
||||
function getWeekdays(locale, firstDayOfWeek, weekdayFormat) {
|
||||
const daysFromSunday = firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0;
|
||||
return createRange(7).map(i => {
|
||||
const weekday = new Date(sundayJanuarySecond2000);
|
||||
weekday.setDate(sundayJanuarySecond2000.getDate() + daysFromSunday + i);
|
||||
return new Intl.DateTimeFormat(locale, {
|
||||
weekday: weekdayFormat ?? 'narrow'
|
||||
}).format(weekday);
|
||||
});
|
||||
}
|
||||
function format(value, formatString, locale, formats) {
|
||||
const newDate = date(value) ?? new Date();
|
||||
const customFormat = formats?.[formatString];
|
||||
if (typeof customFormat === 'function') {
|
||||
return customFormat(newDate, formatString, locale);
|
||||
}
|
||||
let options = {};
|
||||
switch (formatString) {
|
||||
case 'fullDate':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'fullDateWithWeekday':
|
||||
options = {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'normalDate':
|
||||
const day = newDate.getDate();
|
||||
const month = new Intl.DateTimeFormat(locale, {
|
||||
month: 'long'
|
||||
}).format(newDate);
|
||||
return `${day} ${month}`;
|
||||
case 'normalDateWithWeekday':
|
||||
options = {
|
||||
weekday: 'short',
|
||||
day: 'numeric',
|
||||
month: 'short'
|
||||
};
|
||||
break;
|
||||
case 'shortDate':
|
||||
options = {
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'year':
|
||||
options = {
|
||||
year: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'month':
|
||||
options = {
|
||||
month: 'long'
|
||||
};
|
||||
break;
|
||||
case 'monthShort':
|
||||
options = {
|
||||
month: 'short'
|
||||
};
|
||||
break;
|
||||
case 'monthAndYear':
|
||||
options = {
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'monthAndDate':
|
||||
options = {
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'weekday':
|
||||
options = {
|
||||
weekday: 'long'
|
||||
};
|
||||
break;
|
||||
case 'weekdayShort':
|
||||
options = {
|
||||
weekday: 'short'
|
||||
};
|
||||
break;
|
||||
case 'dayOfMonth':
|
||||
return new Intl.NumberFormat(locale).format(newDate.getDate());
|
||||
case 'hours12h':
|
||||
options = {
|
||||
hour: 'numeric',
|
||||
hour12: true
|
||||
};
|
||||
break;
|
||||
case 'hours24h':
|
||||
options = {
|
||||
hour: 'numeric',
|
||||
hour12: false
|
||||
};
|
||||
break;
|
||||
case 'minutes':
|
||||
options = {
|
||||
minute: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'seconds':
|
||||
options = {
|
||||
second: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'fullTime':
|
||||
options = {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'fullTime12h':
|
||||
options = {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true
|
||||
};
|
||||
break;
|
||||
case 'fullTime24h':
|
||||
options = {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: false
|
||||
};
|
||||
break;
|
||||
case 'fullDateTime':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
};
|
||||
break;
|
||||
case 'fullDateTime12h':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true
|
||||
};
|
||||
break;
|
||||
case 'fullDateTime24h':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: false
|
||||
};
|
||||
break;
|
||||
case 'keyboardDate':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
};
|
||||
break;
|
||||
case 'keyboardDateTime':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
};
|
||||
return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
|
||||
case 'keyboardDateTime12h':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true
|
||||
};
|
||||
return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
|
||||
case 'keyboardDateTime24h':
|
||||
options = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: false
|
||||
};
|
||||
return new Intl.DateTimeFormat(locale, options).format(newDate).replace(/, /g, ' ');
|
||||
default:
|
||||
options = customFormat ?? {
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
}
|
||||
return new Intl.DateTimeFormat(locale, options).format(newDate);
|
||||
}
|
||||
function toISO(adapter, value) {
|
||||
const date = adapter.toJsDate(value);
|
||||
const year = date.getFullYear();
|
||||
const month = padStart(String(date.getMonth() + 1), 2, '0');
|
||||
const day = padStart(String(date.getDate()), 2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
function parseISO(value) {
|
||||
const [year, month, day] = value.split('-').map(Number);
|
||||
return new Date(year, month - 1, day);
|
||||
}
|
||||
function addMinutes(date, amount) {
|
||||
const d = new Date(date);
|
||||
d.setMinutes(d.getMinutes() + amount);
|
||||
return d;
|
||||
}
|
||||
function addHours(date, amount) {
|
||||
const d = new Date(date);
|
||||
d.setHours(d.getHours() + amount);
|
||||
return d;
|
||||
}
|
||||
function addDays(date, amount) {
|
||||
const d = new Date(date);
|
||||
d.setDate(d.getDate() + amount);
|
||||
return d;
|
||||
}
|
||||
function addWeeks(date, amount) {
|
||||
const d = new Date(date);
|
||||
d.setDate(d.getDate() + amount * 7);
|
||||
return d;
|
||||
}
|
||||
function addMonths(date, amount) {
|
||||
const d = new Date(date);
|
||||
d.setDate(1);
|
||||
d.setMonth(d.getMonth() + amount);
|
||||
return d;
|
||||
}
|
||||
function getYear(date) {
|
||||
return date.getFullYear();
|
||||
}
|
||||
function getMonth(date) {
|
||||
return date.getMonth();
|
||||
}
|
||||
function getWeek(date, locale, firstDayOfWeek, firstDayOfYear) {
|
||||
const weekInfoFromLocale = weekInfo(locale);
|
||||
const weekStart = firstDayOfWeek ?? weekInfoFromLocale?.firstDay ?? 0;
|
||||
const minWeekSize = weekInfoFromLocale?.firstWeekSize ?? 1;
|
||||
return firstDayOfYear !== undefined ? calculateWeekWithFirstDayOfYear(date, locale, weekStart, firstDayOfYear) : calculateWeekWithMinWeekSize(date, locale, weekStart, minWeekSize);
|
||||
}
|
||||
function calculateWeekWithFirstDayOfYear(date, locale, weekStart, firstDayOfYear) {
|
||||
const firstDayOfYearOffset = (7 + firstDayOfYear - weekStart) % 7;
|
||||
const currentWeekStart = startOfWeek(date, locale, weekStart);
|
||||
const currentWeekEnd = addDays(currentWeekStart, 6);
|
||||
function yearStartWeekdayOffset(year) {
|
||||
return (7 + new Date(year, 0, 1).getDay() - weekStart) % 7;
|
||||
}
|
||||
let year = getYear(currentWeekStart);
|
||||
if (year < getYear(currentWeekEnd) && yearStartWeekdayOffset(year + 1) <= firstDayOfYearOffset) {
|
||||
year++;
|
||||
}
|
||||
const yearStart = new Date(year, 0, 1);
|
||||
const offset = yearStartWeekdayOffset(year);
|
||||
const d1w1 = offset <= firstDayOfYearOffset ? addDays(yearStart, -offset) : addDays(yearStart, 7 - offset);
|
||||
return 1 + getDiff(endOfDay(currentWeekStart), startOfDay(d1w1), 'weeks');
|
||||
}
|
||||
function calculateWeekWithMinWeekSize(date, locale, weekStart, minWeekSize) {
|
||||
const currentWeekStart = startOfWeek(date, locale, weekStart);
|
||||
const currentWeekEnd = addDays(startOfWeek(date, locale, weekStart), 6);
|
||||
function firstWeekSize(year) {
|
||||
const yearStart = new Date(year, 0, 1);
|
||||
return 7 - getDiff(yearStart, startOfWeek(yearStart, locale, weekStart), 'days');
|
||||
}
|
||||
let year = getYear(currentWeekStart);
|
||||
if (year < getYear(currentWeekEnd) && firstWeekSize(year + 1) >= minWeekSize) {
|
||||
year++;
|
||||
}
|
||||
const yearStart = new Date(year, 0, 1);
|
||||
const size = firstWeekSize(year);
|
||||
const d1w1 = size >= minWeekSize ? addDays(yearStart, size - 7) : addDays(yearStart, size);
|
||||
return 1 + getDiff(endOfDay(currentWeekStart), startOfDay(d1w1), 'weeks');
|
||||
}
|
||||
function getDate(date) {
|
||||
return date.getDate();
|
||||
}
|
||||
function getNextMonth(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth() + 1, 1);
|
||||
}
|
||||
function getPreviousMonth(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth() - 1, 1);
|
||||
}
|
||||
function getHours(date) {
|
||||
return date.getHours();
|
||||
}
|
||||
function getMinutes(date) {
|
||||
return date.getMinutes();
|
||||
}
|
||||
function startOfYear(date) {
|
||||
return new Date(date.getFullYear(), 0, 1);
|
||||
}
|
||||
function endOfYear(date) {
|
||||
return new Date(date.getFullYear(), 11, 31);
|
||||
}
|
||||
function isWithinRange(date, range) {
|
||||
return isEqual(date, range[0]) || isEqual(date, range[1]) || isAfter(date, range[0]) && isBefore(date, range[1]);
|
||||
}
|
||||
function isValid(date) {
|
||||
const d = new Date(date);
|
||||
return d instanceof Date && !isNaN(d.getTime());
|
||||
}
|
||||
function isAfter(date, comparing) {
|
||||
return date.getTime() > comparing.getTime();
|
||||
}
|
||||
function isAfterDay(date, comparing) {
|
||||
return isAfter(startOfDay(date), startOfDay(comparing));
|
||||
}
|
||||
function isBefore(date, comparing) {
|
||||
return date.getTime() < comparing.getTime();
|
||||
}
|
||||
function isEqual(date, comparing) {
|
||||
return date.getTime() === comparing.getTime();
|
||||
}
|
||||
function isSameDay(date, comparing) {
|
||||
return date.getDate() === comparing.getDate() && date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
|
||||
}
|
||||
function isSameMonth(date, comparing) {
|
||||
return date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
|
||||
}
|
||||
function isSameYear(date, comparing) {
|
||||
return date.getFullYear() === comparing.getFullYear();
|
||||
}
|
||||
function getDiff(date, comparing, unit) {
|
||||
const d = new Date(date);
|
||||
const c = new Date(comparing);
|
||||
switch (unit) {
|
||||
case 'years':
|
||||
return d.getFullYear() - c.getFullYear();
|
||||
case 'quarters':
|
||||
return Math.floor((d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12) / 4);
|
||||
case 'months':
|
||||
return d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12;
|
||||
case 'weeks':
|
||||
return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24 * 7));
|
||||
case 'days':
|
||||
return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24));
|
||||
case 'hours':
|
||||
return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60));
|
||||
case 'minutes':
|
||||
return Math.floor((d.getTime() - c.getTime()) / (1000 * 60));
|
||||
case 'seconds':
|
||||
return Math.floor((d.getTime() - c.getTime()) / 1000);
|
||||
default:
|
||||
{
|
||||
return d.getTime() - c.getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
function setHours(date, count) {
|
||||
const d = new Date(date);
|
||||
d.setHours(count);
|
||||
return d;
|
||||
}
|
||||
function setMinutes(date, count) {
|
||||
const d = new Date(date);
|
||||
d.setMinutes(count);
|
||||
return d;
|
||||
}
|
||||
function setMonth(date, count) {
|
||||
const d = new Date(date);
|
||||
d.setMonth(count);
|
||||
return d;
|
||||
}
|
||||
function setDate(date, day) {
|
||||
const d = new Date(date);
|
||||
d.setDate(day);
|
||||
return d;
|
||||
}
|
||||
function setYear(date, year) {
|
||||
const d = new Date(date);
|
||||
d.setFullYear(year);
|
||||
return d;
|
||||
}
|
||||
function startOfDay(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
|
||||
}
|
||||
function endOfDay(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
|
||||
}
|
||||
export class VuetifyDateAdapter {
|
||||
constructor(options) {
|
||||
this.locale = options.locale;
|
||||
this.formats = options.formats;
|
||||
}
|
||||
date(value) {
|
||||
return date(value);
|
||||
}
|
||||
toJsDate(date) {
|
||||
return date;
|
||||
}
|
||||
toISO(date) {
|
||||
return toISO(this, date);
|
||||
}
|
||||
parseISO(date) {
|
||||
return parseISO(date);
|
||||
}
|
||||
addMinutes(date, amount) {
|
||||
return addMinutes(date, amount);
|
||||
}
|
||||
addHours(date, amount) {
|
||||
return addHours(date, amount);
|
||||
}
|
||||
addDays(date, amount) {
|
||||
return addDays(date, amount);
|
||||
}
|
||||
addWeeks(date, amount) {
|
||||
return addWeeks(date, amount);
|
||||
}
|
||||
addMonths(date, amount) {
|
||||
return addMonths(date, amount);
|
||||
}
|
||||
getWeekArray(date, firstDayOfWeek) {
|
||||
const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
|
||||
return getWeekArray(date, this.locale, firstDay);
|
||||
}
|
||||
startOfWeek(date, firstDayOfWeek) {
|
||||
const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
|
||||
return startOfWeek(date, this.locale, firstDay);
|
||||
}
|
||||
endOfWeek(date) {
|
||||
return endOfWeek(date, this.locale);
|
||||
}
|
||||
startOfMonth(date) {
|
||||
return startOfMonth(date);
|
||||
}
|
||||
endOfMonth(date) {
|
||||
return endOfMonth(date);
|
||||
}
|
||||
format(date, formatString) {
|
||||
return format(date, formatString, this.locale, this.formats);
|
||||
}
|
||||
isEqual(date, comparing) {
|
||||
return isEqual(date, comparing);
|
||||
}
|
||||
isValid(date) {
|
||||
return isValid(date);
|
||||
}
|
||||
isWithinRange(date, range) {
|
||||
return isWithinRange(date, range);
|
||||
}
|
||||
isAfter(date, comparing) {
|
||||
return isAfter(date, comparing);
|
||||
}
|
||||
isAfterDay(date, comparing) {
|
||||
return isAfterDay(date, comparing);
|
||||
}
|
||||
isBefore(date, comparing) {
|
||||
return !isAfter(date, comparing) && !isEqual(date, comparing);
|
||||
}
|
||||
isSameDay(date, comparing) {
|
||||
return isSameDay(date, comparing);
|
||||
}
|
||||
isSameMonth(date, comparing) {
|
||||
return isSameMonth(date, comparing);
|
||||
}
|
||||
isSameYear(date, comparing) {
|
||||
return isSameYear(date, comparing);
|
||||
}
|
||||
setMinutes(date, count) {
|
||||
return setMinutes(date, count);
|
||||
}
|
||||
setHours(date, count) {
|
||||
return setHours(date, count);
|
||||
}
|
||||
setMonth(date, count) {
|
||||
return setMonth(date, count);
|
||||
}
|
||||
setDate(date, day) {
|
||||
return setDate(date, day);
|
||||
}
|
||||
setYear(date, year) {
|
||||
return setYear(date, year);
|
||||
}
|
||||
getDiff(date, comparing, unit) {
|
||||
return getDiff(date, comparing, unit);
|
||||
}
|
||||
getWeekdays(firstDayOfWeek, weekdayFormat) {
|
||||
const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
|
||||
return getWeekdays(this.locale, firstDay, weekdayFormat);
|
||||
}
|
||||
getYear(date) {
|
||||
return getYear(date);
|
||||
}
|
||||
getMonth(date) {
|
||||
return getMonth(date);
|
||||
}
|
||||
getWeek(date, firstDayOfWeek, firstDayOfYear) {
|
||||
const firstDay = firstDayOfWeek !== undefined ? Number(firstDayOfWeek) : undefined;
|
||||
const firstWeekStart = firstDayOfYear !== undefined ? Number(firstDayOfYear) : undefined;
|
||||
return getWeek(date, this.locale, firstDay, firstWeekStart);
|
||||
}
|
||||
getDate(date) {
|
||||
return getDate(date);
|
||||
}
|
||||
getNextMonth(date) {
|
||||
return getNextMonth(date);
|
||||
}
|
||||
getPreviousMonth(date) {
|
||||
return getPreviousMonth(date);
|
||||
}
|
||||
getHours(date) {
|
||||
return getHours(date);
|
||||
}
|
||||
getMinutes(date) {
|
||||
return getMinutes(date);
|
||||
}
|
||||
startOfDay(date) {
|
||||
return startOfDay(date);
|
||||
}
|
||||
endOfDay(date) {
|
||||
return endOfDay(date);
|
||||
}
|
||||
startOfYear(date) {
|
||||
return startOfYear(date);
|
||||
}
|
||||
endOfYear(date) {
|
||||
return endOfYear(date);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=vuetify.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+76
@@ -0,0 +1,76 @@
|
||||
import type { InjectionKey } from 'vue';
|
||||
import type { DateAdapter } from './DateAdapter.js';
|
||||
import type { LocaleInstance } from '../locale.js';
|
||||
export interface DateInstance extends DateModule.InternalAdapter {
|
||||
locale?: any;
|
||||
}
|
||||
/** Supports module augmentation to specify date adapter types */
|
||||
export declare namespace DateModule {
|
||||
interface Adapter {
|
||||
}
|
||||
export type InternalAdapter = {} extends Adapter ? DateAdapter : Adapter;
|
||||
|
||||
}
|
||||
export type InternalDateOptions = {
|
||||
adapter: (new (options: {
|
||||
locale: any;
|
||||
formats?: any;
|
||||
}) => DateInstance) | DateInstance;
|
||||
formats?: Record<string, any>;
|
||||
locale: Record<string, any>;
|
||||
};
|
||||
export type DateOptions = Partial<InternalDateOptions>;
|
||||
export declare const DateOptionsSymbol: InjectionKey<InternalDateOptions>;
|
||||
export declare const DateAdapterSymbol: InjectionKey<DateInstance>;
|
||||
export declare function createDate(options: DateOptions | undefined, locale: LocaleInstance): {
|
||||
options: InternalDateOptions;
|
||||
instance: {
|
||||
date: (value?: any) => unknown;
|
||||
format: (date: unknown, formatString: string) => string;
|
||||
toJsDate: (value: unknown) => Date;
|
||||
parseISO: (date: string) => unknown;
|
||||
toISO: (date: unknown) => string;
|
||||
startOfDay: (date: unknown) => unknown;
|
||||
endOfDay: (date: unknown) => unknown;
|
||||
startOfWeek: (date: unknown, firstDayOfWeek?: number | string) => unknown;
|
||||
endOfWeek: (date: unknown) => unknown;
|
||||
startOfMonth: (date: unknown) => unknown;
|
||||
endOfMonth: (date: unknown) => unknown;
|
||||
startOfYear: (date: unknown) => unknown;
|
||||
endOfYear: (date: unknown) => unknown;
|
||||
isAfter: (date: unknown, comparing: unknown) => boolean;
|
||||
isAfterDay: (date: unknown, comparing: unknown) => boolean;
|
||||
isSameDay: (date: unknown, comparing: unknown) => boolean;
|
||||
isSameMonth: (date: unknown, comparing: unknown) => boolean;
|
||||
isSameYear: (date: unknown, comparing: unknown) => boolean;
|
||||
isBefore: (date: unknown, comparing: unknown) => boolean;
|
||||
isEqual: (date: unknown, comparing: unknown) => boolean;
|
||||
isValid: (date: any) => boolean;
|
||||
isWithinRange: (date: unknown, range: [unknown, unknown]) => boolean;
|
||||
addMinutes: (date: unknown, amount: number) => unknown;
|
||||
addHours: (date: unknown, amount: number) => unknown;
|
||||
addDays: (date: unknown, amount: number) => unknown;
|
||||
addWeeks: (date: unknown, amount: number) => unknown;
|
||||
addMonths: (date: unknown, amount: number) => unknown;
|
||||
getYear: (date: unknown) => number;
|
||||
setYear: (date: unknown, year: number) => unknown;
|
||||
getDiff: (date: unknown, comparing: unknown, unit?: string) => number;
|
||||
getWeekArray: (date: unknown, firstDayOfWeek?: number | string) => unknown[][];
|
||||
getWeekdays: (firstDayOfWeek?: number | string, weekdayFormat?: 'long' | 'short' | 'narrow') => string[];
|
||||
getWeek: (date: unknown, firstDayOfWeek?: number | string, firstDayOfYear?: number | string) => number;
|
||||
getMonth: (date: unknown) => number;
|
||||
setMonth: (date: unknown, month: number) => unknown;
|
||||
getDate: (date: unknown) => number;
|
||||
setDate: (date: unknown, day: number) => unknown;
|
||||
getNextMonth: (date: unknown) => unknown;
|
||||
getPreviousMonth: (date: unknown) => unknown;
|
||||
getHours: (date: unknown) => number;
|
||||
setHours: (date: unknown, hours: number) => unknown;
|
||||
getMinutes: (date: unknown) => number;
|
||||
setMinutes: (date: unknown, minutes: number) => unknown;
|
||||
locale?: any;
|
||||
};
|
||||
};
|
||||
export declare function createDateRange(adapter: DateInstance, start: unknown, stop?: unknown): unknown[];
|
||||
export declare function daysDiff(adapter: DateInstance, start: unknown, stop?: unknown): number;
|
||||
export declare function useDate(): DateInstance;
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Composables
|
||||
import { useLocale } from "../locale.js"; // Utilities
|
||||
import { inject, reactive, watch } from 'vue';
|
||||
import { mergeDeep } from "../../util/index.js"; // Types
|
||||
// Adapters
|
||||
import { VuetifyDateAdapter } from "./adapters/vuetify.js";
|
||||
/** Supports module augmentation to specify date adapter types */
|
||||
export let DateModule;
|
||||
export const DateOptionsSymbol = Symbol.for('vuetify:date-options');
|
||||
export const DateAdapterSymbol = Symbol.for('vuetify:date-adapter');
|
||||
export function createDate(options, locale) {
|
||||
const _options = mergeDeep({
|
||||
adapter: VuetifyDateAdapter,
|
||||
locale: {
|
||||
af: 'af-ZA',
|
||||
// ar: '', # not the same value for all variants
|
||||
bg: 'bg-BG',
|
||||
ca: 'ca-ES',
|
||||
ckb: '',
|
||||
cs: 'cs-CZ',
|
||||
de: 'de-DE',
|
||||
el: 'el-GR',
|
||||
en: 'en-US',
|
||||
// es: '', # not the same value for all variants
|
||||
et: 'et-EE',
|
||||
fa: 'fa-IR',
|
||||
fi: 'fi-FI',
|
||||
// fr: '', #not the same value for all variants
|
||||
hr: 'hr-HR',
|
||||
hu: 'hu-HU',
|
||||
he: 'he-IL',
|
||||
id: 'id-ID',
|
||||
it: 'it-IT',
|
||||
ja: 'ja-JP',
|
||||
ko: 'ko-KR',
|
||||
lv: 'lv-LV',
|
||||
lt: 'lt-LT',
|
||||
nl: 'nl-NL',
|
||||
no: 'no-NO',
|
||||
pl: 'pl-PL',
|
||||
pt: 'pt-PT',
|
||||
ro: 'ro-RO',
|
||||
ru: 'ru-RU',
|
||||
sk: 'sk-SK',
|
||||
sl: 'sl-SI',
|
||||
srCyrl: 'sr-SP',
|
||||
srLatn: 'sr-SP',
|
||||
sv: 'sv-SE',
|
||||
th: 'th-TH',
|
||||
tr: 'tr-TR',
|
||||
az: 'az-AZ',
|
||||
uk: 'uk-UA',
|
||||
vi: 'vi-VN',
|
||||
zhHans: 'zh-CN',
|
||||
zhHant: 'zh-TW'
|
||||
}
|
||||
}, options);
|
||||
return {
|
||||
options: _options,
|
||||
instance: createInstance(_options, locale)
|
||||
};
|
||||
}
|
||||
export function createDateRange(adapter, start, stop) {
|
||||
const diff = daysDiff(adapter, start, stop);
|
||||
const datesInRange = [start];
|
||||
for (let i = 1; i < diff; i++) {
|
||||
const nextDate = adapter.addDays(start, i);
|
||||
datesInRange.push(nextDate);
|
||||
}
|
||||
if (stop) {
|
||||
datesInRange.push(adapter.endOfDay(stop));
|
||||
}
|
||||
return datesInRange;
|
||||
}
|
||||
export function daysDiff(adapter, start, stop) {
|
||||
const iso = [`${adapter.toISO(stop ?? start).split('T')[0]}T00:00:00Z`, `${adapter.toISO(start).split('T')[0]}T00:00:00Z`];
|
||||
return typeof adapter.date() === 'string' ? adapter.getDiff(iso[0], iso[1], 'days') // for StringDateAdapter
|
||||
: adapter.getDiff(adapter.date(iso[0]), adapter.date(iso[1]), 'days');
|
||||
}
|
||||
function createInstance(options, locale) {
|
||||
const instance = reactive(typeof options.adapter === 'function'
|
||||
// eslint-disable-next-line new-cap
|
||||
? new options.adapter({
|
||||
locale: options.locale[locale.current.value] ?? locale.current.value,
|
||||
formats: options.formats
|
||||
}) : options.adapter);
|
||||
watch(locale.current, value => {
|
||||
instance.locale = options.locale[value] ?? value ?? instance.locale;
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
export function useDate() {
|
||||
const options = inject(DateOptionsSymbol);
|
||||
if (!options) throw new Error('[Vuetify] Could not find injected date options');
|
||||
const locale = useLocale();
|
||||
return createInstance(options, locale);
|
||||
}
|
||||
//# sourceMappingURL=date.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+4
@@ -0,0 +1,4 @@
|
||||
export { createDate, useDate, DateAdapterSymbol } from './date.js';
|
||||
export type { DateAdapter } from './DateAdapter.js';
|
||||
export type { DateOptions, DateInstance, DateModule } from './date.js';
|
||||
export { VuetifyDateAdapter } from './adapters/vuetify.js';
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { createDate, useDate, DateAdapterSymbol } from "./date.js";
|
||||
export { VuetifyDateAdapter } from "./adapters/vuetify.js";
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","names":["createDate","useDate","DateAdapterSymbol","VuetifyDateAdapter"],"sources":["../../../src/composables/date/index.ts"],"sourcesContent":["export { createDate, useDate, DateAdapterSymbol } from './date'\nexport type { DateAdapter } from './DateAdapter'\nexport type { DateOptions, DateInstance, DateModule } from './date'\nexport { VuetifyDateAdapter } from './adapters/vuetify'\n"],"mappings":"SAASA,UAAU,EAAEC,OAAO,EAAEC,iBAAiB;AAAA,SAGtCC,kBAAkB","ignoreList":[]}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import type { Ref } from 'vue';
|
||||
export interface DateFormatProps {
|
||||
inputFormat?: string;
|
||||
}
|
||||
export declare const makeDateFormatProps: <Defaults extends {
|
||||
inputFormat?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
inputFormat: unknown extends Defaults["inputFormat"] ? {
|
||||
type: StringConstructor;
|
||||
validator: (v: string) => boolean;
|
||||
} : Omit<{
|
||||
type: StringConstructor;
|
||||
validator: (v: string) => boolean;
|
||||
}, "default" | "type"> & {
|
||||
type: import("vue").PropType<unknown extends Defaults["inputFormat"] ? string : string | Defaults["inputFormat"]>;
|
||||
default: unknown extends Defaults["inputFormat"] ? string : string | Defaults["inputFormat"];
|
||||
};
|
||||
};
|
||||
export declare function useDateFormat(props: DateFormatProps, locale: Ref<string>): {
|
||||
isValid: (text: string) => boolean;
|
||||
parseDate: (dateString: string) => unknown;
|
||||
formatDate: (value: unknown) => string;
|
||||
parserFormat: Readonly<Ref<string, string>>;
|
||||
};
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// Composables
|
||||
import { useDate } from "./date/date.js"; // Utilities
|
||||
import { toRef } from 'vue';
|
||||
import { consoleWarn, propsFactory } from "../util/index.js"; // Types
|
||||
// Types
|
||||
class DateFormatSpec {
|
||||
constructor(order,
|
||||
// mdy | dmy | ymd
|
||||
separator // / | - | .
|
||||
) {
|
||||
this.order = order;
|
||||
this.separator = separator;
|
||||
}
|
||||
get format() {
|
||||
return this.order.split('').map(sign => `${sign}${sign}`).join(this.separator).replace('yy', 'yyyy');
|
||||
}
|
||||
static canBeParsed(v) {
|
||||
if (typeof v !== 'string') return false;
|
||||
const lowercase = v.toLowerCase();
|
||||
return ['y', 'm', 'd'].every(sign => lowercase.includes(sign)) && ['/', '-', '.'].some(sign => v.includes(sign));
|
||||
}
|
||||
static parse(v) {
|
||||
if (!DateFormatSpec.canBeParsed(v)) {
|
||||
throw new Error(`[${v}] cannot be parsed into date format specification`);
|
||||
}
|
||||
const order = v.toLowerCase().split('').filter((c, i, all) => 'dmy'.includes(c) && all.indexOf(c) === i).join('');
|
||||
const separator = ['/', '-', '.'].find(sign => v.includes(sign));
|
||||
return new DateFormatSpec(order, separator);
|
||||
}
|
||||
}
|
||||
export const makeDateFormatProps = propsFactory({
|
||||
inputFormat: {
|
||||
type: String,
|
||||
validator: v => !v || DateFormatSpec.canBeParsed(v)
|
||||
}
|
||||
}, 'date-format');
|
||||
export function useDateFormat(props, locale) {
|
||||
const adapter = useDate();
|
||||
function inferFromLocale() {
|
||||
const localeForDateFormat = locale.value ?? 'en-US';
|
||||
const formatFromLocale = Intl.DateTimeFormat(localeForDateFormat, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}).format(adapter.toJsDate(adapter.parseISO('1999-12-07'))).replace(/(07)|(٠٧)|(٢٩)|(۱۶)|(০৭)/, 'dd').replace(/(12)|(١٢)|(٠٨)|(۰۹)|(১২)/, 'mm').replace(/(1999)|(2542)|(١٩٩٩)|(١٤٢٠)|(۱۳۷۸)|(১৯৯৯)/, 'yyyy').replace(/[^ymd\-/.]/g, '').replace(/\.$/, '');
|
||||
if (!DateFormatSpec.canBeParsed(formatFromLocale)) {
|
||||
consoleWarn(`Date format inferred from locale [${localeForDateFormat}] is invalid: [${formatFromLocale}]`);
|
||||
return 'mm/dd/yyyy';
|
||||
}
|
||||
return formatFromLocale;
|
||||
}
|
||||
const currentFormat = toRef(() => {
|
||||
return DateFormatSpec.canBeParsed(props.inputFormat) ? DateFormatSpec.parse(props.inputFormat) : DateFormatSpec.parse(inferFromLocale());
|
||||
});
|
||||
function parseDate(dateString) {
|
||||
function parseDateParts(text) {
|
||||
const parts = text.trim().split(currentFormat.value.separator);
|
||||
return {
|
||||
y: Number(parts[currentFormat.value.order.indexOf('y')]),
|
||||
m: Number(parts[currentFormat.value.order.indexOf('m')]),
|
||||
d: Number(parts[currentFormat.value.order.indexOf('d')])
|
||||
};
|
||||
}
|
||||
function validateDateParts(dateParts) {
|
||||
const {
|
||||
y: year,
|
||||
m: month,
|
||||
d: day
|
||||
} = dateParts;
|
||||
if (!year || !month || !day) return null;
|
||||
if (month < 1 || month > 12) return null;
|
||||
if (day < 1 || day > 31) return null;
|
||||
return {
|
||||
year: autoFixYear(year),
|
||||
month,
|
||||
day
|
||||
};
|
||||
}
|
||||
function autoFixYear(year) {
|
||||
const currentYear = adapter.getYear(adapter.date());
|
||||
if (year > 100 || currentYear % 100 >= 50) {
|
||||
return year;
|
||||
}
|
||||
const currentCentury = ~~(currentYear / 100) * 100;
|
||||
return year < 50 ? currentCentury + year : currentCentury - 100 + year;
|
||||
}
|
||||
const dateParts = parseDateParts(dateString);
|
||||
const validatedParts = validateDateParts(dateParts);
|
||||
if (!validatedParts) return null;
|
||||
const {
|
||||
year,
|
||||
month,
|
||||
day
|
||||
} = validatedParts;
|
||||
const pad = v => String(v).padStart(2, '0');
|
||||
return adapter.parseISO(`${year}-${pad(month)}-${pad(day)}`);
|
||||
}
|
||||
function isValid(text) {
|
||||
return !!parseDate(text);
|
||||
}
|
||||
function formatDate(value) {
|
||||
const parts = adapter.toISO(value).split('T')[0].split('-');
|
||||
return currentFormat.value.order.split('').map(sign => parts['ymd'.indexOf(sign)]).join(currentFormat.value.separator);
|
||||
}
|
||||
return {
|
||||
isValid,
|
||||
parseDate,
|
||||
formatDate,
|
||||
parserFormat: toRef(() => currentFormat.value.format)
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=dateFormat.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+22
@@ -0,0 +1,22 @@
|
||||
import type { ComputedRef, InjectionKey, Ref } from 'vue';
|
||||
import type { MaybeRef } from '../util/index.js';
|
||||
export type DefaultsInstance = undefined | {
|
||||
[key: string]: undefined | Record<string, unknown>;
|
||||
global?: Record<string, unknown>;
|
||||
};
|
||||
export type DefaultsOptions = Partial<DefaultsInstance>;
|
||||
export declare const DefaultsSymbol: InjectionKey<Ref<DefaultsInstance>>;
|
||||
export declare function createDefaults(options?: DefaultsInstance): Ref<DefaultsInstance>;
|
||||
export declare function injectDefaults(): Ref<DefaultsInstance, DefaultsInstance>;
|
||||
export declare function provideDefaults(defaults?: MaybeRef<DefaultsInstance | undefined>, options?: {
|
||||
disabled?: MaybeRef<boolean | undefined>;
|
||||
reset?: MaybeRef<number | string | undefined>;
|
||||
root?: MaybeRef<boolean | string | undefined>;
|
||||
scoped?: MaybeRef<boolean | undefined>;
|
||||
}): ComputedRef<DefaultsInstance>;
|
||||
export declare function internalUseDefaults(props?: Record<string, any>, name?: string, defaults?: Ref<DefaultsInstance, DefaultsInstance>): {
|
||||
props: Record<string, any>;
|
||||
provideSubDefaults: () => void;
|
||||
};
|
||||
export declare function useDefaults<T extends Record<string, any>>(props: T, name?: string): T;
|
||||
export declare function useDefaults(props?: undefined, name?: string): Record<string, any>;
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
// Utilities
|
||||
import { computed, inject, provide, ref, shallowRef, unref, watchEffect } from 'vue';
|
||||
import { getCurrentInstance } from "../util/getCurrentInstance.js";
|
||||
import { mergeDeep, toKebabCase } from "../util/helpers.js";
|
||||
import { injectSelf } from "../util/injectSelf.js"; // Types
|
||||
export const DefaultsSymbol = Symbol.for('vuetify:defaults');
|
||||
export function createDefaults(options) {
|
||||
return ref(options);
|
||||
}
|
||||
export function injectDefaults() {
|
||||
const defaults = inject(DefaultsSymbol);
|
||||
if (!defaults) throw new Error('[Vuetify] Could not find defaults instance');
|
||||
return defaults;
|
||||
}
|
||||
export function provideDefaults(defaults, options) {
|
||||
const injectedDefaults = injectDefaults();
|
||||
const providedDefaults = ref(defaults);
|
||||
const newDefaults = computed(() => {
|
||||
const disabled = unref(options?.disabled);
|
||||
if (disabled) return injectedDefaults.value;
|
||||
const scoped = unref(options?.scoped);
|
||||
const reset = unref(options?.reset);
|
||||
const root = unref(options?.root);
|
||||
if (providedDefaults.value == null && !(scoped || reset || root)) return injectedDefaults.value;
|
||||
let properties = mergeDeep(providedDefaults.value, {
|
||||
prev: injectedDefaults.value
|
||||
});
|
||||
if (scoped) return properties;
|
||||
if (reset || root) {
|
||||
const len = Number(reset || Infinity);
|
||||
for (let i = 0; i <= len; i++) {
|
||||
if (!properties || !('prev' in properties)) {
|
||||
break;
|
||||
}
|
||||
properties = properties.prev;
|
||||
}
|
||||
if (properties && typeof root === 'string' && root in properties) {
|
||||
properties = mergeDeep(mergeDeep(properties, {
|
||||
prev: properties
|
||||
}), properties[root]);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
return properties.prev ? mergeDeep(properties.prev, properties, undefined, (_, v) => v !== undefined) : properties;
|
||||
});
|
||||
provide(DefaultsSymbol, newDefaults);
|
||||
return newDefaults;
|
||||
}
|
||||
function propIsDefined(vnode, prop) {
|
||||
return vnode.props && (typeof vnode.props[prop] !== 'undefined' || typeof vnode.props[toKebabCase(prop)] !== 'undefined');
|
||||
}
|
||||
export function internalUseDefaults(props = {}, name, defaults = injectDefaults()) {
|
||||
const vm = getCurrentInstance('useDefaults');
|
||||
name = name ?? vm.type.name ?? vm.type.__name;
|
||||
if (!name) {
|
||||
throw new Error('[Vuetify] Could not determine component name');
|
||||
}
|
||||
const componentDefaults = computed(() => defaults.value?.[props._as ?? name]);
|
||||
const _props = new Proxy(props, {
|
||||
get(target, prop) {
|
||||
const propValue = Reflect.get(target, prop);
|
||||
if (prop === 'class' || prop === 'style') {
|
||||
return [componentDefaults.value?.[prop], propValue].filter(v => v != null);
|
||||
}
|
||||
if (propIsDefined(vm.vnode, prop)) return propValue;
|
||||
const _componentDefault = componentDefaults.value?.[prop];
|
||||
if (_componentDefault !== undefined) return _componentDefault;
|
||||
const _globalDefault = defaults.value?.global?.[prop];
|
||||
if (_globalDefault !== undefined) return _globalDefault;
|
||||
return propValue;
|
||||
}
|
||||
});
|
||||
const _subcomponentDefaults = shallowRef();
|
||||
watchEffect(() => {
|
||||
if (componentDefaults.value) {
|
||||
const subComponents = Object.entries(componentDefaults.value).filter(([key]) => key.startsWith(key[0].toUpperCase()));
|
||||
_subcomponentDefaults.value = subComponents.length ? Object.fromEntries(subComponents) : undefined;
|
||||
} else {
|
||||
_subcomponentDefaults.value = undefined;
|
||||
}
|
||||
});
|
||||
function provideSubDefaults() {
|
||||
const injected = injectSelf(DefaultsSymbol, vm);
|
||||
provide(DefaultsSymbol, computed(() => {
|
||||
return _subcomponentDefaults.value ? mergeDeep(injected?.value ?? {}, _subcomponentDefaults.value) : injected?.value;
|
||||
}));
|
||||
}
|
||||
return {
|
||||
props: _props,
|
||||
provideSubDefaults
|
||||
};
|
||||
}
|
||||
export function useDefaults(props = {}, name) {
|
||||
const {
|
||||
props: _props,
|
||||
provideSubDefaults
|
||||
} = internalUseDefaults(props, name);
|
||||
provideSubDefaults();
|
||||
return _props;
|
||||
}
|
||||
//# sourceMappingURL=defaults.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
||||
export interface DelayProps {
|
||||
closeDelay?: number | string;
|
||||
openDelay?: number | string;
|
||||
}
|
||||
export declare const makeDelayProps: <Defaults extends {
|
||||
closeDelay?: unknown;
|
||||
openDelay?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
closeDelay: unknown extends Defaults["closeDelay"] ? (NumberConstructor | StringConstructor)[] : {
|
||||
type: import("vue").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: import("vue").PropType<unknown extends Defaults["openDelay"] ? string | number : string | number | Defaults["openDelay"]>;
|
||||
default: unknown extends Defaults["openDelay"] ? string | number : Defaults["openDelay"] | NonNullable<string | number>;
|
||||
};
|
||||
};
|
||||
export declare function useDelay(props: DelayProps, cb?: (value: boolean) => void): {
|
||||
clearDelay: () => void;
|
||||
runOpenDelay: () => Promise<unknown>;
|
||||
runCloseDelay: (options?: {
|
||||
minDelay: number;
|
||||
}) => Promise<unknown>;
|
||||
};
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Utilities
|
||||
import { defer, propsFactory } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export const makeDelayProps = propsFactory({
|
||||
closeDelay: [Number, String],
|
||||
openDelay: [Number, String]
|
||||
}, 'delay');
|
||||
export function useDelay(props, cb) {
|
||||
let clearDelay = () => {};
|
||||
function runDelay(isOpening, options) {
|
||||
clearDelay?.();
|
||||
const delay = isOpening ? props.openDelay : props.closeDelay;
|
||||
const normalizedDelay = Math.max(options?.minDelay ?? 0, Number(delay ?? 0));
|
||||
return new Promise(resolve => {
|
||||
clearDelay = defer(normalizedDelay, () => {
|
||||
cb?.(isOpening);
|
||||
resolve(isOpening);
|
||||
});
|
||||
});
|
||||
}
|
||||
function runOpenDelay() {
|
||||
return runDelay(true);
|
||||
}
|
||||
function runCloseDelay(options) {
|
||||
return runDelay(false, options);
|
||||
}
|
||||
return {
|
||||
clearDelay,
|
||||
runOpenDelay,
|
||||
runCloseDelay
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=delay.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"delay.js","names":["defer","propsFactory","makeDelayProps","closeDelay","Number","String","openDelay","useDelay","props","cb","clearDelay","runDelay","isOpening","options","delay","normalizedDelay","Math","max","minDelay","Promise","resolve","runOpenDelay","runCloseDelay"],"sources":["../../src/composables/delay.ts"],"sourcesContent":["// Utilities\nimport { defer, propsFactory } from '@/util'\n\n// Types\nexport interface DelayProps {\n closeDelay?: number | string\n openDelay?: number | string\n}\n\n// Composables\nexport const makeDelayProps = propsFactory({\n closeDelay: [Number, String],\n openDelay: [Number, String],\n}, 'delay')\n\nexport function useDelay (props: DelayProps, cb?: (value: boolean) => void) {\n let clearDelay: (() => void) = () => {}\n\n function runDelay (isOpening: boolean, options?: { minDelay: number }) {\n clearDelay?.()\n\n const delay = isOpening ? props.openDelay : props.closeDelay\n\n const normalizedDelay = Math.max(\n options?.minDelay ?? 0,\n Number(delay ?? 0)\n )\n\n return new Promise(resolve => {\n clearDelay = defer(normalizedDelay, () => {\n cb?.(isOpening)\n resolve(isOpening)\n })\n })\n }\n\n function runOpenDelay () {\n return runDelay(true)\n }\n\n function runCloseDelay (options?: { minDelay: number }) {\n return runDelay(false, options)\n }\n\n return {\n clearDelay,\n runOpenDelay,\n runCloseDelay,\n }\n}\n"],"mappings":"AAAA;AAAA,SACSA,KAAK,EAAEC,YAAY,4BAE5B;AAMA;AACA,OAAO,MAAMC,cAAc,GAAGD,YAAY,CAAC;EACzCE,UAAU,EAAE,CAACC,MAAM,EAAEC,MAAM,CAAC;EAC5BC,SAAS,EAAE,CAACF,MAAM,EAAEC,MAAM;AAC5B,CAAC,EAAE,OAAO,CAAC;AAEX,OAAO,SAASE,QAAQA,CAAEC,KAAiB,EAAEC,EAA6B,EAAE;EAC1E,IAAIC,UAAwB,GAAGA,CAAA,KAAM,CAAC,CAAC;EAEvC,SAASC,QAAQA,CAAEC,SAAkB,EAAEC,OAA8B,EAAE;IACrEH,UAAU,GAAG,CAAC;IAEd,MAAMI,KAAK,GAAGF,SAAS,GAAGJ,KAAK,CAACF,SAAS,GAAGE,KAAK,CAACL,UAAU;IAE5D,MAAMY,eAAe,GAAGC,IAAI,CAACC,GAAG,CAC9BJ,OAAO,EAAEK,QAAQ,IAAI,CAAC,EACtBd,MAAM,CAACU,KAAK,IAAI,CAAC,CACnB,CAAC;IAED,OAAO,IAAIK,OAAO,CAACC,OAAO,IAAI;MAC5BV,UAAU,GAAGV,KAAK,CAACe,eAAe,EAAE,MAAM;QACxCN,EAAE,GAAGG,SAAS,CAAC;QACfQ,OAAO,CAACR,SAAS,CAAC;MACpB,CAAC,CAAC;IACJ,CAAC,CAAC;EACJ;EAEA,SAASS,YAAYA,CAAA,EAAI;IACvB,OAAOV,QAAQ,CAAC,IAAI,CAAC;EACvB;EAEA,SAASW,aAAaA,CAAET,OAA8B,EAAE;IACtD,OAAOF,QAAQ,CAAC,KAAK,EAAEE,OAAO,CAAC;EACjC;EAEA,OAAO;IACLH,UAAU;IACVW,YAAY;IACZC;EACF,CAAC;AACH","ignoreList":[]}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import type { PropType } from 'vue';
|
||||
export type Density = null | 'default' | 'comfortable' | 'compact';
|
||||
export interface DensityProps {
|
||||
density?: Density;
|
||||
}
|
||||
export declare const makeDensityProps: <Defaults extends {
|
||||
density?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
density: unknown extends Defaults["density"] ? {
|
||||
type: PropType<Density>;
|
||||
default: string;
|
||||
validator: (v: any) => boolean;
|
||||
} : Omit<{
|
||||
type: PropType<Density>;
|
||||
default: string;
|
||||
validator: (v: any) => boolean;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["density"] ? Density : Defaults["density"] | Density>;
|
||||
default: unknown extends Defaults["density"] ? Density : Defaults["density"] | NonNullable<Density>;
|
||||
};
|
||||
};
|
||||
export declare function useDensity(props: DensityProps, name?: string): {
|
||||
densityClasses: Readonly<import("vue").Ref<string, string>>;
|
||||
};
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Utilities
|
||||
import { toRef } from 'vue';
|
||||
import { getCurrentInstanceName, propsFactory } from "../util/index.js"; // Types
|
||||
const allowedDensities = [null, 'default', 'comfortable', 'compact'];
|
||||
|
||||
// typeof allowedDensities[number] evaluates to any
|
||||
// when generating api types for whatever reason.
|
||||
|
||||
// Composables
|
||||
export const makeDensityProps = propsFactory({
|
||||
density: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: v => allowedDensities.includes(v)
|
||||
}
|
||||
}, 'density');
|
||||
export function useDensity(props, name = getCurrentInstanceName()) {
|
||||
const densityClasses = toRef(() => {
|
||||
return `${name}--density-${props.density}`;
|
||||
});
|
||||
return {
|
||||
densityClasses
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=density.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"density.js","names":["toRef","getCurrentInstanceName","propsFactory","allowedDensities","makeDensityProps","density","type","String","default","validator","v","includes","useDensity","props","name","densityClasses"],"sources":["../../src/composables/density.ts"],"sourcesContent":["// Utilities\nimport { toRef } from 'vue'\nimport { getCurrentInstanceName, propsFactory } from '@/util'\n\n// Types\nimport type { PropType } from 'vue'\n\nconst allowedDensities = [null, 'default', 'comfortable', 'compact'] as const\n\n// typeof allowedDensities[number] evaluates to any\n// when generating api types for whatever reason.\nexport type Density = null | 'default' | 'comfortable' | 'compact'\n\nexport interface DensityProps {\n density?: Density\n}\n\n// Composables\nexport const makeDensityProps = propsFactory({\n density: {\n type: String as PropType<Density>,\n default: 'default',\n validator: (v: any) => allowedDensities.includes(v),\n },\n}, 'density')\n\nexport function useDensity (\n props: DensityProps,\n name = getCurrentInstanceName(),\n) {\n const densityClasses = toRef(() => {\n return `${name}--density-${props.density}`\n })\n\n return { densityClasses }\n}\n"],"mappings":"AAAA;AACA,SAASA,KAAK,QAAQ,KAAK;AAAA,SAClBC,sBAAsB,EAAEC,YAAY,4BAE7C;AAGA,MAAMC,gBAAgB,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,CAAU;;AAE7E;AACA;;AAOA;AACA,OAAO,MAAMC,gBAAgB,GAAGF,YAAY,CAAC;EAC3CG,OAAO,EAAE;IACPC,IAAI,EAAEC,MAA2B;IACjCC,OAAO,EAAE,SAAS;IAClBC,SAAS,EAAGC,CAAM,IAAKP,gBAAgB,CAACQ,QAAQ,CAACD,CAAC;EACpD;AACF,CAAC,EAAE,SAAS,CAAC;AAEb,OAAO,SAASE,UAAUA,CACxBC,KAAmB,EACnBC,IAAI,GAAGb,sBAAsB,CAAC,CAAC,EAC/B;EACA,MAAMc,cAAc,GAAGf,KAAK,CAAC,MAAM;IACjC,OAAO,GAAGc,IAAI,aAAaD,KAAK,CAACR,OAAO,EAAE;EAC5C,CAAC,CAAC;EAEF,OAAO;IAAEU;EAAe,CAAC;AAC3B","ignoreList":[]}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
export interface DimensionProps {
|
||||
height?: number | string;
|
||||
maxHeight?: number | string;
|
||||
maxWidth?: number | string;
|
||||
minHeight?: number | string;
|
||||
minWidth?: number | string;
|
||||
width?: number | string;
|
||||
}
|
||||
export declare const makeDimensionProps: <Defaults extends {
|
||||
height?: unknown;
|
||||
maxHeight?: unknown;
|
||||
maxWidth?: unknown;
|
||||
minHeight?: unknown;
|
||||
minWidth?: unknown;
|
||||
width?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
height: unknown extends Defaults["height"] ? (NumberConstructor | StringConstructor)[] : {
|
||||
type: import("vue").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: import("vue").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: import("vue").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: import("vue").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: import("vue").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: import("vue").PropType<unknown extends Defaults["width"] ? string | number : string | number | Defaults["width"]>;
|
||||
default: unknown extends Defaults["width"] ? string | number : Defaults["width"] | NonNullable<string | number>;
|
||||
};
|
||||
};
|
||||
export declare function useDimension(props: DimensionProps): {
|
||||
dimensionStyles: import("vue").ComputedRef<Record<string, any>>;
|
||||
};
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Utilities
|
||||
import { computed } from 'vue';
|
||||
import { convertToUnit, propsFactory } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export const makeDimensionProps = propsFactory({
|
||||
height: [Number, String],
|
||||
maxHeight: [Number, String],
|
||||
maxWidth: [Number, String],
|
||||
minHeight: [Number, String],
|
||||
minWidth: [Number, String],
|
||||
width: [Number, String]
|
||||
}, 'dimension');
|
||||
export function useDimension(props) {
|
||||
const dimensionStyles = computed(() => {
|
||||
const styles = {};
|
||||
const height = convertToUnit(props.height);
|
||||
const maxHeight = convertToUnit(props.maxHeight);
|
||||
const maxWidth = convertToUnit(props.maxWidth);
|
||||
const minHeight = convertToUnit(props.minHeight);
|
||||
const minWidth = convertToUnit(props.minWidth);
|
||||
const width = convertToUnit(props.width);
|
||||
if (height != null) styles.height = height;
|
||||
if (maxHeight != null) styles.maxHeight = maxHeight;
|
||||
if (maxWidth != null) styles.maxWidth = maxWidth;
|
||||
if (minHeight != null) styles.minHeight = minHeight;
|
||||
if (minWidth != null) styles.minWidth = minWidth;
|
||||
if (width != null) styles.width = width;
|
||||
return styles;
|
||||
});
|
||||
return {
|
||||
dimensionStyles
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=dimensions.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dimensions.js","names":["computed","convertToUnit","propsFactory","makeDimensionProps","height","Number","String","maxHeight","maxWidth","minHeight","minWidth","width","useDimension","props","dimensionStyles","styles"],"sources":["../../src/composables/dimensions.ts"],"sourcesContent":["// Utilities\nimport { computed } from 'vue'\nimport { convertToUnit, propsFactory } from '@/util'\n\n// Types\nexport interface DimensionProps {\n height?: number | string\n maxHeight?: number | string\n maxWidth?: number | string\n minHeight?: number | string\n minWidth?: number | string\n width?: number | string\n}\n\n// Composables\nexport const makeDimensionProps = propsFactory({\n height: [Number, String],\n maxHeight: [Number, String],\n maxWidth: [Number, String],\n minHeight: [Number, String],\n minWidth: [Number, String],\n width: [Number, String],\n}, 'dimension')\n\nexport function useDimension (props: DimensionProps) {\n const dimensionStyles = computed(() => {\n const styles: Record<string, any> = {}\n\n const height = convertToUnit(props.height)\n const maxHeight = convertToUnit(props.maxHeight)\n const maxWidth = convertToUnit(props.maxWidth)\n const minHeight = convertToUnit(props.minHeight)\n const minWidth = convertToUnit(props.minWidth)\n const width = convertToUnit(props.width)\n\n if (height != null) styles.height = height\n if (maxHeight != null) styles.maxHeight = maxHeight\n if (maxWidth != null) styles.maxWidth = maxWidth\n if (minHeight != null) styles.minHeight = minHeight\n if (minWidth != null) styles.minWidth = minWidth\n if (width != null) styles.width = width\n\n return styles\n })\n\n return { dimensionStyles }\n}\n"],"mappings":"AAAA;AACA,SAASA,QAAQ,QAAQ,KAAK;AAAA,SACrBC,aAAa,EAAEC,YAAY,4BAEpC;AAUA;AACA,OAAO,MAAMC,kBAAkB,GAAGD,YAAY,CAAC;EAC7CE,MAAM,EAAE,CAACC,MAAM,EAAEC,MAAM,CAAC;EACxBC,SAAS,EAAE,CAACF,MAAM,EAAEC,MAAM,CAAC;EAC3BE,QAAQ,EAAE,CAACH,MAAM,EAAEC,MAAM,CAAC;EAC1BG,SAAS,EAAE,CAACJ,MAAM,EAAEC,MAAM,CAAC;EAC3BI,QAAQ,EAAE,CAACL,MAAM,EAAEC,MAAM,CAAC;EAC1BK,KAAK,EAAE,CAACN,MAAM,EAAEC,MAAM;AACxB,CAAC,EAAE,WAAW,CAAC;AAEf,OAAO,SAASM,YAAYA,CAAEC,KAAqB,EAAE;EACnD,MAAMC,eAAe,GAAGd,QAAQ,CAAC,MAAM;IACrC,MAAMe,MAA2B,GAAG,CAAC,CAAC;IAEtC,MAAMX,MAAM,GAAGH,aAAa,CAACY,KAAK,CAACT,MAAM,CAAC;IAC1C,MAAMG,SAAS,GAAGN,aAAa,CAACY,KAAK,CAACN,SAAS,CAAC;IAChD,MAAMC,QAAQ,GAAGP,aAAa,CAACY,KAAK,CAACL,QAAQ,CAAC;IAC9C,MAAMC,SAAS,GAAGR,aAAa,CAACY,KAAK,CAACJ,SAAS,CAAC;IAChD,MAAMC,QAAQ,GAAGT,aAAa,CAACY,KAAK,CAACH,QAAQ,CAAC;IAC9C,MAAMC,KAAK,GAAGV,aAAa,CAACY,KAAK,CAACF,KAAK,CAAC;IAExC,IAAIP,MAAM,IAAI,IAAI,EAAEW,MAAM,CAACX,MAAM,GAAGA,MAAM;IAC1C,IAAIG,SAAS,IAAI,IAAI,EAAEQ,MAAM,CAACR,SAAS,GAAGA,SAAS;IACnD,IAAIC,QAAQ,IAAI,IAAI,EAAEO,MAAM,CAACP,QAAQ,GAAGA,QAAQ;IAChD,IAAIC,SAAS,IAAI,IAAI,EAAEM,MAAM,CAACN,SAAS,GAAGA,SAAS;IACnD,IAAIC,QAAQ,IAAI,IAAI,EAAEK,MAAM,CAACL,QAAQ,GAAGA,QAAQ;IAChD,IAAIC,KAAK,IAAI,IAAI,EAAEI,MAAM,CAACJ,KAAK,GAAGA,KAAK;IAEvC,OAAOI,MAAM;EACf,CAAC,CAAC;EAEF,OAAO;IAAED;EAAgB,CAAC;AAC5B","ignoreList":[]}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import type { Component, DirectiveBinding, ObjectDirective, VNode } from 'vue';
|
||||
import type { ComponentInstance } from '../util/index.js';
|
||||
type ExcludeProps = 'v-slots' | `v-slot:${string}` | `on${Uppercase<string>}${string}` | 'key' | 'ref' | 'ref_for' | 'ref_key' | '$children';
|
||||
declare const CustomDirectiveSymbol: unique symbol;
|
||||
type DirectiveHook<B extends DirectiveBinding> = (el: any, binding: B, vnode: VNode<any, any>, prevVNode: VNode<any, any>) => void;
|
||||
export interface CustomDirective<B extends DirectiveBinding = DirectiveBinding> {
|
||||
created?: DirectiveHook<B>;
|
||||
beforeMount?: DirectiveHook<B>;
|
||||
mounted?: DirectiveHook<B>;
|
||||
beforeUpdate?: DirectiveHook<B>;
|
||||
updated?: DirectiveHook<B>;
|
||||
beforeUnmount?: DirectiveHook<B>;
|
||||
unmounted?: DirectiveHook<B>;
|
||||
[CustomDirectiveSymbol]: true;
|
||||
}
|
||||
export declare function useDirectiveComponent<Binding extends DirectiveBinding>(component: string | Component, props?: (binding: Binding) => Record<string, any>): CustomDirective<Binding>;
|
||||
export declare function useDirectiveComponent<C extends Component, Props = Omit<ComponentInstance<C>['$props'], ExcludeProps>>(component: string | C, props?: Record<string, any>): ObjectDirective<any, Props>;
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Utilities
|
||||
import { h, mergeProps, render, resolveComponent } from 'vue';
|
||||
import { consoleError, isObject } from "../util/index.js"; // Types
|
||||
export function useDirectiveComponent(component, props) {
|
||||
const concreteComponent = typeof component === 'string' ? resolveComponent(component) : component;
|
||||
const hook = mountComponent(concreteComponent, props);
|
||||
return {
|
||||
mounted: hook,
|
||||
updated: hook,
|
||||
unmounted(el) {
|
||||
render(null, el);
|
||||
}
|
||||
};
|
||||
}
|
||||
function mountComponent(component, props) {
|
||||
return function (el, binding, vnode) {
|
||||
const _props = typeof props === 'function' ? props(binding) : props;
|
||||
const text = binding.value?.text ?? binding.value ?? _props?.text;
|
||||
const value = isObject(binding.value) ? binding.value : {};
|
||||
|
||||
// Get the children from the props or directive value, or the element's children
|
||||
const children = () => text ?? el.textContent;
|
||||
|
||||
// If vnode.ctx is the same as the instance, then we're bound to a plain element
|
||||
// and need to find the nearest parent component instance to inherit provides from
|
||||
const provides = (vnode.ctx === binding.instance.$ ? findComponentParent(vnode, binding.instance.$)?.provides : vnode.ctx?.provides) ?? binding.instance.$.provides;
|
||||
const node = h(component, mergeProps(_props, value), children);
|
||||
node.appContext = Object.assign(Object.create(null), binding.instance.$.appContext, {
|
||||
provides
|
||||
});
|
||||
render(node, el);
|
||||
};
|
||||
}
|
||||
function findComponentParent(vnode, root) {
|
||||
// Walk the tree from root until we find the child vnode
|
||||
const stack = new Set();
|
||||
const walk = children => {
|
||||
for (const child of children) {
|
||||
if (!child) continue;
|
||||
if (child === vnode || child.el && vnode.el && child.el === vnode.el) {
|
||||
return true;
|
||||
}
|
||||
stack.add(child);
|
||||
let result;
|
||||
if (child.suspense) {
|
||||
result = walk([child.ssContent]);
|
||||
} else if (Array.isArray(child.children)) {
|
||||
result = walk(child.children);
|
||||
} else if (child.component?.vnode) {
|
||||
result = walk([child.component?.subTree]);
|
||||
}
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
stack.delete(child);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (!walk([root.subTree])) {
|
||||
consoleError('Could not find original vnode, component will not inherit provides');
|
||||
return root;
|
||||
}
|
||||
|
||||
// Return the first component parent
|
||||
const result = Array.from(stack).reverse();
|
||||
for (const child of result) {
|
||||
if (child.component) {
|
||||
return child.component;
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
//# sourceMappingURL=directiveComponent.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+114
@@ -0,0 +1,114 @@
|
||||
import type { InjectionKey, PropType, Ref } from 'vue';
|
||||
export declare const breakpoints: readonly ['sm', 'md', 'lg', 'xl', 'xxl'];
|
||||
export type Breakpoint = (typeof breakpoints)[number];
|
||||
export type DisplayBreakpoint = 'xs' | Breakpoint;
|
||||
export type DisplayThresholds = {
|
||||
[key in DisplayBreakpoint]: number;
|
||||
};
|
||||
export interface DisplayProps {
|
||||
mobile?: boolean | null;
|
||||
mobileBreakpoint?: number | DisplayBreakpoint;
|
||||
}
|
||||
export interface DisplayOptions {
|
||||
mobileBreakpoint?: number | DisplayBreakpoint;
|
||||
thresholds?: Partial<DisplayThresholds>;
|
||||
}
|
||||
export interface InternalDisplayOptions {
|
||||
mobileBreakpoint: number | DisplayBreakpoint;
|
||||
thresholds: DisplayThresholds;
|
||||
}
|
||||
export type SSROptions = boolean | {
|
||||
clientWidth: number;
|
||||
clientHeight?: number;
|
||||
};
|
||||
export interface DisplayPlatform {
|
||||
android: boolean;
|
||||
ios: boolean;
|
||||
cordova: boolean;
|
||||
electron: boolean;
|
||||
chrome: boolean;
|
||||
edge: boolean;
|
||||
firefox: boolean;
|
||||
opera: boolean;
|
||||
win: boolean;
|
||||
mac: boolean;
|
||||
linux: boolean;
|
||||
touch: boolean;
|
||||
ssr: boolean;
|
||||
}
|
||||
export interface DisplayInstance {
|
||||
xs: Ref<boolean>;
|
||||
sm: Ref<boolean>;
|
||||
md: Ref<boolean>;
|
||||
lg: Ref<boolean>;
|
||||
xl: Ref<boolean>;
|
||||
xxl: Ref<boolean>;
|
||||
smAndUp: Ref<boolean>;
|
||||
mdAndUp: Ref<boolean>;
|
||||
lgAndUp: Ref<boolean>;
|
||||
xlAndUp: Ref<boolean>;
|
||||
smAndDown: Ref<boolean>;
|
||||
mdAndDown: Ref<boolean>;
|
||||
lgAndDown: Ref<boolean>;
|
||||
xlAndDown: Ref<boolean>;
|
||||
name: Ref<DisplayBreakpoint>;
|
||||
height: Ref<number>;
|
||||
width: Ref<number>;
|
||||
mobile: Ref<boolean>;
|
||||
mobileBreakpoint: Ref<number | DisplayBreakpoint>;
|
||||
platform: Ref<DisplayPlatform>;
|
||||
thresholds: Ref<DisplayThresholds>;
|
||||
update(): void;
|
||||
}
|
||||
export declare const DisplaySymbol: InjectionKey<DisplayInstance>;
|
||||
export declare function createDisplay(options?: DisplayOptions, ssr?: SSROptions): DisplayInstance;
|
||||
export declare const makeDisplayProps: <Defaults extends {
|
||||
mobile?: unknown;
|
||||
mobileBreakpoint?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
mobile: unknown extends Defaults["mobile"] ? {
|
||||
type: PropType<boolean | null>;
|
||||
default: boolean;
|
||||
} : Omit<{
|
||||
type: PropType<boolean | null>;
|
||||
default: boolean;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["mobile"] ? boolean | null : boolean | Defaults["mobile"] | null>;
|
||||
default: unknown extends Defaults["mobile"] ? boolean | null : Defaults["mobile"] | NonNullable<boolean | null>;
|
||||
};
|
||||
mobileBreakpoint: unknown extends Defaults["mobileBreakpoint"] ? PropType<number | DisplayBreakpoint> : {
|
||||
type: PropType<unknown extends Defaults["mobileBreakpoint"] ? number | DisplayBreakpoint : number | Defaults["mobileBreakpoint"] | DisplayBreakpoint>;
|
||||
default: unknown extends Defaults["mobileBreakpoint"] ? number | DisplayBreakpoint : Defaults["mobileBreakpoint"] | NonNullable<number | DisplayBreakpoint>;
|
||||
};
|
||||
};
|
||||
export declare function useDisplay(props?: DisplayProps, name?: string): {
|
||||
xs: Ref<boolean>;
|
||||
sm: Ref<boolean>;
|
||||
md: Ref<boolean>;
|
||||
lg: Ref<boolean>;
|
||||
xl: Ref<boolean>;
|
||||
xxl: Ref<boolean>;
|
||||
smAndUp: Ref<boolean>;
|
||||
mdAndUp: Ref<boolean>;
|
||||
lgAndUp: Ref<boolean>;
|
||||
xlAndUp: Ref<boolean>;
|
||||
smAndDown: Ref<boolean>;
|
||||
mdAndDown: Ref<boolean>;
|
||||
lgAndDown: Ref<boolean>;
|
||||
xlAndDown: Ref<boolean>;
|
||||
name: Ref<DisplayBreakpoint>;
|
||||
height: Ref<number>;
|
||||
width: Ref<number>;
|
||||
mobileBreakpoint: Ref<number | DisplayBreakpoint>;
|
||||
platform: Ref<DisplayPlatform>;
|
||||
thresholds: Ref<DisplayThresholds>;
|
||||
/** @internal */
|
||||
ssr: boolean;
|
||||
update(): void;
|
||||
displayClasses: Readonly<Ref<{
|
||||
[x: string]: boolean;
|
||||
}, {
|
||||
[x: string]: boolean;
|
||||
}>>;
|
||||
mobile: import("vue").ComputedRef<boolean>;
|
||||
};
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
// Utilities
|
||||
import { computed, inject, onScopeDispose, reactive, shallowRef, toRef, toRefs, watchEffect } from 'vue';
|
||||
import { getCurrentInstanceName, mergeDeep, propsFactory } from "../util/index.js";
|
||||
import { IN_BROWSER, SUPPORTS_TOUCH } from "../util/globals.js"; // Types
|
||||
export const breakpoints = ['sm', 'md', 'lg', 'xl', 'xxl']; // no xs
|
||||
|
||||
export const DisplaySymbol = Symbol.for('vuetify:display');
|
||||
const defaultDisplayOptions = {
|
||||
mobileBreakpoint: 'lg',
|
||||
thresholds: {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 840,
|
||||
lg: 1145,
|
||||
xl: 1545,
|
||||
xxl: 2138
|
||||
}
|
||||
};
|
||||
const parseDisplayOptions = (options = defaultDisplayOptions) => {
|
||||
return mergeDeep(defaultDisplayOptions, options);
|
||||
};
|
||||
function getClientWidth(ssr) {
|
||||
return IN_BROWSER && !ssr ? window.innerWidth : typeof ssr === 'object' && ssr.clientWidth || 0;
|
||||
}
|
||||
function getClientHeight(ssr) {
|
||||
return IN_BROWSER && !ssr ? window.innerHeight : typeof ssr === 'object' && ssr.clientHeight || 0;
|
||||
}
|
||||
function getPlatform(ssr) {
|
||||
const userAgent = IN_BROWSER && !ssr ? window.navigator.userAgent : 'ssr';
|
||||
function match(regexp) {
|
||||
return Boolean(userAgent.match(regexp));
|
||||
}
|
||||
const android = match(/android/i);
|
||||
const ios = match(/iphone|ipad|ipod/i);
|
||||
const cordova = match(/cordova/i);
|
||||
const electron = match(/electron/i);
|
||||
const chrome = match(/chrome/i);
|
||||
const edge = match(/edge/i);
|
||||
const firefox = match(/firefox/i);
|
||||
const opera = match(/opera/i);
|
||||
const win = match(/win/i);
|
||||
const mac = match(/mac/i);
|
||||
const linux = match(/linux/i);
|
||||
return {
|
||||
android,
|
||||
ios,
|
||||
cordova,
|
||||
electron,
|
||||
chrome,
|
||||
edge,
|
||||
firefox,
|
||||
opera,
|
||||
win,
|
||||
mac,
|
||||
linux,
|
||||
touch: SUPPORTS_TOUCH,
|
||||
ssr: userAgent === 'ssr'
|
||||
};
|
||||
}
|
||||
export function createDisplay(options, ssr) {
|
||||
const {
|
||||
thresholds,
|
||||
mobileBreakpoint
|
||||
} = parseDisplayOptions(options);
|
||||
const height = shallowRef(getClientHeight(ssr));
|
||||
const platform = shallowRef(getPlatform(ssr));
|
||||
const state = reactive({});
|
||||
const width = shallowRef(getClientWidth(ssr));
|
||||
function updateSize() {
|
||||
height.value = getClientHeight();
|
||||
width.value = getClientWidth();
|
||||
}
|
||||
function update() {
|
||||
updateSize();
|
||||
platform.value = getPlatform();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
watchEffect(() => {
|
||||
const xs = width.value < thresholds.sm;
|
||||
const sm = width.value < thresholds.md && !xs;
|
||||
const md = width.value < thresholds.lg && !(sm || xs);
|
||||
const lg = width.value < thresholds.xl && !(md || sm || xs);
|
||||
const xl = width.value < thresholds.xxl && !(lg || md || sm || xs);
|
||||
const xxl = width.value >= thresholds.xxl;
|
||||
const name = xs ? 'xs' : sm ? 'sm' : md ? 'md' : lg ? 'lg' : xl ? 'xl' : 'xxl';
|
||||
const breakpointValue = typeof mobileBreakpoint === 'number' ? mobileBreakpoint : thresholds[mobileBreakpoint];
|
||||
const mobile = width.value < breakpointValue;
|
||||
state.xs = xs;
|
||||
state.sm = sm;
|
||||
state.md = md;
|
||||
state.lg = lg;
|
||||
state.xl = xl;
|
||||
state.xxl = xxl;
|
||||
state.smAndUp = !xs;
|
||||
state.mdAndUp = !(xs || sm);
|
||||
state.lgAndUp = !(xs || sm || md);
|
||||
state.xlAndUp = !(xs || sm || md || lg);
|
||||
state.smAndDown = !(md || lg || xl || xxl);
|
||||
state.mdAndDown = !(lg || xl || xxl);
|
||||
state.lgAndDown = !(xl || xxl);
|
||||
state.xlAndDown = !xxl;
|
||||
state.name = name;
|
||||
state.height = height.value;
|
||||
state.width = width.value;
|
||||
state.mobile = mobile;
|
||||
state.mobileBreakpoint = mobileBreakpoint;
|
||||
state.platform = platform.value;
|
||||
state.thresholds = thresholds;
|
||||
});
|
||||
if (IN_BROWSER) {
|
||||
window.addEventListener('resize', updateSize, {
|
||||
passive: true
|
||||
});
|
||||
onScopeDispose(() => {
|
||||
window.removeEventListener('resize', updateSize);
|
||||
}, true);
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
update,
|
||||
ssr: !!ssr
|
||||
};
|
||||
}
|
||||
export const makeDisplayProps = propsFactory({
|
||||
mobile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mobileBreakpoint: [Number, String]
|
||||
}, 'display');
|
||||
export function useDisplay(props = {
|
||||
mobile: null
|
||||
}, name = getCurrentInstanceName()) {
|
||||
const display = inject(DisplaySymbol);
|
||||
if (!display) throw new Error('Could not find Vuetify display injection');
|
||||
const mobile = computed(() => {
|
||||
if (props.mobile) {
|
||||
return true;
|
||||
} else if (typeof props.mobileBreakpoint === 'number') {
|
||||
return display.width.value < props.mobileBreakpoint;
|
||||
} else if (props.mobileBreakpoint) {
|
||||
return display.width.value < display.thresholds.value[props.mobileBreakpoint];
|
||||
} else if (props.mobile === null) {
|
||||
return display.mobile.value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
const displayClasses = toRef(() => {
|
||||
if (!name) return {};
|
||||
return {
|
||||
[`${name}--mobile`]: mobile.value
|
||||
};
|
||||
});
|
||||
return {
|
||||
...display,
|
||||
displayClasses,
|
||||
mobile
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=display.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
export declare function useDocumentVisibility(): import("vue").ShallowRef<DocumentVisibilityState, DocumentVisibilityState>;
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// Utilities
|
||||
import { onBeforeUnmount, shallowRef } from 'vue';
|
||||
import { IN_BROWSER } from "../util/globals.js";
|
||||
export function useDocumentVisibility() {
|
||||
const visibility = shallowRef(IN_BROWSER ? document.visibilityState : 'visible');
|
||||
if (IN_BROWSER) {
|
||||
const onVisibilityChange = () => {
|
||||
visibility.value = document.visibilityState;
|
||||
};
|
||||
document.addEventListener('visibilitychange', onVisibilityChange, {
|
||||
passive: true
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('visibilitychange', onVisibilityChange);
|
||||
});
|
||||
}
|
||||
return visibility;
|
||||
}
|
||||
//# sourceMappingURL=documentVisibility.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"documentVisibility.js","names":["onBeforeUnmount","shallowRef","IN_BROWSER","useDocumentVisibility","visibility","document","visibilityState","onVisibilityChange","value","addEventListener","passive","removeEventListener"],"sources":["../../src/composables/documentVisibility.ts"],"sourcesContent":["// Utilities\nimport { onBeforeUnmount, shallowRef } from 'vue'\nimport { IN_BROWSER } from '@/util/globals'\n\nexport function useDocumentVisibility () {\n const visibility = shallowRef(IN_BROWSER ? document.visibilityState : 'visible')\n\n if (IN_BROWSER) {\n const onVisibilityChange = () => {\n visibility.value = document.visibilityState\n }\n document.addEventListener('visibilitychange', onVisibilityChange, { passive: true })\n onBeforeUnmount(() => {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n })\n }\n\n return visibility\n}\n"],"mappings":"AAAA;AACA,SAASA,eAAe,EAAEC,UAAU,QAAQ,KAAK;AAAA,SACxCC,UAAU;AAEnB,OAAO,SAASC,qBAAqBA,CAAA,EAAI;EACvC,MAAMC,UAAU,GAAGH,UAAU,CAACC,UAAU,GAAGG,QAAQ,CAACC,eAAe,GAAG,SAAS,CAAC;EAEhF,IAAIJ,UAAU,EAAE;IACd,MAAMK,kBAAkB,GAAGA,CAAA,KAAM;MAC/BH,UAAU,CAACI,KAAK,GAAGH,QAAQ,CAACC,eAAe;IAC7C,CAAC;IACDD,QAAQ,CAACI,gBAAgB,CAAC,kBAAkB,EAAEF,kBAAkB,EAAE;MAAEG,OAAO,EAAE;IAAK,CAAC,CAAC;IACpFV,eAAe,CAAC,MAAM;MACpBK,QAAQ,CAACM,mBAAmB,CAAC,kBAAkB,EAAEJ,kBAAkB,CAAC;IACtE,CAAC,CAAC;EACJ;EAEA,OAAOH,UAAU;AACnB","ignoreList":[]}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import type { Ref } from 'vue';
|
||||
export interface ElevationProps {
|
||||
elevation?: number | string | null;
|
||||
}
|
||||
export declare const makeElevationProps: <Defaults extends {
|
||||
elevation?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
elevation: unknown extends Defaults["elevation"] ? {
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
validator: (value: string | number) => boolean;
|
||||
} : Omit<{
|
||||
type: (NumberConstructor | StringConstructor)[];
|
||||
validator: (value: string | number) => boolean;
|
||||
}, "default" | "type"> & {
|
||||
type: import("vue").PropType<unknown extends Defaults["elevation"] ? string | number : string | number | Defaults["elevation"]>;
|
||||
default: unknown extends Defaults["elevation"] ? string | number : Defaults["elevation"] | NonNullable<string | number>;
|
||||
};
|
||||
};
|
||||
type ElevationData = {
|
||||
elevationClasses: Ref<string[]>;
|
||||
};
|
||||
export declare function useElevation(props: ElevationProps | Ref<number | string | undefined>): ElevationData;
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Utilities
|
||||
import { isRef, toRef } from 'vue';
|
||||
import { propsFactory } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export const makeElevationProps = propsFactory({
|
||||
elevation: {
|
||||
type: [Number, String],
|
||||
// no limit to allow both 0-6 (MD3) and legacy 0-24 (MD2)
|
||||
validator: value => parseInt(value) >= 0
|
||||
}
|
||||
}, 'elevation');
|
||||
export function useElevation(props) {
|
||||
const elevationClasses = toRef(() => {
|
||||
const elevation = isRef(props) ? props.value : props.elevation;
|
||||
if (elevation == null) return [];
|
||||
return [`elevation-${parseInt(elevation)}`];
|
||||
});
|
||||
return {
|
||||
elevationClasses
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=elevation.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"elevation.js","names":["isRef","toRef","propsFactory","makeElevationProps","elevation","type","Number","String","validator","value","parseInt","useElevation","props","elevationClasses"],"sources":["../../src/composables/elevation.ts"],"sourcesContent":["// Utilities\nimport { isRef, toRef } from 'vue'\nimport { propsFactory } from '@/util'\n\n// Types\nimport type { Ref } from 'vue'\nexport interface ElevationProps {\n elevation?: number | string | null\n}\n\n// Composables\nexport const makeElevationProps = propsFactory({\n elevation: {\n type: [Number, String],\n // no limit to allow both 0-6 (MD3) and legacy 0-24 (MD2)\n validator: (value: string | number) => parseInt(value) >= 0,\n },\n}, 'elevation')\n\ntype ElevationData = {\n elevationClasses: Ref<string[]>\n}\n\nexport function useElevation (props: ElevationProps | Ref<number | string | undefined>): ElevationData {\n const elevationClasses = toRef(() => {\n const elevation = isRef(props) ? props.value : props.elevation\n if (elevation == null) return []\n return [`elevation-${parseInt(elevation)}`]\n })\n\n return { elevationClasses }\n}\n"],"mappings":"AAAA;AACA,SAASA,KAAK,EAAEC,KAAK,QAAQ,KAAK;AAAA,SACzBC,YAAY,4BAErB;AAMA;AACA,OAAO,MAAMC,kBAAkB,GAAGD,YAAY,CAAC;EAC7CE,SAAS,EAAE;IACTC,IAAI,EAAE,CAACC,MAAM,EAAEC,MAAM,CAAC;IACtB;IACAC,SAAS,EAAGC,KAAsB,IAAKC,QAAQ,CAACD,KAAK,CAAC,IAAI;EAC5D;AACF,CAAC,EAAE,WAAW,CAAC;AAMf,OAAO,SAASE,YAAYA,CAAEC,KAAwD,EAAiB;EACrG,MAAMC,gBAAgB,GAAGZ,KAAK,CAAC,MAAM;IACnC,MAAMG,SAAS,GAAGJ,KAAK,CAACY,KAAK,CAAC,GAAGA,KAAK,CAACH,KAAK,GAAGG,KAAK,CAACR,SAAS;IAC9D,IAAIA,SAAS,IAAI,IAAI,EAAE,OAAO,EAAE;IAChC,OAAO,CAAC,aAAaM,QAAQ,CAACN,SAAS,CAAC,EAAE,CAAC;EAC7C,CAAC,CAAC;EAEF,OAAO;IAAES;EAAiB,CAAC;AAC7B","ignoreList":[]}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export declare function useFileDrop(): {
|
||||
handleDrop: (e: DragEvent) => Promise<File[]>;
|
||||
hasFilesOrFolders: (e: DragEvent) => boolean;
|
||||
};
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// Types
|
||||
|
||||
export function useFileDrop() {
|
||||
function hasFilesOrFolders(e) {
|
||||
const entries = [...(e.dataTransfer?.items ?? [])].filter(x => x.kind === 'file').map(x => x.webkitGetAsEntry()).filter(Boolean);
|
||||
return entries.length > 0 || [...(e.dataTransfer?.files ?? [])].length > 0;
|
||||
}
|
||||
async function handleDrop(e) {
|
||||
const result = [];
|
||||
const entries = [...(e.dataTransfer?.items ?? [])].filter(x => x.kind === 'file').map(x => x.webkitGetAsEntry()).filter(Boolean);
|
||||
if (entries.length) {
|
||||
for (const entry of entries) {
|
||||
const files = await traverseFileTree(entry, appendIfDirectory('.', entry));
|
||||
result.push(...files.map(x => x.file));
|
||||
}
|
||||
} else {
|
||||
result.push(...[...(e.dataTransfer?.files ?? [])]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return {
|
||||
handleDrop,
|
||||
hasFilesOrFolders
|
||||
};
|
||||
}
|
||||
function traverseFileTree(item, path = '') {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (item.isFile) {
|
||||
const fileEntry = item;
|
||||
fileEntry.file(file => resolve([{
|
||||
file,
|
||||
path
|
||||
}]), reject);
|
||||
} else if (item.isDirectory) {
|
||||
const directoryReader = item.createReader();
|
||||
directoryReader.readEntries(async entries => {
|
||||
const files = [];
|
||||
for (const entry of entries) {
|
||||
files.push(...(await traverseFileTree(entry, appendIfDirectory(path, entry))));
|
||||
}
|
||||
resolve(files);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function appendIfDirectory(path, item) {
|
||||
return item.isDirectory ? `${path}/${item.name}` : path;
|
||||
}
|
||||
//# sourceMappingURL=fileDrop.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"fileDrop.js","names":["useFileDrop","hasFilesOrFolders","e","entries","dataTransfer","items","filter","x","kind","map","webkitGetAsEntry","Boolean","length","files","handleDrop","result","entry","traverseFileTree","appendIfDirectory","push","file","item","path","Promise","resolve","reject","isFile","fileEntry","isDirectory","directoryReader","createReader","readEntries","name"],"sources":["../../src/composables/fileDrop.ts"],"sourcesContent":["// Types\ntype FileSelection = { file: File, path: string }\n\nexport function useFileDrop () {\n function hasFilesOrFolders (e: DragEvent): boolean {\n const entries = [...e.dataTransfer?.items ?? []]\n .filter(x => x.kind === 'file')\n .map(x => x.webkitGetAsEntry())\n .filter(Boolean)\n\n return entries.length > 0 || [...e.dataTransfer?.files ?? []].length > 0\n }\n\n async function handleDrop (e: DragEvent) {\n const result: File[] = []\n\n const entries = [...e.dataTransfer?.items ?? []]\n .filter(x => x.kind === 'file')\n .map(x => x.webkitGetAsEntry())\n .filter(Boolean)\n\n if (entries.length) {\n for (const entry of entries) {\n const files = await traverseFileTree(entry!, appendIfDirectory('.', entry!))\n result.push(...files.map(x => x.file))\n }\n } else {\n result.push(...[...e.dataTransfer?.files ?? []])\n }\n\n return result\n }\n\n return {\n handleDrop,\n hasFilesOrFolders,\n }\n}\n\nfunction traverseFileTree (item: FileSystemEntry, path = ''): Promise<FileSelection[]> {\n return new Promise<FileSelection[]>((resolve, reject) => {\n if (item.isFile) {\n const fileEntry = item as FileSystemFileEntry\n fileEntry.file((file: File) => resolve([{ file, path }]), reject)\n } else if (item.isDirectory) {\n const directoryReader = (item as FileSystemDirectoryEntry).createReader()\n directoryReader.readEntries(async entries => {\n const files = [] as FileSelection[]\n for (const entry of entries) {\n files.push(...(await traverseFileTree(entry, appendIfDirectory(path, entry))))\n }\n resolve(files)\n })\n }\n })\n}\n\nfunction appendIfDirectory (path: string, item: FileSystemEntry) {\n return item.isDirectory\n ? `${path}/${item.name}`\n : path\n}\n"],"mappings":"AAAA;;AAGA,OAAO,SAASA,WAAWA,CAAA,EAAI;EAC7B,SAASC,iBAAiBA,CAAEC,CAAY,EAAW;IACjD,MAAMC,OAAO,GAAG,CAAC,IAAGD,CAAC,CAACE,YAAY,EAAEC,KAAK,IAAI,EAAE,EAAC,CAC7CC,MAAM,CAACC,CAAC,IAAIA,CAAC,CAACC,IAAI,KAAK,MAAM,CAAC,CAC9BC,GAAG,CAACF,CAAC,IAAIA,CAAC,CAACG,gBAAgB,CAAC,CAAC,CAAC,CAC9BJ,MAAM,CAACK,OAAO,CAAC;IAElB,OAAOR,OAAO,CAACS,MAAM,GAAG,CAAC,IAAI,CAAC,IAAGV,CAAC,CAACE,YAAY,EAAES,KAAK,IAAI,EAAE,EAAC,CAACD,MAAM,GAAG,CAAC;EAC1E;EAEA,eAAeE,UAAUA,CAAEZ,CAAY,EAAE;IACvC,MAAMa,MAAc,GAAG,EAAE;IAEzB,MAAMZ,OAAO,GAAG,CAAC,IAAGD,CAAC,CAACE,YAAY,EAAEC,KAAK,IAAI,EAAE,EAAC,CAC7CC,MAAM,CAACC,CAAC,IAAIA,CAAC,CAACC,IAAI,KAAK,MAAM,CAAC,CAC9BC,GAAG,CAACF,CAAC,IAAIA,CAAC,CAACG,gBAAgB,CAAC,CAAC,CAAC,CAC9BJ,MAAM,CAACK,OAAO,CAAC;IAElB,IAAIR,OAAO,CAACS,MAAM,EAAE;MAClB,KAAK,MAAMI,KAAK,IAAIb,OAAO,EAAE;QAC3B,MAAMU,KAAK,GAAG,MAAMI,gBAAgB,CAACD,KAAK,EAAGE,iBAAiB,CAAC,GAAG,EAAEF,KAAM,CAAC,CAAC;QAC5ED,MAAM,CAACI,IAAI,CAAC,GAAGN,KAAK,CAACJ,GAAG,CAACF,CAAC,IAAIA,CAAC,CAACa,IAAI,CAAC,CAAC;MACxC;IACF,CAAC,MAAM;MACLL,MAAM,CAACI,IAAI,CAAC,GAAG,CAAC,IAAGjB,CAAC,CAACE,YAAY,EAAES,KAAK,IAAI,EAAE,EAAC,CAAC;IAClD;IAEA,OAAOE,MAAM;EACf;EAEA,OAAO;IACLD,UAAU;IACVb;EACF,CAAC;AACH;AAEA,SAASgB,gBAAgBA,CAAEI,IAAqB,EAAEC,IAAI,GAAG,EAAE,EAA4B;EACrF,OAAO,IAAIC,OAAO,CAAkB,CAACC,OAAO,EAAEC,MAAM,KAAK;IACvD,IAAIJ,IAAI,CAACK,MAAM,EAAE;MACf,MAAMC,SAAS,GAAGN,IAA2B;MAC7CM,SAAS,CAACP,IAAI,CAAEA,IAAU,IAAKI,OAAO,CAAC,CAAC;QAAEJ,IAAI;QAAEE;MAAK,CAAC,CAAC,CAAC,EAAEG,MAAM,CAAC;IACnE,CAAC,MAAM,IAAIJ,IAAI,CAACO,WAAW,EAAE;MAC3B,MAAMC,eAAe,GAAIR,IAAI,CAA8BS,YAAY,CAAC,CAAC;MACzED,eAAe,CAACE,WAAW,CAAC,MAAM5B,OAAO,IAAI;QAC3C,MAAMU,KAAK,GAAG,EAAqB;QACnC,KAAK,MAAMG,KAAK,IAAIb,OAAO,EAAE;UAC3BU,KAAK,CAACM,IAAI,CAAC,IAAI,MAAMF,gBAAgB,CAACD,KAAK,EAAEE,iBAAiB,CAACI,IAAI,EAAEN,KAAK,CAAC,CAAC,CAAC,CAAC;QAChF;QACAQ,OAAO,CAACX,KAAK,CAAC;MAChB,CAAC,CAAC;IACJ;EACF,CAAC,CAAC;AACJ;AAEA,SAASK,iBAAiBA,CAAEI,IAAY,EAAED,IAAqB,EAAE;EAC/D,OAAOA,IAAI,CAACO,WAAW,GACnB,GAAGN,IAAI,IAAID,IAAI,CAACW,IAAI,EAAE,GACtBV,IAAI;AACV","ignoreList":[]}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
export interface FileFilterProps {
|
||||
filterByType?: string;
|
||||
}
|
||||
export type FileFilterResult = {
|
||||
accepted: File[];
|
||||
rejected: File[];
|
||||
};
|
||||
export declare const makeFileFilterProps: <Defaults extends {
|
||||
filterByType?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
filterByType: unknown extends Defaults["filterByType"] ? StringConstructor : {
|
||||
type: import("vue").PropType<unknown extends Defaults["filterByType"] ? string : string | Defaults["filterByType"]>;
|
||||
default: unknown extends Defaults["filterByType"] ? string : string | Defaults["filterByType"];
|
||||
};
|
||||
};
|
||||
export declare function useFileFilter(props: FileFilterProps): {
|
||||
filterAccepted: (files: File[]) => FileFilterResult;
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Utilities
|
||||
import { computed } from 'vue';
|
||||
import { propsFactory } from "../util/index.js";
|
||||
// Composables
|
||||
export const makeFileFilterProps = propsFactory({
|
||||
filterByType: String
|
||||
}, 'file-accept');
|
||||
export function useFileFilter(props) {
|
||||
const fileFilter = computed(() => props.filterByType ? createFilter(props.filterByType) : null);
|
||||
function filterAccepted(files) {
|
||||
if (fileFilter.value) {
|
||||
const accepted = files.filter(fileFilter.value);
|
||||
return {
|
||||
accepted,
|
||||
rejected: files.filter(f => !accepted.includes(f))
|
||||
};
|
||||
}
|
||||
return {
|
||||
accepted: files,
|
||||
rejected: []
|
||||
};
|
||||
}
|
||||
return {
|
||||
filterAccepted
|
||||
};
|
||||
}
|
||||
function createFilter(v) {
|
||||
const types = v.split(',').map(x => x.trim().toLowerCase());
|
||||
const extensionsToMatch = types.filter(x => x.startsWith('.'));
|
||||
const wildcards = types.filter(x => x.endsWith('/*'));
|
||||
const typesToMatch = types.filter(x => !extensionsToMatch.includes(x) && !wildcards.includes(x));
|
||||
return file => {
|
||||
const extension = file.name.split('.').at(-1)?.toLowerCase() ?? '';
|
||||
const typeGroup = file.type.split('/').at(0)?.toLowerCase() ?? '';
|
||||
return typesToMatch.includes(file.type) || extensionsToMatch.includes(`.${extension}`) || wildcards.includes(`${typeGroup}/*`);
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=fileFilter.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"fileFilter.js","names":["computed","propsFactory","makeFileFilterProps","filterByType","String","useFileFilter","props","fileFilter","createFilter","filterAccepted","files","value","accepted","filter","rejected","f","includes","v","types","split","map","x","trim","toLowerCase","extensionsToMatch","startsWith","wildcards","endsWith","typesToMatch","file","extension","name","at","typeGroup","type"],"sources":["../../src/composables/fileFilter.ts"],"sourcesContent":["// Utilities\nimport { computed } from 'vue'\nimport { propsFactory } from '@/util'\n\nexport interface FileFilterProps {\n filterByType?: string\n}\n\nexport type FileFilterResult = {\n accepted: File[]\n rejected: File[]\n}\n\n// Composables\nexport const makeFileFilterProps = propsFactory({\n filterByType: String,\n}, 'file-accept')\n\nexport function useFileFilter (props: FileFilterProps) {\n const fileFilter = computed(() => props.filterByType ? createFilter(props.filterByType) : null)\n\n function filterAccepted (files: File[]): FileFilterResult {\n if (fileFilter.value) {\n const accepted = files.filter(fileFilter.value)\n return {\n accepted,\n rejected: files.filter(f => !accepted.includes(f)),\n }\n }\n return {\n accepted: files,\n rejected: [],\n }\n }\n\n return {\n filterAccepted,\n }\n}\n\nfunction createFilter (v: string): ((v: File) => boolean) {\n const types = v.split(',').map(x => x.trim().toLowerCase())\n const extensionsToMatch = types.filter(x => x.startsWith('.'))\n const wildcards = types.filter(x => x.endsWith('/*'))\n const typesToMatch = types.filter(x => !extensionsToMatch.includes(x) && !wildcards.includes(x))\n\n return (file: File): boolean => {\n const extension = file.name.split('.').at(-1)?.toLowerCase() ?? ''\n const typeGroup = file.type.split('/').at(0)?.toLowerCase() ?? ''\n return typesToMatch.includes(file.type) ||\n extensionsToMatch.includes(`.${extension}`) ||\n wildcards.includes(`${typeGroup}/*`)\n }\n}\n"],"mappings":"AAAA;AACA,SAASA,QAAQ,QAAQ,KAAK;AAAA,SACrBC,YAAY;AAWrB;AACA,OAAO,MAAMC,mBAAmB,GAAGD,YAAY,CAAC;EAC9CE,YAAY,EAAEC;AAChB,CAAC,EAAE,aAAa,CAAC;AAEjB,OAAO,SAASC,aAAaA,CAAEC,KAAsB,EAAE;EACrD,MAAMC,UAAU,GAAGP,QAAQ,CAAC,MAAMM,KAAK,CAACH,YAAY,GAAGK,YAAY,CAACF,KAAK,CAACH,YAAY,CAAC,GAAG,IAAI,CAAC;EAE/F,SAASM,cAAcA,CAAEC,KAAa,EAAoB;IACxD,IAAIH,UAAU,CAACI,KAAK,EAAE;MACpB,MAAMC,QAAQ,GAAGF,KAAK,CAACG,MAAM,CAACN,UAAU,CAACI,KAAK,CAAC;MAC/C,OAAO;QACLC,QAAQ;QACRE,QAAQ,EAAEJ,KAAK,CAACG,MAAM,CAACE,CAAC,IAAI,CAACH,QAAQ,CAACI,QAAQ,CAACD,CAAC,CAAC;MACnD,CAAC;IACH;IACA,OAAO;MACLH,QAAQ,EAAEF,KAAK;MACfI,QAAQ,EAAE;IACZ,CAAC;EACH;EAEA,OAAO;IACLL;EACF,CAAC;AACH;AAEA,SAASD,YAAYA,CAAES,CAAS,EAA0B;EACxD,MAAMC,KAAK,GAAGD,CAAC,CAACE,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CAACC,CAAC,IAAIA,CAAC,CAACC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC,CAAC;EAC3D,MAAMC,iBAAiB,GAAGN,KAAK,CAACL,MAAM,CAACQ,CAAC,IAAIA,CAAC,CAACI,UAAU,CAAC,GAAG,CAAC,CAAC;EAC9D,MAAMC,SAAS,GAAGR,KAAK,CAACL,MAAM,CAACQ,CAAC,IAAIA,CAAC,CAACM,QAAQ,CAAC,IAAI,CAAC,CAAC;EACrD,MAAMC,YAAY,GAAGV,KAAK,CAACL,MAAM,CAACQ,CAAC,IAAI,CAACG,iBAAiB,CAACR,QAAQ,CAACK,CAAC,CAAC,IAAI,CAACK,SAAS,CAACV,QAAQ,CAACK,CAAC,CAAC,CAAC;EAEhG,OAAQQ,IAAU,IAAc;IAC9B,MAAMC,SAAS,GAAGD,IAAI,CAACE,IAAI,CAACZ,KAAK,CAAC,GAAG,CAAC,CAACa,EAAE,CAAC,CAAC,CAAC,CAAC,EAAET,WAAW,CAAC,CAAC,IAAI,EAAE;IAClE,MAAMU,SAAS,GAAGJ,IAAI,CAACK,IAAI,CAACf,KAAK,CAAC,GAAG,CAAC,CAACa,EAAE,CAAC,CAAC,CAAC,EAAET,WAAW,CAAC,CAAC,IAAI,EAAE;IACjE,OAAOK,YAAY,CAACZ,QAAQ,CAACa,IAAI,CAACK,IAAI,CAAC,IACrCV,iBAAiB,CAACR,QAAQ,CAAC,IAAIc,SAAS,EAAE,CAAC,IAC3CJ,SAAS,CAACV,QAAQ,CAAC,GAAGiB,SAAS,IAAI,CAAC;EACxC,CAAC;AACH","ignoreList":[]}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
import type { PropType, Ref } from 'vue';
|
||||
import type { MaybeRef } from '../util/index.js';
|
||||
/**
|
||||
* - boolean: match without highlight
|
||||
* - number: single match (index), length already known
|
||||
* - []: single match (start, end)
|
||||
* - [][]: multiple matches (start, end), shouldn't overlap
|
||||
*/
|
||||
export type FilterMatchArraySingle = readonly [number, number];
|
||||
export type FilterMatchArrayMultiple = readonly FilterMatchArraySingle[];
|
||||
export type FilterMatchArray = FilterMatchArraySingle | FilterMatchArrayMultiple;
|
||||
export type FilterMatch = boolean | number | FilterMatchArray;
|
||||
export type FilterFunction = (value: string, query: string, item?: InternalItem) => FilterMatch;
|
||||
export type FilterKeyFunctions = Record<string, FilterFunction>;
|
||||
export type FilterKeys = string | string[];
|
||||
export type FilterMode = 'some' | 'every' | 'union' | 'intersection';
|
||||
export interface FilterProps {
|
||||
customFilter?: FilterFunction;
|
||||
customKeyFilter?: FilterKeyFunctions;
|
||||
filterKeys?: FilterKeys;
|
||||
filterMode?: FilterMode;
|
||||
noFilter?: boolean;
|
||||
}
|
||||
export interface InternalItem<T = any> {
|
||||
value: any;
|
||||
raw: T;
|
||||
type?: string;
|
||||
}
|
||||
type FilterResult = {
|
||||
index: number;
|
||||
matches: Record<string, FilterMatchArrayMultiple | undefined>;
|
||||
type?: 'divider' | 'subheader';
|
||||
};
|
||||
export declare const defaultFilter: FilterFunction;
|
||||
export declare const makeFilterProps: <Defaults extends {
|
||||
customFilter?: unknown;
|
||||
customKeyFilter?: unknown;
|
||||
filterKeys?: unknown;
|
||||
filterMode?: unknown;
|
||||
noFilter?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
customFilter: unknown extends Defaults["customFilter"] ? PropType<FilterFunction> : {
|
||||
type: PropType<unknown extends Defaults["customFilter"] ? FilterFunction : FilterFunction | Defaults["customFilter"]>;
|
||||
default: unknown extends Defaults["customFilter"] ? FilterFunction : FilterFunction | Defaults["customFilter"];
|
||||
};
|
||||
customKeyFilter: unknown extends Defaults["customKeyFilter"] ? PropType<FilterKeyFunctions> : {
|
||||
type: PropType<unknown extends Defaults["customKeyFilter"] ? FilterKeyFunctions : FilterKeyFunctions | Defaults["customKeyFilter"]>;
|
||||
default: unknown extends Defaults["customKeyFilter"] ? FilterKeyFunctions : FilterKeyFunctions | Defaults["customKeyFilter"];
|
||||
};
|
||||
filterKeys: unknown extends Defaults["filterKeys"] ? PropType<FilterKeys> : {
|
||||
type: PropType<unknown extends Defaults["filterKeys"] ? FilterKeys : Defaults["filterKeys"] | FilterKeys>;
|
||||
default: unknown extends Defaults["filterKeys"] ? FilterKeys : Defaults["filterKeys"] | NonNullable<FilterKeys>;
|
||||
};
|
||||
filterMode: unknown extends Defaults["filterMode"] ? {
|
||||
type: PropType<FilterMode>;
|
||||
default: string;
|
||||
} : Omit<{
|
||||
type: PropType<FilterMode>;
|
||||
default: string;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["filterMode"] ? FilterMode : Defaults["filterMode"] | FilterMode>;
|
||||
default: unknown extends Defaults["filterMode"] ? FilterMode : Defaults["filterMode"] | NonNullable<FilterMode>;
|
||||
};
|
||||
noFilter: unknown extends Defaults["noFilter"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["noFilter"] ? boolean : boolean | Defaults["noFilter"]>;
|
||||
default: unknown extends Defaults["noFilter"] ? boolean : boolean | Defaults["noFilter"];
|
||||
};
|
||||
};
|
||||
export declare function filterItems(items: readonly (readonly [item: InternalItem, transformed: {}])[] | readonly InternalItem[], query: string, options?: {
|
||||
customKeyFilter?: FilterKeyFunctions;
|
||||
default?: FilterFunction;
|
||||
filterKeys?: FilterKeys;
|
||||
filterMode?: FilterMode;
|
||||
noFilter?: boolean;
|
||||
}): FilterResult[];
|
||||
export declare function useFilter<T extends InternalItem>(props: FilterProps, items: MaybeRef<T[]>, query: Ref<string | undefined> | (() => string | undefined), options?: {
|
||||
transform?: (item: T) => {};
|
||||
customKeyFilter?: MaybeRef<FilterKeyFunctions | undefined>;
|
||||
}): {
|
||||
filteredItems: import("vue").ShallowRef<T[], T[]>;
|
||||
filteredMatches: import("vue").ShallowRef<Map<unknown, Record<string, FilterMatchArrayMultiple | undefined>>, Map<unknown, Record<string, FilterMatchArrayMultiple | undefined>>>;
|
||||
getMatches: (item: T) => Record<string, FilterMatchArrayMultiple | undefined> | undefined;
|
||||
};
|
||||
export declare function highlightResult(name: string, text: string, matches: FilterMatchArrayMultiple | undefined): string | JSX.Element[];
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/* eslint-disable max-statements */
|
||||
/* eslint-disable no-labels */
|
||||
|
||||
// Utilities
|
||||
import { computed, shallowRef, unref, watchEffect, normalizeClass as _normalizeClass, createElementVNode as _createElementVNode, Fragment as _Fragment } from 'vue';
|
||||
import { getPropertyFromItem, propsFactory, wrapInArray } from "../util/index.js"; // Types
|
||||
/**
|
||||
* - boolean: match without highlight
|
||||
* - number: single match (index), length already known
|
||||
* - []: single match (start, end)
|
||||
* - [][]: multiple matches (start, end), shouldn't overlap
|
||||
*/
|
||||
// Composables
|
||||
export const defaultFilter = (value, query, item) => {
|
||||
if (value == null || query == null) return -1;
|
||||
if (!query.length) return 0;
|
||||
value = value.toString().toLocaleLowerCase();
|
||||
query = query.toString().toLocaleLowerCase();
|
||||
const result = [];
|
||||
let idx = value.indexOf(query);
|
||||
while (~idx) {
|
||||
result.push([idx, idx + query.length]);
|
||||
idx = value.indexOf(query, idx + query.length);
|
||||
}
|
||||
return result.length ? result : -1;
|
||||
};
|
||||
function normaliseMatch(match, query) {
|
||||
if (match == null || typeof match === 'boolean' || match === -1) return;
|
||||
if (typeof match === 'number') return [[match, match + query.length]];
|
||||
if (Array.isArray(match[0])) return match;
|
||||
return [match];
|
||||
}
|
||||
export const makeFilterProps = propsFactory({
|
||||
customFilter: Function,
|
||||
customKeyFilter: Object,
|
||||
filterKeys: [Array, String],
|
||||
filterMode: {
|
||||
type: String,
|
||||
default: 'intersection'
|
||||
},
|
||||
noFilter: Boolean
|
||||
}, 'filter');
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export function filterItems(items, query, options) {
|
||||
const array = [];
|
||||
// always ensure we fall back to a functioning filter
|
||||
const filter = options?.default ?? defaultFilter;
|
||||
const keys = options?.filterKeys ? wrapInArray(options.filterKeys) : false;
|
||||
const customFiltersLength = Object.keys(options?.customKeyFilter ?? {}).length;
|
||||
if (!items?.length) return array;
|
||||
let lookAheadItems = [];
|
||||
loop: for (let i = 0; i < items.length; i++) {
|
||||
const [item, transformed = item] = wrapInArray(items[i]);
|
||||
const customMatches = {};
|
||||
const defaultMatches = {};
|
||||
let match = -1;
|
||||
if ((query || customFiltersLength > 0) && !options?.noFilter) {
|
||||
let hasOnlyCustomFilters = false;
|
||||
if (typeof item === 'object') {
|
||||
if (item.type === 'divider' || item.type === 'subheader') {
|
||||
if (lookAheadItems.at(-1)?.type !== 'divider' || item.type !== 'subheader') {
|
||||
// clear unless, divider appears before subheader
|
||||
lookAheadItems = [];
|
||||
}
|
||||
lookAheadItems.push({
|
||||
index: i,
|
||||
matches: {},
|
||||
type: item.type
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const filterKeys = keys || Object.keys(transformed);
|
||||
hasOnlyCustomFilters = filterKeys.length === customFiltersLength;
|
||||
for (const key of filterKeys) {
|
||||
const value = getPropertyFromItem(transformed, key);
|
||||
const keyFilter = options?.customKeyFilter?.[key];
|
||||
match = keyFilter ? keyFilter(value, query, item) : filter(value, query, item);
|
||||
if (match !== -1 && match !== false) {
|
||||
if (keyFilter) customMatches[key] = normaliseMatch(match, query);else defaultMatches[key] = normaliseMatch(match, query);
|
||||
} else if (options?.filterMode === 'every') {
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match = filter(item, query, item);
|
||||
if (match !== -1 && match !== false) {
|
||||
defaultMatches.title = normaliseMatch(match, query);
|
||||
}
|
||||
}
|
||||
const defaultMatchesLength = Object.keys(defaultMatches).length;
|
||||
const customMatchesLength = Object.keys(customMatches).length;
|
||||
if (!defaultMatchesLength && !customMatchesLength) continue;
|
||||
if (options?.filterMode === 'union' && customMatchesLength !== customFiltersLength && !defaultMatchesLength) continue;
|
||||
if (options?.filterMode === 'intersection' && (customMatchesLength !== customFiltersLength || !defaultMatchesLength && customFiltersLength > 0 && !hasOnlyCustomFilters)) continue;
|
||||
}
|
||||
if (lookAheadItems.length) {
|
||||
array.push(...lookAheadItems);
|
||||
lookAheadItems = [];
|
||||
}
|
||||
array.push({
|
||||
index: i,
|
||||
matches: {
|
||||
...defaultMatches,
|
||||
...customMatches
|
||||
}
|
||||
});
|
||||
}
|
||||
return array;
|
||||
}
|
||||
export function useFilter(props, items, query, options) {
|
||||
const filteredItems = shallowRef([]);
|
||||
const filteredMatches = shallowRef(new Map());
|
||||
const transformedItems = computed(() => options?.transform ? unref(items).map(item => [item, options.transform(item)]) : unref(items));
|
||||
watchEffect(() => {
|
||||
const _query = typeof query === 'function' ? query() : unref(query);
|
||||
const strQuery = typeof _query !== 'string' && typeof _query !== 'number' ? '' : String(_query);
|
||||
const results = filterItems(transformedItems.value, strQuery, {
|
||||
customKeyFilter: {
|
||||
...props.customKeyFilter,
|
||||
...unref(options?.customKeyFilter)
|
||||
},
|
||||
default: props.customFilter,
|
||||
filterKeys: props.filterKeys,
|
||||
filterMode: props.filterMode,
|
||||
noFilter: props.noFilter
|
||||
});
|
||||
const originalItems = unref(items);
|
||||
const _filteredItems = [];
|
||||
const _filteredMatches = new Map();
|
||||
results.forEach(({
|
||||
index,
|
||||
matches
|
||||
}) => {
|
||||
const item = originalItems[index];
|
||||
_filteredItems.push(item);
|
||||
_filteredMatches.set(item.value, matches);
|
||||
});
|
||||
filteredItems.value = _filteredItems;
|
||||
filteredMatches.value = _filteredMatches;
|
||||
});
|
||||
function getMatches(item) {
|
||||
return filteredMatches.value.get(item.value);
|
||||
}
|
||||
return {
|
||||
filteredItems,
|
||||
filteredMatches,
|
||||
getMatches
|
||||
};
|
||||
}
|
||||
export function highlightResult(name, text, matches) {
|
||||
if (matches == null || !matches.length) return text;
|
||||
return matches.map((match, i) => {
|
||||
const start = i === 0 ? 0 : matches[i - 1][1];
|
||||
const result = [_createElementVNode("span", {
|
||||
"class": _normalizeClass(`${name}__unmask`)
|
||||
}, [text.slice(start, match[0])]), _createElementVNode("span", {
|
||||
"class": _normalizeClass(`${name}__mask`)
|
||||
}, [text.slice(match[0], match[1])])];
|
||||
if (i === matches.length - 1) {
|
||||
result.push(_createElementVNode("span", {
|
||||
"class": _normalizeClass(`${name}__unmask`)
|
||||
}, [text.slice(match[1])]));
|
||||
}
|
||||
return _createElementVNode(_Fragment, null, [result]);
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=filter.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+29
@@ -0,0 +1,29 @@
|
||||
export interface FocusProps {
|
||||
focused: boolean;
|
||||
'onUpdate:focused': ((focused: boolean) => any) | undefined;
|
||||
}
|
||||
export declare const makeFocusProps: <Defaults extends {
|
||||
focused?: unknown;
|
||||
'onUpdate:focused'?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
focused: unknown extends Defaults["focused"] ? BooleanConstructor : {
|
||||
type: import("vue").PropType<unknown extends Defaults["focused"] ? boolean : boolean | Defaults["focused"]>;
|
||||
default: unknown extends Defaults["focused"] ? boolean : boolean | Defaults["focused"];
|
||||
};
|
||||
'onUpdate:focused': unknown extends Defaults["onUpdate:focused"] ? import("vue").PropType<(args_0: boolean) => void> : {
|
||||
type: import("vue").PropType<unknown extends Defaults["onUpdate:focused"] ? (args_0: boolean) => void : ((args_0: boolean) => void) | Defaults["onUpdate:focused"]>;
|
||||
default: unknown extends Defaults["onUpdate:focused"] ? (args_0: boolean) => void : ((args_0: boolean) => void) | Defaults["onUpdate:focused"];
|
||||
};
|
||||
};
|
||||
export declare function useFocus(props: FocusProps, name?: string): {
|
||||
focusClasses: Readonly<import("vue").Ref<{
|
||||
[x: string]: boolean;
|
||||
}, {
|
||||
[x: string]: boolean;
|
||||
}>>;
|
||||
isFocused: import("vue").Ref<boolean, boolean> & {
|
||||
readonly externalValue: boolean;
|
||||
};
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
};
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Composables
|
||||
import { useProxiedModel } from "./proxiedModel.js"; // Utilities
|
||||
import { toRef } from 'vue';
|
||||
import { EventProp, getCurrentInstanceName, propsFactory } from "../util/index.js"; // Types
|
||||
// Composables
|
||||
export const makeFocusProps = propsFactory({
|
||||
focused: Boolean,
|
||||
'onUpdate:focused': EventProp()
|
||||
}, 'focus');
|
||||
export function useFocus(props, name = getCurrentInstanceName()) {
|
||||
const isFocused = useProxiedModel(props, 'focused');
|
||||
const focusClasses = toRef(() => {
|
||||
return {
|
||||
[`${name}--focused`]: isFocused.value
|
||||
};
|
||||
});
|
||||
function focus() {
|
||||
isFocused.value = true;
|
||||
}
|
||||
function blur() {
|
||||
isFocused.value = false;
|
||||
}
|
||||
return {
|
||||
focusClasses,
|
||||
isFocused,
|
||||
focus,
|
||||
blur
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=focus.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"focus.js","names":["useProxiedModel","toRef","EventProp","getCurrentInstanceName","propsFactory","makeFocusProps","focused","Boolean","useFocus","props","name","isFocused","focusClasses","value","focus","blur"],"sources":["../../src/composables/focus.ts"],"sourcesContent":["// Composables\nimport { useProxiedModel } from '@/composables/proxiedModel'\n\n// Utilities\nimport { toRef } from 'vue'\nimport { EventProp, getCurrentInstanceName, propsFactory } from '@/util'\n\n// Types\nexport interface FocusProps {\n focused: boolean\n 'onUpdate:focused': ((focused: boolean) => any) | undefined\n}\n\n// Composables\nexport const makeFocusProps = propsFactory({\n focused: Boolean,\n 'onUpdate:focused': EventProp<[boolean]>(),\n}, 'focus')\n\nexport function useFocus (\n props: FocusProps,\n name = getCurrentInstanceName()\n) {\n const isFocused = useProxiedModel(props, 'focused')\n const focusClasses = toRef(() => {\n return ({\n [`${name}--focused`]: isFocused.value,\n })\n })\n\n function focus () {\n isFocused.value = true\n }\n\n function blur () {\n isFocused.value = false\n }\n\n return { focusClasses, isFocused, focus, blur }\n}\n"],"mappings":"AAAA;AAAA,SACSA,eAAe,6BAExB;AACA,SAASC,KAAK,QAAQ,KAAK;AAAA,SAClBC,SAAS,EAAEC,sBAAsB,EAAEC,YAAY,4BAExD;AAMA;AACA,OAAO,MAAMC,cAAc,GAAGD,YAAY,CAAC;EACzCE,OAAO,EAAEC,OAAO;EAChB,kBAAkB,EAAEL,SAAS,CAAY;AAC3C,CAAC,EAAE,OAAO,CAAC;AAEX,OAAO,SAASM,QAAQA,CACtBC,KAAiB,EACjBC,IAAI,GAAGP,sBAAsB,CAAC,CAAC,EAC/B;EACA,MAAMQ,SAAS,GAAGX,eAAe,CAACS,KAAK,EAAE,SAAS,CAAC;EACnD,MAAMG,YAAY,GAAGX,KAAK,CAAC,MAAM;IAC/B,OAAQ;MACN,CAAC,GAAGS,IAAI,WAAW,GAAGC,SAAS,CAACE;IAClC,CAAC;EACH,CAAC,CAAC;EAEF,SAASC,KAAKA,CAAA,EAAI;IAChBH,SAAS,CAACE,KAAK,GAAG,IAAI;EACxB;EAEA,SAASE,IAAIA,CAAA,EAAI;IACfJ,SAAS,CAACE,KAAK,GAAG,KAAK;EACzB;EAEA,OAAO;IAAED,YAAY;IAAED,SAAS;IAAEG,KAAK;IAAEC;EAAK,CAAC;AACjD","ignoreList":[]}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import type { MaybeRefOrGetter, Ref } from 'vue';
|
||||
import type { VList } from '../components/VList/index.js';
|
||||
type FocusGroup = {
|
||||
type: 'list';
|
||||
contentRef: Ref<VList | undefined>;
|
||||
displayItemsCount: MaybeRefOrGetter<number>;
|
||||
} | {
|
||||
type: 'element';
|
||||
contentRef: Ref<HTMLElement | undefined>;
|
||||
};
|
||||
export declare function useFocusGroups({ groups, onLeave }: {
|
||||
groups: FocusGroup[];
|
||||
onLeave: () => void;
|
||||
}): {
|
||||
onTabKeydown: (e: KeyboardEvent) => void;
|
||||
};
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// Utilities
|
||||
import { toValue } from 'vue';
|
||||
import { focusableChildren } from "../util/index.js"; // Types
|
||||
export function useFocusGroups({
|
||||
groups,
|
||||
onLeave
|
||||
}) {
|
||||
function getContentRef(group) {
|
||||
return group.type === 'list' ? group.contentRef.value?.$el : group.contentRef.value;
|
||||
}
|
||||
function getChildren(group) {
|
||||
const contentRef = getContentRef(group);
|
||||
return contentRef ? focusableChildren(contentRef) : [];
|
||||
}
|
||||
function onTabKeydown(e) {
|
||||
const target = e.target;
|
||||
const direction = e.shiftKey ? 'backward' : 'forward';
|
||||
const children = groups.map(getChildren);
|
||||
const currentGroupIndex = groups.map(g => g.type === 'list' ? g.contentRef.value?.$el : g.contentRef.value).findIndex(el => el?.contains(target));
|
||||
const nextIndex = nextFocusGroup(children, currentGroupIndex, direction, target);
|
||||
if (nextIndex === null) {
|
||||
const originGroup = groups[currentGroupIndex];
|
||||
const origin = children[currentGroupIndex];
|
||||
const isListGroup = originGroup.type === 'list';
|
||||
const atEdge = isListGroup || (direction === 'forward' ? origin.at(-1) === e.target : origin.at(0) === e.target);
|
||||
if (atEdge) {
|
||||
onLeave();
|
||||
}
|
||||
} else {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
const nextGroup = groups[nextIndex];
|
||||
if (nextGroup.type === 'list' && toValue(nextGroup.displayItemsCount) > 0) {
|
||||
nextGroup.contentRef.value?.focus(0);
|
||||
} else {
|
||||
const fromBefore = direction === 'forward';
|
||||
children[nextIndex].at(fromBefore ? 0 : -1).focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
function nextFocusGroup(children, currentIndex, direction, target) {
|
||||
const originGroup = groups[currentIndex];
|
||||
const origin = children[currentIndex];
|
||||
|
||||
// List groups always allow leaving (VList manages internal focus)
|
||||
// Element groups require being at the edge focusable child
|
||||
if (originGroup.type !== 'list') {
|
||||
const isAtEdge = direction === 'forward' ? origin.at(-1) === target : origin.at(0) === target;
|
||||
if (!isAtEdge) return null;
|
||||
}
|
||||
const step = direction === 'forward' ? 1 : -1;
|
||||
for (let i = currentIndex + step; i >= 0 && i < groups.length; i += step) {
|
||||
const group = groups[i];
|
||||
if (children[i].length > 0 || group.type === 'list' && toValue(group.displayItemsCount) > 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
onTabKeydown
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=focusGroups.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+30
@@ -0,0 +1,30 @@
|
||||
import type { Ref } from 'vue';
|
||||
export interface FocusTrapProps {
|
||||
retainFocus: boolean;
|
||||
captureFocus: boolean;
|
||||
disableInitialFocus?: boolean;
|
||||
}
|
||||
export declare const makeFocusTrapProps: <Defaults extends {
|
||||
retainFocus?: unknown;
|
||||
captureFocus?: unknown;
|
||||
disableInitialFocus?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
retainFocus: unknown extends Defaults["retainFocus"] ? BooleanConstructor : {
|
||||
type: import("vue").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: import("vue").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: import("vue").PropType<unknown extends Defaults["disableInitialFocus"] ? boolean : boolean | Defaults["disableInitialFocus"]>;
|
||||
default: unknown extends Defaults["disableInitialFocus"] ? boolean : boolean | Defaults["disableInitialFocus"];
|
||||
};
|
||||
};
|
||||
export declare function useFocusTrap(props: FocusTrapProps, { isActive, localTop, activatorEl, contentEl }: {
|
||||
isActive: Ref<boolean>;
|
||||
localTop: Readonly<Ref<boolean>>;
|
||||
activatorEl?: Readonly<Ref<HTMLElement | undefined>>;
|
||||
contentEl: Readonly<Ref<HTMLElement | undefined>>;
|
||||
}): void;
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
// Utilities
|
||||
import { nextTick, onScopeDispose, toRef, toValue, watch } from 'vue';
|
||||
import { focusableChildren, IN_BROWSER, propsFactory } from "../util/index.js"; // Types
|
||||
// Types
|
||||
// Composables
|
||||
export const makeFocusTrapProps = propsFactory({
|
||||
retainFocus: Boolean,
|
||||
captureFocus: Boolean,
|
||||
/** @deprecated */
|
||||
disableInitialFocus: Boolean
|
||||
}, 'focusTrap');
|
||||
const registry = new Map();
|
||||
let subscribers = 0;
|
||||
function onKeydown(e) {
|
||||
const activeElement = document.activeElement;
|
||||
if (e.key !== 'Tab' || !activeElement) return;
|
||||
const parentTraps = Array.from(registry.values()).filter(({
|
||||
isActive,
|
||||
contentEl
|
||||
}) => isActive.value && contentEl.value?.contains(activeElement)).map(x => x.contentEl.value);
|
||||
let closestTrap;
|
||||
let currentParent = activeElement.parentElement;
|
||||
while (currentParent) {
|
||||
if (parentTraps.includes(currentParent)) {
|
||||
closestTrap = currentParent;
|
||||
break;
|
||||
}
|
||||
currentParent = currentParent.parentElement;
|
||||
}
|
||||
if (!closestTrap) return;
|
||||
const focusable = focusableChildren(closestTrap)
|
||||
// excluding VListItems with tabindex="-2"
|
||||
.filter(x => x.tabIndex >= 0);
|
||||
if (!focusable.length) return;
|
||||
const active = document.activeElement;
|
||||
if (focusable.length === 1 && focusable[0].classList.contains('v-list') && focusable[0].contains(active)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
const firstElement = focusable[0];
|
||||
const lastElement = focusable[focusable.length - 1];
|
||||
if (e.shiftKey && (active === firstElement || firstElement.classList.contains('v-list') && firstElement.contains(active))) {
|
||||
e.preventDefault();
|
||||
lastElement.focus();
|
||||
}
|
||||
if (!e.shiftKey && (active === lastElement || lastElement.classList.contains('v-list') && lastElement.contains(active))) {
|
||||
e.preventDefault();
|
||||
firstElement.focus();
|
||||
}
|
||||
}
|
||||
export function useFocusTrap(props, {
|
||||
isActive,
|
||||
localTop,
|
||||
activatorEl,
|
||||
contentEl
|
||||
}) {
|
||||
const trapId = Symbol('trap');
|
||||
let focusTrapSuppressed = false;
|
||||
let focusTrapSuppressionTimeout = -1;
|
||||
async function onPointerdown() {
|
||||
focusTrapSuppressed = true;
|
||||
focusTrapSuppressionTimeout = window.setTimeout(() => {
|
||||
focusTrapSuppressed = false;
|
||||
}, 100);
|
||||
}
|
||||
async function captureOnFocus(e) {
|
||||
const before = e.relatedTarget;
|
||||
const after = e.target;
|
||||
document.removeEventListener('pointerdown', onPointerdown);
|
||||
document.removeEventListener('keydown', captureOnKeydown);
|
||||
await nextTick();
|
||||
if (isActive.value && !focusTrapSuppressed && before !== after && contentEl.value &&
|
||||
// We're the menu without open submenus or overlays
|
||||
toValue(localTop) &&
|
||||
// It isn't the document or the container body
|
||||
![document, contentEl.value].includes(after) &&
|
||||
// It isn't inside the container body
|
||||
!contentEl.value.contains(after)) {
|
||||
const focusable = focusableChildren(contentEl.value);
|
||||
focusable[0]?.focus();
|
||||
}
|
||||
}
|
||||
function captureOnKeydown(e) {
|
||||
if (e.key !== 'Tab') return;
|
||||
document.removeEventListener('keydown', captureOnKeydown);
|
||||
if (isActive.value && contentEl.value && e.target && !contentEl.value.contains(e.target)) {
|
||||
const allFocusableElements = focusableChildren(document.documentElement);
|
||||
if (e.shiftKey && e.target === allFocusableElements.at(0) || !e.shiftKey && e.target === allFocusableElements.at(-1)) {
|
||||
const focusable = focusableChildren(contentEl.value);
|
||||
if (focusable.length > 0) {
|
||||
e.preventDefault();
|
||||
focusable[0].focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const shouldCapture = toRef(() => isActive.value && props.captureFocus && !props.disableInitialFocus);
|
||||
if (IN_BROWSER) {
|
||||
watch(() => props.retainFocus, val => {
|
||||
if (val) {
|
||||
registry.set(trapId, {
|
||||
isActive,
|
||||
contentEl
|
||||
});
|
||||
} else {
|
||||
registry.delete(trapId);
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
});
|
||||
watch(shouldCapture, val => {
|
||||
if (val) {
|
||||
document.addEventListener('pointerdown', onPointerdown);
|
||||
document.addEventListener('focusin', captureOnFocus, {
|
||||
once: true
|
||||
});
|
||||
document.addEventListener('keydown', captureOnKeydown);
|
||||
} else {
|
||||
document.removeEventListener('pointerdown', onPointerdown);
|
||||
document.removeEventListener('focusin', captureOnFocus);
|
||||
document.removeEventListener('keydown', captureOnKeydown);
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
});
|
||||
if (subscribers++ < 1) {
|
||||
document.addEventListener('keydown', onKeydown);
|
||||
}
|
||||
}
|
||||
onScopeDispose(() => {
|
||||
registry.delete(trapId);
|
||||
if (!IN_BROWSER) return;
|
||||
clearTimeout(focusTrapSuppressionTimeout);
|
||||
document.removeEventListener('pointerdown', onPointerdown);
|
||||
document.removeEventListener('focusin', captureOnFocus);
|
||||
document.removeEventListener('keydown', captureOnKeydown);
|
||||
if (--subscribers < 1) {
|
||||
document.removeEventListener('keydown', onKeydown);
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=focusTrap.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+149
@@ -0,0 +1,149 @@
|
||||
import type { ComponentInternalInstance, InjectionKey, PropType, Raw, Ref } from 'vue';
|
||||
import type { ValidationProps } from './validation.js';
|
||||
import type { EventProp } from '../util/index.js';
|
||||
export interface FormProvide {
|
||||
register: (item: {
|
||||
id: number | string;
|
||||
vm: ComponentInternalInstance;
|
||||
validate: () => Promise<string[]>;
|
||||
reset: () => Promise<void>;
|
||||
resetValidation: () => Promise<void>;
|
||||
}) => void;
|
||||
unregister: (id: number | string) => void;
|
||||
update: (id: number | string, isValid: boolean | null, errorMessages: string[]) => void;
|
||||
items: Ref<FormField[]>;
|
||||
isDisabled: Readonly<Ref<boolean>>;
|
||||
isReadonly: Readonly<Ref<boolean>>;
|
||||
isValidating: Ref<boolean>;
|
||||
isValid: Ref<boolean | null>;
|
||||
validateOn: Ref<FormProps['validateOn']>;
|
||||
}
|
||||
export interface FormField {
|
||||
id: number | string;
|
||||
validate: () => Promise<string[]>;
|
||||
reset: () => Promise<void>;
|
||||
resetValidation: () => Promise<void>;
|
||||
vm: Raw<ComponentInternalInstance>;
|
||||
isValid: boolean | null;
|
||||
errorMessages: string[];
|
||||
}
|
||||
export interface FieldValidationResult {
|
||||
id: number | string;
|
||||
errorMessages: string[];
|
||||
}
|
||||
export interface FormValidationResult {
|
||||
valid: boolean;
|
||||
errors: FieldValidationResult[];
|
||||
}
|
||||
export interface SubmitEventPromise extends SubmitEvent, Promise<FormValidationResult> {
|
||||
}
|
||||
export declare const FormKey: InjectionKey<FormProvide>;
|
||||
export interface FormProps {
|
||||
disabled: boolean;
|
||||
fastFail: boolean;
|
||||
readonly: boolean;
|
||||
modelValue: boolean | null;
|
||||
'onUpdate:modelValue': EventProp<[boolean | null]> | undefined;
|
||||
validateOn: ValidationProps['validateOn'];
|
||||
}
|
||||
export declare const makeFormProps: <Defaults extends {
|
||||
disabled?: unknown;
|
||||
fastFail?: unknown;
|
||||
readonly?: unknown;
|
||||
modelValue?: unknown;
|
||||
validateOn?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
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"];
|
||||
};
|
||||
fastFail: unknown extends Defaults["fastFail"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["fastFail"] ? boolean : boolean | Defaults["fastFail"]>;
|
||||
default: unknown extends Defaults["fastFail"] ? boolean : boolean | Defaults["fastFail"];
|
||||
};
|
||||
readonly: unknown extends Defaults["readonly"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"]>;
|
||||
default: unknown extends Defaults["readonly"] ? boolean : boolean | Defaults["readonly"];
|
||||
};
|
||||
modelValue: unknown extends Defaults["modelValue"] ? {
|
||||
type: PropType<boolean | null>;
|
||||
default: null;
|
||||
} : Omit<{
|
||||
type: PropType<boolean | null>;
|
||||
default: null;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["modelValue"] ? boolean | null : boolean | Defaults["modelValue"] | null>;
|
||||
default: unknown extends Defaults["modelValue"] ? boolean | null : Defaults["modelValue"] | NonNullable<boolean | null>;
|
||||
};
|
||||
validateOn: unknown extends Defaults["validateOn"] ? {
|
||||
type: PropType<FormProps['validateOn']>;
|
||||
default: string;
|
||||
} : Omit<{
|
||||
type: PropType<FormProps['validateOn']>;
|
||||
default: string;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["validateOn"] ? ("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined : Defaults["validateOn"] | ("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined>;
|
||||
default: unknown extends Defaults["validateOn"] ? ("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined : Defaults["validateOn"] | NonNullable<("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined>;
|
||||
};
|
||||
};
|
||||
export declare function createForm(props: FormProps): {
|
||||
errors: Ref<{
|
||||
id: number | string;
|
||||
errorMessages: string[];
|
||||
}[], FieldValidationResult[] | {
|
||||
id: number | string;
|
||||
errorMessages: string[];
|
||||
}[]>;
|
||||
isDisabled: Readonly<Ref<boolean, boolean>>;
|
||||
isReadonly: Readonly<Ref<boolean, boolean>>;
|
||||
isValidating: import("vue").ShallowRef<boolean, boolean>;
|
||||
isValid: Ref<boolean | null, boolean | null> & {
|
||||
readonly externalValue: boolean | null;
|
||||
};
|
||||
items: Ref<{
|
||||
id: number | string;
|
||||
validate: () => Promise<string[]>;
|
||||
reset: () => Promise<void>;
|
||||
resetValidation: () => Promise<void>;
|
||||
vm: Raw<ComponentInternalInstance>;
|
||||
isValid: boolean | null;
|
||||
errorMessages: string[];
|
||||
}[], FormField[] | {
|
||||
id: number | string;
|
||||
validate: () => Promise<string[]>;
|
||||
reset: () => Promise<void>;
|
||||
resetValidation: () => Promise<void>;
|
||||
vm: Raw<ComponentInternalInstance>;
|
||||
isValid: boolean | null;
|
||||
errorMessages: string[];
|
||||
}[]>;
|
||||
validate: () => Promise<{
|
||||
valid: boolean;
|
||||
errors: {
|
||||
id: number | string;
|
||||
errorMessages: string[];
|
||||
}[];
|
||||
}>;
|
||||
reset: () => void;
|
||||
resetValidation: () => void;
|
||||
};
|
||||
export declare function useForm(props?: {
|
||||
readonly: boolean | null;
|
||||
disabled: boolean | null;
|
||||
}): {
|
||||
register?: ((item: {
|
||||
id: number | string;
|
||||
vm: ComponentInternalInstance;
|
||||
validate: () => Promise<string[]>;
|
||||
reset: () => Promise<void>;
|
||||
resetValidation: () => Promise<void>;
|
||||
}) => void) | undefined;
|
||||
unregister?: ((id: number | string) => void) | undefined;
|
||||
update?: ((id: number | string, isValid: boolean | null, errorMessages: string[]) => void) | undefined;
|
||||
items?: Ref<FormField[], FormField[]> | undefined;
|
||||
isValidating?: Ref<boolean, boolean> | undefined;
|
||||
isValid?: Ref<boolean | null, boolean | null> | undefined;
|
||||
validateOn?: Ref<("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined, ("blur eager" | "blur lazy" | "eager" | "eager blur" | "eager input" | "eager invalid-input" | "eager submit" | "input eager" | "input lazy" | "invalid-input eager" | "invalid-input lazy" | "lazy" | "lazy blur" | "lazy input" | "lazy invalid-input" | "lazy submit" | "submit eager" | "submit lazy" | ("blur" | "input" | "invalid-input" | "submit")) | undefined> | undefined;
|
||||
isReadonly: import("vue").ComputedRef<boolean>;
|
||||
isDisabled: import("vue").ComputedRef<boolean>;
|
||||
};
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
// Composables
|
||||
import { useProxiedModel } from "./proxiedModel.js"; // Utilities
|
||||
import { computed, inject, markRaw, provide, ref, shallowRef, toRef, watch } from 'vue';
|
||||
import { consoleWarn, propsFactory } from "../util/index.js"; // Types
|
||||
export const FormKey = Symbol.for('vuetify:form');
|
||||
export const makeFormProps = propsFactory({
|
||||
disabled: Boolean,
|
||||
fastFail: Boolean,
|
||||
readonly: Boolean,
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
},
|
||||
validateOn: {
|
||||
type: String,
|
||||
default: 'input'
|
||||
}
|
||||
}, 'form');
|
||||
export function createForm(props) {
|
||||
const model = useProxiedModel(props, 'modelValue');
|
||||
const isDisabled = toRef(() => props.disabled);
|
||||
const isReadonly = toRef(() => props.readonly);
|
||||
const isValidating = shallowRef(false);
|
||||
const items = ref([]);
|
||||
const errors = ref([]);
|
||||
async function validate() {
|
||||
const results = [];
|
||||
let valid = true;
|
||||
errors.value = [];
|
||||
isValidating.value = true;
|
||||
for (const item of items.value) {
|
||||
const itemErrorMessages = await item.validate();
|
||||
if (itemErrorMessages.length > 0) {
|
||||
valid = false;
|
||||
results.push({
|
||||
id: item.id,
|
||||
errorMessages: itemErrorMessages
|
||||
});
|
||||
}
|
||||
if (!valid && props.fastFail) break;
|
||||
}
|
||||
errors.value = results;
|
||||
isValidating.value = false;
|
||||
return {
|
||||
valid,
|
||||
errors: errors.value
|
||||
};
|
||||
}
|
||||
function reset() {
|
||||
items.value.forEach(item => item.reset());
|
||||
}
|
||||
function resetValidation() {
|
||||
items.value.forEach(item => item.resetValidation());
|
||||
}
|
||||
watch(items, () => {
|
||||
let valid = 0;
|
||||
let invalid = 0;
|
||||
const results = [];
|
||||
for (const item of items.value) {
|
||||
if (item.isValid === false) {
|
||||
invalid++;
|
||||
results.push({
|
||||
id: item.id,
|
||||
errorMessages: item.errorMessages
|
||||
});
|
||||
} else if (item.isValid === true) valid++;
|
||||
}
|
||||
errors.value = results;
|
||||
model.value = invalid > 0 ? false : valid === items.value.length ? true : null;
|
||||
}, {
|
||||
deep: true,
|
||||
flush: 'post'
|
||||
});
|
||||
provide(FormKey, {
|
||||
register: ({
|
||||
id,
|
||||
vm,
|
||||
validate,
|
||||
reset,
|
||||
resetValidation
|
||||
}) => {
|
||||
if (items.value.some(item => item.id === id)) {
|
||||
consoleWarn(`Duplicate input name "${id}"`);
|
||||
}
|
||||
items.value.push({
|
||||
id,
|
||||
validate,
|
||||
reset,
|
||||
resetValidation,
|
||||
vm: markRaw(vm),
|
||||
isValid: null,
|
||||
errorMessages: []
|
||||
});
|
||||
},
|
||||
unregister: id => {
|
||||
items.value = items.value.filter(item => {
|
||||
return item.id !== id;
|
||||
});
|
||||
},
|
||||
update: (id, isValid, errorMessages) => {
|
||||
const found = items.value.find(item => item.id === id);
|
||||
if (!found) return;
|
||||
found.isValid = isValid;
|
||||
found.errorMessages = errorMessages;
|
||||
},
|
||||
isDisabled,
|
||||
isReadonly,
|
||||
isValidating,
|
||||
isValid: model,
|
||||
items,
|
||||
validateOn: toRef(() => props.validateOn)
|
||||
});
|
||||
return {
|
||||
errors,
|
||||
isDisabled,
|
||||
isReadonly,
|
||||
isValidating,
|
||||
isValid: model,
|
||||
items,
|
||||
validate,
|
||||
reset,
|
||||
resetValidation
|
||||
};
|
||||
}
|
||||
export function useForm(props) {
|
||||
const form = inject(FormKey, null);
|
||||
return {
|
||||
...form,
|
||||
isReadonly: computed(() => !!(props?.readonly ?? form?.isReadonly.value)),
|
||||
isDisabled: computed(() => !!(props?.disabled ?? form?.isDisabled.value))
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=form.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
||||
import type { ComponentOptionsBase, ComponentPublicInstance, Ref, UnwrapRef } from 'vue';
|
||||
import type { NonEmptyArray, UnionToIntersection } from '../util/index.js';
|
||||
/** Omit properties starting with P */
|
||||
type OmitPrefix<T, P extends string, E = Extract<keyof T, `${P}${any}`>> = [E] extends [never] ? T : Omit<T, `${P}${any}`>;
|
||||
type OmitPrivate<T> = OmitPrefix<T, '$'>;
|
||||
/** Omit keyof $props from T */
|
||||
type OmitProps<T> = T extends {
|
||||
$props: any;
|
||||
} ? Omit<T, keyof T['$props']> : T;
|
||||
export declare function forwardRefs<T extends {}, U extends NonEmptyArray<Ref<HTMLElement | Omit<ComponentPublicInstance, '$emit' | '$slots'> | undefined>>, UU = {
|
||||
[K in keyof U]: NonNullable<UnwrapRef<U[K]>>;
|
||||
}[number], UC = {
|
||||
[K in keyof U]: OmitPrivate<OmitProps<NonNullable<UnwrapRef<U[K]>>>>;
|
||||
}[number], R = T & UnionToIntersection<UC> & {
|
||||
_allExposed: T | (UU extends {
|
||||
$options: infer O;
|
||||
} ? O extends ComponentOptionsBase<any, infer E, any, any, any, any, any, any> ? E : never : never);
|
||||
}>(target: T, ...refs: U): R;
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
// Types
|
||||
|
||||
const Refs = Symbol('Forwarded refs');
|
||||
|
||||
/** Omit properties starting with P */
|
||||
|
||||
/** Omit keyof $props from T */
|
||||
|
||||
function getDescriptor(obj, key) {
|
||||
let currentObj = obj;
|
||||
while (currentObj) {
|
||||
const descriptor = Reflect.getOwnPropertyDescriptor(currentObj, key);
|
||||
if (descriptor) return descriptor;
|
||||
currentObj = Object.getPrototypeOf(currentObj);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function forwardRefs(target, ...refs) {
|
||||
target[Refs] = refs;
|
||||
return new Proxy(target, {
|
||||
get(target, key) {
|
||||
if (Reflect.has(target, key)) {
|
||||
return Reflect.get(target, key);
|
||||
}
|
||||
|
||||
// Skip internal properties
|
||||
if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return;
|
||||
for (const ref of refs) {
|
||||
if (ref.value && Reflect.has(ref.value, key)) {
|
||||
const val = Reflect.get(ref.value, key);
|
||||
return typeof val === 'function' ? val.bind(ref.value) : val;
|
||||
}
|
||||
}
|
||||
},
|
||||
has(target, key) {
|
||||
if (Reflect.has(target, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip internal properties
|
||||
if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return false;
|
||||
for (const ref of refs) {
|
||||
if (ref.value && Reflect.has(ref.value, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
set(target, key, value) {
|
||||
if (Reflect.has(target, key)) {
|
||||
return Reflect.set(target, key, value);
|
||||
}
|
||||
|
||||
// Skip internal properties
|
||||
if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return false;
|
||||
for (const ref of refs) {
|
||||
if (ref.value && Reflect.has(ref.value, key)) {
|
||||
return Reflect.set(ref.value, key, value);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getOwnPropertyDescriptor(target, key) {
|
||||
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
||||
if (descriptor) return descriptor;
|
||||
|
||||
// Skip internal properties
|
||||
if (typeof key === 'symbol' || key.startsWith('$') || key.startsWith('__')) return;
|
||||
|
||||
// Check each ref's own properties
|
||||
for (const ref of refs) {
|
||||
if (!ref.value) continue;
|
||||
const descriptor = getDescriptor(ref.value, key) ?? ('_' in ref.value ? getDescriptor(ref.value._?.setupState, key) : undefined);
|
||||
if (descriptor) return descriptor;
|
||||
}
|
||||
|
||||
// Recursive search up each ref's prototype
|
||||
for (const ref of refs) {
|
||||
const childRefs = ref.value && ref.value[Refs];
|
||||
if (!childRefs) continue;
|
||||
const queue = childRefs.slice();
|
||||
while (queue.length) {
|
||||
const ref = queue.shift();
|
||||
const descriptor = getDescriptor(ref.value, key);
|
||||
if (descriptor) return descriptor;
|
||||
const childRefs = ref.value && ref.value[Refs];
|
||||
if (childRefs) queue.push(...childRefs);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=forwardRefs.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+23
@@ -0,0 +1,23 @@
|
||||
import type { ComponentPublicInstance, InjectionKey, Ref } from 'vue';
|
||||
import type { LocaleInstance, RtlInstance } from './locale.js';
|
||||
import type { EasingFunction } from '../util/index.js';
|
||||
export interface GoToInstance {
|
||||
rtl: Ref<boolean>;
|
||||
options: InternalGoToOptions;
|
||||
}
|
||||
export interface InternalGoToOptions {
|
||||
container: ComponentPublicInstance | HTMLElement | string;
|
||||
duration: number;
|
||||
layout: boolean;
|
||||
offset: number;
|
||||
easing: string | EasingFunction;
|
||||
patterns: Record<string, EasingFunction>;
|
||||
}
|
||||
export type GoToOptions = Partial<InternalGoToOptions>;
|
||||
export declare const GoToSymbol: InjectionKey<GoToInstance>;
|
||||
export declare function createGoTo(options: GoToOptions | undefined, locale: LocaleInstance & RtlInstance): GoToInstance;
|
||||
export declare function scrollTo(_target: ComponentPublicInstance | HTMLElement | number | string, _options: GoToOptions, horizontal?: boolean, goTo?: GoToInstance): Promise<unknown>;
|
||||
export declare function useGoTo(_options?: GoToOptions): {
|
||||
(target: ComponentPublicInstance | HTMLElement | string | number, options?: Partial<GoToOptions>): Promise<unknown>;
|
||||
horizontal: (target: ComponentPublicInstance | HTMLElement | string | number, options?: Partial<GoToOptions>) => Promise<unknown>;
|
||||
};
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
// Utilities
|
||||
import { inject, toRef } from 'vue';
|
||||
import { useRtl } from "./locale.js";
|
||||
import { clamp, consoleWarn, easingPatterns, mergeDeep, PREFERS_REDUCED_MOTION, refElement } from "../util/index.js"; // Types
|
||||
export const GoToSymbol = Symbol.for('vuetify:goto');
|
||||
function genDefaults() {
|
||||
return {
|
||||
container: undefined,
|
||||
duration: 300,
|
||||
layout: false,
|
||||
offset: 0,
|
||||
easing: 'easeInOutCubic',
|
||||
patterns: easingPatterns
|
||||
};
|
||||
}
|
||||
function getContainer(el) {
|
||||
return getTarget(el) ?? (document.scrollingElement || document.body);
|
||||
}
|
||||
function getTarget(el) {
|
||||
return typeof el === 'string' ? document.querySelector(el) : refElement(el);
|
||||
}
|
||||
function getOffset(target, horizontal, rtl) {
|
||||
if (typeof target === 'number') return horizontal && rtl ? -target : target;
|
||||
let el = getTarget(target);
|
||||
let totalOffset = 0;
|
||||
while (el) {
|
||||
totalOffset += horizontal ? el.offsetLeft : el.offsetTop;
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return totalOffset;
|
||||
}
|
||||
export function createGoTo(options, locale) {
|
||||
return {
|
||||
rtl: locale.isRtl,
|
||||
options: mergeDeep(genDefaults(), options)
|
||||
};
|
||||
}
|
||||
export async function scrollTo(_target, _options, horizontal, goTo) {
|
||||
const property = horizontal ? 'scrollLeft' : 'scrollTop';
|
||||
const options = mergeDeep(goTo?.options ?? genDefaults(), _options);
|
||||
const rtl = goTo?.rtl.value;
|
||||
const target = (typeof _target === 'number' ? _target : getTarget(_target)) ?? 0;
|
||||
const container = options.container === 'parent' && target instanceof HTMLElement ? target.parentElement : getContainer(options.container);
|
||||
const ease = PREFERS_REDUCED_MOTION() ? options.patterns.instant : typeof options.easing === 'function' ? options.easing : options.patterns[options.easing];
|
||||
if (!ease) throw new TypeError(`Easing function "${options.easing}" not found.`);
|
||||
let targetLocation;
|
||||
if (typeof target === 'number') {
|
||||
targetLocation = getOffset(target, horizontal, rtl);
|
||||
} else {
|
||||
targetLocation = getOffset(target, horizontal, rtl) - getOffset(container, horizontal, rtl);
|
||||
if (options.layout) {
|
||||
const styles = window.getComputedStyle(target);
|
||||
const layoutOffset = styles.getPropertyValue('--v-layout-top');
|
||||
if (layoutOffset) targetLocation -= parseInt(layoutOffset, 10);
|
||||
}
|
||||
}
|
||||
targetLocation += options.offset;
|
||||
targetLocation = clampTarget(container, targetLocation, !!rtl, !!horizontal);
|
||||
const startLocation = container[property] ?? 0;
|
||||
if (targetLocation === startLocation) return Promise.resolve(targetLocation);
|
||||
const startTime = performance.now();
|
||||
return new Promise(resolve => requestAnimationFrame(function step(currentTime) {
|
||||
const timeElapsed = currentTime - startTime;
|
||||
const progress = timeElapsed / options.duration;
|
||||
const location = Math.floor(startLocation + (targetLocation - startLocation) * ease(clamp(progress, 0, 1)));
|
||||
container[property] = location;
|
||||
|
||||
// Allow for some jitter if target time has elapsed
|
||||
if (progress >= 1 && Math.abs(location - container[property]) < 10) {
|
||||
return resolve(targetLocation);
|
||||
} else if (progress > 2) {
|
||||
// The target might not be reachable
|
||||
consoleWarn('Scroll target is not reachable');
|
||||
return resolve(container[property]);
|
||||
}
|
||||
requestAnimationFrame(step);
|
||||
}));
|
||||
}
|
||||
export function useGoTo(_options = {}) {
|
||||
const goToInstance = inject(GoToSymbol);
|
||||
const {
|
||||
isRtl
|
||||
} = useRtl();
|
||||
if (!goToInstance) throw new Error('[Vuetify] Could not find injected goto instance');
|
||||
const goTo = {
|
||||
...goToInstance,
|
||||
// can be set via VLocaleProvider
|
||||
rtl: toRef(() => goToInstance.rtl.value || isRtl.value)
|
||||
};
|
||||
async function go(target, options) {
|
||||
return scrollTo(target, mergeDeep(_options, options), false, goTo);
|
||||
}
|
||||
go.horizontal = async (target, options) => {
|
||||
return scrollTo(target, mergeDeep(_options, options), true, goTo);
|
||||
};
|
||||
return go;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp target value to achieve a smooth scroll animation
|
||||
* when the value goes outside the scroll container size
|
||||
*/
|
||||
function clampTarget(container, value, rtl, horizontal) {
|
||||
const {
|
||||
scrollWidth,
|
||||
scrollHeight
|
||||
} = container;
|
||||
const [containerWidth, containerHeight] = container === document.scrollingElement ? [window.innerWidth, window.innerHeight] : [container.offsetWidth, container.offsetHeight];
|
||||
let min;
|
||||
let max;
|
||||
if (horizontal) {
|
||||
if (rtl) {
|
||||
min = -(scrollWidth - containerWidth);
|
||||
max = 0;
|
||||
} else {
|
||||
min = 0;
|
||||
max = scrollWidth - containerWidth;
|
||||
}
|
||||
} else {
|
||||
min = 0;
|
||||
max = scrollHeight + -containerHeight;
|
||||
}
|
||||
return clamp(value, min, max);
|
||||
}
|
||||
//# sourceMappingURL=goto.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+113
@@ -0,0 +1,113 @@
|
||||
import type { ComponentInternalInstance, ExtractPropTypes, InjectionKey, PropType, Ref } from 'vue';
|
||||
import type { EventProp } from '../util/index.js';
|
||||
export interface GroupItem {
|
||||
id: string;
|
||||
value: Ref<unknown>;
|
||||
disabled: Ref<boolean | undefined>;
|
||||
useIndexAsValue?: boolean;
|
||||
}
|
||||
export interface GroupProps {
|
||||
disabled: boolean;
|
||||
modelValue: unknown;
|
||||
multiple?: boolean;
|
||||
mandatory?: boolean | 'force' | undefined;
|
||||
max?: number | undefined;
|
||||
selectedClass: string | undefined;
|
||||
'onUpdate:modelValue': EventProp<[unknown]> | undefined;
|
||||
}
|
||||
export interface GroupProvide {
|
||||
register: (item: GroupItem, cmp: ComponentInternalInstance) => void;
|
||||
unregister: (id: string) => void;
|
||||
select: (id: string, value: boolean) => void;
|
||||
selected: Ref<Readonly<string[]>>;
|
||||
isSelected: (id: string) => boolean;
|
||||
prev: () => void;
|
||||
next: () => void;
|
||||
selectedClass: Ref<string | undefined>;
|
||||
items: Readonly<Ref<{
|
||||
id: string;
|
||||
value: unknown;
|
||||
disabled: boolean | undefined;
|
||||
}[]>>;
|
||||
disabled: Ref<boolean | undefined>;
|
||||
getItemIndex: (value: unknown) => number;
|
||||
}
|
||||
export interface GroupItemProvide {
|
||||
id: string;
|
||||
isSelected: Ref<boolean>;
|
||||
isFirst: Ref<boolean>;
|
||||
isLast: Ref<boolean>;
|
||||
toggle: () => void;
|
||||
select: (value: boolean) => void;
|
||||
selectedClass: Ref<(string | undefined)[] | false>;
|
||||
value: Ref<unknown>;
|
||||
disabled: Ref<boolean | undefined>;
|
||||
group: GroupProvide;
|
||||
register: () => void;
|
||||
unregister: () => void;
|
||||
}
|
||||
export declare const makeGroupProps: <Defaults extends {
|
||||
modelValue?: unknown;
|
||||
multiple?: unknown;
|
||||
mandatory?: unknown;
|
||||
max?: unknown;
|
||||
selectedClass?: unknown;
|
||||
disabled?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
modelValue: unknown extends Defaults["modelValue"] ? {
|
||||
type: null;
|
||||
default: undefined;
|
||||
} : Omit<{
|
||||
type: null;
|
||||
default: undefined;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["modelValue"] ? any : any>;
|
||||
default: unknown extends Defaults["modelValue"] ? any : any;
|
||||
};
|
||||
multiple: unknown extends Defaults["multiple"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["multiple"] ? boolean : boolean | Defaults["multiple"]>;
|
||||
default: unknown extends Defaults["multiple"] ? boolean : boolean | Defaults["multiple"];
|
||||
};
|
||||
mandatory: unknown extends Defaults["mandatory"] ? PropType<"force" | boolean> : {
|
||||
type: PropType<unknown extends Defaults["mandatory"] ? "force" | boolean : "force" | boolean | Defaults["mandatory"]>;
|
||||
default: unknown extends Defaults["mandatory"] ? "force" | boolean : Defaults["mandatory"] | NonNullable<"force" | boolean>;
|
||||
};
|
||||
max: unknown extends Defaults["max"] ? NumberConstructor : {
|
||||
type: PropType<unknown extends Defaults["max"] ? number : number | Defaults["max"]>;
|
||||
default: unknown extends Defaults["max"] ? number : number | Defaults["max"];
|
||||
};
|
||||
selectedClass: unknown extends Defaults["selectedClass"] ? StringConstructor : {
|
||||
type: PropType<unknown extends Defaults["selectedClass"] ? string : string | Defaults["selectedClass"]>;
|
||||
default: unknown extends Defaults["selectedClass"] ? string : string | Defaults["selectedClass"];
|
||||
};
|
||||
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"];
|
||||
};
|
||||
};
|
||||
export declare const makeGroupItemProps: <Defaults extends {
|
||||
value?: unknown;
|
||||
disabled?: unknown;
|
||||
selectedClass?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
value: unknown extends Defaults["value"] ? null : {
|
||||
type: PropType<unknown extends Defaults["value"] ? any : any>;
|
||||
default: unknown extends Defaults["value"] ? 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"];
|
||||
};
|
||||
selectedClass: unknown extends Defaults["selectedClass"] ? StringConstructor : {
|
||||
type: PropType<unknown extends Defaults["selectedClass"] ? string : string | Defaults["selectedClass"]>;
|
||||
default: unknown extends Defaults["selectedClass"] ? string : string | Defaults["selectedClass"];
|
||||
};
|
||||
};
|
||||
export interface GroupItemProps extends ExtractPropTypes<ReturnType<typeof makeGroupItemProps>> {
|
||||
'onGroup:selected': EventProp<[{
|
||||
value: boolean;
|
||||
}]> | undefined;
|
||||
}
|
||||
export declare function useGroupItem(props: GroupItemProps, injectKey: InjectionKey<GroupProvide>, required?: true): GroupItemProvide;
|
||||
export declare function useGroupItem(props: GroupItemProps, injectKey: InjectionKey<GroupProvide>, required: false): GroupItemProvide | null;
|
||||
export declare function useGroup(props: GroupProps, injectKey: InjectionKey<GroupProvide>): GroupProvide;
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
// Composables
|
||||
import { useProxiedModel } from "./proxiedModel.js"; // Utilities
|
||||
import { computed, inject, onBeforeUnmount, onMounted, onUpdated, provide, reactive, toRef, unref, useId, watch } from 'vue';
|
||||
import { consoleWarn, deepEqual, findChildrenWithProvide, getCurrentInstance, propsFactory, wrapInArray } from "../util/index.js"; // Types
|
||||
export const makeGroupProps = propsFactory({
|
||||
modelValue: {
|
||||
type: null,
|
||||
default: undefined
|
||||
},
|
||||
multiple: Boolean,
|
||||
mandatory: [Boolean, String],
|
||||
max: Number,
|
||||
selectedClass: String,
|
||||
disabled: Boolean
|
||||
}, 'group');
|
||||
export const makeGroupItemProps = propsFactory({
|
||||
value: null,
|
||||
disabled: Boolean,
|
||||
selectedClass: String
|
||||
}, 'group-item');
|
||||
|
||||
// Composables
|
||||
|
||||
export function useGroupItem(props, injectKey, required = true) {
|
||||
const vm = getCurrentInstance('useGroupItem');
|
||||
if (!vm) {
|
||||
throw new Error('[Vuetify] useGroupItem composable must be used inside a component setup function');
|
||||
}
|
||||
const id = useId();
|
||||
provide(Symbol.for(`${injectKey.description}:id`), id);
|
||||
const group = inject(injectKey, null);
|
||||
if (!group) {
|
||||
if (!required) return group;
|
||||
throw new Error(`[Vuetify] Could not find useGroup injection with symbol ${injectKey.description}`);
|
||||
}
|
||||
const value = toRef(() => props.value);
|
||||
const disabled = computed(() => !!(group.disabled.value || props.disabled));
|
||||
function register() {
|
||||
group?.register({
|
||||
id,
|
||||
value,
|
||||
disabled
|
||||
}, vm);
|
||||
}
|
||||
function unregister() {
|
||||
group?.unregister(id);
|
||||
}
|
||||
register();
|
||||
onBeforeUnmount(() => unregister());
|
||||
const isSelected = computed(() => {
|
||||
return group.isSelected(id);
|
||||
});
|
||||
const isFirst = computed(() => {
|
||||
return group.items.value[0].id === id;
|
||||
});
|
||||
const isLast = computed(() => {
|
||||
return group.items.value[group.items.value.length - 1].id === id;
|
||||
});
|
||||
const selectedClass = computed(() => isSelected.value && [group.selectedClass.value, props.selectedClass]);
|
||||
watch(isSelected, value => {
|
||||
vm.emit('group:selected', {
|
||||
value
|
||||
});
|
||||
}, {
|
||||
flush: 'sync'
|
||||
});
|
||||
return {
|
||||
id,
|
||||
isSelected,
|
||||
isFirst,
|
||||
isLast,
|
||||
toggle: () => group.select(id, !isSelected.value),
|
||||
select: value => group.select(id, value),
|
||||
selectedClass,
|
||||
value,
|
||||
disabled,
|
||||
group,
|
||||
register,
|
||||
unregister
|
||||
};
|
||||
}
|
||||
export function useGroup(props, injectKey) {
|
||||
let isUnmounted = false;
|
||||
const items = reactive([]);
|
||||
const selected = useProxiedModel(props, 'modelValue', [], v => {
|
||||
if (v === undefined) return [];
|
||||
return getIds(items, v === null ? [null] : wrapInArray(v));
|
||||
}, v => {
|
||||
const arr = getValues(items, v);
|
||||
return props.multiple ? arr : arr[0];
|
||||
});
|
||||
const groupVm = getCurrentInstance('useGroup');
|
||||
function register(item, vm) {
|
||||
// Is there a better way to fix this typing?
|
||||
const unwrapped = item;
|
||||
const key = Symbol.for(`${injectKey.description}:id`);
|
||||
const children = findChildrenWithProvide(key, groupVm?.vnode);
|
||||
const index = children.indexOf(vm);
|
||||
if (unref(unwrapped.value) === undefined) {
|
||||
unwrapped.value = index;
|
||||
unwrapped.useIndexAsValue = true;
|
||||
}
|
||||
if (index > -1) {
|
||||
items.splice(index, 0, unwrapped);
|
||||
} else {
|
||||
items.push(unwrapped);
|
||||
}
|
||||
}
|
||||
function unregister(id) {
|
||||
if (isUnmounted) return;
|
||||
|
||||
// TODO: re-evaluate this line's importance in the future
|
||||
// should we only modify the model if mandatory is set.
|
||||
// selected.value = selected.value.filter(v => v !== id)
|
||||
|
||||
forceMandatoryValue();
|
||||
const index = items.findIndex(item => item.id === id);
|
||||
items.splice(index, 1);
|
||||
}
|
||||
|
||||
// If mandatory and nothing is selected, then select first non-disabled item
|
||||
function forceMandatoryValue() {
|
||||
const item = items.find(item => !item.disabled);
|
||||
if (item && props.mandatory === 'force' && !selected.value.length) {
|
||||
selected.value = [item.id];
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
forceMandatoryValue();
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
isUnmounted = true;
|
||||
});
|
||||
onUpdated(() => {
|
||||
// #19655 update the items that use the index as the value.
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].useIndexAsValue) {
|
||||
items[i].value = i;
|
||||
}
|
||||
}
|
||||
});
|
||||
function select(id, value) {
|
||||
const item = items.find(item => item.id === id);
|
||||
if (value && item?.disabled) return;
|
||||
if (props.multiple) {
|
||||
const internalValue = selected.value.slice();
|
||||
const index = internalValue.findIndex(v => v === id);
|
||||
const isSelected = ~index;
|
||||
value = value ?? !isSelected;
|
||||
|
||||
// We can't remove value if group is
|
||||
// mandatory, value already exists,
|
||||
// and it is the only value
|
||||
if (isSelected && props.mandatory && internalValue.length <= 1) return;
|
||||
|
||||
// We can't add value if it would
|
||||
// cause max limit to be exceeded
|
||||
if (!isSelected && props.max != null && internalValue.length + 1 > props.max) return;
|
||||
if (index < 0 && value) internalValue.push(id);else if (index >= 0 && !value) internalValue.splice(index, 1);
|
||||
selected.value = internalValue;
|
||||
} else {
|
||||
const isSelected = selected.value.includes(id);
|
||||
if (props.mandatory && isSelected) return;
|
||||
if (!isSelected && !value) return;
|
||||
selected.value = value ?? !isSelected ? [id] : [];
|
||||
}
|
||||
}
|
||||
function step(offset) {
|
||||
// getting an offset from selected value obviously won't work with multiple values
|
||||
if (props.multiple) consoleWarn('This method is not supported when using "multiple" prop');
|
||||
if (!selected.value.length) {
|
||||
const item = items.find(item => !item.disabled);
|
||||
item && (selected.value = [item.id]);
|
||||
} else {
|
||||
const currentId = selected.value[0];
|
||||
const currentIndex = items.findIndex(i => i.id === currentId);
|
||||
let newIndex = (currentIndex + offset) % items.length;
|
||||
let newItem = items[newIndex];
|
||||
while (newItem.disabled && newIndex !== currentIndex) {
|
||||
newIndex = (newIndex + offset) % items.length;
|
||||
newItem = items[newIndex];
|
||||
}
|
||||
if (newItem.disabled) return;
|
||||
selected.value = [items[newIndex].id];
|
||||
}
|
||||
}
|
||||
const state = {
|
||||
register,
|
||||
unregister,
|
||||
selected,
|
||||
select,
|
||||
disabled: toRef(() => props.disabled),
|
||||
prev: () => step(items.length - 1),
|
||||
next: () => step(1),
|
||||
isSelected: id => selected.value.includes(id),
|
||||
selectedClass: toRef(() => props.selectedClass),
|
||||
items: toRef(() => items),
|
||||
getItemIndex: value => getItemIndex(items, value)
|
||||
};
|
||||
provide(injectKey, state);
|
||||
return state;
|
||||
}
|
||||
function getItemIndex(items, value) {
|
||||
const ids = getIds(items, [value]);
|
||||
if (!ids.length) return -1;
|
||||
return items.findIndex(item => item.id === ids[0]);
|
||||
}
|
||||
function getIds(items, modelValue) {
|
||||
const ids = [];
|
||||
modelValue.forEach(value => {
|
||||
const item = items.find(item => deepEqual(value, item.value));
|
||||
const itemByIndex = items[value];
|
||||
if (item?.value !== undefined) {
|
||||
ids.push(item.id);
|
||||
} else if (itemByIndex?.useIndexAsValue) {
|
||||
ids.push(itemByIndex.id);
|
||||
}
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
function getValues(items, ids) {
|
||||
const values = [];
|
||||
ids.forEach(id => {
|
||||
const itemIndex = items.findIndex(item => item.id === id);
|
||||
if (~itemIndex) {
|
||||
const item = items[itemIndex];
|
||||
values.push(item.value !== undefined ? item.value : itemIndex);
|
||||
}
|
||||
});
|
||||
return values;
|
||||
}
|
||||
//# sourceMappingURL=group.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+25
@@ -0,0 +1,25 @@
|
||||
export type KeyCombination = Sequence | Alternate | Combo | Key;
|
||||
export interface Sequence {
|
||||
type: 'sequence';
|
||||
parts: (Alternate | Combo | Key)[];
|
||||
}
|
||||
export interface Alternate {
|
||||
type: 'alternate';
|
||||
parts: (Combo | Key)[];
|
||||
}
|
||||
export interface Combo {
|
||||
type: 'combo';
|
||||
parts: Key[];
|
||||
}
|
||||
export type Key = string;
|
||||
/**
|
||||
* Splits a single combination string into individual key parts.
|
||||
* Grammar:
|
||||
*
|
||||
* sequence = alternate *('-' alternate)
|
||||
* alternate = combo *('/' combo)
|
||||
* combo = key *(('+' | '_') key)
|
||||
* key = /./ *(/[^-/+_ ]/)
|
||||
*
|
||||
*/
|
||||
export declare function parseKeyCombination(input: string): KeyCombination;
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// Utilities
|
||||
import { normalizeKey } from "./key-aliases.js";
|
||||
import { consoleWarn, includes } from "../../util/index.js"; // Types
|
||||
class ParseError extends Error {}
|
||||
|
||||
/**
|
||||
* Splits a single combination string into individual key parts.
|
||||
* Grammar:
|
||||
*
|
||||
* sequence = alternate *('-' alternate)
|
||||
* alternate = combo *('/' combo)
|
||||
* combo = key *(('+' | '_') key)
|
||||
* key = /./ *(/[^-/+_ ]/)
|
||||
*
|
||||
*/
|
||||
export function parseKeyCombination(input) {
|
||||
let pos = 0;
|
||||
try {
|
||||
const result = parseSequence();
|
||||
if (!atEnd()) {
|
||||
throw new ParseError(`Unexpected character '${peek()}' at position ${pos}`);
|
||||
}
|
||||
return result;
|
||||
} catch (err) {
|
||||
if (err instanceof ParseError) {
|
||||
consoleWarn(`Invalid hotkey combination: ${err.message}\n ${input}\n ${' '.repeat(pos)}^`);
|
||||
return '';
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function peek(ahead = 0) {
|
||||
return pos + ahead < input.length ? input[pos + ahead] : null;
|
||||
}
|
||||
function consume() {
|
||||
if (pos >= input.length) {
|
||||
throw new ParseError('Unexpected end of input');
|
||||
}
|
||||
return input[pos++];
|
||||
}
|
||||
function atEnd() {
|
||||
return pos >= input.length;
|
||||
}
|
||||
|
||||
// sequence = alternate *('-' alternate)
|
||||
function parseSequence() {
|
||||
const parts = [parseAlternate()];
|
||||
while (peek() === '-') {
|
||||
consume();
|
||||
parts.push(parseAlternate());
|
||||
}
|
||||
if (parts.length === 1) return parts[0];
|
||||
return {
|
||||
type: 'sequence',
|
||||
parts
|
||||
};
|
||||
}
|
||||
|
||||
// alternate = combo *('/' combo)
|
||||
function parseAlternate() {
|
||||
const parts = [parseCombo()];
|
||||
while (peek() === '/') {
|
||||
consume();
|
||||
parts.push(parseCombo());
|
||||
}
|
||||
if (parts.length === 1) return parts[0];
|
||||
return {
|
||||
type: 'alternate',
|
||||
parts
|
||||
};
|
||||
}
|
||||
|
||||
// combo = key *(('+' | '_') key)
|
||||
function parseCombo() {
|
||||
const keys = [parseKey()];
|
||||
while (includes(['+', '_'], peek())) {
|
||||
consume();
|
||||
keys.push(parseKey());
|
||||
}
|
||||
if (keys.length === 1) return keys[0];
|
||||
return {
|
||||
type: 'combo',
|
||||
parts: keys
|
||||
};
|
||||
}
|
||||
|
||||
// key = /./ *(/[^-/+_ ]/)
|
||||
function parseKey() {
|
||||
const ch = peek();
|
||||
if (ch == null) {
|
||||
throw new ParseError('Unexpected end of input');
|
||||
}
|
||||
const next = peek(1);
|
||||
if (isSep(ch) && next != null && !isSep(next)) {
|
||||
throw new ParseError(`Unexpected separator '${ch}' at position ${pos}`);
|
||||
}
|
||||
const first = consume();
|
||||
// separator keys are always a single character
|
||||
if (isSep(first)) return first;
|
||||
const chars = [first];
|
||||
while (!atEnd() && !isSep(peek()) && peek() !== ' ') {
|
||||
chars.push(consume());
|
||||
}
|
||||
return normalizeKey(chars.join(''));
|
||||
}
|
||||
}
|
||||
function isSep(char) {
|
||||
return includes(['-', '/', '+', '_'], char);
|
||||
}
|
||||
//# sourceMappingURL=hotkey-parsing.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+9
@@ -0,0 +1,9 @@
|
||||
import type { MaybeRef } from '../../util/index.js';
|
||||
interface HotkeyOptions {
|
||||
event?: MaybeRef<'keydown' | 'keyup'>;
|
||||
inputs?: MaybeRef<boolean>;
|
||||
preventDefault?: MaybeRef<boolean>;
|
||||
sequenceTimeout?: MaybeRef<number>;
|
||||
}
|
||||
export declare function useHotkey(keys: MaybeRef<string | undefined>, callback: (e: KeyboardEvent) => void, options?: HotkeyOptions): () => void;
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
// Composables
|
||||
import { parseKeyCombination } from "./hotkey-parsing.js"; // Utilities
|
||||
import { onScopeDispose, toValue, watch } from 'vue';
|
||||
import { IN_BROWSER } from "../../util/index.js"; // Types
|
||||
const MODIFIERS = ['ctrl', 'shift', 'alt', 'meta', 'cmd'];
|
||||
const modifiersSet = new Set(MODIFIERS);
|
||||
function isModifier(key) {
|
||||
return modifiersSet.has(key);
|
||||
}
|
||||
const emptyModifiers = Object.fromEntries(MODIFIERS.map(m => [m, false]));
|
||||
export function useHotkey(keys, callback, options = {}) {
|
||||
if (!IN_BROWSER) return function () {};
|
||||
const {
|
||||
event = 'keydown',
|
||||
inputs = false,
|
||||
preventDefault = true,
|
||||
sequenceTimeout = 1000
|
||||
} = options;
|
||||
const isMac = navigator?.userAgent?.includes('Macintosh') ?? false;
|
||||
let timeout = 0;
|
||||
let keyGroups;
|
||||
let isSequence = false;
|
||||
let groupIndex = 0;
|
||||
function isInputFocused() {
|
||||
if (toValue(inputs)) return false;
|
||||
const activeElement = document.activeElement;
|
||||
return activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable || activeElement.contentEditable === 'true');
|
||||
}
|
||||
function resetSequence() {
|
||||
groupIndex = 0;
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
function handler(e) {
|
||||
const group = keyGroups[groupIndex];
|
||||
if (!group || isInputFocused()) return;
|
||||
if (!matchesKeyGroup(e, group, isMac)) {
|
||||
if (isSequence) resetSequence();
|
||||
return;
|
||||
}
|
||||
if (toValue(preventDefault)) e.preventDefault();
|
||||
if (!isSequence) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
groupIndex++;
|
||||
if (groupIndex === keyGroups.length) {
|
||||
callback(e);
|
||||
resetSequence();
|
||||
return;
|
||||
}
|
||||
timeout = window.setTimeout(resetSequence, toValue(sequenceTimeout));
|
||||
}
|
||||
function cleanup() {
|
||||
window.removeEventListener(toValue(event), handler);
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
watch(() => toValue(keys), newKeys => {
|
||||
cleanup();
|
||||
if (newKeys) {
|
||||
const parsed = parseKeyCombination(newKeys.toLowerCase());
|
||||
if (parsed) {
|
||||
const parts = typeof parsed !== 'string' && parsed.type === 'sequence' ? parsed.parts : [parsed];
|
||||
isSequence = parts.length > 1;
|
||||
keyGroups = parts;
|
||||
resetSequence();
|
||||
window.addEventListener(toValue(event), handler);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
});
|
||||
|
||||
// Watch for changes in the event type to re-register the listener
|
||||
watch(() => toValue(event), (newEvent, oldEvent) => {
|
||||
if (oldEvent && keyGroups && keyGroups.length > 0) {
|
||||
window.removeEventListener(oldEvent, handler);
|
||||
window.addEventListener(newEvent, handler);
|
||||
}
|
||||
});
|
||||
onScopeDispose(cleanup, true);
|
||||
return cleanup;
|
||||
}
|
||||
function matchesKeyGroup(e, group, isMac) {
|
||||
if (typeof group !== 'string' && group.type === 'alternate') {
|
||||
return group.parts.some(part => matchesKeyGroup(e, part, isMac));
|
||||
}
|
||||
const {
|
||||
modifiers,
|
||||
actualKey
|
||||
} = parseKeyGroup(group);
|
||||
const expectCtrl = modifiers.ctrl || !isMac && (modifiers.cmd || modifiers.meta);
|
||||
const expectMeta = isMac && (modifiers.cmd || modifiers.meta);
|
||||
return e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt && e.key.toLowerCase() === actualKey?.toLowerCase();
|
||||
}
|
||||
function parseKeyGroup(group) {
|
||||
const parts = typeof group === 'string' ? [group] : group.parts;
|
||||
const modifiers = {
|
||||
...emptyModifiers
|
||||
};
|
||||
let actualKey;
|
||||
for (const part of parts) {
|
||||
if (isModifier(part)) {
|
||||
modifiers[part] = true;
|
||||
} else {
|
||||
// TODO: handle multiple keys
|
||||
actualKey = part;
|
||||
}
|
||||
}
|
||||
return {
|
||||
modifiers,
|
||||
actualKey
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=hotkey.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
export { useHotkey } from './hotkey.js';
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export { useHotkey } from "./hotkey.js";
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","names":["useHotkey"],"sources":["../../../src/composables/hotkey/index.ts"],"sourcesContent":["export { useHotkey } from './hotkey'\n"],"mappings":"SAASA,SAAS","ignoreList":[]}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Centralized key alias mapping for consistent key normalization across the hotkey system.
|
||||
*
|
||||
* This maps various user-friendly aliases to canonical key names that match
|
||||
* KeyboardEvent.key values (in lowercase) where possible.
|
||||
*/
|
||||
export declare const keyAliasMap: Record<string, string>;
|
||||
/**
|
||||
* Normalizes a key string to its canonical form using the alias map.
|
||||
*
|
||||
* @param key - The key string to normalize
|
||||
* @returns The canonical key name in lowercase
|
||||
*/
|
||||
export declare function normalizeKey(key: string): string;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user