From 20ffadc9d73fe57d357edde56d7e907a7135bcee Mon Sep 17 00:00:00 2001 From: Kael Date: Mon, 15 Apr 2024 22:27:48 +1000 Subject: [PATCH] feat(date): support typescript module augmentation for adapters closes #18710 --- packages/docs/src/pages/en/features/dates.md | 46 +++++++++++++------ .../vuetify/build/rollup.types.config.mjs | 5 ++ .../composables/date/__tests__/date.spec.ts | 2 +- packages/vuetify/src/composables/date/date.ts | 18 ++++---- .../vuetify/src/composables/date/index.ts | 2 +- packages/vuetify/src/framework.ts | 2 +- 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/packages/docs/src/pages/en/features/dates.md b/packages/docs/src/pages/en/features/dates.md index 3c2f234bbdf..41e95852a3e 100644 --- a/packages/docs/src/pages/en/features/dates.md +++ b/packages/docs/src/pages/en/features/dates.md @@ -29,19 +29,6 @@ This feature was introduced in [v3.4.0 (Blackguard)](/getting-started/release-no The date composable provides a shared architecture that is used by components such as date picker and calendar. The default implementation is built using the native Date object, but can be swapped out for another date library. If no other date adapter is given, the default Vuetify one is used. -The following example demonstrates explicitly importing the Vuetify date adapter and passing it to the date options. - -```js { resource="src/plugins/vuetify.js" } -import { createVuetify } from 'vuetify' -import { VuetifyDateAdapter } from 'vuetify/date/adapters/vuetify' - -export default createVuetify({ - date: { - adapter: VuetifyDateAdapter, - }, -}) -``` - Within your application, import the **useDate** function and use it to access the date composable. ```html { resource="src/views/Date.vue" } @@ -124,11 +111,40 @@ The built-in date adapter implements a subset of functionality from the [DateIOF import { createVuetify } from 'vuetify' import LuxonAdapter from "@date-io/luxon" -const luxon = new LuxonAdapter({ locale: "sv" }); +export default createVuetify({ + date: { + adapter: LuxonAdapter, + }, +}) +``` + +For TypeScript users, an interface is also exposed for [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation): +```ts { resource="src/plugins/vuetify.js" } export default createVuetify({ + ... +}) + +declare module 'vuetify' { + namespace DateModule { + interface Adapter extends LuxonAdapter {} + } +} +``` + +### Localization + +The date composable will use the current vuetify [locale](/features/internationalization/) for formatting and getting the first day of the week. These do not always line up perfectly, so a list of aliases can be provided to map language codes to locales. The following configuration will look up `en` keys for translations, but use `en-GB` for date formatting: + +```js { resource="src/plugins/vuetify.js" } +export default createVuetify({ + locale: { + locale: 'en', + }, date: { - adapter: luxon, + locale: { + en: 'en-GB', + }, }, }) ``` diff --git a/packages/vuetify/build/rollup.types.config.mjs b/packages/vuetify/build/rollup.types.config.mjs index 16e069b0ee8..15470d083ca 100644 --- a/packages/vuetify/build/rollup.types.config.mjs +++ b/packages/vuetify/build/rollup.types.config.mjs @@ -49,8 +49,13 @@ function createTypesConfig (input, output, renderChunk, filter) { code = new MagicString(code) if (renderChunk) await renderChunk(code) + + // vue-router is optional but we need to include some of its types code.replaceAll(/import([^;])*?from 'vue-router'/gm, '// @ts-ignore\n$&') + // tsc adds extra export statements to namespaces + code.replaceAll(/^\s*export \{\s*\};?$/gm, '') + const map = code.generateMap({ // source: 'source.js', // file: 'converted.js.map', diff --git a/packages/vuetify/src/composables/date/__tests__/date.spec.ts b/packages/vuetify/src/composables/date/__tests__/date.spec.ts index b2af27f9939..27e79662243 100644 --- a/packages/vuetify/src/composables/date/__tests__/date.spec.ts +++ b/packages/vuetify/src/composables/date/__tests__/date.spec.ts @@ -13,7 +13,7 @@ function expectAssignable (value: T2): void {} describe('date.ts', () => { // Cannot define properties that don't exist in date-io - expectAssignable({} as IUtils) + expectAssignable({} as IUtils) // @ts-expect-error Can implement a subset of date-io expectAssignable>({} as DateAdapter) diff --git a/packages/vuetify/src/composables/date/date.ts b/packages/vuetify/src/composables/date/date.ts index b95c4297adf..1e4ac4eaea0 100644 --- a/packages/vuetify/src/composables/date/date.ts +++ b/packages/vuetify/src/composables/date/date.ts @@ -13,22 +13,24 @@ import type { LocaleInstance } from '@/composables/locale' // Adapters import { VuetifyDateAdapter } from './adapters/vuetify' -export interface DateInstance extends DateAdapter { +export interface DateInstance extends DateModule.InternalAdapter { locale?: any } -/** Supports module augmentation to specify date object types */ -export interface DateInstanceType { - instanceType: unknown +/** Supports module augmentation to specify date adapter types */ +export namespace DateModule { + interface Adapter {} + + export type InternalAdapter = {} extends Adapter ? DateAdapter : Adapter } -export type InternalDateOptions = { - adapter: (new (options: { locale: any, formats?: any }) => DateInstance) | DateInstance +export type InternalDateOptions = { + adapter: (new (options: { locale: any, formats?: any }) => DateInstance) | DateInstance formats?: Record locale: Record } -export type DateOptions = Partial> +export type DateOptions = Partial export const DateOptionsSymbol: InjectionKey = Symbol.for('vuetify:date-options') export const DateAdapterSymbol: InjectionKey = Symbol.for('vuetify:date-adapter') @@ -105,7 +107,7 @@ function createInstance (options: InternalDateOptions, locale: LocaleInstance) { return instance } -export function useDate () { +export function useDate (): DateInstance { const options = inject(DateOptionsSymbol) if (!options) throw new Error('[Vuetify] Could not find injected date options') diff --git a/packages/vuetify/src/composables/date/index.ts b/packages/vuetify/src/composables/date/index.ts index f2381478787..bef8c040daa 100644 --- a/packages/vuetify/src/composables/date/index.ts +++ b/packages/vuetify/src/composables/date/index.ts @@ -1,3 +1,3 @@ export { createDate, useDate, DateAdapterSymbol } from './date' export type { DateAdapter } from './DateAdapter' -export type { DateOptions, DateInstance } from './date' +export type { DateOptions, DateInstance, DateModule } from './date' diff --git a/packages/vuetify/src/framework.ts b/packages/vuetify/src/framework.ts index 93d73be180b..f9c00298a3e 100644 --- a/packages/vuetify/src/framework.ts +++ b/packages/vuetify/src/framework.ts @@ -21,7 +21,7 @@ import type { IconOptions } from '@/composables/icons' import type { LocaleOptions, RtlOptions } from '@/composables/locale' import type { ThemeOptions } from '@/composables/theme' export * from './composables' -export type { DateOptions, DateInstance } from '@/composables/date' +export type { DateOptions, DateInstance, DateModule } from '@/composables/date' export interface VuetifyOptions { aliases?: Record