@vkontakte/vkui 7.6.3 → 7.7.0

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 (149) hide show
  1. package/dist/components/Calendar/Calendar.d.ts.map +1 -1
  2. package/dist/components/Calendar/Calendar.js +1 -2
  3. package/dist/components/Calendar/Calendar.js.map +1 -1
  4. package/dist/components/CalendarHeader/CalendarHeader.js +1 -1
  5. package/dist/components/CalendarHeader/CalendarHeader.js.map +1 -1
  6. package/dist/components/CalendarRange/CalendarRange.d.ts.map +1 -1
  7. package/dist/components/CalendarRange/CalendarRange.js +2 -3
  8. package/dist/components/CalendarRange/CalendarRange.js.map +1 -1
  9. package/dist/components/CalendarRange/utils.d.ts.map +1 -1
  10. package/dist/components/CalendarRange/utils.js +1 -2
  11. package/dist/components/CalendarRange/utils.js.map +1 -1
  12. package/dist/components/CalendarTime/CalendarTime.js +1 -1
  13. package/dist/components/CalendarTime/CalendarTime.js.map +1 -1
  14. package/dist/components/CarouselBase/CarouselBase.d.ts +1 -1
  15. package/dist/components/CarouselBase/CarouselBase.d.ts.map +1 -1
  16. package/dist/components/CarouselBase/CarouselBase.js +44 -19
  17. package/dist/components/CarouselBase/CarouselBase.js.map +1 -1
  18. package/dist/components/CarouselBase/CarouselViewPort.d.ts +3 -2
  19. package/dist/components/CarouselBase/CarouselViewPort.d.ts.map +1 -1
  20. package/dist/components/CarouselBase/CarouselViewPort.js +13 -1
  21. package/dist/components/CarouselBase/CarouselViewPort.js.map +1 -1
  22. package/dist/components/CarouselBase/ScrollArrows.d.ts +3 -2
  23. package/dist/components/CarouselBase/ScrollArrows.d.ts.map +1 -1
  24. package/dist/components/CarouselBase/ScrollArrows.js +22 -11
  25. package/dist/components/CarouselBase/ScrollArrows.js.map +1 -1
  26. package/dist/components/CarouselBase/hooks.d.ts +1 -0
  27. package/dist/components/CarouselBase/hooks.d.ts.map +1 -1
  28. package/dist/components/CarouselBase/hooks.js +4 -0
  29. package/dist/components/CarouselBase/hooks.js.map +1 -1
  30. package/dist/components/CarouselBase/types.d.ts +9 -0
  31. package/dist/components/CarouselBase/types.d.ts.map +1 -1
  32. package/dist/components/CarouselBase/types.js.map +1 -1
  33. package/dist/components/Cell/Cell.d.ts +4 -0
  34. package/dist/components/Cell/Cell.d.ts.map +1 -1
  35. package/dist/components/Cell/Cell.js +3 -1
  36. package/dist/components/Cell/Cell.js.map +1 -1
  37. package/dist/components/CustomSelect/CustomSelect.d.ts.map +1 -1
  38. package/dist/components/CustomSelect/CustomSelect.js +4 -2
  39. package/dist/components/CustomSelect/CustomSelect.js.map +1 -1
  40. package/dist/components/DateInput/DateInput.d.ts.map +1 -1
  41. package/dist/components/DateInput/DateInput.js +1 -2
  42. package/dist/components/DateInput/DateInput.js.map +1 -1
  43. package/dist/components/Gallery/Gallery.d.ts +5 -1
  44. package/dist/components/Gallery/Gallery.d.ts.map +1 -1
  45. package/dist/components/Gallery/Gallery.js +19 -3
  46. package/dist/components/Gallery/Gallery.js.map +1 -1
  47. package/dist/components/ModalPage/ModalPageInternal.js +16 -8
  48. package/dist/components/ModalPage/ModalPageInternal.js.map +1 -1
  49. package/dist/components/ModalPage/types.d.ts +2 -2
  50. package/dist/components/ModalPage/types.d.ts.map +1 -1
  51. package/dist/components/ModalPage/types.js.map +1 -1
  52. package/dist/components/Search/Search.d.ts +5 -1
  53. package/dist/components/Search/Search.d.ts.map +1 -1
  54. package/dist/components/Search/Search.js +6 -4
  55. package/dist/components/Search/Search.js.map +1 -1
  56. package/dist/components.css +1 -1
  57. package/dist/components.css.map +1 -1
  58. package/dist/cssm/components/Calendar/Calendar.js +1 -2
  59. package/dist/cssm/components/Calendar/Calendar.js.map +1 -1
  60. package/dist/cssm/components/CalendarHeader/CalendarHeader.js +1 -1
  61. package/dist/cssm/components/CalendarHeader/CalendarHeader.js.map +1 -1
  62. package/dist/cssm/components/CalendarRange/CalendarRange.js +2 -3
  63. package/dist/cssm/components/CalendarRange/CalendarRange.js.map +1 -1
  64. package/dist/cssm/components/CalendarRange/utils.js +1 -2
  65. package/dist/cssm/components/CalendarRange/utils.js.map +1 -1
  66. package/dist/cssm/components/CalendarTime/CalendarTime.js +1 -1
  67. package/dist/cssm/components/CalendarTime/CalendarTime.js.map +1 -1
  68. package/dist/cssm/components/CarouselBase/CarouselBase.js +37 -16
  69. package/dist/cssm/components/CarouselBase/CarouselBase.js.map +1 -1
  70. package/dist/cssm/components/CarouselBase/CarouselBase.module.css +2 -0
  71. package/dist/cssm/components/CarouselBase/CarouselViewPort.js +13 -1
  72. package/dist/cssm/components/CarouselBase/CarouselViewPort.js.map +1 -1
  73. package/dist/cssm/components/CarouselBase/ScrollArrows.js +14 -7
  74. package/dist/cssm/components/CarouselBase/ScrollArrows.js.map +1 -1
  75. package/dist/cssm/components/CarouselBase/hooks.js +4 -0
  76. package/dist/cssm/components/CarouselBase/hooks.js.map +1 -1
  77. package/dist/cssm/components/CarouselBase/types.js.map +1 -1
  78. package/dist/cssm/components/Cell/Cell.js +2 -1
  79. package/dist/cssm/components/Cell/Cell.js.map +1 -1
  80. package/dist/cssm/components/CustomSelect/CustomSelect.js +4 -2
  81. package/dist/cssm/components/CustomSelect/CustomSelect.js.map +1 -1
  82. package/dist/cssm/components/DateInput/DateInput.js +1 -2
  83. package/dist/cssm/components/DateInput/DateInput.js.map +1 -1
  84. package/dist/cssm/components/Gallery/Gallery.js +14 -1
  85. package/dist/cssm/components/Gallery/Gallery.js.map +1 -1
  86. package/dist/cssm/components/ModalCard/ModalCard.module.css +0 -1
  87. package/dist/cssm/components/ModalOutlet/ModalOutlet.module.css +1 -0
  88. package/dist/cssm/components/ModalPage/ModalPage.module.css +2 -9
  89. package/dist/cssm/components/ModalPage/ModalPageInternal.js +16 -8
  90. package/dist/cssm/components/ModalPage/ModalPageInternal.js.map +1 -1
  91. package/dist/cssm/components/ModalPage/types.js.map +1 -1
  92. package/dist/cssm/components/Search/Search.js +4 -3
  93. package/dist/cssm/components/Search/Search.js.map +1 -1
  94. package/dist/cssm/components/Slider/SliderThumb/SliderThumb.module.css +2 -2
  95. package/dist/cssm/hooks/useCalendar.js +1 -2
  96. package/dist/cssm/hooks/useCalendar.js.map +1 -1
  97. package/dist/cssm/hooks/useTodayDate.js +2 -2
  98. package/dist/cssm/hooks/useTodayDate.js.map +1 -1
  99. package/dist/cssm/lib/calendar.js +8 -12
  100. package/dist/cssm/lib/calendar.js.map +1 -1
  101. package/dist/cssm/lib/date.js +142 -1
  102. package/dist/cssm/lib/date.js.map +1 -1
  103. package/dist/cssm/styles/constants.css +3 -0
  104. package/dist/hooks/useCalendar.d.ts.map +1 -1
  105. package/dist/hooks/useCalendar.js +1 -2
  106. package/dist/hooks/useCalendar.js.map +1 -1
  107. package/dist/hooks/useTodayDate.js +2 -2
  108. package/dist/hooks/useTodayDate.js.map +1 -1
  109. package/dist/lib/calendar.d.ts.map +1 -1
  110. package/dist/lib/calendar.js +8 -12
  111. package/dist/lib/calendar.js.map +1 -1
  112. package/dist/lib/date.d.ts +41 -0
  113. package/dist/lib/date.d.ts.map +1 -1
  114. package/dist/lib/date.js +142 -1
  115. package/dist/lib/date.js.map +1 -1
  116. package/dist/vkui.css +1 -1
  117. package/dist/vkui.css.map +1 -1
  118. package/package.json +3 -4
  119. package/src/components/Calendar/Calendar.tsx +6 -2
  120. package/src/components/CalendarHeader/CalendarHeader.tsx +1 -1
  121. package/src/components/CalendarRange/CalendarRange.tsx +9 -3
  122. package/src/components/CalendarRange/utils.ts +1 -2
  123. package/src/components/CalendarTime/CalendarTime.tsx +1 -1
  124. package/src/components/CarouselBase/CarouselBase.module.css +2 -0
  125. package/src/components/CarouselBase/CarouselBase.module.css.d.ts.map +1 -1
  126. package/src/components/CarouselBase/CarouselBase.tsx +47 -17
  127. package/src/components/CarouselBase/CarouselViewPort.tsx +25 -2
  128. package/src/components/CarouselBase/ScrollArrows.tsx +14 -2
  129. package/src/components/CarouselBase/hooks.ts +6 -0
  130. package/src/components/CarouselBase/types.ts +9 -0
  131. package/src/components/Cell/Cell.tsx +6 -0
  132. package/src/components/CustomSelect/CustomSelect.tsx +4 -2
  133. package/src/components/DateInput/DateInput.tsx +8 -2
  134. package/src/components/Gallery/Gallery.tsx +20 -0
  135. package/src/components/ModalCard/ModalCard.module.css +0 -1
  136. package/src/components/ModalCard/ModalCard.module.css.d.ts.map +1 -1
  137. package/src/components/ModalOutlet/ModalOutlet.module.css +1 -0
  138. package/src/components/ModalPage/ModalPage.module.css +2 -9
  139. package/src/components/ModalPage/ModalPage.module.css.d.ts.map +1 -1
  140. package/src/components/ModalPage/ModalPageInternal.tsx +8 -11
  141. package/src/components/ModalPage/types.ts +5 -2
  142. package/src/components/Search/Search.tsx +44 -31
  143. package/src/components/Slider/SliderThumb/SliderThumb.module.css +1 -1
  144. package/src/hooks/useCalendar.ts +1 -2
  145. package/src/hooks/useTodayDate.ts +2 -2
  146. package/src/lib/calendar.ts +12 -10
  147. package/src/lib/date.ts +187 -0
  148. package/src/lib/floating/useFloatingWithInteractions/__snapshots__/useFloatingWithInteractions.test.tsx.snap +1 -1
  149. package/src/styles/constants.css +3 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/ModalPage/ModalPageInternal.tsx"],"sourcesContent":["'use client';\n/* eslint-disable jsdoc/require-jsdoc */\n\nimport { type ComponentType, type KeyboardEvent, useCallback } from 'react';\nimport { classNames, noop } from '@vkontakte/vkjs';\nimport { mergeStyle } from '../../helpers/mergeStyle';\nimport { useAdaptivityWithJSMediaQueries } from '../../hooks/useAdaptivityWithJSMediaQueries';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useVirtualKeyboardState } from '../../hooks/useVirtualKeyboardState';\nimport { Keys, pressedKey } from '../../lib/accessibility';\nimport { useCSSTransition, type UseCSSTransitionState } from '../../lib/animation';\nimport { type SnapPoint, type SnapPointChange, useBottomSheet } from '../../lib/sheet';\nimport type { CSSCustomProperties } from '../../types';\nimport { useScrollLock } from '../AppRoot/ScrollContext';\nimport { useConfigProvider } from '../ConfigProvider/ConfigProviderContext';\nimport { FocusTrap } from '../FocusTrap/FocusTrap';\nimport { ModalOutlet } from '../ModalOutlet/ModalOutlet';\nimport {\n ModalOverlay as ModalOverlayDefault,\n type ModalOverlayProps,\n} from '../ModalOverlay/ModalOverlay';\nimport { ModalPageBase } from './ModalPageBase';\nimport type { ModalPageProps } from './types';\nimport styles from './ModalPage.module.css';\n\nconst transitionStateClassNames: Partial<Record<UseCSSTransitionState, string>> = {\n appear: styles['documentStateEnter'],\n appearing: styles['documentStateEntering'],\n\n enter: styles['documentStateEnter'],\n entering: styles['documentStateEntering'],\n\n exiting: styles['documentStateExiting'],\n exited: styles['documentStateExited'],\n};\n\nexport interface ModalPageInternalProps\n extends Omit<ModalPageProps, 'nav' | 'keepMounted' | 'settlingHeight' | 'dynamicContentHeight'> {\n snapPoint: SnapPoint;\n ModalOverlay?: ComponentType<ModalOverlayProps>;\n onSnapPointChange?: SnapPointChange;\n}\n\n/**\n * В компоненте заложена вся логика модального окна.\n *\n * @private\n */\nexport const ModalPageInternal = ({\n open,\n header,\n footer,\n size: desktopMaxWidth,\n height,\n children,\n className,\n style,\n snapPoint,\n onSnapPointChange,\n getModalContentRef,\n ModalOverlay = ModalOverlayDefault,\n modalOverlayTestId,\n modalContentTestId,\n modalDismissButtonTestId,\n modalDismissButtonLabel = 'Закрыть',\n outsideButtons,\n noFocusToDialog,\n hideCloseButton,\n preventClose,\n disableContentPanningGesture,\n restoreFocus,\n onOpen,\n onOpened,\n onClose = noop,\n onClosed,\n disableFocusTrap,\n disableModalOverlay,\n ...restProps\n}: ModalPageInternalProps) => {\n const { hasCustomPanelHeaderAfter } = useConfigProvider();\n const [transitionState, { ref, onTransitionEnd }] = useCSSTransition<HTMLDivElement>(open, {\n enableAppear: true,\n onEnter() {\n onOpen?.();\n },\n onEntered() {\n onOpened?.();\n },\n onExited() {\n onClosed?.();\n },\n });\n const opened = transitionState === 'appeared' || transitionState === 'entered';\n const hidden = transitionState === 'exited';\n const closable = !preventClose && opened;\n\n const { sizeX, isDesktop } = useAdaptivityWithJSMediaQueries();\n const bottomSheetEnabled = !isDesktop && !preventClose && transitionState !== 'exited';\n const { opened: keyboardOpened } = useVirtualKeyboardState(bottomSheetEnabled);\n\n const [{ initialStyle, setSheetEl, setSheetScrollEl, setBackdropEl }, bottomSheetEventHandlers] =\n useBottomSheet(bottomSheetEnabled, {\n blocked: keyboardOpened,\n snapPoint,\n sheetCSSProperty: '--vkui_internal_ModalPageDocument--snapPoint',\n backdropCSSProperty: '--vkui_internal--modal-overlay--opacity',\n onSnapPointChange,\n onDismiss() {\n onClose('swipe-down');\n },\n });\n const documentStyle = keyboardOpened\n ? {\n '--vkui_internal_ModalPageDocument--safeAreaInsetBottom': '0px',\n ...initialStyle,\n }\n : initialStyle;\n const handleSheetRef = useExternRef<HTMLDivElement>(setSheetEl, ref);\n const handleSheetScrollRef = useExternRef<HTMLDivElement>(setSheetScrollEl, getModalContentRef);\n\n const [desktopMaxWidthClassName, desktopMaxWidthStyle] = resolveDesktopMaxWidth(\n isDesktop ? desktopMaxWidth : 's',\n );\n\n const modalOverlay = !disableModalOverlay && (\n <ModalOverlay\n getRootRef={setBackdropEl}\n data-testid={modalOverlayTestId}\n visible={open}\n onClick={\n closable\n ? function handleBackdropClick(event) {\n onClose('click-overlay', event);\n }\n : undefined\n }\n />\n );\n const handleEscKeyDown = useCallback(\n (event: KeyboardEvent<HTMLElement>) => {\n if (closable && pressedKey(event) === Keys.ESCAPE) {\n onClose('escape-key');\n }\n },\n [closable, onClose],\n );\n\n useScrollLock(!hidden);\n\n return (\n <ModalOutlet\n hidden={hidden}\n isDesktop={isDesktop}\n onKeyDown={handleEscKeyDown}\n disableModalOverlay={disableModalOverlay}\n >\n {modalOverlay}\n <FocusTrap\n {...restProps}\n autoFocus={!noFocusToDialog}\n restoreFocus={restoreFocus}\n role=\"dialog\"\n aria-modal=\"true\"\n disabled={!opened || hidden || disableFocusTrap}\n className={classNames(\n className,\n styles.host,\n isDesktop ? styles.hostDesktop : styles.hostMobile,\n !isDesktop &&\n (hasCustomPanelHeaderAfter\n ? styles.hostMobileSafeAreaInsetTopWithCustomOffset\n : styles.hostMobileSafeAreaInsetTop),\n desktopMaxWidthClassName,\n sizeX === 'regular' && 'vkuiInternalModalPage--sizeX-regular',\n )}\n style={mergeStyle(mergeStyle(desktopMaxWidthStyle, getHeightCSSVariable(height)), style)}\n >\n <ModalPageBase\n {...bottomSheetEventHandlers}\n getRootRef={handleSheetRef}\n getRef={handleSheetScrollRef}\n style={documentStyle}\n className={classNames(\n isDesktop ? styles.documentDesktop : styles.documentMobile,\n transitionStateClassNames[transitionState],\n )}\n onTransitionEnd={onTransitionEnd}\n isDesktop={isDesktop}\n disableContentPanningGesture={disableContentPanningGesture}\n header={header}\n footer={footer}\n outsideButtons={outsideButtons}\n modalContentTestId={modalContentTestId}\n modalDismissButtonTestId={modalDismissButtonTestId}\n modalDismissButtonLabel={modalDismissButtonLabel}\n hideCloseButton={hideCloseButton}\n closable={closable}\n onClose={onClose}\n >\n {children}\n </ModalPageBase>\n </FocusTrap>\n </ModalOutlet>\n );\n};\n\nconst desktopMaxWidthClassNames = {\n s: styles['hostDesktopMaxWidthS'],\n m: styles['hostDesktopMaxWidthM'],\n l: styles['hostDesktopMaxWidthL'],\n};\n\nfunction resolveDesktopMaxWidth(\n desktopMaxWidth: ModalPageInternalProps['size'] = 's',\n): [string | undefined, CSSCustomProperties | undefined] {\n if (typeof desktopMaxWidth === 'string') {\n return [desktopMaxWidthClassNames[desktopMaxWidth], undefined];\n }\n\n return [\n undefined,\n typeof desktopMaxWidth === 'number'\n ? { '--vkui_internal_ModalPage--desktopMaxWidth': `${desktopMaxWidth}px` }\n : undefined,\n ];\n}\n\nfunction getHeightCSSVariable(height?: number | string): CSSCustomProperties | undefined {\n return height !== undefined\n ? {\n '--vkui_internal_ModalPage--userHeight':\n typeof height === 'number' ? `${height}px` : height,\n }\n : undefined;\n}\n"],"names":["useCallback","classNames","noop","mergeStyle","useAdaptivityWithJSMediaQueries","useExternRef","useVirtualKeyboardState","Keys","pressedKey","useCSSTransition","useBottomSheet","useScrollLock","useConfigProvider","FocusTrap","ModalOutlet","ModalOverlay","ModalOverlayDefault","ModalPageBase","styles","transitionStateClassNames","appear","appearing","enter","entering","exiting","exited","ModalPageInternal","open","header","footer","size","desktopMaxWidth","height","children","className","style","snapPoint","onSnapPointChange","getModalContentRef","modalOverlayTestId","modalContentTestId","modalDismissButtonTestId","modalDismissButtonLabel","outsideButtons","noFocusToDialog","hideCloseButton","preventClose","disableContentPanningGesture","restoreFocus","onOpen","onOpened","onClose","onClosed","disableFocusTrap","disableModalOverlay","restProps","hasCustomPanelHeaderAfter","transitionState","ref","onTransitionEnd","enableAppear","onEnter","onEntered","onExited","opened","hidden","closable","sizeX","isDesktop","bottomSheetEnabled","keyboardOpened","initialStyle","setSheetEl","setSheetScrollEl","setBackdropEl","bottomSheetEventHandlers","blocked","sheetCSSProperty","backdropCSSProperty","onDismiss","documentStyle","handleSheetRef","handleSheetScrollRef","desktopMaxWidthClassName","desktopMaxWidthStyle","resolveDesktopMaxWidth","modalOverlay","getRootRef","data-testid","visible","onClick","handleBackdropClick","event","undefined","handleEscKeyDown","ESCAPE","onKeyDown","autoFocus","role","aria-modal","disabled","host","hostDesktop","hostMobile","hostMobileSafeAreaInsetTopWithCustomOffset","hostMobileSafeAreaInsetTop","getHeightCSSVariable","getRef","documentDesktop","documentMobile","desktopMaxWidthClassNames","s","m","l"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/ModalPage/ModalPageInternal.tsx"],"sourcesContent":["'use client';\n/* eslint-disable jsdoc/require-jsdoc */\n\nimport { type ComponentType, type KeyboardEvent, useCallback } from 'react';\nimport { classNames, noop } from '@vkontakte/vkjs';\nimport { mergeStyle } from '../../helpers/mergeStyle';\nimport { useAdaptivityWithJSMediaQueries } from '../../hooks/useAdaptivityWithJSMediaQueries';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useVirtualKeyboardState } from '../../hooks/useVirtualKeyboardState';\nimport { Keys, pressedKey } from '../../lib/accessibility';\nimport { useCSSTransition, type UseCSSTransitionState } from '../../lib/animation';\nimport { type SnapPoint, type SnapPointChange, useBottomSheet } from '../../lib/sheet';\nimport type { CSSCustomProperties } from '../../types';\nimport { useScrollLock } from '../AppRoot/ScrollContext';\nimport { useConfigProvider } from '../ConfigProvider/ConfigProviderContext';\nimport { FocusTrap } from '../FocusTrap/FocusTrap';\nimport { ModalOutlet } from '../ModalOutlet/ModalOutlet';\nimport {\n ModalOverlay as ModalOverlayDefault,\n type ModalOverlayProps,\n} from '../ModalOverlay/ModalOverlay';\nimport { ModalPageBase } from './ModalPageBase';\nimport type { ModalPageProps } from './types';\nimport styles from './ModalPage.module.css';\n\nconst transitionStateClassNames: Partial<Record<UseCSSTransitionState, string>> = {\n appear: styles['documentStateEnter'],\n appearing: styles['documentStateEntering'],\n\n enter: styles['documentStateEnter'],\n entering: styles['documentStateEntering'],\n\n exiting: styles['documentStateExiting'],\n exited: styles['documentStateExited'],\n};\n\nexport interface ModalPageInternalProps\n extends Omit<ModalPageProps, 'nav' | 'keepMounted' | 'settlingHeight' | 'dynamicContentHeight'> {\n snapPoint: SnapPoint;\n ModalOverlay?: ComponentType<ModalOverlayProps>;\n onSnapPointChange?: SnapPointChange;\n}\n\n/**\n * В компоненте заложена вся логика модального окна.\n *\n * @private\n */\nexport const ModalPageInternal = ({\n open,\n header,\n footer,\n size: desktopMaxWidth,\n height,\n children,\n className,\n style,\n snapPoint,\n onSnapPointChange,\n getModalContentRef,\n ModalOverlay = ModalOverlayDefault,\n modalOverlayTestId,\n modalContentTestId,\n modalDismissButtonTestId,\n modalDismissButtonLabel = 'Закрыть',\n outsideButtons,\n noFocusToDialog,\n hideCloseButton,\n preventClose,\n disableContentPanningGesture,\n restoreFocus,\n onOpen,\n onOpened,\n onClose = noop,\n onClosed,\n disableFocusTrap,\n disableModalOverlay,\n ...restProps\n}: ModalPageInternalProps) => {\n const { hasCustomPanelHeaderAfter } = useConfigProvider();\n const [transitionState, { ref, onTransitionEnd }] = useCSSTransition<HTMLDivElement>(open, {\n enableAppear: true,\n onEnter() {\n onOpen?.();\n },\n onEntered() {\n onOpened?.();\n },\n onExited() {\n onClosed?.();\n },\n });\n const opened = transitionState === 'appeared' || transitionState === 'entered';\n const hidden = transitionState === 'exited';\n const closable = !preventClose && opened;\n\n const { sizeX, isDesktop } = useAdaptivityWithJSMediaQueries();\n const bottomSheetEnabled = !isDesktop && !preventClose && transitionState !== 'exited';\n const { opened: keyboardOpened } = useVirtualKeyboardState(bottomSheetEnabled);\n\n const [{ initialStyle, setSheetEl, setSheetScrollEl, setBackdropEl }, bottomSheetEventHandlers] =\n useBottomSheet(bottomSheetEnabled, {\n blocked: keyboardOpened,\n snapPoint,\n sheetCSSProperty: '--vkui_internal_ModalPageDocument--snapPoint',\n backdropCSSProperty: '--vkui_internal--modal-overlay--opacity',\n onSnapPointChange,\n onDismiss() {\n onClose('swipe-down');\n },\n });\n const documentStyle = keyboardOpened\n ? {\n '--vkui_internal_ModalPageDocument--safeAreaInsetBottom': '0px',\n ...initialStyle,\n }\n : initialStyle;\n const handleSheetRef = useExternRef<HTMLDivElement>(setSheetEl, ref);\n const handleSheetScrollRef = useExternRef<HTMLDivElement>(setSheetScrollEl, getModalContentRef);\n\n const [desktopMaxWidthClassName, desktopMaxWidthStyle] = isDesktop\n ? resolveDesktopMaxWidth(desktopMaxWidth)\n : [undefined, undefined];\n\n const modalOverlay = !disableModalOverlay && (\n <ModalOverlay\n getRootRef={setBackdropEl}\n data-testid={modalOverlayTestId}\n visible={open}\n onClick={\n closable\n ? function handleBackdropClick(event) {\n onClose('click-overlay', event);\n }\n : undefined\n }\n />\n );\n const handleEscKeyDown = useCallback(\n (event: KeyboardEvent<HTMLElement>) => {\n if (closable && pressedKey(event) === Keys.ESCAPE) {\n onClose('escape-key');\n }\n },\n [closable, onClose],\n );\n\n useScrollLock(!hidden);\n\n return (\n <ModalOutlet\n hidden={hidden}\n isDesktop={isDesktop}\n onKeyDown={handleEscKeyDown}\n disableModalOverlay={disableModalOverlay}\n >\n {modalOverlay}\n <FocusTrap\n {...restProps}\n autoFocus={!noFocusToDialog}\n restoreFocus={restoreFocus}\n role=\"dialog\"\n aria-modal=\"true\"\n disabled={!opened || hidden || disableFocusTrap}\n className={classNames(\n className,\n styles.host,\n isDesktop ? styles.hostDesktop : styles.hostMobile,\n !isDesktop &&\n (hasCustomPanelHeaderAfter\n ? styles.hostMobileSafeAreaInsetTopWithCustomOffset\n : styles.hostMobileSafeAreaInsetTop),\n desktopMaxWidthClassName,\n sizeX === 'regular' && 'vkuiInternalModalPage--sizeX-regular',\n )}\n style={mergeStyle(mergeStyle(desktopMaxWidthStyle, getHeightCSSVariable(height)), style)}\n >\n <ModalPageBase\n {...bottomSheetEventHandlers}\n getRootRef={handleSheetRef}\n getRef={handleSheetScrollRef}\n style={documentStyle}\n className={classNames(\n isDesktop ? styles.documentDesktop : styles.documentMobile,\n transitionStateClassNames[transitionState],\n )}\n onTransitionEnd={onTransitionEnd}\n isDesktop={isDesktop}\n disableContentPanningGesture={disableContentPanningGesture}\n header={header}\n footer={footer}\n outsideButtons={outsideButtons}\n modalContentTestId={modalContentTestId}\n modalDismissButtonTestId={modalDismissButtonTestId}\n modalDismissButtonLabel={modalDismissButtonLabel}\n hideCloseButton={hideCloseButton}\n closable={closable}\n onClose={onClose}\n >\n {children}\n </ModalPageBase>\n </FocusTrap>\n </ModalOutlet>\n );\n};\n\nconst desktopMaxWidthClassNames = {\n s: styles['hostDesktopMaxWidthS'],\n m: styles['hostDesktopMaxWidthM'],\n l: styles['hostDesktopMaxWidthL'],\n};\n\nfunction resolveDesktopMaxWidth(\n desktopMaxWidth: ModalPageInternalProps['size'] = 's',\n): [string | undefined, CSSCustomProperties | undefined] {\n if (typeof desktopMaxWidth === 'number') {\n return [undefined, { '--vkui_internal_ModalPage--desktopMaxWidth': `${desktopMaxWidth}px` }];\n }\n\n return desktopMaxWidthClassNames.hasOwnProperty(desktopMaxWidth)\n ? [desktopMaxWidthClassNames[desktopMaxWidth], undefined]\n : [undefined, { '--vkui_internal_ModalPage--desktopMaxWidth': desktopMaxWidth }];\n}\n\nfunction getHeightCSSVariable(height?: number | string): CSSCustomProperties | undefined {\n return height !== undefined\n ? {\n '--vkui_internal_ModalPage--userHeight':\n typeof height === 'number' ? `${height}px` : height,\n }\n : undefined;\n}\n"],"names":["useCallback","classNames","noop","mergeStyle","useAdaptivityWithJSMediaQueries","useExternRef","useVirtualKeyboardState","Keys","pressedKey","useCSSTransition","useBottomSheet","useScrollLock","useConfigProvider","FocusTrap","ModalOutlet","ModalOverlay","ModalOverlayDefault","ModalPageBase","styles","transitionStateClassNames","appear","appearing","enter","entering","exiting","exited","ModalPageInternal","open","header","footer","size","desktopMaxWidth","height","children","className","style","snapPoint","onSnapPointChange","getModalContentRef","modalOverlayTestId","modalContentTestId","modalDismissButtonTestId","modalDismissButtonLabel","outsideButtons","noFocusToDialog","hideCloseButton","preventClose","disableContentPanningGesture","restoreFocus","onOpen","onOpened","onClose","onClosed","disableFocusTrap","disableModalOverlay","restProps","hasCustomPanelHeaderAfter","transitionState","ref","onTransitionEnd","enableAppear","onEnter","onEntered","onExited","opened","hidden","closable","sizeX","isDesktop","bottomSheetEnabled","keyboardOpened","initialStyle","setSheetEl","setSheetScrollEl","setBackdropEl","bottomSheetEventHandlers","blocked","sheetCSSProperty","backdropCSSProperty","onDismiss","documentStyle","handleSheetRef","handleSheetScrollRef","desktopMaxWidthClassName","desktopMaxWidthStyle","resolveDesktopMaxWidth","undefined","modalOverlay","getRootRef","data-testid","visible","onClick","handleBackdropClick","event","handleEscKeyDown","ESCAPE","onKeyDown","autoFocus","role","aria-modal","disabled","host","hostDesktop","hostMobile","hostMobileSafeAreaInsetTopWithCustomOffset","hostMobileSafeAreaInsetTop","getHeightCSSVariable","getRef","documentDesktop","documentMobile","desktopMaxWidthClassNames","s","m","l","hasOwnProperty"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/ModalPage/types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode, Ref, UIEvent } from 'react';\nimport { type UseFocusTrapProps } from '../../hooks/useFocusTrap';\nimport type { NavIdProps } from '../../lib/getNavId';\nimport type { HTMLAttributesWithRootRef } from '../../types';\n\nexport type ModalPageCloseReason =\n | 'click-overlay'\n | 'click-close-button'\n | 'escape-key'\n | 'swipe-down';\n\ntype OmittedStyleAttribute = {\n /**\n * Дополнительные стили.\n */\n style?: Omit<CSSProperties, 'height' | 'maxWidth' | 'maxHeight'>;\n};\n\nexport interface ModalPageProps\n extends NavIdProps,\n Omit<HTMLAttributesWithRootRef<HTMLDivElement>, 'id' | 'style'>,\n Pick<UseFocusTrapProps, 'restoreFocus'>,\n OmittedStyleAttribute {\n /**\n * Состояние видимости.\n *\n * @default false\n */\n open?: boolean;\n /**\n * Сохранять ли компонент в DOM при `open={false}`.\n *\n * @default false\n */\n keepMounted?: boolean;\n /**\n * Шапка модальной страницы, `<ModalPageHeader />`.\n */\n header?: ReactNode;\n /**\n * Подвал модальной страницы, `<ModalPageFooter />`.\n */\n footer?: ReactNode;\n /**\n * Задаёт контенту максимальную ширину на десктопе.\n */\n size?: 's' | 'm' | 'l' | number;\n /**\n * Задаёт модальному окну фиксированную высоту.\n * Можно передать числовое значение в пикселях, а можно строкой, в том числе и в процентах \"50%\".\n * В мобильной версии 'settlingHeight' будет считаться относительно заданного height.\n */\n height?: string | number;\n /**\n * Процент, на который изначально будет открыта модальная страница.\n *\n * > ⚠️ Следует использовать следующие значения: `25`, `50`, `75`, `100`.\n * > При передаче `< 25` значение приведётся к `25`, при передаче `> 75` значение приведётся к `75`.\n *\n * Игнорируется при включении `dynamicContentHeight`.\n */\n settlingHeight?: number;\n /**\n * Если высота контента в модальной странице может поменяться, нужно установить это свойство.\n */\n dynamicContentHeight?: boolean;\n /**\n * Отключает фокус на интерактивный элемент после открытия модалки.\n *\n * > Важно установить фокус после открытия в любое место модалки используя событие `onOpened`, иначе не будет работать закрытие по нажатию `Esc`.\n */\n noFocusToDialog?: boolean;\n /**\n * Скрывает кнопку закрытия (актуально для iOS, так как можно отрисовать кнопку закрытия внутри модалки).\n */\n hideCloseButton?: boolean;\n /**\n * `data-testid` для содержимого модального окна.\n */\n modalContentTestId?: string;\n /**\n * Возвращает DOM-элемент содержимого модального окна.\n */\n getModalContentRef?: Ref<HTMLDivElement>;\n /**\n * `data-testid` для оверлея.\n */\n modalOverlayTestId?: string;\n /**\n * `data-testid` для кнопки закрытия.\n */\n modalDismissButtonTestId?: string;\n /**\n * Текст для скринридера.\n */\n modalDismissButtonLabel?: string;\n /**\n * Позволяет отключить возможность закрытия модальной страницы (смахивание, клавиша `ESC`, нажатие на подложку).\n *\n * ⚠️ ВНИМАНИЕ: использование этой опции негативно сказывается на пользовательском опыте.\n */\n preventClose?: boolean;\n /**\n * Отключает раскрытие и закрытие панели в мобильном виде.\n */\n disableContentPanningGesture?: boolean;\n /**\n * Будет вызвано при начале открытия модалки.\n */\n onOpen?: VoidFunction;\n /**\n * Будет вызвано при окончательном открытии модалки.\n */\n onOpened?: VoidFunction;\n /**\n * Будет вызвано при начале закрытия модалки.\n */\n onClose?: (reason: ModalPageCloseReason, event?: UIEvent<HTMLElement>) => void;\n /**\n * Будет вызвано при окончательном закрытии модалки.\n */\n onClosed?: VoidFunction;\n /**\n * Управляющие элементы под кнопкой закрытия.\n *\n * Доступно только в `compact`-режиме. Рекомендуется размещать иконки размера 20, обернутые в ModalOutsideButton.\n *\n */\n outsideButtons?: React.ReactNode;\n /**\n * Позволяет отключить захват фокуса.\n *\n * Нужно использовать, когда поверх одной модалки открывается другая, чтобы два `FocusTrap` не конфликтовали.\n */\n disableFocusTrap?: UseFocusTrapProps['disabled'];\n /**\n * Отключает отображение и взаимодействие с фоном модалки.\n * > При использовании `ModalPage` внутри `ModalRoot` есть особенность использования этого свойства.\n * > Об этом можно почитать на странице документации [`ModalRoot`](/components/modal-root#otklyuchenie-zadnego-fona-u-konkretnogo-modalnogo-okna).\n */\n disableModalOverlay?: boolean;\n}\n"],"names":[],"mappings":"AAkBA,WA2HC"}
1
+ {"version":3,"sources":["../../../../src/components/ModalPage/types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode, Ref, UIEvent } from 'react';\nimport { type UseFocusTrapProps } from '../../hooks/useFocusTrap';\nimport type { NavIdProps } from '../../lib/getNavId';\nimport type { HTMLAttributesWithRootRef, LiteralUnion } from '../../types';\n\nexport type ModalPageCloseReason =\n | 'click-overlay'\n | 'click-close-button'\n | 'escape-key'\n | 'swipe-down';\n\ntype OmittedStyleAttribute = {\n /**\n * Дополнительные стили.\n */\n style?: Omit<CSSProperties, 'height' | 'maxWidth' | 'maxHeight'>;\n};\n\nexport interface ModalPageProps\n extends NavIdProps,\n Omit<HTMLAttributesWithRootRef<HTMLDivElement>, 'id' | 'style'>,\n Pick<UseFocusTrapProps, 'restoreFocus'>,\n OmittedStyleAttribute {\n /**\n * Состояние видимости.\n *\n * @default false\n */\n open?: boolean;\n /**\n * Сохранять ли компонент в DOM при `open={false}`.\n *\n * @default false\n */\n keepMounted?: boolean;\n /**\n * Шапка модальной страницы, `<ModalPageHeader />`.\n */\n header?: ReactNode;\n /**\n * Подвал модальной страницы, `<ModalPageFooter />`.\n */\n footer?: ReactNode;\n /**\n * Задаёт контенту максимальную ширину на десктопе.\n */\n size?: LiteralUnion<\n 's' | 'm' | 'l' | 'auto' | 'fit-content' | 'max-content' | 'min-content',\n string | number\n >;\n /**\n * Задаёт модальному окну фиксированную высоту.\n * Можно передать числовое значение в пикселях, а можно строкой, в том числе и в процентах \"50%\".\n * В мобильной версии 'settlingHeight' будет считаться относительно заданного height.\n */\n height?: string | number;\n /**\n * Процент, на который изначально будет открыта модальная страница.\n *\n * > ⚠️ Следует использовать следующие значения: `25`, `50`, `75`, `100`.\n * > При передаче `< 25` значение приведётся к `25`, при передаче `> 75` значение приведётся к `75`.\n *\n * Игнорируется при включении `dynamicContentHeight`.\n */\n settlingHeight?: number;\n /**\n * Если высота контента в модальной странице может поменяться, нужно установить это свойство.\n */\n dynamicContentHeight?: boolean;\n /**\n * Отключает фокус на интерактивный элемент после открытия модалки.\n *\n * > Важно установить фокус после открытия в любое место модалки используя событие `onOpened`, иначе не будет работать закрытие по нажатию `Esc`.\n */\n noFocusToDialog?: boolean;\n /**\n * Скрывает кнопку закрытия (актуально для iOS, так как можно отрисовать кнопку закрытия внутри модалки).\n */\n hideCloseButton?: boolean;\n /**\n * `data-testid` для содержимого модального окна.\n */\n modalContentTestId?: string;\n /**\n * Возвращает DOM-элемент содержимого модального окна.\n */\n getModalContentRef?: Ref<HTMLDivElement>;\n /**\n * `data-testid` для оверлея.\n */\n modalOverlayTestId?: string;\n /**\n * `data-testid` для кнопки закрытия.\n */\n modalDismissButtonTestId?: string;\n /**\n * Текст для скринридера.\n */\n modalDismissButtonLabel?: string;\n /**\n * Позволяет отключить возможность закрытия модальной страницы (смахивание, клавиша `ESC`, нажатие на подложку).\n *\n * ⚠️ ВНИМАНИЕ: использование этой опции негативно сказывается на пользовательском опыте.\n */\n preventClose?: boolean;\n /**\n * Отключает раскрытие и закрытие панели в мобильном виде.\n */\n disableContentPanningGesture?: boolean;\n /**\n * Будет вызвано при начале открытия модалки.\n */\n onOpen?: VoidFunction;\n /**\n * Будет вызвано при окончательном открытии модалки.\n */\n onOpened?: VoidFunction;\n /**\n * Будет вызвано при начале закрытия модалки.\n */\n onClose?: (reason: ModalPageCloseReason, event?: UIEvent<HTMLElement>) => void;\n /**\n * Будет вызвано при окончательном закрытии модалки.\n */\n onClosed?: VoidFunction;\n /**\n * Управляющие элементы под кнопкой закрытия.\n *\n * Доступно только в `compact`-режиме. Рекомендуется размещать иконки размера 20, обернутые в ModalOutsideButton.\n *\n */\n outsideButtons?: React.ReactNode;\n /**\n * Позволяет отключить захват фокуса.\n *\n * Нужно использовать, когда поверх одной модалки открывается другая, чтобы два `FocusTrap` не конфликтовали.\n */\n disableFocusTrap?: UseFocusTrapProps['disabled'];\n /**\n * Отключает отображение и взаимодействие с фоном модалки.\n * > При использовании `ModalPage` внутри `ModalRoot` есть особенность использования этого свойства.\n * > Об этом можно почитать на странице документации [`ModalRoot`](/components/modal-root#otklyuchenie-zadnego-fona-u-konkretnogo-modalnogo-okna).\n */\n disableModalOverlay?: boolean;\n}\n"],"names":[],"mappings":"AAkBA,WA8HC"}
@@ -20,7 +20,7 @@ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
20
20
  import styles from "./Search.module.css";
21
21
  /**
22
22
  * @see https://vkui.io/components/search
23
- */ export const Search = ({ id: idProp, before = /*#__PURE__*/ _jsx(Icon16SearchOutline, {}), className, placeholder = 'Поиск', after = 'Отмена', getRef, icon: iconProp, onIconClick, style, autoComplete = 'off', onChange, iconLabel, clearLabel = 'Очистить', clearButtonTestId, noPadding, getRootRef, findButtonText = 'Найти', findButtonTestId, onFindButtonClick, ...inputProps })=>{
23
+ */ export const Search = ({ id: idProp, before = /*#__PURE__*/ _jsx(Icon16SearchOutline, {}), className, placeholder = 'Поиск', after = 'Отмена', getRef, icon: iconProp, onIconClick, style, autoComplete = 'off', onChange, iconLabel, clearLabel = 'Очистить', clearButtonTestId, noPadding, getRootRef, findButtonText = 'Найти', findButtonTestId, onFindButtonClick, hideClearButton, ...inputProps })=>{
24
24
  const direction = useConfigDirection();
25
25
  const isRtl = direction === 'rtl';
26
26
  const inputRef = useExternRef(getRef);
@@ -90,6 +90,7 @@ import styles from "./Search.module.css";
90
90
  icon
91
91
  ]
92
92
  });
93
+ const showControls = Boolean(iconProp || !hideClearButton || adaptiveSizeY.compact && onFindButtonClick);
93
94
  return /*#__PURE__*/ _jsxs("div", {
94
95
  className: classNames('vkuiInternalSearch', styles.host, sizeY === 'none' && styles.sizeYNone, sizeY === 'compact' && styles.sizeYCompact, isFocused && styles.focused, hasValue && styles.hasValue, hasAfter && styles.hasAfter, iconProp && styles.hasIcon, inputProps.disabled && styles.disabled, !noPadding && styles.withPadding, isRtl && styles.rtl, className),
95
96
  ref: getRootRef,
@@ -124,11 +125,11 @@ import styles from "./Search.module.css";
124
125
  })
125
126
  ]
