@synerise/ds-date-picker 2.1.0 → 2.1.2

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 CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.1.2](https://github.com/Synerise/synerise-design/compare/@synerise/ds-date-picker@2.1.1...@synerise/ds-date-picker@2.1.2) (2026-09-18)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-date-picker
9
+
10
+
11
+
12
+
13
+
14
+ ## [2.1.1](https://github.com/Synerise/synerise-design/compare/@synerise/ds-date-picker@2.1.0...@synerise/ds-date-picker@2.1.1) (2026-09-16)
15
+
16
+ ### Bug Fixes
17
+
18
+ - **date-picker:** keep the local clock when a day click crosses a DST boundary ([81fb588](https://github.com/Synerise/synerise-design/commit/81fb5883286faa1a938d3ec5909a1e48a6cb68b7))
19
+
6
20
  # [2.1.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-date-picker@2.0.3...@synerise/ds-date-picker@2.1.0) (2026-09-10)
7
21
 
8
22
  ### Features
package/CLAUDE.md CHANGED
@@ -30,7 +30,7 @@ src/
30
30
  fns.tsx — date-fns re-exports (named, from the package root)
31
31
  format.ts — fnsFormat wrapper
32
32
  localeUtils.ts — weekday/month name tables; adapted into react-day-picker formatters/labels
33
- utils.ts — changeDayWithHoursPreserved and other helpers
33
+ utils.ts — range / getDecadeRange / getCenturyRange helpers
34
34
  index.ts — public exports
35
35
  ```
36
36
 
@@ -140,7 +140,7 @@ import { RawDatePicker } from '@synerise/ds-date-picker';
140
140
  - **`readOnly` short-circuits the Dropdown** — when `readOnly={true}`, the component renders only the `PickerInput` (or `renderTrigger` output) with no calendar attached.
141
141
  - **Mode switching** — clicking the month name in `DayPicker` switches to `'month'` mode; clicking the year name switches to `'year'` mode. The back navigation in those modes returns to `'date'`. Selecting a day when `showTime=true` switches to `'time'` mode automatically.
142
142
  - **`useStartOfDay` / `useEndOfDay`** — applied on day click, before `onValueChange` fires. `useStartOfDay` takes precedence if both are set (implemented as `if/else if` in `handleDayClick`).
143
- - **Time preserved on day change** — when changing the day while already having a time selected (`changed=true`), hours/minutes/seconds from the previous value are preserved (`changeDayWithHoursPreserved`).
143
+ - **Time preserved on day change** — clicking a day rewrites only the calendar fields of the current `value` (`setYear`/`setMonth`/`setDate`), so its local clock carries over. Local fields are the whole mechanism, and they are what makes this correct across a DST boundary; do not reintroduce a seconds-difference round-trip here. The removed `changeDayWithHoursPreserved` did exactly that and multiplied a calendar-day count by a hard-coded `86400`, so any pair of dates straddling a transition came out an hour wrong — and with `useStartOfDay`/`useEndOfDay` that hour crossed midnight and moved the day.
144
144
  - **Apply vs onChange** — `onValueChange` fires on every day/time interaction. `onApply` fires only when the user explicitly clicks Apply (or selects a quick pick), and also closes the dropdown.
145
145
  - **`dropdownProps.open`** — if provided, it OR-s with internal `dropVisible` state: `open={(dropdownProps?.open || dropVisible) && !disabled}`. This means both sources can open the dropdown independently.
146
146
  - **`format` has been removed** — use `valueFormatOptions: DateToFormatOptions` (from `@synerise/ds-core`). It took a token pattern, which no consumer passed and which disagreed with `formatValue` for every locale. `PickerInput` now renders a `Date` and an ISO string identically; whether a value is an *instant* is signalled by `isInstantValue`, not inferred from its runtime type.
@@ -55,7 +55,7 @@ const PickerInput = forwardRef(({
55
55
  event.stopPropagation();
56
56
  onClick && onClick();
57
57
  }, [onClick]);
58
- const iconInput = useMemo(() => (hovered || highlight) && allowClear && !readOnly && !!value ? /* @__PURE__ */ jsx(ClearIconWrapper, { children: /* @__PURE__ */ jsx(Tooltip, { title: clearTooltip, children: /* @__PURE__ */ jsx(Icon, { component: /* @__PURE__ */ jsx(Close3S, {}), onClick: handleIconClick }) }) }) : /* @__PURE__ */ jsx(DefaultIconWrapper, { children: /* @__PURE__ */ jsx(Icon, { component: /* @__PURE__ */ jsx(CalendarM, {}), color: theme.palette["grey-400"] }) }), [hovered, highlight, allowClear, readOnly, value, theme, clearTooltip, handleIconClick]);
58
+ const iconInput = useMemo(() => (hovered || highlight) && allowClear && !readOnly && value ? /* @__PURE__ */ jsx(ClearIconWrapper, { children: /* @__PURE__ */ jsx(Tooltip, { title: clearTooltip, children: /* @__PURE__ */ jsx(Icon, { component: /* @__PURE__ */ jsx(Close3S, {}), onClick: handleIconClick }) }) }) : /* @__PURE__ */ jsx(DefaultIconWrapper, { children: /* @__PURE__ */ jsx(Icon, { component: /* @__PURE__ */ jsx(CalendarM, {}), color: theme.palette["grey-400"] }) }), [hovered, highlight, allowClear, readOnly, value, theme, clearTooltip, handleIconClick]);
59
59
  const {
60
60
  className,
61
61
  ...restAttributes
@@ -11,7 +11,6 @@ import TimePicker from "../Elements/TimePicker/TimePicker.js";
11
11
  import YearPicker from "../Elements/YearPicker/YearPicker.js";
12
12
  import { setYear, setMonth, setDate, startOfDay, endOfDay, addDays, startOfMonth } from "date-fns";
13
13
  import toDateValue from "../toDateValue.js";
14
- import { changeDayWithHoursPreserved } from "../utils.js";
15
14
  import { getDefaultTexts } from "../utils/getDefaultTexts.js";
16
15
  const _RawDatePicker = class _RawDatePicker extends React.Component {
17
16
  constructor(props) {
@@ -20,24 +19,11 @@ const _RawDatePicker = class _RawDatePicker extends React.Component {
20
19
  const {
21
20
  onValueChange
22
21
  } = this.props;
23
- const {
24
- mode,
25
- value: valueFromState
26
- } = this.state;
27
- if (mode === "date" && !!valueFromState && !!value) {
28
- const dateToBeUpdated = changeDayWithHoursPreserved(valueFromState, value);
29
- this.setState({
30
- value: dateToBeUpdated,
31
- changed: true
32
- });
33
- onValueChange && onValueChange(dateToBeUpdated);
34
- } else {
35
- this.setState({
36
- value,
37
- changed: true
38
- });
39
- onValueChange && onValueChange(value);
40
- }
22
+ this.setState({
23
+ value,
24
+ changed: true
25
+ });
26
+ onValueChange && onValueChange(value);
41
27
  };
42
28
  this.handleDayMouseEnter = (day) => this.setState({
43
29
  enteredTo: day
@@ -47,7 +33,6 @@ const _RawDatePicker = class _RawDatePicker extends React.Component {
47
33
  });
48
34
  this.handleDayClick = (day, modifiers) => {
49
35
  const {
50
- changed: isChanged,
51
36
  value
52
37
  } = this.state;
53
38
  const {
@@ -58,7 +43,7 @@ const _RawDatePicker = class _RawDatePicker extends React.Component {
58
43
  if (modifiers.disabled) {
59
44
  return;
60
45
  }
61
- let nextDateWithCurrentTime = isChanged && value ? value : /* @__PURE__ */ new Date();
46
+ let nextDateWithCurrentTime = value || /* @__PURE__ */ new Date();
62
47
  nextDateWithCurrentTime = setYear(nextDateWithCurrentTime, day.getFullYear());
63
48
  nextDateWithCurrentTime = setMonth(nextDateWithCurrentTime, day.getMonth());
64
49
  nextDateWithCurrentTime = setDate(nextDateWithCurrentTime, day.getDate());
package/dist/fns.d.ts CHANGED
@@ -1,23 +1,2 @@
1
1
  import { addDays as fnsAddDays, addMonths as fnsAddMonths, addSeconds as fnsAddSeconds, addYears as fnsAddYears, differenceInSeconds as fnsDifferenceInSeconds, differenceInYears as fnsDifferenceInYears, endOfDay as fnsEndOfDay, endOfMonth as fnsEndOfMonth, format as fnsFormat, getSeconds as fnsGetSeconds, getYear as fnsGetYear, isAfter as fnsIsAfter, isBefore as fnsIsBefore, isEqual as fnsIsEqual, isSameDay as fnsIsSameDay, isSameMonth as fnsIsSameMonth, isSameYear as fnsIsSameYear, setDate as fnsSetDate, setMonth as fnsSetMonth, setYear as fnsSetYear, startOfDay as fnsStartOfDay, startOfMonth as fnsStartOfMonth } from 'date-fns';
2
- export { fnsGetSeconds };
3
- export { fnsDifferenceInSeconds };
4
- export { fnsStartOfMonth };
5
- export { fnsSetDate };
6
- export { fnsSetMonth };
7
- export { fnsSetYear };
8
- export { fnsStartOfDay };
9
- export { fnsEndOfDay };
10
- export { fnsAddYears };
11
- export { fnsEndOfMonth };
12
- export { fnsIsSameMonth };
13
- export { fnsIsBefore };
14
- export { fnsIsAfter };
15
- export { fnsAddMonths };
16
- export { fnsFormat };
17
- export { fnsIsSameYear };
18
- export { fnsGetYear };
19
- export { fnsAddDays };
20
- export { fnsAddSeconds };
21
- export { fnsDifferenceInYears };
22
- export { fnsIsEqual };
23
- export { fnsIsSameDay };
2
+ export { fnsAddDays, fnsAddMonths, fnsAddSeconds, fnsAddYears, fnsDifferenceInSeconds, fnsDifferenceInYears, fnsEndOfDay, fnsEndOfMonth, fnsFormat, fnsGetSeconds, fnsGetYear, fnsIsAfter, fnsIsBefore, fnsIsEqual, fnsIsSameDay, fnsIsSameMonth, fnsIsSameYear, fnsSetDate, fnsSetMonth, fnsSetYear, fnsStartOfDay, fnsStartOfMonth, };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,11 @@
1
- export { default } from './DatePicker';
2
- export { default as RawDatePicker } from './RawDatePicker/RawDatePicker';
3
- export { default as DatePicker } from './DatePicker';
4
- export { default as MonthPicker } from './Elements/MonthPicker/MonthPicker';
5
- export { default as YearPicker } from './Elements/YearPicker/YearPicker';
1
+ export { default, default as DatePicker } from './DatePicker';
2
+ export type { DatePickerProps } from './DatePicker.types';
6
3
  export { default as DayPicker } from './Elements/DayPicker/DayPicker';
4
+ export { default as MonthPicker } from './Elements/MonthPicker/MonthPicker';
7
5
  export { default as TimePicker } from './Elements/TimePicker/TimePicker';
8
- export type { DatePickerProps } from './DatePicker.types';
6
+ export { default as YearPicker } from './Elements/YearPicker/YearPicker';
7
+ export * from './fns';
9
8
  export { default as datePickerFormat } from './format';
10
9
  export { default as localeUtils } from './localeUtils';
11
- export * from './fns';
10
+ export { default as RawDatePicker } from './RawDatePicker/RawDatePicker';
12
11
  export { getDefaultTexts } from './utils/getDefaultTexts';
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
1
  import { default as default2, default as default3 } from "./DatePicker.js";
2
- import { default as default4 } from "./RawDatePicker/RawDatePicker.js";
2
+ import { default as default4 } from "./Elements/DayPicker/DayPicker.js";
3
3
  import { default as default5 } from "./Elements/MonthPicker/MonthPicker.js";
4
- import { default as default6 } from "./Elements/YearPicker/YearPicker.js";
5
- import { default as default7 } from "./Elements/DayPicker/DayPicker.js";
6
- import { default as default8 } from "./Elements/TimePicker/TimePicker.js";
7
- import { default as default9 } from "./format.js";
8
- import { default as default10 } from "./localeUtils.js";
4
+ import { default as default6 } from "./Elements/TimePicker/TimePicker.js";
5
+ import { default as default7 } from "./Elements/YearPicker/YearPicker.js";
9
6
  import { addDays, addMonths, addSeconds, addYears, differenceInSeconds, differenceInYears, endOfDay, endOfMonth, format, getSeconds, getYear, isAfter, isBefore, isEqual, isSameDay, isSameMonth, isSameYear, setDate, setMonth, setYear, startOfDay, startOfMonth } from "date-fns";
7
+ import { default as default8 } from "./format.js";
8
+ import { default as default9 } from "./localeUtils.js";
9
+ import { default as default10 } from "./RawDatePicker/RawDatePicker.js";
10
10
  import { getDefaultTexts } from "./utils/getDefaultTexts.js";
11
11
  export {
12
12
  default2 as DatePicker,
13
- default7 as DayPicker,
13
+ default4 as DayPicker,
14
14
  default5 as MonthPicker,
15
- default4 as RawDatePicker,
16
- default8 as TimePicker,
17
- default6 as YearPicker,
18
- default9 as datePickerFormat,
15
+ default10 as RawDatePicker,
16
+ default6 as TimePicker,
17
+ default7 as YearPicker,
18
+ default8 as datePickerFormat,
19
19
  default3 as default,
20
20
  addDays as fnsAddDays,
21
21
  addMonths as fnsAddMonths,
@@ -40,5 +40,5 @@ export {
40
40
  startOfDay as fnsStartOfDay,
41
41
  startOfMonth as fnsStartOfMonth,
42
42
  getDefaultTexts,
43
- default10 as localeUtils
43
+ default9 as localeUtils
44
44
  };
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export declare const range: (start: number, end: number) => number[];
2
2
  export declare function getDecadeRange(cursor: Date): number[];
3
3
  export declare function getCenturyRange(cursor: Date): number[];
4
- export declare function changeDayWithHoursPreserved(oldDate: Date, chosenDate: Date): Date;
package/dist/utils.js CHANGED
@@ -1,5 +1,4 @@
1
- import { getYear, differenceInCalendarDays, differenceInSeconds, addSeconds } from "date-fns";
2
- import toDateValue from "./toDateValue.js";
1
+ import { getYear } from "date-fns";
3
2
  const range = (start, end) => {
4
3
  if (end <= start) {
5
4
  return [];
@@ -17,14 +16,7 @@ function getCenturyRange(cursor) {
17
16
  const endYear = startYear + 99;
18
17
  return [startYear, endYear];
19
18
  }
20
- function changeDayWithHoursPreserved(oldDate, chosenDate) {
21
- const dayDifferenceInSeconds = differenceInCalendarDays(toDateValue(oldDate), toDateValue(chosenDate)) * 24 * 60 * 60;
22
- const difference = differenceInSeconds(oldDate, chosenDate) - dayDifferenceInSeconds;
23
- const dateToBeUpdated = addSeconds(chosenDate, difference);
24
- return dateToBeUpdated;
25
- }
26
19
  export {
27
- changeDayWithHoursPreserved,
28
20
  getCenturyRange,
29
21
  getDecadeRange,
30
22
  range
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-date-picker",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "DatePicker UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "Synerise/synerise-design",
@@ -30,7 +30,8 @@
30
30
  "build:watch": "vite build --watch",
31
31
  "pack:ci": "pnpm pack --pack-destination ../../storybook/storybook-static/static",
32
32
  "prepublish": "pnpm run build",
33
- "test": "vitest run",
33
+ "test": "vitest run && pnpm test:dst",
34
+ "test:dst": "TZ=Europe/Warsaw vitest run -t DaylightSavings",
34
35
  "test:watch": "vitest",
35
36
  "types": "tsc --noEmit",
36
37
  "check:circular-dependencies": "madge --circular --extensions ts,tsx,js,jsx --ts-config tsconfig.json src/ --exclude '/dist/'",
@@ -42,14 +43,14 @@
42
43
  ],
43
44
  "types": "dist/index.d.ts",
44
45
  "dependencies": {
45
- "@synerise/ds-button": "^2.0.2",
46
- "@synerise/ds-dropdown": "^2.0.3",
47
- "@synerise/ds-icon": "^2.1.0",
48
- "@synerise/ds-input": "^2.0.3",
49
- "@synerise/ds-time-picker": "^2.0.3",
50
- "@synerise/ds-tooltip": "^2.0.2",
51
- "@synerise/ds-typography": "^2.0.2",
52
- "@synerise/ds-utils": "^2.0.0",
46
+ "@synerise/ds-button": "^2.0.4",
47
+ "@synerise/ds-dropdown": "^2.1.1",
48
+ "@synerise/ds-icon": "^2.1.2",
49
+ "@synerise/ds-input": "^2.0.5",
50
+ "@synerise/ds-time-picker": "^2.0.5",
51
+ "@synerise/ds-tooltip": "^2.0.4",
52
+ "@synerise/ds-typography": "^2.0.4",
53
+ "@synerise/ds-utils": "^2.1.1",
53
54
  "classnames": "^2.5.1",
54
55
  "date-fns": "^4.1.0",
55
56
  "lodash.range": "^3.2.0",
@@ -66,5 +67,5 @@
66
67
  "react-intl": ">=3.12.0 <= 6.8",
67
68
  "styled-components": "^5.3.3"
68
69
  },
69
- "gitHead": "a49acd96b6f71f5617548ae5ce6126cb9b0985dc"
70
+ "gitHead": "b1d905617dfb186b5d80966d63ce55bf29df743d"
70
71
  }