@cloud-ru/ds-calendar 1.0.22 → 1.1.1

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +3 -0
  3. package/dist/cjs/components/TimePickerDropdown/TimePickerDropdown.d.ts +3 -0
  4. package/dist/cjs/constants.d.ts +4 -0
  5. package/dist/cjs/constants.js +5 -1
  6. package/dist/cjs/helperComponents/DesktopTimePickerDropdown/DesktopTimePickerDropdown.d.ts +1 -1
  7. package/dist/cjs/helperComponents/DesktopTimePickerDropdown/DesktopTimePickerDropdown.js +2 -2
  8. package/dist/cjs/helperComponents/Footer/Footer.d.ts +2 -1
  9. package/dist/cjs/helperComponents/Footer/Footer.js +15 -10
  10. package/dist/cjs/helperComponents/MobileTimePickerDropdown/MobileTimePickerDropdown.d.ts +1 -1
  11. package/dist/cjs/helperComponents/MobileTimePickerDropdown/MobileTimePickerDropdown.js +4 -2
  12. package/dist/cjs/helperComponents/TimePickerBase/TimePickerBase.js +2 -2
  13. package/dist/cjs/types.d.ts +2 -1
  14. package/dist/esm/components/TimePickerDropdown/TimePickerDropdown.d.ts +3 -0
  15. package/dist/esm/constants.d.ts +4 -0
  16. package/dist/esm/constants.js +4 -0
  17. package/dist/esm/helperComponents/DesktopTimePickerDropdown/DesktopTimePickerDropdown.d.ts +1 -1
  18. package/dist/esm/helperComponents/DesktopTimePickerDropdown/DesktopTimePickerDropdown.js +3 -3
  19. package/dist/esm/helperComponents/Footer/Footer.d.ts +2 -1
  20. package/dist/esm/helperComponents/Footer/Footer.js +15 -10
  21. package/dist/esm/helperComponents/MobileTimePickerDropdown/MobileTimePickerDropdown.d.ts +1 -1
  22. package/dist/esm/helperComponents/MobileTimePickerDropdown/MobileTimePickerDropdown.js +5 -3
  23. package/dist/esm/helperComponents/TimePickerBase/TimePickerBase.js +2 -2
  24. package/dist/esm/types.d.ts +2 -1
  25. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  26. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  27. package/package.json +6 -6
  28. package/src/components/TimePickerDropdown/TimePickerDropdown.tsx +3 -0
  29. package/src/constants.ts +5 -0
  30. package/src/helperComponents/DesktopTimePickerDropdown/DesktopTimePickerDropdown.tsx +7 -2
  31. package/src/helperComponents/Footer/Footer.tsx +19 -10
  32. package/src/helperComponents/MobileTimePickerDropdown/MobileTimePickerDropdown.tsx +7 -2
  33. package/src/helperComponents/TimePickerBase/TimePickerBase.tsx +2 -2
  34. package/src/types.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-ru/ds-calendar",
3
- "version": "1.0.22",
3
+ "version": "1.1.1",
4
4
  "description": "Пакет календаря и выбора времени — Calendar с режимами даты, диапазона и месяца/года, TimePicker и TimePickerDropdown для времени в составе полей ввода.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,16 +48,16 @@
48
48
  "@tanstack/react-virtual": "^3.14.8",
49
49
  "classnames": "^2.5.1",
50
50
  "weekstart": "^2.0.0",
51
- "@cloud-ru/ds-button": "^1.0.4",
52
51
  "@cloud-ru/ds-adaptive": "^1.0.2",
53
52
  "@cloud-ru/ds-bottom-sheet": "^1.1.6",
54
- "@cloud-ru/ds-divider": "^1.0.2",
55
- "@cloud-ru/ds-list": "^2.2.4",
56
53
  "@cloud-ru/ds-dropdown": "^1.0.13",
54
+ "@cloud-ru/ds-button": "^1.0.4",
55
+ "@cloud-ru/ds-divider": "^1.0.2",
57
56
  "@cloud-ru/ds-icons": "^1.3.0",
58
57
  "@cloud-ru/ds-locale": "^1.0.0",
59
58
  "@cloud-ru/ds-materials": "^2.0.1",
60
- "@cloud-ru/ds-utils": "^1.2.0",
61
- "@cloud-ru/ds-scroll": "^1.0.5"
59
+ "@cloud-ru/ds-scroll": "^1.0.5",
60
+ "@cloud-ru/ds-list": "^2.2.5",
61
+ "@cloud-ru/ds-utils": "^1.2.0"
62
62
  }
63
63
  }
@@ -5,6 +5,7 @@ import { ReactNode } from 'react';
5
5
 
6
6
  import { DesktopTimePickerDropdown } from '../../helperComponents/DesktopTimePickerDropdown';
7
7
  import { MobileTimePickerDropdown } from '../../helperComponents/MobileTimePickerDropdown';
