diff --git a/.changeset/giant-cycles-clap.md b/.changeset/giant-cycles-clap.md new file mode 100644 index 0000000000..cea23fd5aa --- /dev/null +++ b/.changeset/giant-cycles-clap.md @@ -0,0 +1,57 @@ +--- +"@salt-ds/date-adapters": patch +"@salt-ds/lab": patch +--- + +Refine peer dependency management for DatePicker adapters by splitting them into sub-packages. You now import only the specific date framework adapter you need, simplifying dependency handling. + +- **For `date-fns`:** + + ```diff + - import { AdapterDateFns } from "@salt-ds/date-adapters"; + + import { AdapterDateFns } from "@salt-ds/date-adapters/date-fns"; + ``` + +- **For `dayjs`:** + + ```diff + - import { AdapterDayjs } from "@salt-ds/date-adapters"; + + import { AdapterDayjs } from "@salt-ds/date-adapters/dayjs"; + ``` + +- **For `luxon`:** + + ```diff + - import { AdapterLuxon } from "@salt-ds/date-adapters"; + + import { AdapterLuxon } from "@salt-ds/date-adapters/luxon"; + ``` + +- **For `moment`:** + + ```diff + - import { AdapterMoment } from "@salt-ds/date-adapters"; + + import { AdapterMoment } from "@salt-ds/date-adapters/moment"; + ``` + +Additionally, `DateDetailErrorEnum` is now a simpler `DateDetailError` of type `DateDetailErrorType`. + +```diff +- import { DateDetailErrorEnum } from "@salt-ds/date-adapters"; ++ import { DateDetailError } from "@salt-ds/date-adapters/moment"; +``` + +### Instructions + +1. Modify your import statements to use the specific sub-package for the date adapter you require. + +2. Ensure your `package.json` includes the necessary date framework as a dependency. For example, if using `date-fns`: + + ```json + { + "dependencies": { + "date-fns": "^x.x.x" + } + } + ``` + +This change helps streamline the integration of date frameworks with the DatePicker component by ensuring only the necessary adapters and dependencies are included. diff --git a/cypress.config.ts b/cypress.config.ts index f2417ff233..2bf3dbb9e3 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -56,10 +56,6 @@ async function getViteConfig(config: UserConfig) { __dirname, "./dist/salt-ds-countries", ), - "@salt-ds/date-adapters": path.resolve( - __dirname, - "./dist/salt-ds-date-adapters", - ), "@salt-ds/data-grid": path.resolve( __dirname, "./dist/salt-ds-data-grid", @@ -73,7 +69,6 @@ async function getViteConfig(config: UserConfig) { optimizeDeps: { include: [ "@salt-ds/core", - "@salt-ds/data-adapters", "@salt-ds/data-grid", "@salt-ds/lab", "@salt-ds/icons", diff --git a/package.json b/package.json index 3a64f0edae..aa3917b404 100644 --- a/package.json +++ b/package.json @@ -140,6 +140,7 @@ "get-tsconfig": "^4.7.5", "rollup": "^4.24.2", "rollup-plugin-esbuild": "^6.1.1", - "rollup-plugin-postcss": "^4.0.2" + "rollup-plugin-postcss": "^4.0.2", + "vite-tsconfig-paths": "^4.2.0" } } diff --git a/packages/date-adapters/package.json b/packages/date-adapters/package.json index 7fb6f523a8..001de7c202 100644 --- a/packages/date-adapters/package.json +++ b/packages/date-adapters/package.json @@ -38,6 +38,6 @@ "provenance": true }, "scripts": { - "build": "yarn node ../../scripts/build.mjs" + "build": "yarn node ./scripts/build.mjs" } } diff --git a/packages/date-adapters/scripts/build.mjs b/packages/date-adapters/scripts/build.mjs new file mode 100644 index 0000000000..55917c87e4 --- /dev/null +++ b/packages/date-adapters/scripts/build.mjs @@ -0,0 +1,164 @@ +import path from "node:path"; +import commonjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import browserslistToEsbuild from "browserslist-to-esbuild"; +import fs from "fs-extra"; +import { rollup } from "rollup"; +import esbuild from "rollup-plugin-esbuild"; +import { makeTypings } from "./../../../scripts/makeTypings.mjs"; +import { transformWorkspaceDeps } from "./../../../scripts/transformWorkspaceDeps.mjs"; +import { distinct } from "./../../../scripts/utils.mjs"; + +const cwd = process.cwd(); + +const packageJson = ( + await import(path.join("file://", cwd, "package.json"), { + with: { type: "json" }, + }) +).default; + +const FILES_TO_COPY = ["README.md", "LICENSE", "CHANGELOG.md"].concat( + packageJson.files ?? [], +); + +const packageName = packageJson.name; +const outputDir = path.join(packageJson.publishConfig.directory); + +console.log(`Building ${packageName}`); + +await fs.mkdirp(outputDir); +await fs.emptyDir(outputDir); + +// Define entry points for each adapter +const entryPoints = { + types: path.join(cwd, "src/types/index.ts"), + moment: path.join(cwd, "src/moment-adapter/index.ts"), + luxon: path.join(cwd, "src/luxon-adapter/index.ts"), + dayjs: path.join(cwd, "src/dayjs-adapter/index.ts"), + "date-fns": path.join(cwd, "src/date-fns-adapter/index.ts"), +}; + +for (const [adapterName, inputPath] of Object.entries(entryPoints)) { + const entryFolder = path.basename(path.dirname(inputPath)); + + await makeTypings(outputDir, path.dirname(inputPath)); + + const bundle = await rollup({ + input: inputPath, + external: (id) => { + if (id === "babel-plugin-transform-async-to-promises/helpers") { + return false; + } + return !id.startsWith(".") && !path.isAbsolute(id); + }, + treeshake: { + propertyReadSideEffects: false, + }, + plugins: [ + nodeResolve({ + extensions: [".ts", ".tsx", ".js", ".jsx"], + browser: true, + mainFields: ["module", "main", "browser"], + }), + commonjs({ include: /\/node_modules\// }), + esbuild({ + target: browserslistToEsbuild(), + minify: false, + sourceMap: true, + }), + json(), + ], + }); + + const transformSourceMap = (relativeSourcePath, sourceMapPath) => { + const absoluteSourcepath = path.resolve( + path.dirname(sourceMapPath), + relativeSourcePath, + ); + const packageRelativeSourcePath = path.relative(cwd, absoluteSourcepath); + + return `../${packageRelativeSourcePath}`; + }; + + await bundle.write({ + freeze: false, + sourcemap: true, + preserveModules: false, + dir: path.join(outputDir, `dist-cjs/${adapterName}`), + format: "cjs", + exports: "named", + sourcemapPathTransform: transformSourceMap, + }); + + await bundle.write({ + freeze: false, + sourcemap: true, + preserveModules: false, + dir: path.join(outputDir, `dist-es/${adapterName}`), + format: "es", + exports: "named", + sourcemapPathTransform: transformSourceMap, + }); + + await bundle.close(); +} + +await fs.writeJSON( + path.join(outputDir, "package.json"), + { + ...packageJson, + dependencies: await transformWorkspaceDeps(packageJson.dependencies), + main: "dist-cjs/index.js", + module: "dist-es/index.js", + typings: "dist-types/types/index.d.ts", + exports: { + ".": { + import: "./dist-es/types/index.js", + require: "./dist-cjs/types/index.js", + types: "./dist-types/types/index.d.ts", + }, + "./date-fns": { + import: "./dist-es/date-fns/index.js", + require: "./dist-cjs/date-fns/index.js", + types: "./dist-types/date-fns-adapter/index.d.ts", + }, + "./dayjs": { + import: "./dist-es/dayjs/index.js", + require: "./dist-cjs/dayjs/index.js", + types: "./dist-types/dayjs-adapter/index.d.ts", + }, + "./luxon": { + import: "./dist-es/luxon/index.js", + require: "./dist-cjs/luxon/index.js", + types: "./dist-types/luxon-adapter/index.d.ts", + }, + "./moment": { + import: "./dist-es/moment/index.js", + require: "./dist-cjs/moment/index.js", + types: "./dist-types/moment-adapter/index.d.ts", + }, + }, + files: distinct([ + ...(packageJson.files ?? []), + "dist-cjs", + "dist-es", + "dist-types", + "CHANGELOG.md", + ]), + }, + { spaces: 2 }, +); + +for (const file of FILES_TO_COPY) { + const filePath = path.join(cwd, file); + try { + await fs.copy(filePath, path.join(outputDir, file)); + } catch (error) { + if (error.code !== "ENOENT") { + throw error; + } + } +} + +console.log(`Built ${packageName} into ${outputDir}`); diff --git a/packages/date-adapters/src/__tests__/date-fns.spec.ts b/packages/date-adapters/src/__tests__/date-fns.spec.ts index 3fb26cf52d..12f6d66b63 100644 --- a/packages/date-adapters/src/__tests__/date-fns.spec.ts +++ b/packages/date-adapters/src/__tests__/date-fns.spec.ts @@ -1,7 +1,7 @@ import { isValid } from "date-fns"; import { enUS } from "date-fns/locale"; import { describe, expect, it } from "vitest"; -import { AdapterDateFns, DateDetailErrorEnum } from "../index"; +import { AdapterDateFns, DateDetailError } from "../index"; describe("GIVEN a AdapterDateFns", () => { const adapter = new AdapterDateFns({ locale: enUS }); @@ -34,7 +34,7 @@ describe("GIVEN a AdapterDateFns", () => { expect(result.errors).toEqual([ { message: "not a valid date", - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, }, ]); }); diff --git a/packages/date-adapters/src/__tests__/dayjs.spec.ts b/packages/date-adapters/src/__tests__/dayjs.spec.ts index ceb1183fce..5edfbf3716 100644 --- a/packages/date-adapters/src/__tests__/dayjs.spec.ts +++ b/packages/date-adapters/src/__tests__/dayjs.spec.ts @@ -3,7 +3,7 @@ import customParseFormat from "dayjs/plugin/customParseFormat"; import timezone from "dayjs/plugin/timezone"; import utc from "dayjs/plugin/utc"; import { describe, expect, it } from "vitest"; -import { AdapterDayjs, DateDetailErrorEnum } from "../index"; +import { AdapterDayjs, DateDetailError } from "../index"; // Extend dayjs with necessary plugins dayjs.extend(utc); @@ -70,7 +70,7 @@ describe("GIVEN a AdapterDayjs", () => { expect(result.errors).toEqual([ { message: "not a valid date", - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, }, ]); }); diff --git a/packages/date-adapters/src/__tests__/luxon.spec.ts b/packages/date-adapters/src/__tests__/luxon.spec.ts index 1b80eadf5e..35da45edf4 100644 --- a/packages/date-adapters/src/__tests__/luxon.spec.ts +++ b/packages/date-adapters/src/__tests__/luxon.spec.ts @@ -1,6 +1,6 @@ import { DateTime } from "luxon"; import { describe, expect, it } from "vitest"; -import { AdapterLuxon, DateDetailErrorEnum } from "../index"; +import { AdapterLuxon, DateDetailError } from "../index"; describe("GIVEN a AdapterLuxon", () => { const adapter = new AdapterLuxon({ locale: "en-US" }); @@ -62,7 +62,7 @@ describe("GIVEN a AdapterLuxon", () => { expect(result.errors).toEqual([ { message: "not a valid date", - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, }, ]); }); diff --git a/packages/date-adapters/src/__tests__/moment.spec.ts b/packages/date-adapters/src/__tests__/moment.spec.ts index 253a75ec38..d4242e7922 100644 --- a/packages/date-adapters/src/__tests__/moment.spec.ts +++ b/packages/date-adapters/src/__tests__/moment.spec.ts @@ -1,7 +1,7 @@ import moment from "moment"; import { describe, expect, it } from "vitest"; import "moment-timezone"; -import { AdapterMoment, DateDetailErrorEnum } from "../index"; +import { AdapterMoment, DateDetailError } from "../index"; describe("GIVEN a AdapterMoment", () => { const adapter = new AdapterMoment({ locale: "en" }); @@ -63,7 +63,7 @@ describe("GIVEN a AdapterMoment", () => { expect(result.errors).toEqual([ { message: "not a valid date", - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, }, ]); }); diff --git a/packages/date-adapters/src/date-fns/index.ts b/packages/date-adapters/src/date-fns-adapter/index.ts similarity index 98% rename from packages/date-adapters/src/date-fns/index.ts rename to packages/date-adapters/src/date-fns-adapter/index.ts index 2765e96a40..83606f7b82 100644 --- a/packages/date-adapters/src/date-fns/index.ts +++ b/packages/date-adapters/src/date-fns-adapter/index.ts @@ -33,7 +33,7 @@ import { import { enUS } from "date-fns/locale"; import { type AdapterOptions, - DateDetailErrorEnum, + DateDetailError, type ParserResult, type RecommendedFormats, type SaltDateAdapter, @@ -41,7 +41,7 @@ import { type Timezone, } from "../types"; -declare module "../types" { +declare module "@salt-ds/date-adapters" { interface DateFrameworkTypeMap { "date-fns": Date; } @@ -213,8 +213,8 @@ export class AdapterDateFns implements SaltDateAdapter { { message: isDateDefined ? "not a valid date" : "no date defined", type: isDateDefined - ? DateDetailErrorEnum.INVALID_DATE - : DateDetailErrorEnum.UNSET, + ? DateDetailError.INVALID_DATE + : DateDetailError.UNSET, }, ], }; diff --git a/packages/date-adapters/src/dayjs/index.ts b/packages/date-adapters/src/dayjs-adapter/index.ts similarity index 99% rename from packages/date-adapters/src/dayjs/index.ts rename to packages/date-adapters/src/dayjs-adapter/index.ts index 1720041087..e391f32f8c 100644 --- a/packages/date-adapters/src/dayjs/index.ts +++ b/packages/date-adapters/src/dayjs-adapter/index.ts @@ -6,7 +6,7 @@ import utc from "dayjs/plugin/utc"; import weekday from "dayjs/plugin/weekday"; import { type AdapterOptions, - DateDetailErrorEnum, + DateDetailError, type ParserResult, type RecommendedFormats, type SaltDateAdapter, @@ -20,7 +20,7 @@ type Constructor = { utc?: (value?: Parameters[0]) => Dayjs; }; -declare module "../types" { +declare module "@salt-ds/date-adapters" { interface DateFrameworkTypeMap { dayjs: Dayjs; } @@ -223,8 +223,8 @@ export class AdapterDayjs implements SaltDateAdapter { { message: isDateDefined ? "not a valid date" : "no date defined", type: isDateDefined - ? DateDetailErrorEnum.INVALID_DATE - : DateDetailErrorEnum.UNSET, + ? DateDetailError.INVALID_DATE + : DateDetailError.UNSET, }, ], }; diff --git a/packages/date-adapters/src/index.ts b/packages/date-adapters/src/index.ts index 126225dc31..b219142d83 100644 --- a/packages/date-adapters/src/index.ts +++ b/packages/date-adapters/src/index.ts @@ -1,18 +1,5 @@ -/** - * To add a new adapter, then, add the adapter's date object to `DateFrameworkTypeMap` interface - * - * declare module "./types" { - * interface DateFrameworkTypeMap { - * luxon: DateTime; - * } - * } - */ -// biome-ignore lint/complexity/noBannedTypes: type augmented by configured adapters -export type DateFrameworkTypeMap = {}; - -export * from "./date-fns"; -export * from "./dayjs"; -export * from "./luxon"; -export * from "./moment"; - +export * from "./date-fns-adapter"; +export * from "./dayjs-adapter"; +export * from "./luxon-adapter"; +export * from "./moment-adapter"; export * from "./types"; diff --git a/packages/date-adapters/src/luxon/index.ts b/packages/date-adapters/src/luxon-adapter/index.ts similarity index 98% rename from packages/date-adapters/src/luxon/index.ts rename to packages/date-adapters/src/luxon-adapter/index.ts index 00d78cf110..13f6ad5d33 100644 --- a/packages/date-adapters/src/luxon/index.ts +++ b/packages/date-adapters/src/luxon-adapter/index.ts @@ -1,7 +1,7 @@ import { DateTime, Duration, Settings } from "luxon"; import { type AdapterOptions, - DateDetailErrorEnum, + DateDetailError, type ParserResult, type RecommendedFormats, type SaltDateAdapter, @@ -9,7 +9,7 @@ import { type Timezone, } from "../types"; -declare module "../types" { +declare module "@salt-ds/date-adapters" { interface DateFrameworkTypeMap { luxon: DateTime; } @@ -234,8 +234,8 @@ export class AdapterLuxon implements SaltDateAdapter { { message: isDateDefined ? "not a valid date" : "no date defined", type: isDateDefined - ? DateDetailErrorEnum.INVALID_DATE - : DateDetailErrorEnum.UNSET, + ? DateDetailError.INVALID_DATE + : DateDetailError.UNSET, }, ], }; diff --git a/packages/date-adapters/src/moment/index.ts b/packages/date-adapters/src/moment-adapter/index.ts similarity index 99% rename from packages/date-adapters/src/moment/index.ts rename to packages/date-adapters/src/moment-adapter/index.ts index 9d20ca5d2a..d52d059218 100644 --- a/packages/date-adapters/src/moment/index.ts +++ b/packages/date-adapters/src/moment-adapter/index.ts @@ -1,7 +1,7 @@ import defaultMoment, { type Moment } from "moment"; import { type AdapterOptions, - DateDetailErrorEnum, + DateDetailError, type ParserResult, type RecommendedFormats, type SaltDateAdapter, @@ -9,7 +9,7 @@ import { type Timezone, } from "../types"; -declare module "../types" { +declare module "@salt-ds/date-adapters" { export interface DateFrameworkTypeMap { moment: Moment; } @@ -215,8 +215,8 @@ export class AdapterMoment implements SaltDateAdapter { { message: isDateDefined ? "not a valid date" : "no date defined", type: isDateDefined - ? DateDetailErrorEnum.INVALID_DATE - : DateDetailErrorEnum.UNSET, + ? DateDetailError.INVALID_DATE + : DateDetailError.UNSET, }, ], }; diff --git a/packages/date-adapters/src/types/DateFrameworkTypeMap.ts b/packages/date-adapters/src/types/DateFrameworkTypeMap.ts new file mode 100644 index 0000000000..0e82963a1f --- /dev/null +++ b/packages/date-adapters/src/types/DateFrameworkTypeMap.ts @@ -0,0 +1,12 @@ +/** + * To add a new adapter, then, add the adapter's date object to `DateFrameworkTypeMap` interface + * + * declare module "@salt-ds/date-adapters" { + * interface DateFrameworkTypeMap { + * luxon: DateTime; + * } + * } + */ + +// biome-ignore lint/complexity/noBannedTypes: type augmented by configured adapters +export type DateFrameworkTypeMap = {}; diff --git a/packages/date-adapters/src/types.ts b/packages/date-adapters/src/types/index.ts similarity index 95% rename from packages/date-adapters/src/types.ts rename to packages/date-adapters/src/types/index.ts index 857a978bd7..abcd9d5b15 100644 --- a/packages/date-adapters/src/types.ts +++ b/packages/date-adapters/src/types/index.ts @@ -1,3 +1,4 @@ +import type { DateFrameworkTypeMap } from "./DateFrameworkTypeMap"; /** * Represents the date object of a date framework. * @@ -11,27 +12,29 @@ export type DateFrameworkType = keyof DateFrameworkTypeMap extends never /** * Enum representing possible date detail error types. */ -export enum DateDetailErrorEnum { +export const DateDetailError = { /** Error type for unset values */ - UNSET = "unset", + UNSET: "unset", /** Error type for values that are not a date */ - NOT_A_DATE = "not-a-date", + NOT_A_DATE: "not-a-date", /** Error type for invalid date values */ - INVALID_DATE = "date", + INVALID_DATE: "date", /** Error type for invalid month values */ - INVALID_MONTH = "month", + INVALID_MONTH: "month", /** Error type for invalid day values */ - INVALID_DAY = "day", + INVALID_DAY: "day", /** Error type for invalid year values */ - INVALID_YEAR = "year", -} + INVALID_YEAR: "year", +} as const; +export type DateDetailErrorType = + (typeof DateDetailError)[keyof typeof DateDetailError]; /** * Represents an error detail for a date. */ export type DateDetailError = { /** The error code */ - type: DateDetailErrorEnum | string; + type: DateDetailErrorType | string; /** The error message */ message: string; }; diff --git a/packages/date-adapters/tsconfig.json b/packages/date-adapters/tsconfig.json new file mode 100644 index 0000000000..ce623bd894 --- /dev/null +++ b/packages/date-adapters/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "baseUrl": "./src", + "declaration": false, + "outDir": "./dist", + "module": "commonjs", + "target": "es2016", + "moduleResolution": "node", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["src/**/*"] +} diff --git a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.a11y.cy.tsx b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.a11y.cy.tsx index 1fa9c6d77e..6e70409e13 100644 --- a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.a11y.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.a11y.cy.tsx @@ -1,7 +1,9 @@ -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, +} from "@salt-ds/date-adapters"; import * as calendarStories from "@stories/calendar/calendar.stories"; import { composeStories } from "@storybook/react"; diff --git a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.cy.tsx b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.cy.tsx index 20532957be..c3c5513511 100644 --- a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.cy.tsx @@ -1,11 +1,11 @@ -import type { - DateFrameworkType, - SaltDateAdapter, +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + type DateFrameworkType, + type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { Calendar, CalendarGrid, diff --git a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.multiselect.cy.tsx b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.multiselect.cy.tsx index 89560972b2..411be8754b 100644 --- a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.multiselect.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.multiselect.cy.tsx @@ -1,11 +1,11 @@ -import type { - DateFrameworkType, - SaltDateAdapter, +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + type DateFrameworkType, + type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { Calendar, CalendarGrid, diff --git a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.offset.cy.tsx b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.offset.cy.tsx index c4439f3d5a..402ab9322c 100644 --- a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.offset.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.offset.cy.tsx @@ -1,11 +1,11 @@ -import type { - DateFrameworkType, - SaltDateAdapter, +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + type DateFrameworkType, + type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { Calendar, CalendarGrid, diff --git a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.single.cy.tsx b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.single.cy.tsx index a6327fec61..877ec15fe5 100644 --- a/packages/lab/src/__tests__/__e2e__/calendar/Calendar.single.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/calendar/Calendar.single.cy.tsx @@ -1,11 +1,11 @@ -import type { - DateFrameworkType, - SaltDateAdapter, +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + type DateFrameworkType, + type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { Calendar, CalendarGrid, diff --git a/packages/lab/src/__tests__/__e2e__/date-input/DateInput.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-input/DateInput.cy.tsx index 6fa1bc3a23..acb6bc772d 100644 --- a/packages/lab/src/__tests__/__e2e__/date-input/DateInput.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-input/DateInput.cy.tsx @@ -1,7 +1,9 @@ -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, +} from "@salt-ds/date-adapters"; import * as dateInputStories from "@stories/date-input/date-input.stories"; import { composeStories } from "@storybook/react"; import { checkAccessibility } from "../../../../../../cypress/tests/checkAccessibility"; diff --git a/packages/lab/src/__tests__/__e2e__/date-input/DateInputRange.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-input/DateInputRange.cy.tsx index d4634c8301..8d46d11c73 100644 --- a/packages/lab/src/__tests__/__e2e__/date-input/DateInputRange.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-input/DateInputRange.cy.tsx @@ -1,9 +1,9 @@ -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { - DateDetailErrorEnum, + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + DateDetailError, type DateFrameworkType, type ParserResult, type SaltDateAdapter, @@ -77,7 +77,7 @@ function assertDateChange( // assert empty start date expect(adapter.isValid(date.startDate)).to.equal(false); expect(details.startDate.errors).to.deep.equal([ - { type: DateDetailErrorEnum.UNSET, message: "no date defined" }, + { type: DateDetailError.UNSET, message: "no date defined" }, ]); expect(details.startDate).to.have.property( "value", @@ -87,7 +87,7 @@ function assertDateChange( // assert invalid start date expect(adapter.isValid(date.startDate)).to.equal(false); expect(details.startDate.errors).to.deep.equal([ - { type: DateDetailErrorEnum.INVALID_DATE, message: "not a valid date" }, + { type: DateDetailError.INVALID_DATE, message: "not a valid date" }, ]); expect(details.startDate).to.have.property( "value", @@ -105,14 +105,14 @@ function assertDateChange( // assert empty end date expect(adapter.isValid(date.endDate)).to.equal(false); expect(details.endDate.errors).to.deep.equal([ - { type: DateDetailErrorEnum.UNSET, message: "no date defined" }, + { type: DateDetailError.UNSET, message: "no date defined" }, ]); expect(details.endDate).to.have.property("value", expectedValue.endDate); } else if (expectedDate?.endDate === null) { // assert invalid end date expect(adapter.isValid(date.endDate)).to.equal(false); expect(details.endDate.errors).to.deep.equal([ - { type: DateDetailErrorEnum.INVALID_DATE, message: "not a valid date" }, + { type: DateDetailError.INVALID_DATE, message: "not a valid date" }, ]); expect(details.endDate).to.have.property("value", expectedValue.endDate); } @@ -367,7 +367,7 @@ describe("GIVEN a DateInputRange", () => { value: "", errors: [ { - type: DateDetailErrorEnum.UNSET, + type: DateDetailError.UNSET, message: "no date defined", }, ], diff --git a/packages/lab/src/__tests__/__e2e__/date-input/DateInputSingle.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-input/DateInputSingle.cy.tsx index 7b723f8212..d498b911ae 100644 --- a/packages/lab/src/__tests__/__e2e__/date-input/DateInputSingle.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-input/DateInputSingle.cy.tsx @@ -1,13 +1,13 @@ import { - DateDetailErrorEnum, + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + DateDetailError, type DateFrameworkType, type ParserResult, type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { DateInputSingle } from "@salt-ds/lab"; import { es as dateFnsEs } from "date-fns/locale"; @@ -70,16 +70,14 @@ function assertDateChange( // assert empty date expect(adapter.isValid(date)).to.equal(false); expect(details).to.deep.equal({ - errors: [{ type: DateDetailErrorEnum.UNSET, message: "no date defined" }], + errors: [{ type: DateDetailError.UNSET, message: "no date defined" }], value: expectedValue, }); } else if (expectedValidDate === null) { // assert invalid date expect(adapter.isValid(date)).to.equal(false); expect(details).to.deep.equal({ - errors: [ - { type: DateDetailErrorEnum.UNSET, message: "not a valid date" }, - ], + errors: [{ type: DateDetailError.UNSET, message: "not a valid date" }], value: expectedValue, }); } diff --git a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.cy.tsx index ec1d88c6b6..4bbc72bcd6 100644 --- a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.cy.tsx @@ -1,7 +1,9 @@ -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, +} from "@salt-ds/date-adapters"; import * as datePickerStories from "@stories/date-picker/date-picker.stories"; import { composeStories } from "@storybook/react"; import { checkAccessibility } from "../../../../../../cypress/tests/checkAccessibility"; diff --git a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx index 86d2e0c0d0..46f57358a4 100644 --- a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx @@ -1,12 +1,12 @@ import { - DateDetailErrorEnum, + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, + DateDetailError, type DateFrameworkType, type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import { DatePicker, DatePickerOverlay, @@ -210,7 +210,7 @@ describe("GIVEN a DatePicker where selectionVariant is single", () => { value: "", errors: [ { - type: DateDetailErrorEnum.UNSET, + type: DateDetailError.UNSET, message: "no date defined", }, ], @@ -256,7 +256,7 @@ describe("GIVEN a DatePicker where selectionVariant is single", () => { value: "bad date", errors: [ { - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, message: "not a valid date", }, ], diff --git a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx index 7759c061a3..d1153326ae 100644 --- a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx @@ -1,12 +1,14 @@ import { - DateDetailErrorEnum, + DateDetailError, type DateFrameworkType, type SaltDateAdapter, } from "@salt-ds/date-adapters"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; +import { + AdapterDateFns, + AdapterDayjs, + AdapterLuxon, + AdapterMoment, +} from "@salt-ds/date-adapters"; import { DatePicker, DatePickerOverlay, @@ -139,7 +141,7 @@ describe("GIVEN a DatePicker where selectionVariant is single", () => { value: "bad date", errors: [ { - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, message: "not a valid date", }, ], @@ -156,7 +158,7 @@ describe("GIVEN a DatePicker where selectionVariant is single", () => { value: "another bad date 2", errors: [ { - type: DateDetailErrorEnum.INVALID_DATE, + type: DateDetailError.INVALID_DATE, message: "not a valid date", }, ], diff --git a/packages/lab/src/calendar/useCalendarSelection.ts b/packages/lab/src/calendar/useCalendarSelection.ts index 4d77673125..83eadff1d0 100644 --- a/packages/lab/src/calendar/useCalendarSelection.ts +++ b/packages/lab/src/calendar/useCalendarSelection.ts @@ -400,7 +400,7 @@ export function useCalendarSelection( case "single": return ( isSingleSelectionValueType(selectedDate) && - dateAdapter.isSame(selectedDate, date, "day") + dateAdapter.isSame(selectedDate as TDate, date, "day") ); case "multiselect": return ( diff --git a/packages/lab/src/date-picker/DatePickerRangeInput.tsx b/packages/lab/src/date-picker/DatePickerRangeInput.tsx index f8a9db18e6..e5f1aa8d7c 100644 --- a/packages/lab/src/date-picker/DatePickerRangeInput.tsx +++ b/packages/lab/src/date-picker/DatePickerRangeInput.tsx @@ -1,6 +1,6 @@ import { Button, makePrefixer, useControlled, useIcon } from "@salt-ds/core"; import { - DateDetailErrorEnum, + DateDetailError, type DateFrameworkType, type SaltDateAdapter, } from "@salt-ds/date-adapters"; @@ -57,7 +57,7 @@ export function defaultRangeValidator( details.startDate = details.startDate || {}; details.startDate.errors = details.startDate.errors || []; details.startDate.errors.push({ - type: DateDetailErrorEnum.UNSET, + type: DateDetailError.UNSET, message: "no start date defined", }); } @@ -65,7 +65,7 @@ export function defaultRangeValidator( details.endDate = details.endDate || {}; details.endDate.errors = details.endDate.errors || []; details.endDate.errors.push({ - type: DateDetailErrorEnum.UNSET, + type: DateDetailError.UNSET, message: "no end date defined", }); } diff --git a/packages/lab/src/date-picker/DatePickerSingleInput.tsx b/packages/lab/src/date-picker/DatePickerSingleInput.tsx index 97c625be45..7350a9b436 100644 --- a/packages/lab/src/date-picker/DatePickerSingleInput.tsx +++ b/packages/lab/src/date-picker/DatePickerSingleInput.tsx @@ -1,6 +1,6 @@ import { Button, makePrefixer, useControlled } from "@salt-ds/core"; import { - DateDetailErrorEnum, + DateDetailError, type DateFrameworkType, type SaltDateAdapter, } from "@salt-ds/date-adapters"; @@ -53,7 +53,7 @@ function defaultSingleValidation( if (!date) { details.errors = details.errors ?? []; details.errors?.push({ - type: DateDetailErrorEnum.UNSET, + type: DateDetailError.UNSET, message: "no date defined", }); } else { diff --git a/packages/lab/stories/date-picker/date-picker.stories.tsx b/packages/lab/stories/date-picker/date-picker.stories.tsx index 8e22b0270b..3c75b63e51 100644 --- a/packages/lab/stories/date-picker/date-picker.stories.tsx +++ b/packages/lab/stories/date-picker/date-picker.stories.tsx @@ -10,7 +10,7 @@ import { Text, } from "@salt-ds/core"; import { - DateDetailErrorEnum, + DateDetailError, type DateFrameworkType, type ParserResult, type TimeFields, @@ -1575,7 +1575,7 @@ export const SingleWithCustomParser: StoryFn< date: parsedDate.date, value: inputDate, errors: [ - { type: DateDetailErrorEnum.UNSET, message: "no date provided" }, + { type: DateDetailError.UNSET, message: "no date provided" }, ], }; } @@ -1714,7 +1714,7 @@ export const RangeWithCustomParser: StoryFn< date: parsedDate.date, value: inputDate, errors: [ - { type: DateDetailErrorEnum.UNSET, message: "no date provided" }, + { type: DateDetailError.UNSET, message: "no date provided" }, ], }; } @@ -1795,7 +1795,7 @@ export const SingleWithCustomValidation: StoryFn< if (date && isWeekend(date)) { updatedDetails.errors = updatedDetails?.errors ?? []; updatedDetails.errors?.push({ - type: DateDetailErrorEnum.INVALID_DAY, + type: DateDetailError.INVALID_DAY, message: "date must be a weekday", }); } @@ -1842,7 +1842,7 @@ export const SingleWithCustomValidation: StoryFn< return details; } details.errors = details.errors.map((error) => { - if (error.type === DateDetailErrorEnum.NOT_A_DATE) { + if (error.type === DateDetailError.NOT_A_DATE) { error.message = "valid dates are any weekday"; } return error; diff --git a/scripts/makeTypings.mjs b/scripts/makeTypings.mjs index 240329f1c0..93a129b5d3 100644 --- a/scripts/makeTypings.mjs +++ b/scripts/makeTypings.mjs @@ -24,8 +24,8 @@ export function reportTSDiagnostics(diagnostics) { } } -export async function makeTypings(outDir) { - const typescriptConfig = await getTypescriptConfig(cwd); +export async function makeTypings(outDir, srcDir = path.join(cwd, "src")) { + const typescriptConfig = await getTypescriptConfig(cwd, srcDir); console.log("generating .d.ts files"); diff --git a/scripts/utils.mjs b/scripts/utils.mjs index 68d03c3fb8..731f6f3b7e 100644 --- a/scripts/utils.mjs +++ b/scripts/utils.mjs @@ -1,17 +1,16 @@ -import path from "node:path"; import { getTsconfig } from "get-tsconfig"; export function distinct(arr) { return [...new Set(arr)]; } -export async function getTypescriptConfig(cwd) { +export async function getTypescriptConfig(cwd, srcDir) { const typescriptConfig = {}; const result = getTsconfig(cwd); Object.assign(typescriptConfig, result.config, { - include: [path.join(cwd, "src")], + include: [srcDir], exclude: distinct( [ // all TS test files, regardless whether co-located or in test/ etc diff --git a/site/docs/components/localization-provider/usage.mdx b/site/docs/components/localization-provider/usage.mdx index 5fc51dcafc..83b40e0e80 100644 --- a/site/docs/components/localization-provider/usage.mdx +++ b/site/docs/components/localization-provider/usage.mdx @@ -37,25 +37,25 @@ To import your chosen adapter adapter use one of the following : ### date-fns ``` -import { AdapterDateFns } from "@salt-ds/date-adapters"; +import { AdapterDateFns } from "@salt-ds/date-adapters/date-fns"; ``` ### dayjs ``` -import { AdapterDayJs } from "@salt-ds/date-adapters"; +import { AdapterDayJs } from "@salt-ds/date-adapters/dayjs"; ``` ### luxon ``` -import { AdapterLuxon } from "@salt-ds/date-adapters"; +import { AdapterLuxon } from "@salt-ds/date-adapters/luxon"; ``` ### moment (legacy) ``` -import { AdapterMoment } from "@salt-ds/date-adapters"; +import { AdapterMoment } from "@salt-ds/date-adapters/moment"; ``` ## Usage @@ -69,6 +69,7 @@ Each adapter imports the date library defined by your peer dependency but for da Passing `dayjs` to `AdapterDayJs` enables you to preconfigure defaults. ``` +import { AdapterDayJs } from "@salt-ds/date-adapters/dayjs"; import dayjs from "dayjs"; dayjs.tz.setDefault('America/New_York'); @@ -78,6 +79,7 @@ const dayjsAdapter = new AdapterDayJs(locale, dayjs); Passing `moment-timezone` to `AdapterMoment` adapter enables timezone support. ``` +import { AdapterMoment } from "@salt-ds/date-adapters/moment"; import moment from "moment-timezone"; const momentAdapter = new AdapterMoment(locale, moment); @@ -376,7 +378,7 @@ Not normally necessary, but in order to add a new adapter that is a valid `TDate /** * To add a new adapter, then, add the adapter's date object to `DateFrameworkTypeMap` interface */ - declare module "./types" { + declare module "@salt-ds/date-adapters" { interface DateFrameworkTypeMap { luxon: DateTime; } diff --git a/site/src/examples/calendar/WithLocale.tsx b/site/src/examples/calendar/WithLocale.tsx index c10bd40a98..8103081982 100644 --- a/site/src/examples/calendar/WithLocale.tsx +++ b/site/src/examples/calendar/WithLocale.tsx @@ -1,4 +1,4 @@ -import { AdapterDateFns } from "@salt-ds/date-adapters"; +import { AdapterDateFns } from "@salt-ds/date-adapters/date-fns"; import { Calendar, CalendarGrid, diff --git a/site/src/examples/date-picker/SingleWithCustomParser.tsx b/site/src/examples/date-picker/SingleWithCustomParser.tsx index f91accf8f2..c2f6501bbf 100644 --- a/site/src/examples/date-picker/SingleWithCustomParser.tsx +++ b/site/src/examples/date-picker/SingleWithCustomParser.tsx @@ -4,7 +4,7 @@ import { FormFieldLabel as FormLabel, } from "@salt-ds/core"; import { - DateDetailErrorEnum, + DateDetailError, type DateFrameworkType, type ParserResult, } from "@salt-ds/date-adapters"; @@ -40,7 +40,7 @@ export const SingleWithCustomParser = (): ReactElement => { >(null); const handleSelectionChange = useCallback( ( - event: SyntheticEvent, + _event: SyntheticEvent, date: SingleDateSelection | null, details: DateInputSingleDetails | undefined, ) => { @@ -83,7 +83,7 @@ export const SingleWithCustomParser = (): ReactElement => { date: parsedDate.date, value: inputDate, errors: [ - { type: DateDetailErrorEnum.UNSET, message: "no date provided" }, + { type: DateDetailError.UNSET, message: "no date provided" }, ], }; } diff --git a/site/src/examples/localization-provider/Locale.tsx b/site/src/examples/localization-provider/Locale.tsx index f173748c36..dba9220f0c 100644 --- a/site/src/examples/localization-provider/Locale.tsx +++ b/site/src/examples/localization-provider/Locale.tsx @@ -4,6 +4,10 @@ import { RadioButton, RadioButtonGroup, } from "@salt-ds/core"; +import { AdapterDateFns } from "@salt-ds/date-adapters/date-fns"; +import { AdapterDayjs } from "@salt-ds/date-adapters/dayjs"; +import { AdapterLuxon } from "@salt-ds/date-adapters/luxon"; +import { AdapterMoment } from "@salt-ds/date-adapters/moment"; import { Calendar, CalendarGrid, @@ -13,10 +17,6 @@ import { } from "@salt-ds/lab"; import { type ChangeEventHandler, type ReactElement, useState } from "react"; import "dayjs/locale/en"; -import { AdapterDateFns } from "@salt-ds/date-adapters"; -import { AdapterDayjs } from "@salt-ds/date-adapters"; -import { AdapterLuxon } from "@salt-ds/date-adapters"; -import { AdapterMoment } from "@salt-ds/date-adapters"; import moment from "moment"; import "moment/locale/zh-cn"; // Import the Chinese locale import { enUS as dateFnsEnUs } from "date-fns/locale"; diff --git a/site/src/examples/localization-provider/MinMax.tsx b/site/src/examples/localization-provider/MinMax.tsx index 1751da8571..408e7b6788 100644 --- a/site/src/examples/localization-provider/MinMax.tsx +++ b/site/src/examples/localization-provider/MinMax.tsx @@ -1,5 +1,6 @@ import { FormField, FormFieldHelperText, FormFieldLabel } from "@salt-ds/core"; -import { AdapterDateFns, type DateFrameworkType } from "@salt-ds/date-adapters"; +import type { DateFrameworkType } from "@salt-ds/date-adapters"; +import { AdapterDateFns } from "@salt-ds/date-adapters/date-fns"; import { Calendar, CalendarGrid, diff --git a/site/tsconfig.json b/site/tsconfig.json index 0d49d55a27..591f40da06 100644 --- a/site/tsconfig.json +++ b/site/tsconfig.json @@ -3,7 +3,10 @@ "compilerOptions": { "baseUrl": ".", "jsx": "preserve", - "incremental": true + "incremental": true, + "paths": { + "@salt-ds/date-adapters/*": ["../packages/date-adapters/src/index.ts"] + } }, "include": ["src/**/*", "globals.d.ts"], "exclude": ["node_modules"] diff --git a/vite.config.ts b/vite.config.ts index f25730da82..b64743b808 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,8 @@ +import tsconfigPaths from "vite-tsconfig-paths"; import { defineConfig } from "vitest/config"; export default defineConfig({ + plugins: [tsconfigPaths() as any], test: { include: ["**/*.spec.[jt]s?(x)"], },