126
127
  }),
127
- /*#__PURE__*/ _jsxs("div", {
128
+ showControls && /*#__PURE__*/ _jsxs("div", {
128
129
  className: styles.controls,
129
130
  children: [
130
131
  iconProp && (typeof iconProp === 'function' ? iconProp(renderIconButton) : renderIconButton(iconProp)),
131
- /*#__PURE__*/ _jsxs(IconButton, {
132
+ !hideClearButton && /*#__PURE__*/ _jsxs(IconButton, {
132
133
  hoverMode: "opacity",
133
134
  onPointerDown: onIconCancelClickStart,
134
135
  onClick: onCancel,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/Search/Search.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Icon16Clear, Icon16SearchOutline, Icon24Cancel } from '@vkontakte/icons';\nimport { classNames, hasReactNode, noop } from '@vkontakte/vkjs';\nimport { useAdaptivity } from '../../hooks/useAdaptivity';\nimport { useAdaptivityConditionalRender } from '../../hooks/useAdaptivityConditionalRender';\nimport { useBooleanState } from '../../hooks/useBooleanState';\nimport { useConfigDirection } from '../../hooks/useConfigDirection';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useNativeFormResetListener } from '../../hooks/useNativeFormResetListener';\nimport { usePlatform } from '../../hooks/usePlatform';\nimport { callMultiple } from '../../lib/callMultiple';\nimport { touchEnabled } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasDataAttribute, HasRef, HasRootRef } from '../../types';\nimport { Button } from '../Button/Button';\nimport { IconButton, type IconButtonProps } from '../IconButton/IconButton';\nimport { Headline } from '../Typography/Headline/Headline';\nimport { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden';\nimport styles from './Search.module.css';\n\nexport type RenderIconButtonFn = (\n icon: React.ReactNode,\n props?: Partial<IconButtonProps> & HasDataAttribute,\n) => React.ReactElement;\n\nexport interface SearchProps\n extends React.InputHTMLAttributes<HTMLInputElement>,\n HasRootRef<HTMLDivElement>,\n HasRef<HTMLInputElement> {\n /**\n * Only iOS. Текст кнопки \"отмена\", которая чистит текстовое поле и убирает фокус.\n */\n after?: React.ReactNode;\n /**\n * Контент, отображаемый перед полем ввода.\n */\n before?: React.ReactNode;\n /**\n * Иконка поиска. Может быть React-элементом или функцией, возвращающей элемент.\n */\n icon?: React.ReactNode | ((renderFn: RenderIconButtonFn) => React.ReactNode);\n /**\n * Обработчик нажатия на иконку поиска.\n */\n onIconClick?: React.PointerEventHandler<HTMLElement>;\n /**\n * Значение поля ввода по умолчанию.\n */\n defaultValue?: string;\n /**\n * Текст для скринридеров, описывающий иконку поиска.\n */\n iconLabel?: string;\n /**\n * Текст для скринридеров, описывающий кнопку очистки.\n */\n clearLabel?: string;\n /**\n * Передает атрибут `data-testid` для кнопки очистки.\n */\n clearButtonTestId?: string;\n /**\n * Удаляет отступы у компонента.\n */\n noPadding?: boolean;\n /**\n * Текст для кнопки Найти.\n */\n findButtonText?: string;\n /**\n * Обработчик, при нажатии на кнопку \"Найти\".\n */\n onFindButtonClick?: React.MouseEventHandler<HTMLElement>;\n /**\n * Передает атрибут `data-testid` для кнопки поиска.\n */\n findButtonTestId?: string;\n}\n\n/**\n * @see https://vkui.io/components/search\n */\nexport const Search = ({\n id: idProp,\n before = <Icon16SearchOutline />,\n className,\n placeholder = 'Поиск',\n after = 'Отмена',\n getRef,\n icon: iconProp,\n onIconClick,\n style,\n autoComplete = 'off',\n onChange,\n iconLabel,\n clearLabel = 'Очистить',\n clearButtonTestId,\n noPadding,\n getRootRef,\n findButtonText = 'Найти',\n findButtonTestId,\n onFindButtonClick,\n ...inputProps\n}: SearchProps): React.ReactNode => {\n const direction = useConfigDirection();\n const isRtl = direction === 'rtl';\n const inputRef = useExternRef(getRef);\n const {\n value: isFocused,\n setTrue: setFocusedTrue,\n setFalse: setFocusedFalse,\n } = useBooleanState(false);\n const generatedId = React.useId();\n const inputId = idProp ? idProp : `search-${generatedId}`;\n\n const [hasValue, setHasValue] = React.useState<boolean>(() =>\n Boolean(inputProps.value || inputProps.defaultValue),\n );\n const checkHasValue: React.ChangeEventHandler<HTMLInputElement> = (e) =>\n setHasValue(Boolean(e.currentTarget.value));\n\n const { sizeY = 'none' } = useAdaptivity();\n const { sizeY: adaptiveSizeY } = useAdaptivityConditionalRender();\n const platform = usePlatform();\n\n const hasAfter = platform === 'ios' && hasReactNode(after);\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n setFocusedTrue();\n inputProps.onFocus && inputProps.onFocus(e);\n };\n\n const onBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n setFocusedFalse();\n inputProps.onBlur && inputProps.onBlur(e);\n };\n\n const onCancel = React.useCallback(() => {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype,\n 'value',\n )?.set;\n nativeInputValueSetter?.call(inputRef.current, '');\n\n const ev2 = new Event('input', { bubbles: true });\n inputRef.current?.dispatchEvent(ev2);\n }, [inputRef]);\n\n const onIconClickStart: React.PointerEventHandler<HTMLElement> = React.useCallback(\n (e) => onIconClick?.(e),\n [onIconClick],\n );\n\n const onIconCancelClickStart: React.PointerEventHandler<HTMLElement> = React.useCallback(\n (e) => {\n e.preventDefault();\n inputRef.current?.focus();\n if (touchEnabled()) {\n onCancel();\n }\n },\n [inputRef, onCancel],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (inputProps.value !== undefined) {\n setHasValue(Boolean(inputProps.value));\n }\n }, [inputProps.value]);\n\n useNativeFormResetListener(inputRef, () => {\n setHasValue(Boolean(inputProps.defaultValue));\n });\n\n const renderIconButton: RenderIconButtonFn = (icon, props = {}) => (\n <IconButton\n hoverMode=\"opacity\"\n onPointerDown={onIconClickStart}\n className={styles.icon}\n onFocus={setFocusedTrue}\n onBlur={setFocusedFalse}\n onClick={noop}\n {...props}\n >\n <VisuallyHidden>{iconLabel}</VisuallyHidden>\n {icon}\n </IconButton>\n );\n\n return (\n <div\n className={classNames(\n 'vkuiInternalSearch',\n styles.host,\n sizeY === 'none' && styles.sizeYNone,\n sizeY === 'compact' && styles.sizeYCompact,\n isFocused && styles.focused,\n hasValue && styles.hasValue,\n hasAfter && styles.hasAfter,\n iconProp && styles.hasIcon,\n inputProps.disabled && styles.disabled,\n !noPadding && styles.withPadding,\n isRtl && styles.rtl,\n className,\n )}\n ref={getRootRef}\n style={style}\n >\n <div className={styles.field}>\n <label htmlFor={inputId} className={styles.label}>\n {placeholder}\n </label>\n <div className={styles.input}>\n {before}\n <Headline\n Component=\"input\"\n type=\"search\"\n level=\"1\"\n weight=\"3\"\n {...inputProps}\n id={inputId}\n placeholder={placeholder}\n autoComplete={autoComplete}\n getRootRef={inputRef}\n className={styles.nativeInput}\n onFocus={onFocus}\n onBlur={onBlur}\n onChange={callMultiple(onChange, checkHasValue)}\n />\n </div>\n <div className={styles.controls}>\n {iconProp &&\n (typeof iconProp === 'function'\n ? iconProp(renderIconButton)\n : renderIconButton(iconProp))}\n <IconButton\n hoverMode=\"opacity\"\n onPointerDown={onIconCancelClickStart}\n onClick={onCancel}\n className={styles.icon}\n tabIndex={hasValue ? undefined : -1}\n disabled={inputProps.disabled}\n data-testid={clearButtonTestId}\n >\n <VisuallyHidden>{clearLabel}</VisuallyHidden>\n {platform === 'ios' ? <Icon16Clear /> : <Icon24Cancel />}\n </IconButton>\n {adaptiveSizeY.compact && onFindButtonClick && (\n <Button\n mode=\"primary\"\n size=\"m\"\n className={classNames(styles.findButton, adaptiveSizeY.compact.className)}\n focusVisibleMode=\"inside\"\n onClick={onFindButtonClick}\n tabIndex={hasValue ? undefined : -1}\n data-testid={findButtonTestId}\n >\n {findButtonText}\n </Button>\n )}\n </div>\n </div>\n {hasAfter && (\n <div className={styles.after}>\n <Button\n mode=\"tertiary\"\n size=\"m\"\n focusVisibleMode=\"inside\"\n hoverMode=\"opacity\"\n activeMode=\"opacity\"\n onClick={onCancel}\n onFocus={setFocusedTrue}\n onBlur={setFocusedFalse}\n >\n <span className={styles.afterTextClip}>{after}</span>\n </Button>\n </div>\n )}\n </div>\n );\n};\n"],"names":["React","Icon16Clear","Icon16SearchOutline","Icon24Cancel","classNames","hasReactNode","noop","useAdaptivity","useAdaptivityConditionalRender","useBooleanState","useConfigDirection","useExternRef","useNativeFormResetListener","usePlatform","callMultiple","touchEnabled","useIsomorphicLayoutEffect","Button","IconButton","Headline","VisuallyHidden","styles","Search","id","idProp","before","className","placeholder","after","getRef","icon","iconProp","onIconClick","style","autoComplete","onChange","iconLabel","clearLabel","clearButtonTestId","noPadding","getRootRef","findButtonText","findButtonTestId","onFindButtonClick","inputProps","direction","isRtl","inputRef","value","isFocused","setTrue","setFocusedTrue","setFalse","setFocusedFalse","generatedId","useId","inputId","hasValue","setHasValue","useState","Boolean","defaultValue","checkHasValue","e","currentTarget","sizeY","adaptiveSizeY","platform","hasAfter","onFocus","onBlur","onCancel","useCallback","nativeInputValueSetter","Object","getOwnPropertyDescriptor","HTMLInputElement","prototype","set","call","current","ev2","Event","bubbles","dispatchEvent","onIconClickStart","onIconCancelClickStart","preventDefault","focus","undefined","renderIconButton","props","hoverMode","onPointerDown","onClick","div","host","sizeYNone","sizeYCompact","focused","hasIcon","disabled","withPadding","rtl","ref","field","label","htmlFor","input","Component","type","level","weight","nativeInput","controls","tabIndex","data-testid","compact","mode","size","findButton","focusVisibleMode","activeMode","span","afterTextClip"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/Search/Search.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Icon16Clear, Icon16SearchOutline, Icon24Cancel } from '@vkontakte/icons';\nimport { classNames, hasReactNode, noop } from '@vkontakte/vkjs';\nimport { useAdaptivity } from '../../hooks/useAdaptivity';\nimport { useAdaptivityConditionalRender } from '../../hooks/useAdaptivityConditionalRender';\nimport { useBooleanState } from '../../hooks/useBooleanState';\nimport { useConfigDirection } from '../../hooks/useConfigDirection';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useNativeFormResetListener } from '../../hooks/useNativeFormResetListener';\nimport { usePlatform } from '../../hooks/usePlatform';\nimport { callMultiple } from '../../lib/callMultiple';\nimport { touchEnabled } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasDataAttribute, HasRef, HasRootRef } from '../../types';\nimport { Button } from '../Button/Button';\nimport { IconButton, type IconButtonProps } from '../IconButton/IconButton';\nimport { Headline } from '../Typography/Headline/Headline';\nimport { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden';\nimport styles from './Search.module.css';\n\nexport type RenderIconButtonFn = (\n icon: React.ReactNode,\n props?: Partial<IconButtonProps> & HasDataAttribute,\n) => React.ReactElement;\n\nexport interface SearchProps\n extends React.InputHTMLAttributes<HTMLInputElement>,\n HasRootRef<HTMLDivElement>,\n HasRef<HTMLInputElement> {\n /**\n * Only iOS. Текст кнопки \"отмена\", которая чистит текстовое поле и убирает фокус.\n */\n after?: React.ReactNode;\n /**\n * Контент, отображаемый перед полем ввода.\n */\n before?: React.ReactNode;\n /**\n * Иконка поиска. Может быть React-элементом или функцией, возвращающей элемент.\n */\n icon?: React.ReactNode | ((renderFn: RenderIconButtonFn) => React.ReactNode);\n /**\n * Обработчик нажатия на иконку поиска.\n */\n onIconClick?: React.PointerEventHandler<HTMLElement>;\n /**\n * Значение поля ввода по умолчанию.\n */\n defaultValue?: string;\n /**\n * Текст для скринридеров, описывающий иконку поиска.\n */\n iconLabel?: string;\n /**\n * Текст для скринридеров, описывающий кнопку очистки.\n */\n clearLabel?: string;\n /**\n * Передает атрибут `data-testid` для кнопки очистки.\n */\n clearButtonTestId?: string;\n /**\n * Удаляет отступы у компонента.\n */\n noPadding?: boolean;\n /**\n * Текст для кнопки Найти.\n */\n findButtonText?: string;\n /**\n * Обработчик, при нажатии на кнопку \"Найти\".\n */\n onFindButtonClick?: React.MouseEventHandler<HTMLElement>;\n /**\n * Передает атрибут `data-testid` для кнопки поиска.\n */\n findButtonTestId?: string;\n /**\n * Скрывает кнопку очистки.\n */\n hideClearButton?: boolean;\n}\n\n/**\n * @see https://vkui.io/components/search\n */\nexport const Search = ({\n id: idProp,\n before = <Icon16SearchOutline />,\n className,\n placeholder = 'Поиск',\n after = 'Отмена',\n getRef,\n icon: iconProp,\n onIconClick,\n style,\n autoComplete = 'off',\n onChange,\n iconLabel,\n clearLabel = 'Очистить',\n clearButtonTestId,\n noPadding,\n getRootRef,\n findButtonText = 'Найти',\n findButtonTestId,\n onFindButtonClick,\n hideClearButton,\n ...inputProps\n}: SearchProps): React.ReactNode => {\n const direction = useConfigDirection();\n const isRtl = direction === 'rtl';\n const inputRef = useExternRef(getRef);\n const {\n value: isFocused,\n setTrue: setFocusedTrue,\n setFalse: setFocusedFalse,\n } = useBooleanState(false);\n const generatedId = React.useId();\n const inputId = idProp ? idProp : `search-${generatedId}`;\n\n const [hasValue, setHasValue] = React.useState<boolean>(() =>\n Boolean(inputProps.value || inputProps.defaultValue),\n );\n const checkHasValue: React.ChangeEventHandler<HTMLInputElement> = (e) =>\n setHasValue(Boolean(e.currentTarget.value));\n\n const { sizeY = 'none' } = useAdaptivity();\n const { sizeY: adaptiveSizeY } = useAdaptivityConditionalRender();\n const platform = usePlatform();\n\n const hasAfter = platform === 'ios' && hasReactNode(after);\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n setFocusedTrue();\n inputProps.onFocus && inputProps.onFocus(e);\n };\n\n const onBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n setFocusedFalse();\n inputProps.onBlur && inputProps.onBlur(e);\n };\n\n const onCancel = React.useCallback(() => {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype,\n 'value',\n )?.set;\n nativeInputValueSetter?.call(inputRef.current, '');\n\n const ev2 = new Event('input', { bubbles: true });\n inputRef.current?.dispatchEvent(ev2);\n }, [inputRef]);\n\n const onIconClickStart: React.PointerEventHandler<HTMLElement> = React.useCallback(\n (e) => onIconClick?.(e),\n [onIconClick],\n );\n\n const onIconCancelClickStart: React.PointerEventHandler<HTMLElement> = React.useCallback(\n (e) => {\n e.preventDefault();\n inputRef.current?.focus();\n if (touchEnabled()) {\n onCancel();\n }\n },\n [inputRef, onCancel],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (inputProps.value !== undefined) {\n setHasValue(Boolean(inputProps.value));\n }\n }, [inputProps.value]);\n\n useNativeFormResetListener(inputRef, () => {\n setHasValue(Boolean(inputProps.defaultValue));\n });\n\n const renderIconButton: RenderIconButtonFn = (icon, props = {}) => (\n <IconButton\n hoverMode=\"opacity\"\n onPointerDown={onIconClickStart}\n className={styles.icon}\n onFocus={setFocusedTrue}\n onBlur={setFocusedFalse}\n onClick={noop}\n {...props}\n >\n <VisuallyHidden>{iconLabel}</VisuallyHidden>\n {icon}\n </IconButton>\n );\n\n const showControls = Boolean(\n iconProp || !hideClearButton || (adaptiveSizeY.compact && onFindButtonClick),\n );\n\n return (\n <div\n className={classNames(\n 'vkuiInternalSearch',\n styles.host,\n sizeY === 'none' && styles.sizeYNone,\n sizeY === 'compact' && styles.sizeYCompact,\n isFocused && styles.focused,\n hasValue && styles.hasValue,\n hasAfter && styles.hasAfter,\n iconProp && styles.hasIcon,\n inputProps.disabled && styles.disabled,\n !noPadding && styles.withPadding,\n isRtl && styles.rtl,\n className,\n )}\n ref={getRootRef}\n style={style}\n >\n <div className={styles.field}>\n <label htmlFor={inputId} className={styles.label}>\n {placeholder}\n </label>\n <div className={styles.input}>\n {before}\n <Headline\n Component=\"input\"\n type=\"search\"\n level=\"1\"\n weight=\"3\"\n {...inputProps}\n id={inputId}\n placeholder={placeholder}\n autoComplete={autoComplete}\n getRootRef={inputRef}\n className={styles.nativeInput}\n onFocus={onFocus}\n onBlur={onBlur}\n onChange={callMultiple(onChange, checkHasValue)}\n />\n </div>\n {showControls && (\n <div className={styles.controls}>\n {iconProp &&\n (typeof iconProp === 'function'\n ? iconProp(renderIconButton)\n : renderIconButton(iconProp))}\n {!hideClearButton && (\n <IconButton\n hoverMode=\"opacity\"\n onPointerDown={onIconCancelClickStart}\n onClick={onCancel}\n className={styles.icon}\n tabIndex={hasValue ? undefined : -1}\n disabled={inputProps.disabled}\n data-testid={clearButtonTestId}\n >\n <VisuallyHidden>{clearLabel}</VisuallyHidden>\n {platform === 'ios' ? <Icon16Clear /> : <Icon24Cancel />}\n </IconButton>\n )}\n {adaptiveSizeY.compact && onFindButtonClick && (\n <Button\n mode=\"primary\"\n size=\"m\"\n className={classNames(styles.findButton, adaptiveSizeY.compact.className)}\n focusVisibleMode=\"inside\"\n onClick={onFindButtonClick}\n tabIndex={hasValue ? undefined : -1}\n data-testid={findButtonTestId}\n >\n {findButtonText}\n </Button>\n )}\n </div>\n )}\n </div>\n {hasAfter && (\n <div className={styles.after}>\n <Button\n mode=\"tertiary\"\n size=\"m\"\n focusVisibleMode=\"inside\"\n hoverMode=\"opacity\"\n activeMode=\"opacity\"\n onClick={onCancel}\n onFocus={setFocusedTrue}\n onBlur={setFocusedFalse}\n >\n <span className={styles.afterTextClip}>{after}</span>\n </Button>\n </div>\n )}\n </div>\n );\n};\n"],"names":["React","Icon16Clear","Icon16SearchOutline","Icon24Cancel","classNames","hasReactNode","noop","useAdaptivity","useAdaptivityConditionalRender","useBooleanState","useConfigDirection","useExternRef","useNativeFormResetListener","usePlatform","callMultiple","touchEnabled","useIsomorphicLayoutEffect","Button","IconButton","Headline","VisuallyHidden","styles","Search","id","idProp","before","className","placeholder","after","getRef","icon","iconProp","onIconClick","style","autoComplete","onChange","iconLabel","clearLabel","clearButtonTestId","noPadding","getRootRef","findButtonText","findButtonTestId","onFindButtonClick","hideClearButton","inputProps","direction","isRtl","inputRef","value","isFocused","setTrue","setFocusedTrue","setFalse","setFocusedFalse","generatedId","useId","inputId","hasValue","setHasValue","useState","Boolean","defaultValue","checkHasValue","e","currentTarget","sizeY","adaptiveSizeY","platform","hasAfter","onFocus","onBlur","onCancel","useCallback","nativeInputValueSetter","Object","getOwnPropertyDescriptor","HTMLInputElement","prototype","set","call","current","ev2","Event","bubbles","dispatchEvent","onIconClickStart","onIconCancelClickStart","preventDefault","focus","undefined","renderIconButton","props","hoverMode","onPointerDown","onClick","showControls","compact","div","host","sizeYNone","sizeYCompact","focused","hasIcon","disabled","withPadding","rtl","ref","field","label","htmlFor","input","Component","type","level","weight","nativeInput","controls","tabIndex","data-testid","mode","size","findButton","focusVisibleMode","activeMode","span","afterTextClip"],"mappings":"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"}
@@ -40,7 +40,7 @@
40
40
  overflow: hidden;
41
41
  white-space: nowrap;
42
42
  border: 0 none;
43
- -webkit-clip-path: rect(0 0 0 0);
44
- clip-path: rect(0 0 0 0);
43
+ -webkit-clip-path: inset(50%);
44
+ clip-path: inset(50%);
45
45
  direction: ltr;
46
46
  }
@@ -1,8 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { isSameDate } from "@vkontakte/vkjs";
3
- import { addMonths, startOfDay, subMonths } from "date-fns";
4
3
  import { DEFAULT_MAX_YEAR, DEFAULT_MIN_YEAR, isDayMinMaxRestricted } from "../lib/calendar.js";
5
- import { endOfDay } from "../lib/date.js";
4
+ import { addMonths, endOfDay, startOfDay, subMonths } from "../lib/date.js";
6
5
  export function useCalendar({ value, disablePast, disableFuture, shouldDisableDate, onHeaderChange, onNextMonth, onPrevMonth, minDateTime, maxDateTime }) {
7
6
  const [viewDate, setViewDate] = React.useState((Array.isArray(value) ? value[0] : value) ?? new Date());
8
7
  // соответствует дню, на котором сейчас есть фокус
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/useCalendar.ts"],"sourcesContent":["import * as React from 'react';\nimport { isSameDate } from '@vkontakte/vkjs';\nimport { addMonths, startOfDay, subMonths } from 'date-fns';\nimport type { CalendarProps } from '../components/Calendar/Calendar';\nimport { DEFAULT_MAX_YEAR, DEFAULT_MIN_YEAR, isDayMinMaxRestricted } from '../lib/calendar';\nimport { endOfDay } from '../lib/date';\n\nexport interface UseCalendarDependencies\n extends Pick<\n CalendarProps,\n | 'onHeaderChange'\n | 'onNextMonth'\n | 'onPrevMonth'\n | 'minDateTime'\n | 'maxDateTime'\n | 'shouldDisableDate'\n | 'disableFuture'\n | 'disablePast'\n > {\n value?: Array<Date | null> | Date | null;\n}\n\nexport function useCalendar({\n value,\n disablePast,\n disableFuture,\n shouldDisableDate,\n onHeaderChange,\n onNextMonth,\n onPrevMonth,\n minDateTime,\n maxDateTime,\n}: UseCalendarDependencies): {\n viewDate: Date;\n setViewDate: (value: Date) => void;\n setPrevMonth: () => void;\n setNextMonth: () => void;\n focusedDay: Date | undefined;\n setFocusedDay: React.Dispatch<React.SetStateAction<Date | undefined>>;\n isDayFocused: (day: Date) => boolean;\n isDayDisabled: (day: Date, withTime?: boolean) => boolean;\n isMonthDisabled: (month: number, year?: number) => boolean;\n isYearDisabled: (year: number) => boolean;\n} {\n const [viewDate, setViewDate] = React.useState(\n (Array.isArray(value) ? value[0] : value) ?? new Date(),\n );\n // соответствует дню, на котором сейчас есть фокус\n // меняется при переключении дней с помощью стрелок\n const [focusedDay, setFocusedDay] = React.useState<Date>();\n\n const setPrevMonth = React.useCallback(() => {\n onPrevMonth?.();\n setViewDate(subMonths(viewDate, 1));\n }, [viewDate, onPrevMonth]);\n const setNextMonth = React.useCallback(() => {\n onNextMonth?.();\n setViewDate(addMonths(viewDate, 1));\n }, [viewDate, onNextMonth]);\n\n const handleSetViewDate = React.useCallback(\n (value: Date) => {\n onHeaderChange?.(value);\n setViewDate(value);\n },\n [onHeaderChange],\n );\n\n const isDayFocused = React.useCallback(\n (day: Date) => Boolean(focusedDay && isSameDate(day, focusedDay)),\n [focusedDay],\n );\n\n const isDayDisabled = React.useCallback(\n (day: Date, withTime?: boolean) => {\n const now = new Date();\n if (shouldDisableDate) {\n return shouldDisableDate(day);\n }\n if (disableFuture) {\n return startOfDay(day) > now;\n }\n if (disablePast) {\n return endOfDay(day) < now;\n }\n if (minDateTime || maxDateTime) {\n return isDayMinMaxRestricted(day, { min: minDateTime, max: maxDateTime, withTime });\n }\n\n return false;\n },\n [disableFuture, disablePast, shouldDisableDate, minDateTime, maxDateTime],\n );\n\n const isMonthDisabled = React.useCallback(\n (month: number, year?: number): boolean => {\n const now = new Date();\n year = year || viewDate.getFullYear();\n const minMonth = minDateTime ? minDateTime.getMonth() : 0;\n const maxMonth = maxDateTime ? maxDateTime.getMonth() : 11;\n const minYear = minDateTime?.getFullYear() || DEFAULT_MIN_YEAR;\n const maxYear = maxDateTime?.getFullYear() || DEFAULT_MAX_YEAR;\n\n let isDisabled =\n year >= minYear && year <= maxYear\n ? (year === minYear && minMonth > month) || (year === maxYear && month > maxMonth)\n : true;\n\n if (disableFuture) {\n isDisabled =\n isDisabled ||\n (year === now.getFullYear() ? month > now.getMonth() : year > now.getFullYear());\n }\n if (disablePast) {\n isDisabled =\n isDisabled ||\n (year === now.getFullYear() ? month < now.getMonth() : year < now.getFullYear());\n }\n\n return isDisabled;\n },\n [disableFuture, disablePast, viewDate, minDateTime, maxDateTime],\n );\n\n const isYearDisabled = React.useCallback(\n (year: number): boolean => {\n const now = new Date();\n const minYear = minDateTime?.getFullYear() || DEFAULT_MIN_YEAR;\n const maxYear = maxDateTime?.getFullYear() || DEFAULT_MAX_YEAR;\n\n let isDisabled = minYear > year || year > maxYear;\n if (disableFuture) {\n isDisabled = isDisabled || year > now.getFullYear();\n }\n if (disablePast) {\n isDisabled = isDisabled || year < now.getFullYear();\n }\n\n return isDisabled;\n },\n [disableFuture, disablePast, minDateTime, maxDateTime],\n );\n\n return {\n viewDate,\n setViewDate: handleSetViewDate,\n setPrevMonth,\n setNextMonth,\n focusedDay,\n setFocusedDay,\n isDayFocused,\n isDayDisabled,\n isMonthDisabled,\n isYearDisabled,\n };\n}\n"],"names":["React","isSameDate","addMonths","startOfDay","subMonths","DEFAULT_MAX_YEAR","DEFAULT_MIN_YEAR","isDayMinMaxRestricted","endOfDay","useCalendar","value","disablePast","disableFuture","shouldDisableDate","onHeaderChange","onNextMonth","onPrevMonth","minDateTime","maxDateTime","viewDate","setViewDate","useState","Array","isArray","Date","focusedDay","setFocusedDay","setPrevMonth","useCallback","setNextMonth","handleSetViewDate","isDayFocused","day","Boolean","isDayDisabled","withTime","now","min","max","isMonthDisabled","month","year","getFullYear","minMonth","getMonth","maxMonth","minYear","maxYear","isDisabled","isYearDisabled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/hooks/useCalendar.ts"],"sourcesContent":["import * as React from 'react';\nimport { isSameDate } from '@vkontakte/vkjs';\nimport type { CalendarProps } from '../components/Calendar/Calendar';\nimport { DEFAULT_MAX_YEAR, DEFAULT_MIN_YEAR, isDayMinMaxRestricted } from '../lib/calendar';\nimport { addMonths, endOfDay, startOfDay, subMonths } from '../lib/date';\n\nexport interface UseCalendarDependencies\n extends Pick<\n CalendarProps,\n | 'onHeaderChange'\n | 'onNextMonth'\n | 'onPrevMonth'\n | 'minDateTime'\n | 'maxDateTime'\n | 'shouldDisableDate'\n | 'disableFuture'\n | 'disablePast'\n > {\n value?: Array<Date | null> | Date | null;\n}\n\nexport function useCalendar({\n value,\n disablePast,\n disableFuture,\n shouldDisableDate,\n onHeaderChange,\n onNextMonth,\n onPrevMonth,\n minDateTime,\n maxDateTime,\n}: UseCalendarDependencies): {\n viewDate: Date;\n setViewDate: (value: Date) => void;\n setPrevMonth: () => void;\n setNextMonth: () => void;\n focusedDay: Date | undefined;\n setFocusedDay: React.Dispatch<React.SetStateAction<Date | undefined>>;\n isDayFocused: (day: Date) => boolean;\n isDayDisabled: (day: Date, withTime?: boolean) => boolean;\n isMonthDisabled: (month: number, year?: number) => boolean;\n isYearDisabled: (year: number) => boolean;\n} {\n const [viewDate, setViewDate] = React.useState(\n (Array.isArray(value) ? value[0] : value) ?? new Date(),\n );\n // соответствует дню, на котором сейчас есть фокус\n // меняется при переключении дней с помощью стрелок\n const [focusedDay, setFocusedDay] = React.useState<Date>();\n\n const setPrevMonth = React.useCallback(() => {\n onPrevMonth?.();\n setViewDate(subMonths(viewDate, 1));\n }, [viewDate, onPrevMonth]);\n const setNextMonth = React.useCallback(() => {\n onNextMonth?.();\n setViewDate(addMonths(viewDate, 1));\n }, [viewDate, onNextMonth]);\n\n const handleSetViewDate = React.useCallback(\n (value: Date) => {\n onHeaderChange?.(value);\n setViewDate(value);\n },\n [onHeaderChange],\n );\n\n const isDayFocused = React.useCallback(\n (day: Date) => Boolean(focusedDay && isSameDate(day, focusedDay)),\n [focusedDay],\n );\n\n const isDayDisabled = React.useCallback(\n (day: Date, withTime?: boolean) => {\n const now = new Date();\n if (shouldDisableDate) {\n return shouldDisableDate(day);\n }\n if (disableFuture) {\n return startOfDay(day) > now;\n }\n if (disablePast) {\n return endOfDay(day) < now;\n }\n if (minDateTime || maxDateTime) {\n return isDayMinMaxRestricted(day, { min: minDateTime, max: maxDateTime, withTime });\n }\n\n return false;\n },\n [disableFuture, disablePast, shouldDisableDate, minDateTime, maxDateTime],\n );\n\n const isMonthDisabled = React.useCallback(\n (month: number, year?: number): boolean => {\n const now = new Date();\n year = year || viewDate.getFullYear();\n const minMonth = minDateTime ? minDateTime.getMonth() : 0;\n const maxMonth = maxDateTime ? maxDateTime.getMonth() : 11;\n const minYear = minDateTime?.getFullYear() || DEFAULT_MIN_YEAR;\n const maxYear = maxDateTime?.getFullYear() || DEFAULT_MAX_YEAR;\n\n let isDisabled =\n year >= minYear && year <= maxYear\n ? (year === minYear && minMonth > month) || (year === maxYear && month > maxMonth)\n : true;\n\n if (disableFuture) {\n isDisabled =\n isDisabled ||\n (year === now.getFullYear() ? month > now.getMonth() : year > now.getFullYear());\n }\n if (disablePast) {\n isDisabled =\n isDisabled ||\n (year === now.getFullYear() ? month < now.getMonth() : year < now.getFullYear());\n }\n\n return isDisabled;\n },\n [disableFuture, disablePast, viewDate, minDateTime, maxDateTime],\n );\n\n const isYearDisabled = React.useCallback(\n (year: number): boolean => {\n const now = new Date();\n const minYear = minDateTime?.getFullYear() || DEFAULT_MIN_YEAR;\n const maxYear = maxDateTime?.getFullYear() || DEFAULT_MAX_YEAR;\n\n let isDisabled = minYear > year || year > maxYear;\n if (disableFuture) {\n isDisabled = isDisabled || year > now.getFullYear();\n }\n if (disablePast) {\n isDisabled = isDisabled || year < now.getFullYear();\n }\n\n return isDisabled;\n },\n [disableFuture, disablePast, minDateTime, maxDateTime],\n );\n\n return {\n viewDate,\n setViewDate: handleSetViewDate,\n setPrevMonth,\n setNextMonth,\n focusedDay,\n setFocusedDay,\n isDayFocused,\n isDayDisabled,\n isMonthDisabled,\n isYearDisabled,\n };\n}\n"],"names":["React","isSameDate","DEFAULT_MAX_YEAR","DEFAULT_MIN_YEAR","isDayMinMaxRestricted","addMonths","endOfDay","startOfDay","subMonths","useCalendar","value","disablePast","disableFuture","shouldDisableDate","onHeaderChange","onNextMonth","onPrevMonth","minDateTime","maxDateTime","viewDate","setViewDate","useState","Array","isArray","Date","focusedDay","setFocusedDay","setPrevMonth","useCallback","setNextMonth","handleSetViewDate","isDayFocused","day","Boolean","isDayDisabled","withTime","now","min","max","isMonthDisabled","month","year","getFullYear","minMonth","getMonth","maxMonth","minYear","maxYear","isDisabled","isYearDisabled"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { isSameDate } from "@vkontakte/vkjs";
3
- import { differenceInMilliseconds, startOfTomorrow } from "date-fns";
3
+ import { startOfTomorrow } from "../lib/date.js";
4
4
  import { useDOM } from "../lib/dom.js";
5
5
  /**
6
6
  * Опционально обновляемая дата сегодняшнего дня
@@ -21,7 +21,7 @@ import { useDOM } from "../lib/dom.js";
21
21
  const recalcTimeout = ()=>{
22
22
  if (document.visibilityState === 'visible') {
23
23
  const now = new Date();
24
- const timeToDayChange = differenceInMilliseconds(startOfTomorrow(), now);
24
+ const timeToDayChange = Number(startOfTomorrow()) - Number(now);
25
25
  // Удаляем старый таймаут
26
26
  window.clearTimeout(timeout);
27
27
  // Создаем новый таймаут
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/useTodayDate.ts"],"sourcesContent":["import * as React from 'react';\nimport { isSameDate } from '@vkontakte/vkjs';\nimport { differenceInMilliseconds, startOfTomorrow } from 'date-fns';\nimport { useDOM } from '../lib/dom';\n\n/**\n * Опционально обновляемая дата сегодняшнего дня\n *\n * Дата - сегодня (в соответствии с системным временем)\n *\n * Часы, минуты, секунды, миллисекунды - произвольные\n *\n * @param listenDayChangesForUpdate - флаг по которому определяется, будет ли создаваться подписка на смену календарного дня\n */\nexport function useTodayDate(listenDayChangesForUpdate = false): Date {\n const { document, window } = useDOM();\n const [todayDate, setTodayDate] = React.useState(() => new Date());\n\n React.useEffect(\n function setupTodaysDateRecalculationListener() {\n if (!listenDayChangesForUpdate || !document || !window) {\n return;\n }\n\n let timeout: number | undefined = undefined;\n\n const recalcTimeout = () => {\n if (document.visibilityState === 'visible') {\n const now = new Date();\n\n const timeToDayChange = differenceInMilliseconds(startOfTomorrow(), now);\n\n // Удаляем старый таймаут\n window.clearTimeout(timeout);\n\n // Создаем новый таймаут\n timeout = window.setTimeout(() => {\n setTodayDate(new Date());\n }, timeToDayChange);\n\n // Если todayDate не обновился в таймаут - обновить при заходе на вкладку\n if (!isSameDate(todayDate, now)) {\n setTodayDate(now);\n }\n }\n };\n\n recalcTimeout();\n\n // Создаем слушатель visibilitychange, чтобы предотвратить пропуск обновления стейта после заморозки вкладки\n // Если человек ее долго не трогал или закрывал крышку ноута и тп\n // https://developer.chrome.com/blog/page-lifecycle-api/\n document.addEventListener('visibilitychange', recalcTimeout);\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('visibilitychange', recalcTimeout);\n };\n },\n [document, listenDayChangesForUpdate, todayDate, window],\n );\n\n return todayDate;\n}\n"],"names":["React","isSameDate","differenceInMilliseconds","startOfTomorrow","useDOM","useTodayDate","listenDayChangesForUpdate","document","window","todayDate","setTodayDate","useState","Date","useEffect","setupTodaysDateRecalculationListener","timeout","undefined","recalcTimeout","visibilityState","now","timeToDayChange","clearTimeout","setTimeout","addEventListener","removeEventListener"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,wBAAwB,EAAEC,eAAe,QAAQ,WAAW;AACrE,SAASC,MAAM,QAAQ,gBAAa;AAEpC;;;;;;;;CAQC,GACD,OAAO,SAASC,aAAaC,4BAA4B,KAAK;IAC5D,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAE,GAAGJ;IAC7B,MAAM,CAACK,WAAWC,aAAa,GAAGV,MAAMW,QAAQ,CAAC,IAAM,IAAIC;IAE3DZ,MAAMa,SAAS,CACb,SAASC;QACP,IAAI,CAACR,6BAA6B,CAACC,YAAY,CAACC,QAAQ;YACtD;QACF;QAEA,IAAIO,UAA8BC;QAElC,MAAMC,gBAAgB;YACpB,IAAIV,SAASW,eAAe,KAAK,WAAW;gBAC1C,MAAMC,MAAM,IAAIP;gBAEhB,MAAMQ,kBAAkBlB,yBAAyBC,mBAAmBgB;gBAEpE,yBAAyB;gBACzBX,OAAOa,YAAY,CAACN;gBAEpB,wBAAwB;gBACxBA,UAAUP,OAAOc,UAAU,CAAC;oBAC1BZ,aAAa,IAAIE;gBACnB,GAAGQ;gBAEH,yEAAyE;gBACzE,IAAI,CAACnB,WAAWQ,WAAWU,MAAM;oBAC/BT,aAAaS;gBACf;YACF;QACF;QAEAF;QAEA,4GAA4G;QAC5G,iEAAiE;QACjE,wDAAwD;QACxDV,SAASgB,gBAAgB,CAAC,oBAAoBN;QAE9C,OAAO;YACLT,OAAOa,YAAY,CAACN;YACpBR,SAASiB,mBAAmB,CAAC,oBAAoBP;QACnD;IACF,GACA;QAACV;QAAUD;QAA2BG;QAAWD;KAAO;IAG1D,OAAOC;AACT"}
1
+ {"version":3,"sources":["../../../src/hooks/useTodayDate.ts"],"sourcesContent":["import * as React from 'react';\nimport { isSameDate } from '@vkontakte/vkjs';\nimport { startOfTomorrow } from '../lib/date';\nimport { useDOM } from '../lib/dom';\n\n/**\n * Опционально обновляемая дата сегодняшнего дня\n *\n * Дата - сегодня (в соответствии с системным временем)\n *\n * Часы, минуты, секунды, миллисекунды - произвольные\n *\n * @param listenDayChangesForUpdate - флаг по которому определяется, будет ли создаваться подписка на смену календарного дня\n */\nexport function useTodayDate(listenDayChangesForUpdate = false): Date {\n const { document, window } = useDOM();\n const [todayDate, setTodayDate] = React.useState(() => new Date());\n\n React.useEffect(\n function setupTodaysDateRecalculationListener() {\n if (!listenDayChangesForUpdate || !document || !window) {\n return;\n }\n\n let timeout: number | undefined = undefined;\n\n const recalcTimeout = () => {\n if (document.visibilityState === 'visible') {\n const now = new Date();\n\n const timeToDayChange = Number(startOfTomorrow()) - Number(now);\n\n // Удаляем старый таймаут\n window.clearTimeout(timeout);\n\n // Создаем новый таймаут\n timeout = window.setTimeout(() => {\n setTodayDate(new Date());\n }, timeToDayChange);\n\n // Если todayDate не обновился в таймаут - обновить при заходе на вкладку\n if (!isSameDate(todayDate, now)) {\n setTodayDate(now);\n }\n }\n };\n\n recalcTimeout();\n\n // Создаем слушатель visibilitychange, чтобы предотвратить пропуск обновления стейта после заморозки вкладки\n // Если человек ее долго не трогал или закрывал крышку ноута и тп\n // https://developer.chrome.com/blog/page-lifecycle-api/\n document.addEventListener('visibilitychange', recalcTimeout);\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('visibilitychange', recalcTimeout);\n };\n },\n [document, listenDayChangesForUpdate, todayDate, window],\n );\n\n return todayDate;\n}\n"],"names":["React","isSameDate","startOfTomorrow","useDOM","useTodayDate","listenDayChangesForUpdate","document","window","todayDate","setTodayDate","useState","Date","useEffect","setupTodaysDateRecalculationListener","timeout","undefined","recalcTimeout","visibilityState","now","timeToDayChange","Number","clearTimeout","setTimeout","addEventListener","removeEventListener"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,eAAe,QAAQ,iBAAc;AAC9C,SAASC,MAAM,QAAQ,gBAAa;AAEpC;;;;;;;;CAQC,GACD,OAAO,SAASC,aAAaC,4BAA4B,KAAK;IAC5D,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAE,GAAGJ;IAC7B,MAAM,CAACK,WAAWC,aAAa,GAAGT,MAAMU,QAAQ,CAAC,IAAM,IAAIC;IAE3DX,MAAMY,SAAS,CACb,SAASC;QACP,IAAI,CAACR,6BAA6B,CAACC,YAAY,CAACC,QAAQ;YACtD;QACF;QAEA,IAAIO,UAA8BC;QAElC,MAAMC,gBAAgB;YACpB,IAAIV,SAASW,eAAe,KAAK,WAAW;gBAC1C,MAAMC,MAAM,IAAIP;gBAEhB,MAAMQ,kBAAkBC,OAAOlB,qBAAqBkB,OAAOF;gBAE3D,yBAAyB;gBACzBX,OAAOc,YAAY,CAACP;gBAEpB,wBAAwB;gBACxBA,UAAUP,OAAOe,UAAU,CAAC;oBAC1Bb,aAAa,IAAIE;gBACnB,GAAGQ;gBAEH,yEAAyE;gBACzE,IAAI,CAAClB,WAAWO,WAAWU,MAAM;oBAC/BT,aAAaS;gBACf;YACF;QACF;QAEAF;QAEA,4GAA4G;QAC5G,iEAAiE;QACjE,wDAAwD;QACxDV,SAASiB,gBAAgB,CAAC,oBAAoBP;QAE9C,OAAO;YACLT,OAAOc,YAAY,CAACP;YACpBR,SAASkB,mBAAmB,CAAC,oBAAoBR;QACnD;IACF,GACA;QAACV;QAAUD;QAA2BG;QAAWD;KAAO;IAG1D,OAAOC;AACT"}
@@ -1,8 +1,7 @@
1
1
  import { isSameDate } from "@vkontakte/vkjs";
2
- import { addDays, addMonths, addWeeks, eachDayOfInterval, endOfWeek, startOfMonth, startOfWeek, subDays, subMonths, subWeeks } from "date-fns";
3
2
  import { clamp as clampNumber } from "../helpers/math.js";
4
3
  import { Keys } from "./accessibility.js";
5
- import { endOfMonth, isLastDayOfMonth } from "./date.js";
4
+ import { addDays, addMonths, addWeeks, eachDayOfInterval, endOfMonth, endOfWeek, isLastDayOfMonth, MONDAY, startOfMonth, startOfWeek, subDays, subMonths, subWeeks } from "./date.js";
6
5
  export const DEFAULT_MAX_YEAR = 9999;
7
6
  // 100 - из-за ограничений dayjs https://github.com/iamkun/dayjs/issues/2591
8
7
  export const DEFAULT_MIN_YEAR = 100;
@@ -38,14 +37,11 @@ export const getDaysNames = (now, weekStartsOn, locale)=>{
38
37
  const longFormatter = new Intl.DateTimeFormat(locale, {
39
38
  weekday: 'long'
40
39
  });
41
- return eachDayOfInterval({
42
- start: startOfWeek(now, {
43
- weekStartsOn
44
- }),
45
- end: endOfWeek(now, {
46
- weekStartsOn
47
- })
48
- }).map((day)=>({
40
+ return eachDayOfInterval(startOfWeek(now, {
41
+ weekStartsOn
42
+ }), endOfWeek(now, {
43
+ weekStartsOn
44
+ })).map((day)=>({
49
45
  short: shortFormatter.format(day),
50
46
  long: longFormatter.format(day)
51
47
  }));
@@ -77,12 +73,12 @@ export const navigateDate = (date, key)=>{
77
73
  break;
78
74
  case Keys.HOME:
79
75
  newDate = startOfWeek(newDate, {
80
- weekStartsOn: 1
76
+ weekStartsOn: MONDAY
81
77
  });
82
78
  break;
83
79
  case Keys.END:
84
80
  newDate = endOfWeek(newDate, {
85
- weekStartsOn: 1
81
+ weekStartsOn: MONDAY
86
82
  });
87
83
  break;
88
84
  case Keys.PAGE_UP:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/calendar.ts"],"sourcesContent":["import { isSameDate } from '@vkontakte/vkjs';\nimport {\n addDays,\n addMonths,\n addWeeks,\n eachDayOfInterval,\n endOfWeek,\n startOfMonth,\n startOfWeek,\n subDays,\n subMonths,\n subWeeks,\n} from 'date-fns';\nimport { clamp as clampNumber } from '../helpers/math';\nimport { Keys, type KeysValues } from './accessibility';\nimport { endOfMonth, isLastDayOfMonth } from './date';\n\nexport const DEFAULT_MAX_YEAR = 9999;\n// 100 - из-за ограничений dayjs https://github.com/iamkun/dayjs/issues/2591\nexport const DEFAULT_MIN_YEAR = 100;\n\nexport const getYears = (\n currentYear: number,\n range: number,\n): Array<{\n value: number;\n label: string;\n}> => {\n const years: Array<{\n value: number;\n label: string;\n }> = [];\n\n const minYear = clampNumber(currentYear - range, DEFAULT_MIN_YEAR, DEFAULT_MAX_YEAR);\n const maxYear = clampNumber(currentYear + range, DEFAULT_MIN_YEAR, DEFAULT_MAX_YEAR);\n\n for (let i = minYear; i <= maxYear; i++) {\n years.push({ label: String(i).padStart(4, '0'), value: i });\n }\n\n return years;\n};\n\nexport const getMonths = (\n locale?: string,\n): Array<{\n value: number;\n label: string;\n}> => {\n const months: Array<{\n value: number;\n label: string;\n }> = [];\n const formatter = new Intl.DateTimeFormat(locale, {\n month: 'long',\n });\n\n for (let i = 0; i < 12; i++) {\n months.push({\n label: formatter.format(new Date(2023, i, 15)),\n value: i,\n });\n }\n\n return months;\n};\n\nexport const getDaysNames = (\n now: Date,\n weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6,\n locale?: string,\n): Array<{ short: string; long: string }> => {\n const shortFormatter = new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n });\n const longFormatter = new Intl.DateTimeFormat(locale, {\n weekday: 'long',\n });\n return eachDayOfInterval({\n start: startOfWeek(now, { weekStartsOn }),\n end: endOfWeek(now, { weekStartsOn }),\n }).map((day) => ({ short: shortFormatter.format(day), long: longFormatter.format(day) }));\n};\n\nexport const NAVIGATION_KEYS: KeysValues[] = [\n Keys.ARROW_UP,\n Keys.ARROW_DOWN,\n Keys.ARROW_LEFT,\n Keys.ARROW_RIGHT,\n Keys.HOME,\n Keys.END,\n Keys.PAGE_UP,\n Keys.PAGE_DOWN,\n];\n\nexport const navigateDate = (date?: Date | null, key?: (typeof NAVIGATION_KEYS)[number]): Date => {\n let newDate = date ?? new Date();\n\n switch (key) {\n case Keys.ARROW_RIGHT:\n newDate = addDays(newDate, 1);\n break;\n case Keys.ARROW_LEFT:\n newDate = subDays(newDate, 1);\n break;\n case Keys.ARROW_UP:\n newDate = subWeeks(newDate, 1);\n break;\n case Keys.ARROW_DOWN:\n newDate = addWeeks(newDate, 1);\n break;\n case Keys.HOME:\n newDate = startOfWeek(newDate, { weekStartsOn: 1 });\n break;\n case Keys.END:\n newDate = endOfWeek(newDate, { weekStartsOn: 1 });\n break;\n case Keys.PAGE_UP:\n newDate = subMonths(newDate, 1);\n break;\n case Keys.PAGE_DOWN:\n newDate = addMonths(newDate, 1);\n break;\n }\n\n return newDate;\n};\n\nexport const getWeeks = (viewDate: Date, weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6): Date[][] => {\n const start = startOfWeek(startOfMonth(viewDate), { weekStartsOn });\n const end = endOfWeek(endOfMonth(viewDate), { weekStartsOn });\n\n let count = 0;\n let current = start;\n const nestedWeeks: Date[][] = [];\n let lastDay = null;\n while (current < end) {\n const weekNumber = Math.floor(count / 7);\n nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];\n const day = current.getDay();\n if (lastDay !== day) {\n lastDay = day;\n nestedWeeks[weekNumber].push(current);\n count += 1;\n }\n current = addDays(current, 1);\n }\n return nestedWeeks;\n};\n\nexport const setTimeEqual = (to: Date, from?: Date | null): Date => {\n if (from) {\n to.setHours(from.getHours());\n to.setMinutes(from.getMinutes());\n to.setSeconds(from.getSeconds());\n to.setMilliseconds(from.getMilliseconds());\n }\n\n return to;\n};\n\nexport const isFirstDay = (day: Date, dayOfWeek: number): boolean =>\n dayOfWeek === 0 || day.getDate() === 1;\n\nexport const isLastDay = (day: Date, dayOfWeek: number): boolean =>\n dayOfWeek === 6 || isLastDayOfMonth(day);\n\n/**\n * Возвращает дату, ограниченную `min` и/или `max` значениями\n */\nexport function clamp(day: Date, options: { min?: Date; max?: Date } = {}): Date {\n const { min, max } = options;\n if (min && day < min) {\n return min;\n }\n if (max && day > max) {\n return max;\n }\n return day;\n}\n\n/**\n * Позволяет определить удовлетворяет ли исходная дата заданным ограничения `min` и/или `max`\n */\nexport function isDayMinMaxRestricted(\n day: Date,\n options: { min?: Date; max?: Date; withTime?: boolean } = {},\n): boolean {\n const { min, max, withTime = false } = options;\n if (!withTime && ((min && isSameDate(day, min)) || (max && isSameDate(day, max)))) {\n return false;\n }\n return Boolean((min && day < min) || (max && day > max));\n}\n"],"names":["isSameDate","addDays","addMonths","addWeeks","eachDayOfInterval","endOfWeek","startOfMonth","startOfWeek","subDays","subMonths","subWeeks","clamp","clampNumber","Keys","endOfMonth","isLastDayOfMonth","DEFAULT_MAX_YEAR","DEFAULT_MIN_YEAR","getYears","currentYear","range","years","minYear","maxYear","i","push","label","String","padStart","value","getMonths","locale","months","formatter","Intl","DateTimeFormat","month","format","Date","getDaysNames","now","weekStartsOn","shortFormatter","weekday","longFormatter","start","end","map","day","short","long","NAVIGATION_KEYS","ARROW_UP","ARROW_DOWN","ARROW_LEFT","ARROW_RIGHT","HOME","END","PAGE_UP","PAGE_DOWN","navigateDate","date","key","newDate","getWeeks","viewDate","count","current","nestedWeeks","lastDay","weekNumber","Math","floor","getDay","setTimeEqual","to","from","setHours","getHours","setMinutes","getMinutes","setSeconds","getSeconds","setMilliseconds","getMilliseconds","isFirstDay","dayOfWeek","getDate","isLastDay","options","min","max","isDayMinMaxRestricted","withTime","Boolean"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/calendar.ts"],"sourcesContent":["import { isSameDate } from '@vkontakte/vkjs';\nimport { clamp as clampNumber } from '../helpers/math';\nimport { Keys, type KeysValues } from './accessibility';\nimport {\n addDays,\n addMonths,\n addWeeks,\n eachDayOfInterval,\n endOfMonth,\n endOfWeek,\n isLastDayOfMonth,\n MONDAY,\n startOfMonth,\n startOfWeek,\n subDays,\n subMonths,\n subWeeks,\n} from './date';\n\nexport const DEFAULT_MAX_YEAR = 9999;\n// 100 - из-за ограничений dayjs https://github.com/iamkun/dayjs/issues/2591\nexport const DEFAULT_MIN_YEAR = 100;\n\nexport const getYears = (\n currentYear: number,\n range: number,\n): Array<{\n value: number;\n label: string;\n}> => {\n const years: Array<{\n value: number;\n label: string;\n }> = [];\n\n const minYear = clampNumber(currentYear - range, DEFAULT_MIN_YEAR, DEFAULT_MAX_YEAR);\n const maxYear = clampNumber(currentYear + range, DEFAULT_MIN_YEAR, DEFAULT_MAX_YEAR);\n\n for (let i = minYear; i <= maxYear; i++) {\n years.push({ label: String(i).padStart(4, '0'), value: i });\n }\n\n return years;\n};\n\nexport const getMonths = (\n locale?: string,\n): Array<{\n value: number;\n label: string;\n}> => {\n const months: Array<{\n value: number;\n label: string;\n }> = [];\n const formatter = new Intl.DateTimeFormat(locale, {\n month: 'long',\n });\n\n for (let i = 0; i < 12; i++) {\n months.push({\n label: formatter.format(new Date(2023, i, 15)),\n value: i,\n });\n }\n\n return months;\n};\n\nexport const getDaysNames = (\n now: Date,\n weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6,\n locale?: string,\n): Array<{ short: string; long: string }> => {\n const shortFormatter = new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n });\n const longFormatter = new Intl.DateTimeFormat(locale, {\n weekday: 'long',\n });\n return eachDayOfInterval(\n startOfWeek(now, { weekStartsOn }),\n endOfWeek(now, { weekStartsOn }),\n ).map((day) => ({ short: shortFormatter.format(day), long: longFormatter.format(day) }));\n};\n\nexport const NAVIGATION_KEYS: KeysValues[] = [\n Keys.ARROW_UP,\n Keys.ARROW_DOWN,\n Keys.ARROW_LEFT,\n Keys.ARROW_RIGHT,\n Keys.HOME,\n Keys.END,\n Keys.PAGE_UP,\n Keys.PAGE_DOWN,\n];\n\nexport const navigateDate = (date?: Date | null, key?: (typeof NAVIGATION_KEYS)[number]): Date => {\n let newDate = date ?? new Date();\n\n switch (key) {\n case Keys.ARROW_RIGHT:\n newDate = addDays(newDate, 1);\n break;\n case Keys.ARROW_LEFT:\n newDate = subDays(newDate, 1);\n break;\n case Keys.ARROW_UP:\n newDate = subWeeks(newDate, 1);\n break;\n case Keys.ARROW_DOWN:\n newDate = addWeeks(newDate, 1);\n break;\n case Keys.HOME:\n newDate = startOfWeek(newDate, { weekStartsOn: MONDAY });\n break;\n case Keys.END:\n newDate = endOfWeek(newDate, { weekStartsOn: MONDAY });\n break;\n case Keys.PAGE_UP:\n newDate = subMonths(newDate, 1);\n break;\n case Keys.PAGE_DOWN:\n newDate = addMonths(newDate, 1);\n break;\n }\n\n return newDate;\n};\n\nexport const getWeeks = (viewDate: Date, weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6): Date[][] => {\n const start = startOfWeek(startOfMonth(viewDate), { weekStartsOn });\n const end = endOfWeek(endOfMonth(viewDate), { weekStartsOn });\n\n let count = 0;\n let current = start;\n const nestedWeeks: Date[][] = [];\n let lastDay = null;\n while (current < end) {\n const weekNumber = Math.floor(count / 7);\n nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];\n const day = current.getDay();\n if (lastDay !== day) {\n lastDay = day;\n nestedWeeks[weekNumber].push(current);\n count += 1;\n }\n current = addDays(current, 1);\n }\n return nestedWeeks;\n};\n\nexport const setTimeEqual = (to: Date, from?: Date | null): Date => {\n if (from) {\n to.setHours(from.getHours());\n to.setMinutes(from.getMinutes());\n to.setSeconds(from.getSeconds());\n to.setMilliseconds(from.getMilliseconds());\n }\n\n return to;\n};\n\nexport const isFirstDay = (day: Date, dayOfWeek: number): boolean =>\n dayOfWeek === 0 || day.getDate() === 1;\n\nexport const isLastDay = (day: Date, dayOfWeek: number): boolean =>\n dayOfWeek === 6 || isLastDayOfMonth(day);\n\n/**\n * Возвращает дату, ограниченную `min` и/или `max` значениями\n */\nexport function clamp(day: Date, options: { min?: Date; max?: Date } = {}): Date {\n const { min, max } = options;\n if (min && day < min) {\n return min;\n }\n if (max && day > max) {\n return max;\n }\n return day;\n}\n\n/**\n * Позволяет определить удовлетворяет ли исходная дата заданным ограничения `min` и/или `max`\n */\nexport function isDayMinMaxRestricted(\n day: Date,\n options: { min?: Date; max?: Date; withTime?: boolean } = {},\n): boolean {\n const { min, max, withTime = false } = options;\n if (!withTime && ((min && isSameDate(day, min)) || (max && isSameDate(day, max)))) {\n return false;\n }\n return Boolean((min && day < min) || (max && day > max));\n}\n"],"names":["isSameDate","clamp","clampNumber","Keys","addDays","addMonths","addWeeks","eachDayOfInterval","endOfMonth","endOfWeek","isLastDayOfMonth","MONDAY","startOfMonth","startOfWeek","subDays","subMonths","subWeeks","DEFAULT_MAX_YEAR","DEFAULT_MIN_YEAR","getYears","currentYear","range","years","minYear","maxYear","i","push","label","String","padStart","value","getMonths","locale","months","formatter","Intl","DateTimeFormat","month","format","Date","getDaysNames","now","weekStartsOn","shortFormatter","weekday","longFormatter","map","day","short","long","NAVIGATION_KEYS","ARROW_UP","ARROW_DOWN","ARROW_LEFT","ARROW_RIGHT","HOME","END","PAGE_UP","PAGE_DOWN","navigateDate","date","key","newDate","getWeeks","viewDate","start","end","count","current","nestedWeeks","lastDay","weekNumber","Math","floor","getDay","setTimeEqual","to","from","setHours","getHours","setMinutes","getMinutes","setSeconds","getSeconds","setMilliseconds","getMilliseconds","isFirstDay","dayOfWeek","getDate","isLastDay","options","min","max","isDayMinMaxRestricted","withTime","Boolean"],"mappings":"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"}
@@ -153,6 +153,14 @@ class DateTimeFormat extends Intl.DateTimeFormat {
153
153
  }
154
154
  // dd.MM.yyyy HH:mm
155
155
  export const dateTimeFormatter = /*#__PURE__*/ new DateTimeFormat();
156
+ /**
157
+ * Возвращает дату начала месяца
158
+ */ export function startOfMonth(date) {
159
+ const result = new Date(date);
160
+ result.setDate(1);
161
+ result.setHours(0, 0, 0, 0);
162
+ return result;
163
+ }
156
164
  /**
157
165
  * Возвращает дату конца месяца
158
166
  */ export function endOfMonth(date) {
@@ -162,11 +170,75 @@ export const dateTimeFormatter = /*#__PURE__*/ new DateTimeFormat();
162
170
  result.setHours(23, 59, 59, 999);
163
171
  return result;
164
172
  }
165
- export function endOfDay(date) {
173
+ export const MONDAY = 1;
174
+ /**
175
+ * Возвращает дату начала недели
176
+ */ export function startOfWeek(date, { weekStartsOn = MONDAY } = {}) {
177
+ const result = new Date(date);
178
+ const day = result.getDay();
179
+ const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
180
+ result.setDate(result.getDate() - diff);
181
+ result.setHours(0, 0, 0, 0);
182
+ return result;
183
+ }
184
+ /**
185
+ * Возвращает дату конца недели
186
+ */ export function endOfWeek(date, { weekStartsOn = MONDAY } = {}) {
187
+ const result = new Date(date);
188
+ const day = result.getDay();
189
+ const diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn);
190
+ result.setDate(result.getDate() + diff);
191
+ result.setHours(23, 59, 59, 999);
192
+ return result;
193
+ }
194
+ /**
195
+ * Возвращает дату начала дня
196
+ */ export function startOfDay(date) {
197
+ const result = new Date(date);
198
+ result.setHours(0, 0, 0, 0);
199
+ return result;
200
+ }
201
+ /**
202
+ * Возвращает дату конца дня
203
+ */ export function endOfDay(date) {
166
204
  const result = new Date(date);
167
205
  result.setHours(23, 59, 59, 999);
168
206
  return result;
169
207
  }
208
+ export function startOfTomorrow() {
209
+ const date = new Date();
210
+ const day = date.getDate();
211
+ date.setDate(day + 1);
212
+ date.setHours(0, 0, 0, 0);
213
+ return date;
214
+ }
215
+ /**
216
+ * Возвращает дату начала минуты
217
+ */ export function startOfMinute(date) {
218
+ const result = new Date(date);
219
+ result.setSeconds(0, 0);
220
+ return result;
221
+ }
222
+ export function eachDayOfInterval(startDate, endDate, { step = 1 } = {}) {
223
+ let reversed = +startDate > +endDate;
224
+ const endTime = reversed ? +startDate : +endDate;
225
+ const date = new Date(reversed ? endDate : startDate);
226
+ date.setHours(0, 0, 0, 0);
227
+ if (!step) {
228
+ return [];
229
+ }
230
+ if (step < 0) {
231
+ step = -step;
232
+ reversed = !reversed;
233
+ }
234
+ const dates = [];
235
+ while(+date <= endTime){
236
+ dates.push(new Date(date));
237
+ date.setDate(date.getDate() + 1);
238
+ date.setHours(0, 0, 0, 0);
239
+ }
240
+ return reversed ? dates.reverse() : dates;
241
+ }
170
242
  /**
171
243
  * Проверяет, что переданные даты относятся к одному и тому же месяцу
172
244
  *
@@ -201,5 +273,74 @@ export function isMatch(input, format) {
201
273
  return !isNaN(+parse(input, format));
202
274
  }
203
275
  export const millisecondsInSecond = 1000;
276
+ export function addDays(date, amount) {
277
+ const result = new Date(date);
278
+ if (!amount) {
279
+ return result;
280
+ }
281
+ result.setDate(result.getDate() + amount);
282
+ return result;
283
+ }
284
+ export function subDays(date, amount) {
285
+ return addDays(date, -amount);
286
+ }
287
+ export function addWeeks(date, amount) {
288
+ return addDays(date, amount * 7);
289
+ }
290
+ export function subWeeks(date, amount) {
291
+ return addWeeks(date, -amount);
292
+ }
293
+ export function addMonths(date, amount) {
294
+ const result = new Date(date);
295
+ if (!amount) {
296
+ return result;
297
+ }
298
+ const dayOfMonth = result.getDate();
299
+ const endOfDesiredMonth = new Date(date);
300
+ endOfDesiredMonth.setMonth(result.getMonth() + amount + 1, 0); // Конец месяца
301
+ const daysInMonth = endOfDesiredMonth.getDate();
302
+ if (dayOfMonth >= daysInMonth) {
303
+ // Если мы уже находимся в конце месяца, то это нужная дата
304
+ return endOfDesiredMonth;
305
+ }
306
+ result.setFullYear(endOfDesiredMonth.getFullYear(), endOfDesiredMonth.getMonth(), dayOfMonth);
307
+ return result;
308
+ }
309
+ export function subMonths(date, amount) {
310
+ return addMonths(date, -amount);
311
+ }
312
+ export function setYear(date, year) {
313
+ const result = new Date(date);
314
+ result.setFullYear(year);
315
+ return result;
316
+ }
317
+ function getDaysInMonth(date) {
318
+ const result = new Date(date);
319
+ const lastDayOfMonth = new Date(result);
320
+ lastDayOfMonth.setFullYear(result.getFullYear(), result.getMonth() + 1, 0);
321
+ lastDayOfMonth.setHours(0, 0, 0, 0);
322
+ return lastDayOfMonth.getDate();
323
+ }
324
+ export function setMonth(date, month) {
325
+ const result = new Date(date);
326
+ const year = result.getFullYear();
327
+ const day = result.getDate();
328
+ const midMonth = new Date(date);
329
+ midMonth.setFullYear(year, month, 15);
330
+ midMonth.setHours(0, 0, 0, 0);
331
+ const daysInMonth = getDaysInMonth(midMonth);
332
+ result.setMonth(month, Math.min(day, daysInMonth));
333
+ return result;
334
+ }
335
+ export function setHours(date, hours) {
336
+ const result = new Date(date);
337
+ result.setHours(hours);
338
+ return result;
339
+ }
340
+ export function setMinutes(date, minutes) {
341
+ const result = new Date(date);
342
+ result.setMinutes(minutes);
343
+ return result;
344
+ }
204
345
 
205
346
  //# sourceMappingURL=date.js.map