|
| 1 | +import { Priorities } from "@core/constants/core.constants"; |
1 | 2 | import { Categories_Event, type Schema_Event } from "@core/types/event.types"; |
2 | 3 | import dayjs from "@core/util/date/dayjs"; |
3 | 4 | import { |
4 | 5 | ID_ALLDAY_COLUMNS, |
5 | 6 | ID_GRID_COLUMNS_TIMED, |
6 | 7 | ID_GRID_MAIN, |
7 | 8 | } from "@web/common/constants/web.constants"; |
| 9 | +import { theme } from "@web/common/styles/theme"; |
| 10 | +import { gridHoverColorByPriority } from "@web/common/styles/theme.util"; |
8 | 11 | import { createSomedayInteractionAdapter } from "@web/components/PlannerSidebar/SomedayEventSections/interaction/adapter/SomedayInteractionAdapter"; |
9 | 12 | import { somedayDropTargetRegistry } from "@web/components/PlannerSidebar/SomedayEventSections/interaction/registry/somedayDropTargetRegistry"; |
10 | 13 | import { somedayEventRegistry } from "@web/components/PlannerSidebar/SomedayEventSections/interaction/registry/somedayEventRegistry"; |
@@ -70,6 +73,34 @@ const makePointerEvent = ( |
70 | 73 | return event; |
71 | 74 | }; |
72 | 75 |
|
| 76 | +const normalizeCssColor = (color: string) => { |
| 77 | + const element = document.createElement("span"); |
| 78 | + |
| 79 | + element.style.color = color; |
| 80 | + |
| 81 | + return element.style.color; |
| 82 | +}; |
| 83 | + |
| 84 | +const setReducedMotionPreference = (matches: boolean) => { |
| 85 | + const originalMatchMedia = window.matchMedia; |
| 86 | + const reducedMotionMatchMedia = mock((query: string) => ({ |
| 87 | + addEventListener: mock(), |
| 88 | + addListener: mock(), |
| 89 | + dispatchEvent: mock(), |
| 90 | + matches: query === "(prefers-reduced-motion: reduce)" ? matches : false, |
| 91 | + media: query, |
| 92 | + onchange: null, |
| 93 | + removeEventListener: mock(), |
| 94 | + removeListener: mock(), |
| 95 | + })); |
| 96 | + |
| 97 | + window.matchMedia = reducedMotionMatchMedia as typeof window.matchMedia; |
| 98 | + |
| 99 | + return () => { |
| 100 | + window.matchMedia = originalMatchMedia; |
| 101 | + }; |
| 102 | +}; |
| 103 | + |
73 | 104 | const createHarness = () => { |
74 | 105 | document.body.innerHTML = ""; |
75 | 106 | somedayDropTargetRegistry.clear(); |
@@ -302,6 +333,87 @@ describe("SomedayInteractionAdapter", () => { |
302 | 333 | }); |
303 | 334 | }); |
304 | 335 |
|
| 336 | + it("transitions dragged Someday overlay text to dark while over the calendar", () => { |
| 337 | + const { adapter, flushFrame, sourceChild, timedColumns } = createHarness(); |
| 338 | + |
| 339 | + adapter.handlePointerDown( |
| 340 | + makePointerEvent("pointerdown", { target: sourceChild, x: 20, y: 12 }), |
| 341 | + ); |
| 342 | + adapter.handlePointerMove( |
| 343 | + makePointerEvent("pointermove", { |
| 344 | + target: timedColumns, |
| 345 | + x: 250, |
| 346 | + y: 220, |
| 347 | + }), |
| 348 | + ); |
| 349 | + flushFrame(); |
| 350 | + |
| 351 | + const overlay = document.body.querySelector<HTMLElement>( |
| 352 | + "[data-calendar-interaction-overlay]", |
| 353 | + ); |
| 354 | + const expectedTextColor = normalizeCssColor(theme.color.text.dark); |
| 355 | + |
| 356 | + expect(overlay).toBeTruthy(); |
| 357 | + expect(overlay?.style.transition).toContain("color 240ms"); |
| 358 | + expect(overlay?.style.color).toBe(expectedTextColor); |
| 359 | + expect(overlay?.querySelector("[data-someday-drag-affordance]")).toBeNull(); |
| 360 | + }); |
| 361 | + |
| 362 | + it("uses the hovered grid color for the dragged Someday overlay over the calendar", () => { |
| 363 | + const { adapter, flushFrame, sourceChild, timedColumns } = createHarness(); |
| 364 | + |
| 365 | + adapter.handlePointerDown( |
| 366 | + makePointerEvent("pointerdown", { target: sourceChild, x: 20, y: 12 }), |
| 367 | + ); |
| 368 | + adapter.handlePointerMove( |
| 369 | + makePointerEvent("pointermove", { |
| 370 | + target: timedColumns, |
| 371 | + x: 250, |
| 372 | + y: 220, |
| 373 | + }), |
| 374 | + ); |
| 375 | + flushFrame(); |
| 376 | + |
| 377 | + const overlay = document.body.querySelector<HTMLElement>( |
| 378 | + "[data-calendar-interaction-overlay]", |
| 379 | + ); |
| 380 | + const expectedHoverColor = normalizeCssColor( |
| 381 | + gridHoverColorByPriority[Priorities.UNASSIGNED], |
| 382 | + ); |
| 383 | + |
| 384 | + expect(overlay).toBeTruthy(); |
| 385 | + expect(overlay?.style.backgroundColor).toBe(expectedHoverColor); |
| 386 | + }); |
| 387 | + |
| 388 | + it("disables Someday overlay motion when reduced motion is preferred", () => { |
| 389 | + const restoreMatchMedia = setReducedMotionPreference(true); |
| 390 | + const { adapter, flushFrame, sourceChild, timedColumns } = createHarness(); |
| 391 | + |
| 392 | + try { |
| 393 | + adapter.handlePointerDown( |
| 394 | + makePointerEvent("pointerdown", { target: sourceChild, x: 20, y: 12 }), |
| 395 | + ); |
| 396 | + adapter.handlePointerMove( |
| 397 | + makePointerEvent("pointermove", { |
| 398 | + target: timedColumns, |
| 399 | + x: 250, |
| 400 | + y: 220, |
| 401 | + }), |
| 402 | + ); |
| 403 | + flushFrame(); |
| 404 | + |
| 405 | + const overlay = document.body.querySelector<HTMLElement>( |
| 406 | + "[data-calendar-interaction-overlay]", |
| 407 | + ); |
| 408 | + |
| 409 | + expect(overlay).toBeTruthy(); |
| 410 | + expect(overlay?.style.transition).toBe("none"); |
| 411 | + expect(overlay?.style.scale).toBe("1"); |
| 412 | + } finally { |
| 413 | + restoreMatchMedia(); |
| 414 | + } |
| 415 | + }); |
| 416 | + |
305 | 417 | it("schedules a dragged Someday event as an all-day event", () => { |
306 | 418 | const { adapter, flushFrame, onCommitSomedayInteraction, sourceChild } = |
307 | 419 | createHarness(); |
|
0 commit comments