@simplybusiness/mobius-datepicker 9.0.1 → 9.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/cjs/index.js +547 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/meta.json +473 -0
- package/dist/esm/DatePickerModal-RVUBO5DW.js +209 -0
- package/dist/esm/DatePickerModal-RVUBO5DW.js.map +7 -0
- package/dist/esm/index.js +54 -363
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/meta.json +75 -50
- package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/utils/mockMatchMedia.d.ts +1 -0
- package/dist/types/vitest.config.d.ts +2 -0
- package/package.json +15 -17
- package/src/components/DatePicker/DatePicker.stories.tsx +1 -1
- package/src/components/DatePicker/DatePicker.test.tsx +36 -23
- package/src/components/DatePicker/DatePickerModal.test.tsx +2 -2
- package/src/components/DatePicker/DatePickerModal.tsx +2 -1
- package/src/components/DatePicker/utils/getStartWeekday.test.ts +2 -2
- package/src/utils/mockMatchMedia.ts +36 -0
- package/dist/types/src/utils/jestMockMatchMedia.d.ts +0 -1
- package/src/utils/jestMockMatchMedia.ts +0 -36
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function mockMatchMedia(matches: boolean): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplybusiness/mobius-datepicker",
|
|
3
3
|
"license": "UNLICENSED",
|
|
4
|
-
"version": "9.0.
|
|
4
|
+
"version": "9.0.3",
|
|
5
5
|
"description": "Mobius date picker component",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
"simplyBusiness": {
|
|
11
11
|
"publishToPublicNpm": true
|
|
12
12
|
},
|
|
13
|
-
"
|
|
14
|
-
"main": "dist/esm/index.js",
|
|
13
|
+
"main": "dist/cjs/index.js",
|
|
15
14
|
"types": "./dist/types/index.d.ts",
|
|
16
15
|
"files": [
|
|
17
16
|
"src",
|
|
@@ -20,18 +19,20 @@
|
|
|
20
19
|
"exports": {
|
|
21
20
|
".": {
|
|
22
21
|
"types": "./dist/types/index.d.ts",
|
|
22
|
+
"require": "./dist/cjs/index.js",
|
|
23
23
|
"import": "./dist/esm/index.js",
|
|
24
24
|
"default": "./dist/esm/index.js"
|
|
25
25
|
},
|
|
26
26
|
"./src/*.css": "./src/*.css"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
|
-
"main": "dist/
|
|
29
|
+
"main": "dist/cjs/index.js",
|
|
30
30
|
"module": "dist/esm/index.js",
|
|
31
31
|
"types": "./dist/types/index.d.ts",
|
|
32
32
|
"exports": {
|
|
33
33
|
".": {
|
|
34
34
|
"types": "./dist/types/index.d.ts",
|
|
35
|
+
"require": "./dist/cjs/index.js",
|
|
35
36
|
"import": "./dist/esm/index.js",
|
|
36
37
|
"default": "./dist/esm/index.js"
|
|
37
38
|
},
|
|
@@ -42,13 +43,14 @@
|
|
|
42
43
|
"clean": "rm -rf dist",
|
|
43
44
|
"build": "yarn run -T turbo run turbo:build",
|
|
44
45
|
"prepack": "yarn run build",
|
|
45
|
-
"turbo:build": "yarn build:esm && yarn build:types",
|
|
46
|
+
"turbo:build": "yarn build:esm && yarn build:cjs && yarn build:types",
|
|
46
47
|
"build:esm": "build-package esm",
|
|
48
|
+
"build:cjs": "build-package cjs",
|
|
47
49
|
"build:types": "tsc --emitDeclarationOnly --project tsconfig.build.json",
|
|
48
50
|
"lint": "eslint",
|
|
49
51
|
"lint:fix": "eslint --fix",
|
|
50
|
-
"test": "
|
|
51
|
-
"test:coverage": "
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"test:coverage": "vitest run --coverage",
|
|
52
54
|
"check-types": "tsc --noEmit --pretty",
|
|
53
55
|
"lint:css": "lint-css",
|
|
54
56
|
"lint:css:fix": "lint-css --fix"
|
|
@@ -60,17 +62,15 @@
|
|
|
60
62
|
"@eslint/js": "^9.39.2",
|
|
61
63
|
"@simplybusiness/build-scripts": "^2.0.1",
|
|
62
64
|
"@simplybusiness/eslint-config": "^2.0.1",
|
|
63
|
-
"@swc/core": "^1.12.5",
|
|
64
|
-
"@swc/jest": "^0.2.39",
|
|
65
65
|
"@testing-library/dom": "^10.4.1",
|
|
66
66
|
"@testing-library/jest-dom": "6.9.1",
|
|
67
67
|
"@testing-library/react": "^16.3.2",
|
|
68
68
|
"@testing-library/user-event": "^14.6.1",
|
|
69
|
-
"@types/jest": "^30.0.0",
|
|
70
69
|
"@types/react": "^19.2.11",
|
|
71
70
|
"@types/react-dom": "^19.2.3",
|
|
72
71
|
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
73
72
|
"@typescript-eslint/parser": "^8.54.0",
|
|
73
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
74
74
|
"eslint": "^9.39.2",
|
|
75
75
|
"eslint-config-prettier": "^10.1.8",
|
|
76
76
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
@@ -81,23 +81,21 @@
|
|
|
81
81
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
82
82
|
"eslint-plugin-ssr-friendly": "^1.3.0",
|
|
83
83
|
"eslint-plugin-testing-library": "^7.15.4",
|
|
84
|
-
"identity-obj-proxy": "^3.0.0",
|
|
85
|
-
"jest": "^30.2.0",
|
|
86
|
-
"jest-config": "^30.2.0",
|
|
87
|
-
"jest-environment-jsdom": "^30.2.0",
|
|
88
84
|
"prettier": "^3.8.1",
|
|
89
85
|
"react": "^19.2.4",
|
|
90
86
|
"react-dom": "^19.2.4",
|
|
91
87
|
"tslib": "^2.8.1",
|
|
92
|
-
"typescript": "^5.9.3"
|
|
88
|
+
"typescript": "^5.9.3",
|
|
89
|
+
"vitest": "^4.0.18"
|
|
93
90
|
},
|
|
94
91
|
"peerDependencies": {
|
|
95
92
|
"react": "^19.2.0",
|
|
96
93
|
"react-dom": "^19.2.0"
|
|
97
94
|
},
|
|
98
95
|
"dependencies": {
|
|
99
|
-
"@simplybusiness/icons": "^5.0.
|
|
100
|
-
"@simplybusiness/mobius": "^
|
|
96
|
+
"@simplybusiness/icons": "^5.0.2",
|
|
97
|
+
"@simplybusiness/mobius": "^9.0.0",
|
|
98
|
+
"@simplybusiness/mobius-hooks": "^0.1.0",
|
|
101
99
|
"classnames": "^2.5.1",
|
|
102
100
|
"date-fns": "^4.1.0",
|
|
103
101
|
"react-day-picker": "^9.13.0"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { add, format } from "date-fns";
|
|
3
3
|
import { excludeControls } from "../../utils";
|
|
4
4
|
import { StoryContainer } from "../../utils/StoryContainer";
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { DatePicker } from ".";
|
|
4
|
-
import {
|
|
4
|
+
import { mockMatchMedia } from "../../utils/mockMatchMedia";
|
|
5
5
|
import { DEFAULT_AFTER_MAX, DEFAULT_BEFORE_MIN } from "./utils";
|
|
6
6
|
|
|
7
|
+
// Eagerly resolve DatePickerModal so React.lazy gets an instant cache hit
|
|
8
|
+
// Without this, the dynamic import can take too long on slow CI runners
|
|
9
|
+
vi.mock("./DatePickerModal", async importOriginal => importOriginal());
|
|
10
|
+
|
|
7
11
|
const DISABLED_CLASS_NAME = "--is-disabled";
|
|
8
12
|
const TOUCH_DEVICE_CLASS_NAME = "--is-touch-device";
|
|
9
13
|
const VALID_CLASS_NAME = "--is-valid";
|
|
@@ -17,7 +21,7 @@ const DEVICES = [
|
|
|
17
21
|
describe("DatePicker", () => {
|
|
18
22
|
describe.each(DEVICES)(`given it is a %s`, (deviceLabel, isTouchDevice) => {
|
|
19
23
|
beforeEach(() => {
|
|
20
|
-
|
|
24
|
+
mockMatchMedia(isTouchDevice as boolean);
|
|
21
25
|
});
|
|
22
26
|
|
|
23
27
|
it("should render without errors", () => {
|
|
@@ -110,7 +114,7 @@ describe("DatePicker", () => {
|
|
|
110
114
|
it("triggers onChange", async () => {
|
|
111
115
|
const labelText = "Start date";
|
|
112
116
|
const testId = "date-picker";
|
|
113
|
-
const onChange =
|
|
117
|
+
const onChange = vi.fn();
|
|
114
118
|
|
|
115
119
|
render(
|
|
116
120
|
<DatePicker
|
|
@@ -216,26 +220,35 @@ describe("DatePicker", () => {
|
|
|
216
220
|
});
|
|
217
221
|
|
|
218
222
|
describe("when TextField is clicked", () => {
|
|
219
|
-
it(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
223
|
+
it(
|
|
224
|
+
`should ${(isTouchDevice && "not") || ""} open the date picker modal`,
|
|
225
|
+
{ retry: 2, timeout: 10000 },
|
|
226
|
+
async () => {
|
|
227
|
+
const labelText = "Start date";
|
|
228
|
+
const testId = "date-picker";
|
|
229
|
+
|
|
230
|
+
render(<DatePicker label={labelText} data-testid={testId} />);
|
|
231
|
+
|
|
232
|
+
const inputField = screen.getByTestId(testId);
|
|
233
|
+
|
|
234
|
+
await userEvent.click(inputField);
|
|
235
|
+
|
|
236
|
+
await waitFor(
|
|
237
|
+
() => {
|
|
238
|
+
if (isTouchDevice) {
|
|
239
|
+
expect(
|
|
240
|
+
screen.queryByTestId("modal-container"),
|
|
241
|
+
).not.toBeInTheDocument();
|
|
242
|
+
} else {
|
|
243
|
+
expect(
|
|
244
|
+
screen.getByTestId("modal-container"),
|
|
245
|
+
).toBeInTheDocument();
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{ timeout: 10000 },
|
|
249
|
+
);
|
|
250
|
+
},
|
|
251
|
+
);
|
|
239
252
|
});
|
|
240
253
|
});
|
|
241
254
|
});
|
|
@@ -73,7 +73,7 @@ describe("DatePickerModal", () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
it("calls onSelected when a day is picked", async () => {
|
|
76
|
-
const onSelected =
|
|
76
|
+
const onSelected = vi.fn();
|
|
77
77
|
|
|
78
78
|
render(<DatePickerModal isOpen top={30} onSelected={onSelected} />);
|
|
79
79
|
|
|
@@ -142,7 +142,7 @@ describe("DatePickerModal", () => {
|
|
|
142
142
|
it.todo("traps focus when opened"); // Move to e2e test with Playwright
|
|
143
143
|
|
|
144
144
|
it("should disable dates before min and after max value", () => {
|
|
145
|
-
const onSelected =
|
|
145
|
+
const onSelected = vi.fn();
|
|
146
146
|
const date = "2025-01-07";
|
|
147
147
|
const min = "2025-01-05";
|
|
148
148
|
const max = "2025-01-10";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useOnClickOutside } from "@simplybusiness/mobius-hooks";
|
|
4
|
+
import { VisuallyHidden } from "@simplybusiness/mobius";
|
|
4
5
|
import classNames from "classnames/dedupe";
|
|
5
6
|
import { parseISO } from "date-fns";
|
|
6
7
|
import { useId, useRef } from "react";
|
|
@@ -3,8 +3,8 @@ import { getStartWeekday } from "./getStartWeekday";
|
|
|
3
3
|
|
|
4
4
|
describe("getStartWeekday", () => {
|
|
5
5
|
beforeEach(() => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
vi.spyOn(navigator, "languages", "get").mockReturnValue([]);
|
|
7
|
+
vi.spyOn(navigator, "language", "get").mockImplementation(() => "en-GB");
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
it("assumes default of en-GB (Monday) when no args supplied", () => {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type MockedFunction } from "vitest";
|
|
2
|
+
|
|
3
|
+
export function mockMatchMedia(matches: boolean) {
|
|
4
|
+
const addListenerMock: MockedFunction<MediaQueryList["addListener"]> =
|
|
5
|
+
vi.fn();
|
|
6
|
+
const removeListenerMock: MockedFunction<MediaQueryList["removeListener"]> =
|
|
7
|
+
vi.fn();
|
|
8
|
+
const addEventListenerMock: MockedFunction<
|
|
9
|
+
MediaQueryList["addEventListener"]
|
|
10
|
+
> = vi.fn();
|
|
11
|
+
const removeEventListenerMock: MockedFunction<
|
|
12
|
+
MediaQueryList["removeEventListener"]
|
|
13
|
+
> = vi.fn();
|
|
14
|
+
const dispatchEventMock: MockedFunction<MediaQueryList["dispatchEvent"]> =
|
|
15
|
+
vi.fn();
|
|
16
|
+
|
|
17
|
+
const matchMediaMock: MockedFunction<typeof window.matchMedia> = vi.fn(
|
|
18
|
+
(query: string) =>
|
|
19
|
+
({
|
|
20
|
+
matches,
|
|
21
|
+
media: query,
|
|
22
|
+
onchange: null,
|
|
23
|
+
addListener: addListenerMock,
|
|
24
|
+
removeListener: removeListenerMock,
|
|
25
|
+
addEventListener: addEventListenerMock,
|
|
26
|
+
removeEventListener: removeEventListenerMock,
|
|
27
|
+
dispatchEvent: dispatchEventMock,
|
|
28
|
+
}) satisfies MediaQueryList,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
Object.defineProperty(window, "matchMedia", {
|
|
32
|
+
writable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
value: matchMediaMock,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function jestMockMatchMedia(matches: boolean): void;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export function jestMockMatchMedia(matches: boolean) {
|
|
2
|
-
const addListenerMock: jest.MockedFunction<MediaQueryList["addListener"]> =
|
|
3
|
-
jest.fn();
|
|
4
|
-
const removeListenerMock: jest.MockedFunction<
|
|
5
|
-
MediaQueryList["removeListener"]
|
|
6
|
-
> = jest.fn();
|
|
7
|
-
const addEventListenerMock: jest.MockedFunction<
|
|
8
|
-
MediaQueryList["addEventListener"]
|
|
9
|
-
> = jest.fn();
|
|
10
|
-
const removeEventListenerMock: jest.MockedFunction<
|
|
11
|
-
MediaQueryList["removeEventListener"]
|
|
12
|
-
> = jest.fn();
|
|
13
|
-
const dispatchEventMock: jest.MockedFunction<
|
|
14
|
-
MediaQueryList["dispatchEvent"]
|
|
15
|
-
> = jest.fn();
|
|
16
|
-
|
|
17
|
-
const matchMediaMock: jest.MockedFunction<typeof window.matchMedia> = jest.fn(
|
|
18
|
-
(query: string) =>
|
|
19
|
-
({
|
|
20
|
-
matches,
|
|
21
|
-
media: query,
|
|
22
|
-
onchange: null,
|
|
23
|
-
addListener: addListenerMock,
|
|
24
|
-
removeListener: removeListenerMock,
|
|
25
|
-
addEventListener: addEventListenerMock,
|
|
26
|
-
removeEventListener: removeEventListenerMock,
|
|
27
|
-
dispatchEvent: dispatchEventMock,
|
|
28
|
-
}) satisfies MediaQueryList,
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
Object.defineProperty(window, "matchMedia", {
|
|
32
|
-
writable: true,
|
|
33
|
-
configurable: true,
|
|
34
|
-
value: matchMediaMock,
|
|
35
|
-
});
|
|
36
|
-
}
|