8
+ import { TimePickerFooterMode } from '../../types';
8
9
  import { TimePickerProps } from '../TimePicker';
9
10
 
10
11
  type DropdownBridgeProps = Pick<
@@ -35,6 +36,8 @@ export type TimePickerDropdownProps = WithSupportProps<
35
36
  DropdownBridgeProps & {
36
37
  /** Контент триггера открытия dropdown */
37
38
  children?: ReactNode;
39
+ /** Режим футера. По умолчанию — current-time-and-apply */
40
+ footerMode?: TimePickerFooterMode;
38
41
  /** Закрыть dropdown после нажатия кнопки Apply */
39
42
  closeOnApply?: boolean;
40
43
  /** Колбек по нажатию Apply */
package/src/constants.ts CHANGED
@@ -14,6 +14,11 @@ export const CALENDAR_MODE = {
14
14
  YearRange: 'year-range',
15
15
  } as const;
16
16
 
17
+ export const TIME_PICKER_FOOTER_MODE = {
18
+ CurrentTimeAndApply: 'current-time-and-apply',
19
+ ApplyOnly: 'apply-only',
20
+ } as const;
21
+
17
22
  export const RANGE_POSITION = {
18
23
  Out: 'out',
19
24
  Start: 'start',
@@ -8,7 +8,7 @@ import { useCallback, useMemo, useRef, useState } from 'react';
8
8
  import { DEFAULT_LOCALE } from '../../components/TimePicker/constants';
9
9
  import styles from '../../components/TimePickerDropdown/styles.module.scss';
10
10
  import { TimePickerDropdownProps } from '../../components/TimePickerDropdown/TimePickerDropdown';
11
- import { SIZE } from '../../constants';
11
+ import { SIZE, TIME_PICKER_FOOTER_MODE } from '../../constants';
12
12
  import { useTimePickerValueBridge } from '../../hooks';
13
13
  import { BuildCellPropsFunction } from '../../types';
14
14
  import { getLocale, getTestIdBuilder } from '../../utils';
@@ -33,6 +33,7 @@ export function DesktopTimePickerDropdown({
33
33
  today: todayProp,
34
34
  children,
35
35
  closeOnApply = false,
36
+ footerMode = TIME_PICKER_FOOTER_MODE.CurrentTimeAndApply,
36
37
  onApply,
37
38
  onCurrent,
38
39
  open: openProp,
@@ -175,7 +176,11 @@ export function DesktopTimePickerDropdown({
175
176
  // отдельный от `content` регион.
176
177
  const footer = (
177
178
  <CalendarContext.Provider value={calendarContextValue}>
178
- <Footer onApply={handleApply} onCurrent={onCurrent} />
179
+ <Footer
180
+ onApply={handleApply}
181
+ onCurrent={onCurrent}
182
+ showCurrent={footerMode === TIME_PICKER_FOOTER_MODE.CurrentTimeAndApply}
183
+ />
179
184
  </CalendarContext.Provider>
180
185
  );
181
186
 
@@ -22,6 +22,7 @@ export type FooterProps = {
22
22
  * где обвязку даёт сам Dropdown.
23
23
  */
24
24
  inline?: boolean;
25
+ showCurrent?: boolean;
25
26
  };
26
27
 
27
28
  /**
@@ -30,7 +31,7 @@ export type FooterProps = {
30
31
  * modal / drawer / bottom-sheet (Figma `popupDropdownFooter`). Читает состояние из
31
32
  * `CalendarContext`, поэтому рендерится только внутри провайдера контекста.
32
33
  */
33
- export function Footer({ onApply, onCurrent, inline = false }: FooterProps) {
34
+ export function Footer({ onApply, onCurrent, inline = false, showCurrent = true }: FooterProps) {
34
35
  const {
35
36
  viewMode,
36
37
  mode,
@@ -80,6 +81,10 @@ export function Footer({ onApply, onCurrent, inline = false }: FooterProps) {
80
81
  };
81
82
 
82
83
  const handleApplyKeyDown: KeyboardEventHandler = event => {
84
+ if (event.key === 'Tab' && event.shiftKey && !showCurrent) {
85
+ handleCurrentKeyDown(event);
86
+ }
87
+
83
88
  if (event.key === 'Tab' && !event.shiftKey) {
84
89
  onFocusLeave?.('next');
85
90
  }
@@ -132,15 +137,19 @@ export function Footer({ onApply, onCurrent, inline = false }: FooterProps) {
132
137
  onClick: handleApplySelection,
133
138
  onKeyDown: handleApplyKeyDown,
134
139
  }}
135
- additionalButton={{
136
- label: t('current'),
137
- // `popupDropdownFooter` держит третью кнопку на `function`, а не на дефолтном
138
- // из `FooterActions` `simple`: у `simple` остаётся горизонтальный паддинг.
139
- view: VIEW.Function,
140
- innerRef: currentButtonRef as RefObject<HTMLButtonElement>,
141
- onClick: handleCurrentClick,
142
- onKeyDown: handleCurrentKeyDown,
143
- }}
140
+ additionalButton={
141
+ showCurrent
142
+ ? {
143
+ label: t('current'),
144
+ // `popupDropdownFooter` держит третью кнопку на `function`, а не на дефолтном
145
+ // из `FooterActions` `simple`: у `simple` остаётся горизонтальный паддинг.
146
+ view: VIEW.Function,
147
+ innerRef: currentButtonRef as RefObject<HTMLButtonElement>,
148
+ onClick: handleCurrentClick,
149
+ onKeyDown: handleCurrentKeyDown,
150
+ }
151
+ : undefined
152
+ }
144
153
  testIds={{
145
154
  approve: getTestId('apply-button') ?? '',
146
155
  additional: getTestId('current-button') ?? '',
@@ -3,7 +3,7 @@ import { extractSupportProps, useLayoutEffect, useUncontrolledProp, useValueCont
3
3
  import { useCallback, useMemo, useRef } from 'react';
4
4
 
5
5
  import { TimePickerDropdownProps } from '../../components/TimePickerDropdown/TimePickerDropdown';
6
- import { SIZE, TEST_IDS } from '../../constants';
6
+ import { SIZE, TEST_IDS, TIME_PICKER_FOOTER_MODE } from '../../constants';
7
7
  import { useDateAndTime, useOpenTrigger, useTimeDrumHandlers } from '../../hooks';
8
8
  import { calendarLocale } from '../../locale';
9
9
  import { TimeValue } from '../../types';
@@ -22,6 +22,7 @@ export function MobileTimePickerDropdown({
22
22
  showSeconds = true,
23
23
  today: todayProp,
24
24
  closeOnApply = false,
25
+ footerMode = TIME_PICKER_FOOTER_MODE.CurrentTimeAndApply,
25
26
  onApply,
26
27
  onCurrent,
27
28
  open: openProp,
@@ -105,7 +106,11 @@ export function MobileTimePickerDropdown({
105
106
  title={t('time')}
106
107
  closeOnPopstate={closeOnPopstate}
107
108
  approveButton={{ label: t('apply'), disabled: !isTimeFilled(), onClick: handleApply }}
108
- additionalButton={{ label: t('current'), view: 'function', onClick: handleCurrent }}
109
+ additionalButton={
110
+ footerMode === TIME_PICKER_FOOTER_MODE.CurrentTimeAndApply
111
+ ? { label: t('current'), view: 'function', onClick: handleCurrent }
112
+ : undefined
113
+ }
109
114
  footerTestIds={{ approve: TEST_IDS.timePickerMobileApply, additional: TEST_IDS.timePickerMobileCurrent }}
110
115
  content={
111
116
  <TimePickerDrum
@@ -102,7 +102,7 @@ export function TimePickerBase({ className, fixedWidth }: TimePickerBaseProps) {
102
102
  if (showSeconds) {
103
103
  secondsKeyboardNavigationRef.current?.focusItem(getDefaultItemId(seconds ?? 0));
104
104
  } else {
105
- currentButtonRef.current?.focus();
105
+ (currentButtonRef.current ?? applyButtonRef.current)?.focus();
106
106
  }
107
107
  }
108
108
  break;
@@ -138,7 +138,7 @@ export function TimePickerBase({ className, fixedWidth }: TimePickerBaseProps) {
138
138
  if (event.shiftKey) {
139
139
  minutesKeyboardNavigationRef.current?.focusItem(getDefaultItemId(minutes ?? 0));
140
140
  } else {
141
- currentButtonRef.current?.focus();
141
+ (currentButtonRef.current ?? applyButtonRef.current)?.focus();
142
142
  }
143
143
  break;
144
144
  case 'Enter':
package/src/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ValueOf } from '@cloud-ru/ds-utils';
2
2
  import { KeyboardEventHandler } from 'react';
3
3
 
4
- import { CALENDAR_MODE, RANGE_POSITION, SIZE, VIEW_MODE } from './constants';
4
+ import { CALENDAR_MODE, RANGE_POSITION, SIZE, TIME_PICKER_FOOTER_MODE, VIEW_MODE } from './constants';
5
5
 
6
6
  export type RangePosition = ValueOf<typeof RANGE_POSITION>;
7
7
 
@@ -54,6 +54,8 @@ export type FocusDirection = 'prev' | 'next';
54
54
  export type BuildCellProps = { isDisabled?: boolean; isHoliday?: boolean };
55
55
  export type BuildCellPropsFunction = (date: Date, viewMode: ViewMode) => BuildCellProps;
56
56
 
57
+ export type TimePickerFooterMode = ValueOf<typeof TIME_PICKER_FOOTER_MODE>;
58
+
57
59
  export type TimeValue = {
58
60
  hours?: number;
59
61
  minutes?: number;