@vchasno/ui-kit 0.4.107 → 0.4.109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.109] - 2026-06-30
9
+
10
+ ### Added
11
+
12
+ - **ProjectsPopover** — add `business` product (Вчасно.Бізнес) linking to https://business.vchasno.ua/, with its tile icon, title, and tooltip hint
13
+
14
+ ### Changed
15
+
16
+ - **ProjectsPopover** — rename the `profile` product to `account` in the `VchasnoProduct` type (and `vchasnoProductsWithoutSiteList`); consumers passing `'profile'` must migrate to `'account'`
17
+
18
+ ## [0.4.108] - 2026-06-26
19
+
20
+ ### Fixed
21
+
22
+ - **DateRangePicker** — selecting a second date earlier than the first now swaps them into a valid ascending range (via react-datepicker `swapRange`) instead of silently resetting the selection; a `normalizeOrder` guard at commit additionally ensures no saved range is ever reversed (also protects unvalidated consumer `presets`)
23
+ - **DateRangePicker** — clicking the same day twice (or re-clicking the end date of a cross-month range) no longer makes the calendar jump back a month; `openToDate` is now anchored in reducer state and refreshed only on open/preset/reset, so the view stays put during selection
24
+
25
+ ### Changed
26
+
27
+ - **DateRangePicker** — for a committed same-month range the calendar now opens anchored on the range's month (left pane) rather than the previous month
28
+
8
29
  ## [0.4.107] - 2026-06-25
9
30
 
10
31
  ### Changed
@@ -4,7 +4,12 @@ import { MaskedInputProps } from 'react-text-mask';
4
4
  import Select from '../../Select/Select.js';
5
5
  import { LoadingFeedback, WithHint, ErrorFeedback, DataQa, HideEmptyMeta, WithPulseAnimation } from '../../types.js';
6
6
 
7
- type ControlledReactDatePickerProps = 'selectsRange' | 'selectsMultiple' | 'startDate' | 'endDate' | 'onChange' | 'value' | 'open' | 'onInputClick' | 'onClickOutside' | 'monthsShown' | 'shouldCloseOnSelect' | 'renderCustomHeader' | 'children' | 'onChangeRaw' | 'customInput';
7
+ declare module 'react-datepicker' {
8
+ interface ReactDatePickerProps<WithRange extends boolean | undefined = undefined, WithMultiple extends boolean | undefined = undefined> {
9
+ swapRange?: boolean | undefined;
10
+ }
11
+ }
12
+ type ControlledReactDatePickerProps = 'selectsRange' | 'selectsMultiple' | 'swapRange' | 'startDate' | 'endDate' | 'onChange' | 'value' | 'open' | 'onInputClick' | 'onClickOutside' | 'monthsShown' | 'shouldCloseOnSelect' | 'renderCustomHeader' | 'children' | 'onChangeRaw' | 'customInput';
8
13
  interface DateRangePickerProps extends Omit<ReactDatePickerProps<true>, ControlledReactDatePickerProps>, Partial<LoadingFeedback & WithHint & ErrorFeedback & DataQa & HideEmptyMeta & WithPulseAnimation> {
9
14
  startDate: Date | null;
10
15
  endDate: Date | null;
@@ -1,2 +1,2 @@
1
- import e from"react";import t from"react-datepicker";import a from"react-text-mask";import n from"classnames";import{format as r,subMonths as l}from"date-fns";import{uk as c}from"date-fns/locale/uk";import i from"../../../icons/arrowLeft.js";import o from"../../../icons/arrowRight.js";import s from"../../../icons/calendar.js";import p from"../../../icons/clear.js";import m from"../../InputMeta/InputMeta.js";import u from"../../LabelText/LabelText.js";import d from"../../Select/Select.js";import"../../Select/SelectCreatable.js";import"react-select/async";import"react-select";import g from"../../Spinner/Spinner.js";import{pickerReducer as y,initialState as h}from"./DateRangePicker.reducer.js";import{buildRangeMask as k,formatRange as v,matchPresetLabel as _,parseRange as f,applyEndFallback as b}from"./utils.js";let E=()=>e.createElement("span",{className:"vchasno-ui-date-range-picker__custom-close-icon"},p),N=({startDate:p,endDate:N,onChange:C,label:D,disabled:w,required:x,loading:j,hint:T,error:S,className:L,dateFormat:M="dd/MM/yyyy",dataQa:R,hideEmptyMeta:I=!1,wide:A=!1,endDefaultsToToday:P=!1,pulse:H,isClearable:O=!1,minDate:q,maxDate:K,popperClassName:z,portalId:B,cancelLabel:F="Скасувати",saveLabel:G="Зберегти",locale:J=c,presets:Q=[],presetPlaceholder:U="Обрати період",presetSelectProps:V,onCancel:W,onConfirm:X,mask:Y,...Z})=>{var $,ee;let[et,ea]=e.useReducer(y,h),{isOpen:en,tempStartDate:er,tempEndDate:el,selectedPreset:ec,calendarKey:ei,inputText:eo}=et,es=e.useRef(null),ep=(Array.isArray(M)?M[0]:M)??"dd/MM/yyyy",em=Y??k(ep),eu={minDate:q,maxDate:K,allowStartOnly:P},ed=v(p,N,ep),eg=_(p,N,Q),ey=(e,t)=>{let[a,n]=b(e,t,P,new Date,K);C([a,n]),X?.([a,n]),ea({type:"close"})},eh=()=>{W?.(),ea({type:"cancel",startDate:p,endDate:N,inputText:ed})},ek=!!p||!!N,ev=!en&&null!==eg&&ek,e_=en?eo:ed;return e.createElement("label",{onClick:e=>e.preventDefault(),"data-qa":R,className:n("vchasno-ui-date-picker","vchasno-ui-date-range-picker",{"--loading":j,"--required":x,"--disabled":w,"--error":S,"--wide":A,"--not-empty":ek,"--filled":!!e_,"--preset-label":ev,"--is-label":!!D},L),onKeyDown:e=>{"Escape"===e.key&&en&&eh()},onKeyDownCapture:e=>{if("Enter"!==e.key)return;let t=e.target;if(!t.matches?.(".react-datepicker__input-container input"))return;e.preventDefault(),e.stopPropagation();let a=f(eo,ep,eu);a&&"empty"!==a&&ey(a.start,a.end)}},e.createElement("span",{ref:es,className:n("vchasno-ui-date-range-picker__wrapper",{"vchasno-ui-pulse-animation":H&&!w})},D&&e.createElement(u,null,D),e.createElement(t,{key:ei,openToDate:($=en?er:p,(ee=en?el:N)?l(ee,1):$||new Date),fixedHeight:!0,locale:J,disabled:w,placeholderText:"ДД/ММ/РРРР - ДД/ММ/РРРР",showPopperArrow:!1,className:n("vchasno-ui-date-range-picker__picker","vchasno-ui-date-picker__picker"),popperClassName:n("vchasno-ui-date-range-picker-popper",z),selectsRange:!0,startDate:en?er:p,endDate:en?el:N,onChange:e=>{let[t,a]=e;ea({type:"tempChange",start:t,end:a,inputText:v(t,a,ep)})},monthsShown:2,shouldCloseOnSelect:!1,open:en,onInputClick:()=>{w||en||ea({type:"open",startDate:p,endDate:N,inputText:ed})},onClickOutside:e=>{let t=e.target;t instanceof Node&&es.current?.contains(t)||eh()},enableTabLoop:!1,minDate:q,maxDate:K,portalId:B,value:e_,onChangeRaw:e=>{if(!(e.target instanceof HTMLInputElement))return;e.preventDefault();let t=e.target.value;ea({type:"typeChange",inputText:t,parsed:f(t,ep,eu)})},customInput:e.createElement(a,{inputMode:"numeric",mask:em,guide:!0}),renderCustomHeader:({monthDate:t,decreaseMonth:a,increaseMonth:n,prevMonthButtonDisabled:l,nextMonthButtonDisabled:c})=>e.createElement("div",{className:"vchasno-ui-date-range-picker__header"},e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__nav-btn",onClick:a,disabled:l},e.createElement(i,null)),e.createElement("span",{className:"vchasno-ui-date-range-picker__month-title"},r(t,"LLLL, yyyy",{locale:"string"==typeof J?void 0:J})),e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__nav-btn",onClick:n,disabled:c},e.createElement(o,null))),...Z},e.createElement("div",{className:"vchasno-ui-date-range-picker__presets"},Q.length>0&&e.createElement(d,{className:"vchasno-ui-date-range-picker__preset-select",isClearable:!0,options:Q.map(e=>({label:e.label,value:e.label})),value:ec,placeholder:U,onChange:e=>{let t=Array.isArray(e)?null:e;if(!t){ea({type:"reset"});return}let a=Q.find(e=>e.label===t.value);a&&ea({type:"presetSelect",option:t,start:a.range[0],end:a.range[1],inputText:v(a.range[0],a.range[1],ep)})},hideEmptyMeta:!0,wide:!0,...V})),e.createElement("div",{className:"vchasno-ui-date-range-picker__actions"},e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__cancel-btn",onClick:eh},F),e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__save-btn",onClick:()=>{ey(er,el)}},G))),ev&&e.createElement("span",{className:"vchasno-ui-date-range-picker__preset-label","aria-hidden":"true"},eg),j?e.createElement(g,{className:"vchasno-ui-date-range-picker__spinner"}):e.createElement(s,{className:"vchasno-ui-date-range-picker__custom-calendar-icon"}),O&&ek&&!w&&e.createElement("button",{type:"button","aria-label":"Очистити",className:"vchasno-ui-date-range-picker__clear-btn",onClick:()=>{C([null,null]),ea({type:"reset"})}},e.createElement(E,null))),!I||S||T?e.createElement(m,{hint:T,error:S}):null)};N.displayName="DateRangePicker";export{N as default};
1
+ import e from"react";import t from"react-datepicker";import a from"react-text-mask";import n from"classnames";import{format as r,isSameMonth as l,subMonths as c}from"date-fns";import{uk as o}from"date-fns/locale/uk";import i from"../../../icons/arrowLeft.js";import s from"../../../icons/arrowRight.js";import p from"../../../icons/calendar.js";import m from"../../../icons/clear.js";import u from"../../InputMeta/InputMeta.js";import d from"../../LabelText/LabelText.js";import g from"../../Select/Select.js";import"../../Select/SelectCreatable.js";import"react-select/async";import"react-select";import y from"../../Spinner/Spinner.js";import{pickerReducer as h,initialState as k}from"./DateRangePicker.reducer.js";import{buildRangeMask as v,formatRange as _,matchPresetLabel as f,parseRange as b,applyEndFallback as E,normalizeOrder as N}from"./utils.js";let C=()=>e.createElement("span",{className:"vchasno-ui-date-range-picker__custom-close-icon"},m),D=({startDate:m,endDate:D,onChange:w,label:T,disabled:x,required:j,loading:S,hint:L,error:M,className:R,dateFormat:I="dd/MM/yyyy",dataQa:A,hideEmptyMeta:P=!1,wide:H=!1,endDefaultsToToday:O=!1,pulse:q,isClearable:K=!1,minDate:z,maxDate:B,popperClassName:F,portalId:G,cancelLabel:J="Скасувати",saveLabel:Q="Зберегти",locale:U=o,presets:V=[],presetPlaceholder:W="Обрати період",presetSelectProps:X,onCancel:Y,onConfirm:Z,mask:$,...ee})=>{let[et,ea]=e.useReducer(h,k),{isOpen:en,tempStartDate:er,tempEndDate:el,selectedPreset:ec,calendarKey:eo,inputText:ei,openToDate:es}=et,ep=e.useRef(null),em=(Array.isArray(I)?I[0]:I)??"dd/MM/yyyy",eu=$??v(em),ed={minDate:z,maxDate:B,allowStartOnly:O},eg=(e,t)=>e&&t?l(e,t)?e:c(t,1):t?c(t,1):e||new Date,ey=_(m,D,em),eh=f(m,D,V),ek=(e,t)=>{let[a,n]=E(e,t,O,new Date,B),[r,l]=N(a,n);w([r,l]),Z?.([r,l]),ea({type:"close"})},ev=()=>{Y?.(),ea({type:"cancel",startDate:m,endDate:D,inputText:ey})},e_=!!m||!!D,ef=!en&&null!==eh&&e_,eb=en?ei:ey;return e.createElement("label",{onClick:e=>e.preventDefault(),"data-qa":A,className:n("vchasno-ui-date-picker","vchasno-ui-date-range-picker",{"--loading":S,"--required":j,"--disabled":x,"--error":M,"--wide":H,"--not-empty":e_,"--filled":!!eb,"--preset-label":ef,"--is-label":!!T},R),onKeyDown:e=>{"Escape"===e.key&&en&&ev()},onKeyDownCapture:e=>{if("Enter"!==e.key)return;let t=e.target;if(!t.matches?.(".react-datepicker__input-container input"))return;e.preventDefault(),e.stopPropagation();let a=b(ei,em,ed);a&&"empty"!==a&&ek(a.start,a.end)}},e.createElement("span",{ref:ep,className:n("vchasno-ui-date-range-picker__wrapper",{"vchasno-ui-pulse-animation":q&&!x})},T&&e.createElement(d,null,T),e.createElement(t,{key:eo,openToDate:es??void 0,fixedHeight:!0,locale:U,disabled:x,placeholderText:"ДД/ММ/РРРР - ДД/ММ/РРРР",showPopperArrow:!1,className:n("vchasno-ui-date-range-picker__picker","vchasno-ui-date-picker__picker"),popperClassName:n("vchasno-ui-date-range-picker-popper",F),selectsRange:!0,swapRange:!0,startDate:en?er:m,endDate:en?el:D,onChange:e=>{let[t,a]=e;ea({type:"tempChange",start:t,end:a,inputText:_(t,a,em)})},monthsShown:2,shouldCloseOnSelect:!1,open:en,onInputClick:()=>{x||en||ea({type:"open",startDate:m,endDate:D,inputText:ey,openToDate:eg(m,D)})},onClickOutside:e=>{let t=e.target;t instanceof Node&&ep.current?.contains(t)||ev()},enableTabLoop:!1,minDate:z,maxDate:B,portalId:G,value:eb,onChangeRaw:e=>{if(!(e.target instanceof HTMLInputElement))return;e.preventDefault();let t=e.target.value;ea({type:"typeChange",inputText:t,parsed:b(t,em,ed)})},customInput:e.createElement(a,{inputMode:"numeric",mask:eu,guide:!0}),renderCustomHeader:({monthDate:t,decreaseMonth:a,increaseMonth:n,prevMonthButtonDisabled:l,nextMonthButtonDisabled:c})=>e.createElement("div",{className:"vchasno-ui-date-range-picker__header"},e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__nav-btn",onClick:a,disabled:l},e.createElement(i,null)),e.createElement("span",{className:"vchasno-ui-date-range-picker__month-title"},r(t,"LLLL, yyyy",{locale:"string"==typeof U?void 0:U})),e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__nav-btn",onClick:n,disabled:c},e.createElement(s,null))),...ee},e.createElement("div",{className:"vchasno-ui-date-range-picker__presets"},V.length>0&&e.createElement(g,{className:"vchasno-ui-date-range-picker__preset-select",isClearable:!0,options:V.map(e=>({label:e.label,value:e.label})),value:ec,placeholder:W,onChange:e=>{let t=Array.isArray(e)?null:e;if(!t){ea({type:"reset",openToDate:eg(null,null)});return}let a=V.find(e=>e.label===t.value);a&&ea({type:"presetSelect",option:t,start:a.range[0],end:a.range[1],inputText:_(a.range[0],a.range[1],em),openToDate:eg(a.range[0],a.range[1])})},hideEmptyMeta:!0,wide:!0,...X})),e.createElement("div",{className:"vchasno-ui-date-range-picker__actions"},e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__cancel-btn",onClick:ev},J),e.createElement("button",{type:"button",className:"vchasno-ui-date-range-picker__save-btn",onClick:()=>{ek(er,el)}},Q))),ef&&e.createElement("span",{className:"vchasno-ui-date-range-picker__preset-label","aria-hidden":"true"},eh),S?e.createElement(y,{className:"vchasno-ui-date-range-picker__spinner"}):e.createElement(p,{className:"vchasno-ui-date-range-picker__custom-calendar-icon"}),K&&e_&&!x&&e.createElement("button",{type:"button","aria-label":"Очистити",className:"vchasno-ui-date-range-picker__clear-btn",onClick:()=>{w([null,null]),ea({type:"reset",openToDate:eg(null,null)})}},e.createElement(C,null))),!P||M||L?e.createElement(u,{hint:L,error:M}):null)};D.displayName="DateRangePicker";export{D as default};
2
2
  //# sourceMappingURL=DateRangePicker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DateRangePicker.js","sources":["../../../../src/components/Datepicker/DateRangePicker/DateRangePicker.tsx"],"sourcesContent":["import React from 'react';\nimport type { ReactDatePickerProps } from 'react-datepicker';\nimport ReactDatePicker from 'react-datepicker';\nimport MaskedInput, { type MaskedInputProps } from 'react-text-mask';\n\nimport cn from 'classnames';\nimport { format, subMonths } from 'date-fns';\nimport { uk } from 'date-fns/locale/uk';\n\nimport ArrowLeftIcon from '../../../icons/arrowLeft';\nimport ArrowRightIcon from '../../../icons/arrowRight';\nimport CalendarIcon from '../../../icons/calendar';\nimport clearRawSvg from '../../../icons/clear';\nimport InputMeta from '../../InputMeta';\nimport LabelText from '../../LabelText';\nimport Select from '../../Select';\nimport type { SelectOption } from '../../Select';\nimport Spinner from '../../Spinner';\nimport type {\n DataQa,\n ErrorFeedback,\n HideEmptyMeta,\n LoadingFeedback,\n WithHint,\n WithPulseAnimation,\n} from '../../types';\nimport { initialState, pickerReducer } from './DateRangePicker.reducer';\nimport {\n applyEndFallback,\n buildRangeMask,\n formatRange,\n matchPresetLabel,\n parseRange,\n} from './utils';\n\nimport '../DatePicker.global.css';\nimport './DateRangePicker.global.css';\n\nconst CloseSvg = () => (\n <span className=\"vchasno-ui-date-range-picker__custom-close-icon\">{clearRawSvg}</span>\n);\n\ntype ControlledReactDatePickerProps =\n | 'selectsRange'\n | 'selectsMultiple'\n | 'startDate'\n | 'endDate'\n | 'onChange'\n | 'value'\n | 'open'\n | 'onInputClick'\n | 'onClickOutside'\n | 'monthsShown'\n | 'shouldCloseOnSelect'\n | 'renderCustomHeader'\n | 'children'\n | 'onChangeRaw'\n | 'customInput';\n\nexport interface DateRangePickerProps\n extends Omit<ReactDatePickerProps<true>, ControlledReactDatePickerProps>,\n Partial<\n LoadingFeedback & WithHint & ErrorFeedback & DataQa & HideEmptyMeta & WithPulseAnimation\n > {\n // Required controlled props (range-mode contract)\n startDate: Date | null;\n endDate: Date | null;\n onChange: (dates: [Date | null, Date | null]) => void;\n\n // UI-kit additions\n label?: string;\n wide?: boolean;\n cancelLabel?: string;\n saveLabel?: string;\n /**\n * перелік іменованих діапазонів для швидкого вибору.\n * У продуктових проєктах підписи слід обгортати через ttag (наприклад t`Сьогодні`),\n * щоб вони потрапили до перекладу — ui-kit отримує вже готові рядки.\n */\n presets?: { label: string; range: [Date, Date] }[];\n presetPlaceholder?: string;\n presetSelectProps?: Omit<React.ComponentProps<typeof Select>, 'options' | 'onChange' | 'value'>;\n\n /**\n * якщо обрано або введено лише дату початку, при збереженні автоматично підставляє\n * поточний момент (точний `new Date()` із часом, без нормалізації до кінця дня) як\n * дату завершення. Для цілодобових діапазонів нормалізуйте кінець у власному onChange.\n */\n endDefaultsToToday?: boolean;\n\n /** викликається при скасуванні вибору */\n onCancel?: () => void;\n /** викликається при підтвердженні вибору */\n onConfirm?: (dates: [Date | null, Date | null]) => void;\n\n /** маска для ручного вводу діапазону (типово виводиться з dateFormat) */\n mask?: MaskedInputProps['mask'];\n\n // Explicit re-declarations for Storybook Controls visibility\n // (types inherited from ReactDatePickerProps<true> via indexed access — zero drift)\n disabled?: ReactDatePickerProps<true>['disabled'];\n required?: ReactDatePickerProps<true>['required'];\n isClearable?: ReactDatePickerProps<true>['isClearable'];\n minDate?: ReactDatePickerProps<true>['minDate'];\n maxDate?: ReactDatePickerProps<true>['maxDate'];\n dateFormat?: ReactDatePickerProps<true>['dateFormat'];\n className?: ReactDatePickerProps<true>['className'];\n popperClassName?: ReactDatePickerProps<true>['popperClassName'];\n portalId?: ReactDatePickerProps<true>['portalId'];\n locale?: ReactDatePickerProps<true>['locale'];\n}\n\nconst DateRangePicker: React.FC<DateRangePickerProps> = ({\n startDate,\n endDate,\n onChange,\n label,\n disabled,\n required,\n loading,\n hint,\n error,\n className,\n dateFormat = 'dd/MM/yyyy',\n dataQa,\n hideEmptyMeta = false,\n wide = false,\n endDefaultsToToday = false,\n pulse,\n isClearable = false,\n minDate,\n maxDate,\n popperClassName,\n portalId,\n cancelLabel = 'Скасувати',\n saveLabel = 'Зберегти',\n locale = uk,\n presets = [],\n presetPlaceholder = 'Обрати період',\n presetSelectProps,\n onCancel,\n onConfirm,\n mask,\n ...props\n}) => {\n const [state, dispatch] = React.useReducer(pickerReducer, initialState);\n const { isOpen, tempStartDate, tempEndDate, selectedPreset, calendarKey, inputText } = state;\n\n const wrapperRef = React.useRef<HTMLSpanElement>(null);\n\n const displayFormat = (Array.isArray(dateFormat) ? dateFormat[0] : dateFormat) ?? 'dd/MM/yyyy';\n const resolvedMask = mask ?? buildRangeMask(displayFormat);\n const parseBounds = { minDate, maxDate, allowStartOnly: endDefaultsToToday };\n\n const resolveOpenToDate = (start: Date | null, end: Date | null): Date => {\n if (end) return subMonths(end, 1);\n if (start) return start;\n return new Date();\n };\n\n const displayValue = formatRange(startDate, endDate, displayFormat);\n const presetLabel = matchPresetLabel(startDate, endDate, presets);\n\n // Єдине місце коміту діапазону: applyEndFallback → onChange → onConfirm → close.\n const commitRange = (start: Date | null, end: Date | null) => {\n const [finalStart, finalEnd] = applyEndFallback(\n start,\n end,\n endDefaultsToToday,\n new Date(),\n maxDate,\n );\n onChange([finalStart, finalEnd]);\n onConfirm?.([finalStart, finalEnd]);\n dispatch({ type: 'close' });\n };\n\n /*\n * Карта workaround-ів: інтеграція з react-datepicker 6.9.0 у controlled-open режимі\n * (кнопки «Зберегти/Скасувати», пресети та masked-ввід змушують тримати `open` зовні,\n * тож бібліотека фаєрить власні події навіть для наших елементів). Шість обхідних місць,\n * кожне з власним «чому»-коментарем біля коду:\n * 1. handleOpen — guard від повторного засіювання temp-стану → проп `onInputClick`;\n * 2. handleClickOutside — containment у власному wrapper → проп `onClickOutside`;\n * 3. handleRawChange — відсіч подій від кліків по днях → проп `onChangeRaw`;\n * 4. handleInputKeyDownCapture — перехоплення Enter → `onKeyDownCapture` на <label>;\n * 5. calendarKey — remount для скиду стану календаря → проп `key` (інкремент у reducer);\n * 6. resolveOpenToDate (вище) — позиціонування місяців при відкритті → проп `openToDate`.\n */\n const handleOpen = () => {\n // Guard against re-seeding temp state on every input click: react-datepicker's\n // onInputClick fires on each click, and `open` reseeds temp from the committed\n // props — so clicking the input again while open would wipe an unsaved selection.\n // First click opens (seeds from props); while open the temp state stays the source\n // of truth so the user can keep editing.\n if (disabled || isOpen) return;\n dispatch({ type: 'open', startDate, endDate, inputText: displayValue });\n };\n\n const handleTempChange = (dates: [Date | null, Date | null]) => {\n const [start, end] = dates;\n dispatch({\n type: 'tempChange',\n start,\n end,\n inputText: formatRange(start, end, displayFormat),\n });\n };\n\n const handleSave = () => {\n commitRange(tempStartDate, tempEndDate);\n };\n\n const handleCancel = () => {\n onCancel?.();\n dispatch({ type: 'cancel', startDate, endDate, inputText: displayValue });\n };\n\n const handleClickOutside = (event: React.MouseEvent<HTMLDivElement>) => {\n // react-datepicker fires onClickOutside for clicks on our own input/icons too: it tracks\n // `open` internally while we drive it via the `open` prop, so its outside-click-ignore class\n // never lands on the input. Skip cancel for clicks inside our wrapper — otherwise clicking the\n // input to start editing wipes an unsaved range (cancel resets temp from empty committed props,\n // closes, then onInputClick reopens empty).\n const target = event.target;\n if (target instanceof Node && wrapperRef.current?.contains(target)) return;\n handleCancel();\n };\n\n const handleClear = () => {\n onChange([null, null]);\n dispatch({ type: 'reset' });\n };\n\n const handlePresetChange = (newValue: SelectOption | readonly SelectOption[] | null) => {\n const option = Array.isArray(newValue) ? null : (newValue as SelectOption | null);\n if (!option) {\n dispatch({ type: 'reset' });\n return;\n }\n const preset = presets.find((p) => p.label === option.value);\n if (preset) {\n dispatch({\n type: 'presetSelect',\n option,\n start: preset.range[0],\n end: preset.range[1],\n inputText: formatRange(preset.range[0], preset.range[1], displayFormat),\n });\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) {\n handleCancel();\n }\n };\n\n const handleRawChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n // react-datepicker fires onChangeRaw from calendar selection too (handleSelect),\n // where the event is a day-cell click with no input value. Only handle real input\n // typing here; otherwise return so the calendar's own onChange (selection) proceeds.\n if (!(e.target instanceof HTMLInputElement)) return;\n e.preventDefault(); // disable react-datepicker's built-in single-date parsing — we own the input\n const raw = e.target.value;\n dispatch({\n type: 'typeChange',\n inputText: raw,\n parsed: parseRange(raw, displayFormat, parseBounds),\n });\n };\n\n /**\n * Перехоплює Enter у capture-фазі, щоб власний onKeyDown react-datepicker\n * (який скидає діапазон до [start, null] і стирає другу дату) ніколи не спрацював.\n *\n * Повністю валідний введений діапазон комітиться; з endDefaultsToToday валідний\n * лише початок комітить [start, зараз]; усе інше невалідне/неповне — no-op.\n *\n * Чому capture-фаза: react-datepicker клонує customInput і навішує власний\n * onKeyDown, тож єдиний спосіб випередити його — перехопити подію на батьківському\n * елементі через onKeyDownCapture. Актуально для react-datepicker 6.9.0.\n */\n const handleInputKeyDownCapture = (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key !== 'Enter') return;\n const target = e.target as HTMLElement;\n if (!target.matches?.('.react-datepicker__input-container input')) return;\n e.preventDefault();\n e.stopPropagation();\n const parsed = parseRange(inputText, displayFormat, parseBounds);\n if (parsed && parsed !== 'empty') {\n commitRange(parsed.start, parsed.end);\n }\n };\n\n const valueExists = !!startDate || !!endDate;\n const showPresetLabel = !isOpen && presetLabel !== null && valueExists;\n // Текст, який реально бачить користувач в інпуті: під час редагування — тимчасовий ввід,\n // інакше — збережене значення. Використовується і для value, і щоб тримати лейбл піднятим.\n const inputDisplayValue = isOpen ? inputText : displayValue;\n\n return (\n <label\n onClick={(e) => e.preventDefault()}\n data-qa={dataQa}\n className={cn(\n 'vchasno-ui-date-picker',\n 'vchasno-ui-date-range-picker',\n {\n '--loading': loading,\n '--required': required,\n '--disabled': disabled,\n '--error': error,\n '--wide': wide,\n '--not-empty': valueExists,\n '--filled': !!inputDisplayValue,\n '--preset-label': showPresetLabel,\n '--is-label': !!label,\n },\n className,\n )}\n onKeyDown={handleKeyDown}\n onKeyDownCapture={handleInputKeyDownCapture}\n >\n <span\n ref={wrapperRef}\n className={cn('vchasno-ui-date-range-picker__wrapper', {\n 'vchasno-ui-pulse-animation': pulse && !disabled,\n })}\n >\n {label && <LabelText>{label}</LabelText>}\n <ReactDatePicker\n key={calendarKey}\n openToDate={resolveOpenToDate(\n isOpen ? tempStartDate : startDate,\n isOpen ? tempEndDate : endDate,\n )}\n fixedHeight\n locale={locale}\n disabled={disabled}\n placeholderText=\"ДД/ММ/РРРР - ДД/ММ/РРРР\"\n showPopperArrow={false}\n className={cn(\n 'vchasno-ui-date-range-picker__picker',\n 'vchasno-ui-date-picker__picker',\n )}\n popperClassName={cn('vchasno-ui-date-range-picker-popper', popperClassName)}\n selectsRange\n startDate={isOpen ? tempStartDate : startDate}\n endDate={isOpen ? tempEndDate : endDate}\n onChange={handleTempChange}\n monthsShown={2}\n shouldCloseOnSelect={false}\n open={isOpen}\n onInputClick={handleOpen}\n onClickOutside={handleClickOutside}\n enableTabLoop={false}\n minDate={minDate}\n maxDate={maxDate}\n portalId={portalId}\n value={inputDisplayValue}\n onChangeRaw={handleRawChange}\n customInput={<MaskedInput inputMode=\"numeric\" mask={resolvedMask} guide />}\n renderCustomHeader={({\n monthDate,\n decreaseMonth,\n increaseMonth,\n prevMonthButtonDisabled,\n nextMonthButtonDisabled,\n }) => (\n <div className=\"vchasno-ui-date-range-picker__header\">\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__nav-btn\"\n onClick={decreaseMonth}\n disabled={prevMonthButtonDisabled}\n >\n <ArrowLeftIcon />\n </button>\n <span className=\"vchasno-ui-date-range-picker__month-title\">\n {format(monthDate, 'LLLL, yyyy', {\n locale: typeof locale === 'string' ? undefined : locale,\n })}\n </span>\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__nav-btn\"\n onClick={increaseMonth}\n disabled={nextMonthButtonDisabled}\n >\n <ArrowRightIcon />\n </button>\n </div>\n )}\n {...props}\n >\n <div className=\"vchasno-ui-date-range-picker__presets\">\n {presets.length > 0 && (\n <Select\n className=\"vchasno-ui-date-range-picker__preset-select\"\n isClearable\n options={presets.map((p) => ({\n label: p.label,\n value: p.label,\n }))}\n value={selectedPreset}\n placeholder={presetPlaceholder}\n onChange={handlePresetChange}\n hideEmptyMeta\n wide\n {...presetSelectProps}\n />\n )}\n </div>\n\n <div className=\"vchasno-ui-date-range-picker__actions\">\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__cancel-btn\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__save-btn\"\n onClick={handleSave}\n >\n {saveLabel}\n </button>\n </div>\n </ReactDatePicker>\n {showPresetLabel && (\n <span className=\"vchasno-ui-date-range-picker__preset-label\" aria-hidden=\"true\">\n {presetLabel}\n </span>\n )}\n {loading ? (\n <Spinner className=\"vchasno-ui-date-range-picker__spinner\" />\n ) : (\n <CalendarIcon className=\"vchasno-ui-date-range-picker__custom-calendar-icon\" />\n )}\n {isClearable && valueExists && !disabled && (\n <button\n type=\"button\"\n aria-label=\"Очистити\"\n className=\"vchasno-ui-date-range-picker__clear-btn\"\n onClick={handleClear}\n >\n <CloseSvg />\n </button>\n )}\n </span>\n {hideEmptyMeta && !error && !hint ? null : <InputMeta hint={hint} error={error} />}\n </label>\n );\n};\n\nDateRangePicker.displayName = 'DateRangePicker';\n\nexport default DateRangePicker;\n"],"names":["CloseSvg","React","span","className","clearRawSvg","DateRangePicker","startDate","endDate","onChange","label","disabled","required","loading","hint","error","dateFormat","dataQa","hideEmptyMeta","wide","endDefaultsToToday","pulse","isClearable","minDate","maxDate","popperClassName","portalId","cancelLabel","saveLabel","locale","uk","presets","presetPlaceholder","presetSelectProps","onCancel","onConfirm","mask","props","start","end","state","dispatch","useReducer","pickerReducer","initialState","isOpen","tempStartDate","tempEndDate","selectedPreset","calendarKey","inputText","wrapperRef","useRef","displayFormat","Array","isArray","resolvedMask","buildRangeMask","parseBounds","allowStartOnly","displayValue","formatRange","presetLabel","matchPresetLabel","commitRange","finalStart","finalEnd","applyEndFallback","Date","type","handleCancel","valueExists","showPresetLabel","inputDisplayValue","onClick","e","preventDefault","data-qa","cn","onKeyDown","key","onKeyDownCapture","target","matches","stopPropagation","parsed","parseRange","ref","createElement","LabelText","ReactDatePicker","openToDate","subMonths","fixedHeight","placeholderText","showPopperArrow","selectsRange","dates","monthsShown","shouldCloseOnSelect","open","onInputClick","onClickOutside","event","Node","current","contains","enableTabLoop","value","onChangeRaw","HTMLInputElement","raw","customInput","MaskedInput","inputMode","guide","renderCustomHeader","monthDate","decreaseMonth","increaseMonth","prevMonthButtonDisabled","nextMonthButtonDisabled","div","button","ArrowLeftIcon","format","undefined","ArrowRightIcon","length","Select","options","map","p","placeholder","newValue","option","preset","find","range","aria-hidden","Spinner","CalendarIcon","aria-label","InputMeta","displayName"],"mappings":"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"}
1
+ {"version":3,"file":"DateRangePicker.js","sources":["../../../../src/components/Datepicker/DateRangePicker/DateRangePicker.tsx"],"sourcesContent":["import React from 'react';\nimport type { ReactDatePickerProps } from 'react-datepicker';\nimport ReactDatePicker from 'react-datepicker';\nimport MaskedInput, { type MaskedInputProps } from 'react-text-mask';\n\nimport cn from 'classnames';\nimport { format, isSameMonth, subMonths } from 'date-fns';\nimport { uk } from 'date-fns/locale/uk';\n\nimport ArrowLeftIcon from '../../../icons/arrowLeft';\nimport ArrowRightIcon from '../../../icons/arrowRight';\nimport CalendarIcon from '../../../icons/calendar';\nimport clearRawSvg from '../../../icons/clear';\nimport InputMeta from '../../InputMeta';\nimport LabelText from '../../LabelText';\nimport Select from '../../Select';\nimport type { SelectOption } from '../../Select';\nimport Spinner from '../../Spinner';\nimport type {\n DataQa,\n ErrorFeedback,\n HideEmptyMeta,\n LoadingFeedback,\n WithHint,\n WithPulseAnimation,\n} from '../../types';\nimport { initialState, pickerReducer } from './DateRangePicker.reducer';\nimport {\n applyEndFallback,\n buildRangeMask,\n formatRange,\n matchPresetLabel,\n normalizeOrder,\n parseRange,\n} from './utils';\n\nimport '../DatePicker.global.css';\nimport './DateRangePicker.global.css';\n\n/*\n * `swapRange` існує у рантаймі react-datepicker 6.9.0, але відсутнє в\n * @types/react-datepicker@6.2.0. Augment-ом додаємо проп до типу замість\n * @ts-expect-error (який став би «unused directive» / TS2578 при апдейті @types).\n * Генерики мають точно збігатися з оголошенням у @types (index.d.ts).\n */\n/* Генерики мають дослівно збігатися з @types для коректного declaration merging,\n тож обидва параметри лишаються незмінними, навіть якщо тут не вживаються напряму. */\n/* eslint-disable @typescript-eslint/no-unused-vars */\ndeclare module 'react-datepicker' {\n interface ReactDatePickerProps<\n WithRange extends boolean | undefined = undefined,\n WithMultiple extends boolean | undefined = undefined,\n > {\n swapRange?: boolean | undefined;\n }\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\nconst CloseSvg = () => (\n <span className=\"vchasno-ui-date-range-picker__custom-close-icon\">{clearRawSvg}</span>\n);\n\ntype ControlledReactDatePickerProps =\n | 'selectsRange'\n | 'selectsMultiple'\n | 'swapRange'\n | 'startDate'\n | 'endDate'\n | 'onChange'\n | 'value'\n | 'open'\n | 'onInputClick'\n | 'onClickOutside'\n | 'monthsShown'\n | 'shouldCloseOnSelect'\n | 'renderCustomHeader'\n | 'children'\n | 'onChangeRaw'\n | 'customInput';\n\nexport interface DateRangePickerProps\n extends Omit<ReactDatePickerProps<true>, ControlledReactDatePickerProps>,\n Partial<\n LoadingFeedback & WithHint & ErrorFeedback & DataQa & HideEmptyMeta & WithPulseAnimation\n > {\n // Required controlled props (range-mode contract)\n startDate: Date | null;\n endDate: Date | null;\n onChange: (dates: [Date | null, Date | null]) => void;\n\n // UI-kit additions\n label?: string;\n wide?: boolean;\n cancelLabel?: string;\n saveLabel?: string;\n /**\n * перелік іменованих діапазонів для швидкого вибору.\n * У продуктових проєктах підписи слід обгортати через ttag (наприклад t`Сьогодні`),\n * щоб вони потрапили до перекладу — ui-kit отримує вже готові рядки.\n */\n presets?: { label: string; range: [Date, Date] }[];\n presetPlaceholder?: string;\n presetSelectProps?: Omit<React.ComponentProps<typeof Select>, 'options' | 'onChange' | 'value'>;\n\n /**\n * якщо обрано або введено лише дату початку, при збереженні автоматично підставляє\n * поточний момент (точний `new Date()` із часом, без нормалізації до кінця дня) як\n * дату завершення. Для цілодобових діапазонів нормалізуйте кінець у власному onChange.\n */\n endDefaultsToToday?: boolean;\n\n /** викликається при скасуванні вибору */\n onCancel?: () => void;\n /** викликається при підтвердженні вибору */\n onConfirm?: (dates: [Date | null, Date | null]) => void;\n\n /** маска для ручного вводу діапазону (типово виводиться з dateFormat) */\n mask?: MaskedInputProps['mask'];\n\n // Explicit re-declarations for Storybook Controls visibility\n // (types inherited from ReactDatePickerProps<true> via indexed access — zero drift)\n disabled?: ReactDatePickerProps<true>['disabled'];\n required?: ReactDatePickerProps<true>['required'];\n isClearable?: ReactDatePickerProps<true>['isClearable'];\n minDate?: ReactDatePickerProps<true>['minDate'];\n maxDate?: ReactDatePickerProps<true>['maxDate'];\n dateFormat?: ReactDatePickerProps<true>['dateFormat'];\n className?: ReactDatePickerProps<true>['className'];\n popperClassName?: ReactDatePickerProps<true>['popperClassName'];\n portalId?: ReactDatePickerProps<true>['portalId'];\n locale?: ReactDatePickerProps<true>['locale'];\n}\n\nconst DateRangePicker: React.FC<DateRangePickerProps> = ({\n startDate,\n endDate,\n onChange,\n label,\n disabled,\n required,\n loading,\n hint,\n error,\n className,\n dateFormat = 'dd/MM/yyyy',\n dataQa,\n hideEmptyMeta = false,\n wide = false,\n endDefaultsToToday = false,\n pulse,\n isClearable = false,\n minDate,\n maxDate,\n popperClassName,\n portalId,\n cancelLabel = 'Скасувати',\n saveLabel = 'Зберегти',\n locale = uk,\n presets = [],\n presetPlaceholder = 'Обрати період',\n presetSelectProps,\n onCancel,\n onConfirm,\n mask,\n ...props\n}) => {\n const [state, dispatch] = React.useReducer(pickerReducer, initialState);\n const { isOpen, tempStartDate, tempEndDate, selectedPreset, calendarKey, inputText, openToDate } =\n state;\n\n const wrapperRef = React.useRef<HTMLSpanElement>(null);\n\n const displayFormat = (Array.isArray(dateFormat) ? dateFormat[0] : dateFormat) ?? 'dd/MM/yyyy';\n const resolvedMask = mask ?? buildRangeMask(displayFormat);\n const parseBounds = { minDate, maxDate, allowStartOnly: endDefaultsToToday };\n\n // Обчислює якір позиціонування (місяць лівої панелі monthsShown={2}).\n // Викликається лише в момент dispatch (open/presetSelect/reset), а не на кожному\n // рендері — результат зберігається в reducer-стані, тож вид не стрибає під час вибору.\n const computeAnchor = (start: Date | null, end: Date | null): Date => {\n if (start && end) {\n // Один місяць (включно зі start === end): якорим на start, щоб уникнути\n // стрибка календаря назад (subMonths показав би попередній місяць зліва).\n if (isSameMonth(start, end)) return start;\n // Багатомісячний діапазон: subMonths(end, 1) ставить місяць кінця в праву панель.\n return subMonths(end, 1);\n }\n if (end) return subMonths(end, 1);\n if (start) return start;\n return new Date();\n };\n\n const displayValue = formatRange(startDate, endDate, displayFormat);\n const presetLabel = matchPresetLabel(startDate, endDate, presets);\n\n // Єдине місце коміту діапазону: applyEndFallback → normalizeOrder → onChange → onConfirm → close.\n const commitRange = (start: Date | null, end: Date | null) => {\n const [fallbackStart, fallbackEnd] = applyEndFallback(\n start,\n end,\n endDefaultsToToday,\n new Date(),\n maxDate,\n );\n // Гард порядку на фінальному tuple (після fallback): жоден збережений діапазон\n // не може бути перевернутим. Захищає й невалідовані presets від споживача.\n const [finalStart, finalEnd] = normalizeOrder(fallbackStart, fallbackEnd);\n onChange([finalStart, finalEnd]);\n onConfirm?.([finalStart, finalEnd]);\n dispatch({ type: 'close' });\n };\n\n /*\n * Карта workaround-ів: інтеграція з react-datepicker 6.9.0 у controlled-open режимі\n * (кнопки «Зберегти/Скасувати», пресети та masked-ввід змушують тримати `open` зовні,\n * тож бібліотека фаєрить власні події навіть для наших елементів). Сім обхідних місць,\n * кожне з власним «чому»-коментарем біля коду:\n * 1. handleOpen — guard від повторного засіювання temp-стану → проп `onInputClick`;\n * 2. handleClickOutside — containment у власному wrapper → проп `onClickOutside`;\n * 3. handleRawChange — відсіч подій від кліків по днях → проп `onChangeRaw`;\n * 4. handleInputKeyDownCapture — перехоплення Enter → `onKeyDownCapture` на <label>;\n * 5. calendarKey — remount для скиду стану календаря → проп `key` (інкремент у reducer);\n * 6. computeAnchor → state.openToDate — позиціонування місяців. openToDate зберігається\n * в reducer-стані й оновлюється ЛИШЕ на open/presetSelect/reset (не на кожному рендері),\n * інакше Calendar.componentDidUpdate перестрибує вид через openToDate-гілку при кліку\n * по тій самій/кінцевій даті (баг стрибка на попередній місяць);\n * 7. swapRange — зворотній клік міняє дати місцями у впорядкований діапазон замість\n * мовчазного скидання вибору; типізований через module augmentation (відсутній у @types).\n */\n const handleOpen = () => {\n // Guard against re-seeding temp state on every input click: react-datepicker's\n // onInputClick fires on each click, and `open` reseeds temp from the committed\n // props — so clicking the input again while open would wipe an unsaved selection.\n // First click opens (seeds from props); while open the temp state stays the source\n // of truth so the user can keep editing.\n if (disabled || isOpen) return;\n dispatch({\n type: 'open',\n startDate,\n endDate,\n inputText: displayValue,\n openToDate: computeAnchor(startDate, endDate),\n });\n };\n\n const handleTempChange = (dates: [Date | null, Date | null]) => {\n const [start, end] = dates;\n dispatch({\n type: 'tempChange',\n start,\n end,\n inputText: formatRange(start, end, displayFormat),\n });\n };\n\n const handleSave = () => {\n commitRange(tempStartDate, tempEndDate);\n };\n\n const handleCancel = () => {\n onCancel?.();\n dispatch({ type: 'cancel', startDate, endDate, inputText: displayValue });\n };\n\n const handleClickOutside = (event: React.MouseEvent<HTMLDivElement>) => {\n // react-datepicker fires onClickOutside for clicks on our own input/icons too: it tracks\n // `open` internally while we drive it via the `open` prop, so its outside-click-ignore class\n // never lands on the input. Skip cancel for clicks inside our wrapper — otherwise clicking the\n // input to start editing wipes an unsaved range (cancel resets temp from empty committed props,\n // closes, then onInputClick reopens empty).\n const target = event.target;\n if (target instanceof Node && wrapperRef.current?.contains(target)) return;\n handleCancel();\n };\n\n const handleClear = () => {\n onChange([null, null]);\n dispatch({ type: 'reset', openToDate: computeAnchor(null, null) });\n };\n\n const handlePresetChange = (newValue: SelectOption | readonly SelectOption[] | null) => {\n const option = Array.isArray(newValue) ? null : (newValue as SelectOption | null);\n if (!option) {\n dispatch({ type: 'reset', openToDate: computeAnchor(null, null) });\n return;\n }\n const preset = presets.find((p) => p.label === option.value);\n if (preset) {\n dispatch({\n type: 'presetSelect',\n option,\n start: preset.range[0],\n end: preset.range[1],\n inputText: formatRange(preset.range[0], preset.range[1], displayFormat),\n openToDate: computeAnchor(preset.range[0], preset.range[1]),\n });\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) {\n handleCancel();\n }\n };\n\n const handleRawChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n // react-datepicker fires onChangeRaw from calendar selection too (handleSelect),\n // where the event is a day-cell click with no input value. Only handle real input\n // typing here; otherwise return so the calendar's own onChange (selection) proceeds.\n if (!(e.target instanceof HTMLInputElement)) return;\n e.preventDefault(); // disable react-datepicker's built-in single-date parsing — we own the input\n const raw = e.target.value;\n dispatch({\n type: 'typeChange',\n inputText: raw,\n parsed: parseRange(raw, displayFormat, parseBounds),\n });\n };\n\n /**\n * Перехоплює Enter у capture-фазі, щоб власний onKeyDown react-datepicker\n * (який скидає діапазон до [start, null] і стирає другу дату) ніколи не спрацював.\n *\n * Повністю валідний введений діапазон комітиться; з endDefaultsToToday валідний\n * лише початок комітить [start, зараз]; усе інше невалідне/неповне — no-op.\n *\n * Чому capture-фаза: react-datepicker клонує customInput і навішує власний\n * onKeyDown, тож єдиний спосіб випередити його — перехопити подію на батьківському\n * елементі через onKeyDownCapture. Актуально для react-datepicker 6.9.0.\n */\n const handleInputKeyDownCapture = (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key !== 'Enter') return;\n const target = e.target as HTMLElement;\n if (!target.matches?.('.react-datepicker__input-container input')) return;\n e.preventDefault();\n e.stopPropagation();\n const parsed = parseRange(inputText, displayFormat, parseBounds);\n if (parsed && parsed !== 'empty') {\n commitRange(parsed.start, parsed.end);\n }\n };\n\n const valueExists = !!startDate || !!endDate;\n const showPresetLabel = !isOpen && presetLabel !== null && valueExists;\n // Текст, який реально бачить користувач в інпуті: під час редагування — тимчасовий ввід,\n // інакше — збережене значення. Використовується і для value, і щоб тримати лейбл піднятим.\n const inputDisplayValue = isOpen ? inputText : displayValue;\n\n return (\n <label\n onClick={(e) => e.preventDefault()}\n data-qa={dataQa}\n className={cn(\n 'vchasno-ui-date-picker',\n 'vchasno-ui-date-range-picker',\n {\n '--loading': loading,\n '--required': required,\n '--disabled': disabled,\n '--error': error,\n '--wide': wide,\n '--not-empty': valueExists,\n '--filled': !!inputDisplayValue,\n '--preset-label': showPresetLabel,\n '--is-label': !!label,\n },\n className,\n )}\n onKeyDown={handleKeyDown}\n onKeyDownCapture={handleInputKeyDownCapture}\n >\n <span\n ref={wrapperRef}\n className={cn('vchasno-ui-date-range-picker__wrapper', {\n 'vchasno-ui-pulse-animation': pulse && !disabled,\n })}\n >\n {label && <LabelText>{label}</LabelText>}\n <ReactDatePicker\n key={calendarKey}\n openToDate={openToDate ?? undefined}\n fixedHeight\n locale={locale}\n disabled={disabled}\n placeholderText=\"ДД/ММ/РРРР - ДД/ММ/РРРР\"\n showPopperArrow={false}\n className={cn(\n 'vchasno-ui-date-range-picker__picker',\n 'vchasno-ui-date-picker__picker',\n )}\n popperClassName={cn('vchasno-ui-date-range-picker-popper', popperClassName)}\n selectsRange\n swapRange\n startDate={isOpen ? tempStartDate : startDate}\n endDate={isOpen ? tempEndDate : endDate}\n onChange={handleTempChange}\n monthsShown={2}\n shouldCloseOnSelect={false}\n open={isOpen}\n onInputClick={handleOpen}\n onClickOutside={handleClickOutside}\n enableTabLoop={false}\n minDate={minDate}\n maxDate={maxDate}\n portalId={portalId}\n value={inputDisplayValue}\n onChangeRaw={handleRawChange}\n customInput={<MaskedInput inputMode=\"numeric\" mask={resolvedMask} guide />}\n renderCustomHeader={({\n monthDate,\n decreaseMonth,\n increaseMonth,\n prevMonthButtonDisabled,\n nextMonthButtonDisabled,\n }) => (\n <div className=\"vchasno-ui-date-range-picker__header\">\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__nav-btn\"\n onClick={decreaseMonth}\n disabled={prevMonthButtonDisabled}\n >\n <ArrowLeftIcon />\n </button>\n <span className=\"vchasno-ui-date-range-picker__month-title\">\n {format(monthDate, 'LLLL, yyyy', {\n locale: typeof locale === 'string' ? undefined : locale,\n })}\n </span>\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__nav-btn\"\n onClick={increaseMonth}\n disabled={nextMonthButtonDisabled}\n >\n <ArrowRightIcon />\n </button>\n </div>\n )}\n {...props}\n >\n <div className=\"vchasno-ui-date-range-picker__presets\">\n {presets.length > 0 && (\n <Select\n className=\"vchasno-ui-date-range-picker__preset-select\"\n isClearable\n options={presets.map((p) => ({\n label: p.label,\n value: p.label,\n }))}\n value={selectedPreset}\n placeholder={presetPlaceholder}\n onChange={handlePresetChange}\n hideEmptyMeta\n wide\n {...presetSelectProps}\n />\n )}\n </div>\n\n <div className=\"vchasno-ui-date-range-picker__actions\">\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__cancel-btn\"\n onClick={handleCancel}\n >\n {cancelLabel}\n </button>\n <button\n type=\"button\"\n className=\"vchasno-ui-date-range-picker__save-btn\"\n onClick={handleSave}\n >\n {saveLabel}\n </button>\n </div>\n </ReactDatePicker>\n {showPresetLabel && (\n <span className=\"vchasno-ui-date-range-picker__preset-label\" aria-hidden=\"true\">\n {presetLabel}\n </span>\n )}\n {loading ? (\n <Spinner className=\"vchasno-ui-date-range-picker__spinner\" />\n ) : (\n <CalendarIcon className=\"vchasno-ui-date-range-picker__custom-calendar-icon\" />\n )}\n {isClearable && valueExists && !disabled && (\n <button\n type=\"button\"\n aria-label=\"Очистити\"\n className=\"vchasno-ui-date-range-picker__clear-btn\"\n onClick={handleClear}\n >\n <CloseSvg />\n </button>\n )}\n </span>\n {hideEmptyMeta && !error && !hint ? null : <InputMeta hint={hint} error={error} />}\n </label>\n );\n};\n\nDateRangePicker.displayName = 'DateRangePicker';\n\nexport default DateRangePicker;\n"],"names":["CloseSvg","React","span","className","clearRawSvg","DateRangePicker","startDate","endDate","onChange","label","disabled","required","loading","hint","error","dateFormat","dataQa","hideEmptyMeta","wide","endDefaultsToToday","pulse","isClearable","minDate","maxDate","popperClassName","portalId","cancelLabel","saveLabel","locale","uk","presets","presetPlaceholder","presetSelectProps","onCancel","onConfirm","mask","props","state","dispatch","useReducer","pickerReducer","initialState","isOpen","tempStartDate","tempEndDate","selectedPreset","calendarKey","inputText","openToDate","wrapperRef","useRef","displayFormat","Array","isArray","resolvedMask","buildRangeMask","parseBounds","allowStartOnly","computeAnchor","start","end","isSameMonth","subMonths","Date","displayValue","formatRange","presetLabel","matchPresetLabel","commitRange","fallbackStart","fallbackEnd","applyEndFallback","finalStart","finalEnd","normalizeOrder","type","handleCancel","valueExists","showPresetLabel","inputDisplayValue","onClick","e","preventDefault","data-qa","cn","onKeyDown","key","onKeyDownCapture","target","matches","stopPropagation","parsed","parseRange","ref","createElement","LabelText","ReactDatePicker","undefined","fixedHeight","placeholderText","showPopperArrow","selectsRange","swapRange","dates","monthsShown","shouldCloseOnSelect","open","onInputClick","onClickOutside","event","Node","current","contains","enableTabLoop","value","onChangeRaw","HTMLInputElement","raw","customInput","MaskedInput","inputMode","guide","renderCustomHeader","monthDate","decreaseMonth","increaseMonth","prevMonthButtonDisabled","nextMonthButtonDisabled","div","button","ArrowLeftIcon","format","ArrowRightIcon","length","Select","options","map","p","placeholder","newValue","option","preset","find","range","aria-hidden","Spinner","CalendarIcon","aria-label","InputMeta","displayName"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- let e={isOpen:!1,tempStartDate:null,tempEndDate:null,selectedPreset:null,calendarKey:0,inputText:""};function t(e,t){switch(t.type){case"open":return{...e,isOpen:!0,tempStartDate:t.startDate,tempEndDate:t.endDate,inputText:t.inputText};case"close":return{...e,isOpen:!1};case"tempChange":return{...e,tempStartDate:t.start,tempEndDate:t.end,selectedPreset:null,inputText:t.inputText};case"typeChange":{let n={...e,inputText:t.inputText,selectedPreset:null};if("empty"===t.parsed)return{...n,tempStartDate:null,tempEndDate:null};if(null!==t.parsed)return{...n,tempStartDate:t.parsed.start,tempEndDate:t.parsed.end};return n}case"cancel":return{...e,isOpen:!1,tempStartDate:t.startDate,tempEndDate:t.endDate,selectedPreset:null,inputText:t.inputText};case"reset":return{...e,tempStartDate:null,tempEndDate:null,selectedPreset:null,calendarKey:e.calendarKey+1,inputText:""};case"presetSelect":return{...e,selectedPreset:t.option,tempStartDate:t.start,tempEndDate:t.end,calendarKey:e.calendarKey+1,inputText:t.inputText}}}export{e as initialState,t as pickerReducer};
1
+ let e={isOpen:!1,tempStartDate:null,tempEndDate:null,selectedPreset:null,calendarKey:0,inputText:"",openToDate:null};function t(e,t){switch(t.type){case"open":return{...e,isOpen:!0,tempStartDate:t.startDate,tempEndDate:t.endDate,inputText:t.inputText,openToDate:t.openToDate};case"close":return{...e,isOpen:!1};case"tempChange":return{...e,tempStartDate:t.start,tempEndDate:t.end,selectedPreset:null,inputText:t.inputText};case"typeChange":{let n={...e,inputText:t.inputText,selectedPreset:null};if("empty"===t.parsed)return{...n,tempStartDate:null,tempEndDate:null};if(null!==t.parsed)return{...n,tempStartDate:t.parsed.start,tempEndDate:t.parsed.end};return n}case"cancel":return{...e,isOpen:!1,tempStartDate:t.startDate,tempEndDate:t.endDate,selectedPreset:null,inputText:t.inputText};case"reset":return{...e,tempStartDate:null,tempEndDate:null,selectedPreset:null,calendarKey:e.calendarKey+1,inputText:"",openToDate:t.openToDate};case"presetSelect":return{...e,selectedPreset:t.option,tempStartDate:t.start,tempEndDate:t.end,calendarKey:e.calendarKey+1,inputText:t.inputText,openToDate:t.openToDate}}}export{e as initialState,t as pickerReducer};
2
2
  //# sourceMappingURL=DateRangePicker.reducer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DateRangePicker.reducer.js","sources":["../../../../src/components/Datepicker/DateRangePicker/DateRangePicker.reducer.ts"],"sourcesContent":["import type { SelectOption } from '../../Select';\nimport type { ParsedRange, ParsedStart } from './utils';\n\nexport type PickerState = {\n isOpen: boolean;\n tempStartDate: Date | null;\n tempEndDate: Date | null;\n selectedPreset: SelectOption | null;\n calendarKey: number;\n inputText: string;\n};\n\nexport type PickerAction =\n | { type: 'open'; startDate: Date | null; endDate: Date | null; inputText: string }\n | { type: 'close' }\n | { type: 'tempChange'; start: Date | null; end: Date | null; inputText: string }\n | { type: 'typeChange'; inputText: string; parsed: ParsedRange | ParsedStart | 'empty' | null }\n | { type: 'cancel'; startDate: Date | null; endDate: Date | null; inputText: string }\n | { type: 'reset' }\n | { type: 'presetSelect'; option: SelectOption; start: Date; end: Date; inputText: string };\n\nexport const initialState: PickerState = {\n isOpen: false,\n tempStartDate: null,\n tempEndDate: null,\n selectedPreset: null,\n calendarKey: 0,\n inputText: '',\n};\n\nexport function pickerReducer(state: PickerState, action: PickerAction): PickerState {\n switch (action.type) {\n case 'open':\n return {\n ...state,\n isOpen: true,\n tempStartDate: action.startDate,\n tempEndDate: action.endDate,\n inputText: action.inputText,\n };\n case 'close':\n return { ...state, isOpen: false };\n case 'tempChange':\n return {\n ...state,\n tempStartDate: action.start,\n tempEndDate: action.end,\n selectedPreset: null,\n inputText: action.inputText,\n };\n case 'typeChange': {\n const base = {\n ...state,\n inputText: action.inputText,\n selectedPreset: null,\n };\n if (action.parsed === 'empty') {\n return { ...base, tempStartDate: null, tempEndDate: null };\n }\n if (action.parsed !== null) {\n return {\n ...base,\n tempStartDate: action.parsed.start,\n tempEndDate: action.parsed.end,\n };\n }\n // parsed === null: invalid/incomplete — leave temp dates unchanged\n return base;\n }\n case 'cancel':\n return {\n ...state,\n isOpen: false,\n tempStartDate: action.startDate,\n tempEndDate: action.endDate,\n selectedPreset: null,\n inputText: action.inputText,\n };\n case 'reset':\n return {\n ...state,\n tempStartDate: null,\n tempEndDate: null,\n selectedPreset: null,\n calendarKey: state.calendarKey + 1,\n inputText: '',\n };\n case 'presetSelect':\n return {\n ...state,\n selectedPreset: action.option,\n tempStartDate: action.start,\n tempEndDate: action.end,\n calendarKey: state.calendarKey + 1,\n inputText: action.inputText,\n };\n }\n}\n"],"names":["initialState","isOpen","tempStartDate","tempEndDate","selectedPreset","calendarKey","inputText","pickerReducer","state","action","type","startDate","endDate","start","end","base","parsed","option"],"mappings":"IAqBaA,EAA4B,CACrCC,OAAQ,CAAA,EACRC,cAAe,KACfC,YAAa,KACbC,eAAgB,KAChBC,YAAa,EACbC,UAAW,EACf,EAEO,SAASC,EAAcC,CAAkB,CAAEC,CAAoB,EAClE,OAAQA,EAAOC,IAAI,EACf,IAAK,OACD,MAAO,CACH,GAAGF,CAAK,CACRP,OAAQ,CAAA,EACRC,cAAeO,EAAOE,SAAS,CAC/BR,YAAaM,EAAOG,OAAO,CAC3BN,UAAWG,EAAOH,SAAAA,AACtB,CACJ,KAAK,QACD,MAAO,CAAE,GAAGE,CAAK,CAAEP,OAAQ,CAAA,CAAM,CACrC,KAAK,aACD,MAAO,CACH,GAAGO,CAAK,CACRN,cAAeO,EAAOI,KAAK,CAC3BV,YAAaM,EAAOK,GAAG,CACvBV,eAAgB,KAChBE,UAAWG,EAAOH,SAAAA,AACtB,CACJ,KAAK,aAAc,CACf,IAAMS,EAAO,CACT,GAAGP,CAAK,CACRF,UAAWG,EAAOH,SAAS,CAC3BF,eAAgB,IACpB,EACA,GAAIK,AAAkB,UAAlBA,EAAOO,MAAM,CACb,MAAO,CAAE,GAAGD,CAAI,CAAEb,cAAe,KAAMC,YAAa,IAAK,EAE7D,GAAIM,AAAkB,OAAlBA,EAAOO,MAAM,CACb,MAAO,CACH,GAAGD,CAAI,CACPb,cAAeO,EAAOO,MAAM,CAACH,KAAK,CAClCV,YAAaM,EAAOO,MAAM,CAACF,GAAAA,AAC/B,EAGJ,OAAOC,CACX,CACA,IAAK,SACD,MAAO,CACH,GAAGP,CAAK,CACRP,OAAQ,CAAA,EACRC,cAAeO,EAAOE,SAAS,CAC/BR,YAAaM,EAAOG,OAAO,CAC3BR,eAAgB,KAChBE,UAAWG,EAAOH,SAAAA,AACtB,CACJ,KAAK,QACD,MAAO,CACH,GAAGE,CAAK,CACRN,cAAe,KACfC,YAAa,KACbC,eAAgB,KAChBC,YAAaG,EAAMH,WAAW,CAAG,EACjCC,UAAW,EACf,CACJ,KAAK,eACD,MAAO,CACH,GAAGE,CAAK,CACRJ,eAAgBK,EAAOQ,MAAM,CAC7Bf,cAAeO,EAAOI,KAAK,CAC3BV,YAAaM,EAAOK,GAAG,CACvBT,YAAaG,EAAMH,WAAW,CAAG,EACjCC,UAAWG,EAAOH,SAAAA,AACtB,CACR,CACJ"}
1
+ {"version":3,"file":"DateRangePicker.reducer.js","sources":["../../../../src/components/Datepicker/DateRangePicker/DateRangePicker.reducer.ts"],"sourcesContent":["import type { SelectOption } from '../../Select';\nimport type { ParsedRange, ParsedStart } from './utils';\n\nexport type PickerState = {\n isOpen: boolean;\n tempStartDate: Date | null;\n tempEndDate: Date | null;\n selectedPreset: SelectOption | null;\n calendarKey: number;\n inputText: string;\n /**\n * Якір позиціонування календаря (місяць у лівій панелі monthsShown={2}).\n * Оновлюється ЛИШЕ на open/presetSelect/reset — заморожений під час вибору,\n * щоб react-datepicker не перестрибував вид через openToDate-гілку\n * Calendar.componentDidUpdate (workaround #6).\n */\n openToDate: Date | null;\n};\n\nexport type PickerAction =\n | {\n type: 'open';\n startDate: Date | null;\n endDate: Date | null;\n inputText: string;\n openToDate: Date;\n }\n | { type: 'close' }\n | { type: 'tempChange'; start: Date | null; end: Date | null; inputText: string }\n | { type: 'typeChange'; inputText: string; parsed: ParsedRange | ParsedStart | 'empty' | null }\n | { type: 'cancel'; startDate: Date | null; endDate: Date | null; inputText: string }\n | { type: 'reset'; openToDate: Date }\n | {\n type: 'presetSelect';\n option: SelectOption;\n start: Date;\n end: Date;\n inputText: string;\n openToDate: Date;\n };\n\nexport const initialState: PickerState = {\n isOpen: false,\n tempStartDate: null,\n tempEndDate: null,\n selectedPreset: null,\n calendarKey: 0,\n inputText: '',\n openToDate: null,\n};\n\nexport function pickerReducer(state: PickerState, action: PickerAction): PickerState {\n switch (action.type) {\n case 'open':\n return {\n ...state,\n isOpen: true,\n tempStartDate: action.startDate,\n tempEndDate: action.endDate,\n inputText: action.inputText,\n openToDate: action.openToDate,\n };\n case 'close':\n return { ...state, isOpen: false };\n case 'tempChange':\n return {\n ...state,\n tempStartDate: action.start,\n tempEndDate: action.end,\n selectedPreset: null,\n inputText: action.inputText,\n };\n case 'typeChange': {\n const base = {\n ...state,\n inputText: action.inputText,\n selectedPreset: null,\n };\n if (action.parsed === 'empty') {\n return { ...base, tempStartDate: null, tempEndDate: null };\n }\n if (action.parsed !== null) {\n return {\n ...base,\n tempStartDate: action.parsed.start,\n tempEndDate: action.parsed.end,\n };\n }\n // parsed === null: invalid/incomplete — leave temp dates unchanged\n return base;\n }\n case 'cancel':\n return {\n ...state,\n isOpen: false,\n tempStartDate: action.startDate,\n tempEndDate: action.endDate,\n selectedPreset: null,\n inputText: action.inputText,\n };\n case 'reset':\n return {\n ...state,\n tempStartDate: null,\n tempEndDate: null,\n selectedPreset: null,\n calendarKey: state.calendarKey + 1,\n inputText: '',\n openToDate: action.openToDate,\n };\n case 'presetSelect':\n return {\n ...state,\n selectedPreset: action.option,\n tempStartDate: action.start,\n tempEndDate: action.end,\n calendarKey: state.calendarKey + 1,\n inputText: action.inputText,\n openToDate: action.openToDate,\n };\n }\n}\n"],"names":["initialState","isOpen","tempStartDate","tempEndDate","selectedPreset","calendarKey","inputText","openToDate","pickerReducer","state","action","type","startDate","endDate","start","end","base","parsed","option"],"mappings":"IAyCaA,EAA4B,CACrCC,OAAQ,CAAA,EACRC,cAAe,KACfC,YAAa,KACbC,eAAgB,KAChBC,YAAa,EACbC,UAAW,GACXC,WAAY,IAChB,EAEO,SAASC,EAAcC,CAAkB,CAAEC,CAAoB,EAClE,OAAQA,EAAOC,IAAI,EACf,IAAK,OACD,MAAO,CACH,GAAGF,CAAK,CACRR,OAAQ,CAAA,EACRC,cAAeQ,EAAOE,SAAS,CAC/BT,YAAaO,EAAOG,OAAO,CAC3BP,UAAWI,EAAOJ,SAAS,CAC3BC,WAAYG,EAAOH,UAAAA,AACvB,CACJ,KAAK,QACD,MAAO,CAAE,GAAGE,CAAK,CAAER,OAAQ,CAAA,CAAM,CACrC,KAAK,aACD,MAAO,CACH,GAAGQ,CAAK,CACRP,cAAeQ,EAAOI,KAAK,CAC3BX,YAAaO,EAAOK,GAAG,CACvBX,eAAgB,KAChBE,UAAWI,EAAOJ,SAAAA,AACtB,CACJ,KAAK,aAAc,CACf,IAAMU,EAAO,CACT,GAAGP,CAAK,CACRH,UAAWI,EAAOJ,SAAS,CAC3BF,eAAgB,IACpB,EACA,GAAIM,AAAkB,UAAlBA,EAAOO,MAAM,CACb,MAAO,CAAE,GAAGD,CAAI,CAAEd,cAAe,KAAMC,YAAa,IAAK,EAE7D,GAAIO,AAAkB,OAAlBA,EAAOO,MAAM,CACb,MAAO,CACH,GAAGD,CAAI,CACPd,cAAeQ,EAAOO,MAAM,CAACH,KAAK,CAClCX,YAAaO,EAAOO,MAAM,CAACF,GAAAA,AAC/B,EAGJ,OAAOC,CACX,CACA,IAAK,SACD,MAAO,CACH,GAAGP,CAAK,CACRR,OAAQ,CAAA,EACRC,cAAeQ,EAAOE,SAAS,CAC/BT,YAAaO,EAAOG,OAAO,CAC3BT,eAAgB,KAChBE,UAAWI,EAAOJ,SAAAA,AACtB,CACJ,KAAK,QACD,MAAO,CACH,GAAGG,CAAK,CACRP,cAAe,KACfC,YAAa,KACbC,eAAgB,KAChBC,YAAaI,EAAMJ,WAAW,CAAG,EACjCC,UAAW,GACXC,WAAYG,EAAOH,UAAAA,AACvB,CACJ,KAAK,eACD,MAAO,CACH,GAAGE,CAAK,CACRL,eAAgBM,EAAOQ,MAAM,CAC7BhB,cAAeQ,EAAOI,KAAK,CAC3BX,YAAaO,EAAOK,GAAG,CACvBV,YAAaI,EAAMJ,WAAW,CAAG,EACjCC,UAAWI,EAAOJ,SAAS,CAC3BC,WAAYG,EAAOH,UAAAA,AACvB,CACR,CACJ"}
@@ -1,2 +1,2 @@
1
- import{format as e,parse as t,isValid as l}from"date-fns";let n=(t,l,n)=>{let i=t?e(t,n):"",r=l?e(l,n):"";return i&&r?`${i} - ${r}`:i||""},i=(e,t,l)=>{let n=(e,t)=>null===e?null===t:null!==t&&e.getTime()===t.getTime(),i=l.find(l=>n(e,l.range[0])&&n(t,l.range[1]));return i?i.label:null},r=e=>[...e].map(e=>/[a-zA-Z]/.test(e)?/\d/:e),g=e=>{let t=r(e);return[...t," ","-"," ",...t]},m=(n,i)=>{let r=n.trim();if(r.length!==i.length)return null;let g=t(r,i,new Date);return l(g)&&e(g,i)===r?g:null},u=(e,t,{minDate:l,maxDate:n,allowStartOnly:i=!1}={})=>{let r=e.trim();if(""===r)return"empty";let g=r.split(" - "),u=g[0],a=void 0!==u?m(u,t):null;if(2===g.length){let e=g[1],i=void 0!==e?m(e,t):null;if(a&&i)return a.getTime()>i.getTime()||l&&a.getTime()<l.getTime()||n&&i.getTime()>n.getTime()?null:{start:a,end:i}}return i&&a?l&&a.getTime()<l.getTime()||n&&a.getTime()>n.getTime()?null:{start:a,end:null}:null},a=(e,t,l,n,i)=>{if(!l||!e||t||e.getTime()>n.getTime())return[e,t];let r=i&&i.getTime()<n.getTime()?i:n;return e.getTime()>r.getTime()?[e,t]:[e,r]};export{a as applyEndFallback,g as buildRangeMask,n as formatRange,i as matchPresetLabel,u as parseRange};
1
+ import{format as e,parse as t,isValid as l}from"date-fns";let n=(t,l,n)=>{let i=t?e(t,n):"",r=l?e(l,n):"";return i&&r?`${i} - ${r}`:i||""},i=(e,t,l)=>{let n=(e,t)=>null===e?null===t:null!==t&&e.getTime()===t.getTime(),i=l.find(l=>n(e,l.range[0])&&n(t,l.range[1]));return i?i.label:null},r=e=>[...e].map(e=>/[a-zA-Z]/.test(e)?/\d/:e),m=e=>{let t=r(e);return[...t," ","-"," ",...t]},g=(n,i)=>{let r=n.trim();if(r.length!==i.length)return null;let m=t(r,i,new Date);return l(m)&&e(m,i)===r?m:null},u=(e,t,{minDate:l,maxDate:n,allowStartOnly:i=!1}={})=>{let r=e.trim();if(""===r)return"empty";let m=r.split(" - "),u=m[0],T=void 0!==u?g(u,t):null;if(2===m.length){let e=m[1],i=void 0!==e?g(e,t):null;if(T&&i)return T.getTime()>i.getTime()||l&&T.getTime()<l.getTime()||n&&i.getTime()>n.getTime()?null:{start:T,end:i}}return i&&T?l&&T.getTime()<l.getTime()||n&&T.getTime()>n.getTime()?null:{start:T,end:null}:null},T=(e,t,l,n,i)=>{if(!l||!e||t||e.getTime()>n.getTime())return[e,t];let r=i&&i.getTime()<n.getTime()?i:n;return e.getTime()>r.getTime()?[e,t]:[e,r]},a=(e,t)=>e&&t&&e.getTime()>t.getTime()?[t,e]:[e,t];export{T as applyEndFallback,m as buildRangeMask,n as formatRange,i as matchPresetLabel,a as normalizeOrder,u as parseRange};
2
2
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/components/Datepicker/DateRangePicker/utils.ts"],"sourcesContent":["import { format, isValid, parse } from 'date-fns';\n\nconst SEPARATOR = ' - ';\n\nexport const formatRange = (\n start: Date | null,\n end: Date | null,\n displayFormat: string,\n): string => {\n const startStr = start ? format(start, displayFormat) : '';\n const endStr = end ? format(end, displayFormat) : '';\n if (startStr && endStr) return `${startStr}${SEPARATOR}${endStr}`;\n if (startStr) return startStr;\n return '';\n};\n\ntype PresetEntry = { label: string; range: [Date, Date] };\n\n/**\n * Якщо діапазон точно збігається з діапазоном іменованого пресету — повертає його підпис,\n * інакше null. Порівняння за getTime() з урахуванням null; за колізії — перший збіг.\n */\nexport const matchPresetLabel = (\n start: Date | null,\n end: Date | null,\n presets: ReadonlyArray<PresetEntry>,\n): string | null => {\n const sameInstant = (a: Date | null, b: Date | null): boolean =>\n a === null ? b === null : b !== null && a.getTime() === b.getTime();\n const match = presets.find(\n (p) => sameInstant(start, p.range[0]) && sameInstant(end, p.range[1]),\n );\n return match ? match.label : null;\n};\n\n/**\n * Builds a react-text-mask mask for a single date from a date-fns format string:\n * every pattern letter becomes a digit slot, every other character stays a literal.\n * Targets numeric date formats (dd/MM/yyyy, dd.MM.yyyy, yyyy-MM-dd, …).\n */\nconst buildDateMask = (displayFormat: string): (string | RegExp)[] =>\n [...displayFormat].map((char) => (/[a-zA-Z]/.test(char) ? /\\d/ : char));\n\n/** Builds the full range mask (`<date> - <date>`) derived from the given format. */\nexport const buildRangeMask = (displayFormat: string): (string | RegExp)[] => {\n const dateMask = buildDateMask(displayFormat);\n return [...dateMask, ' ', '-', ' ', ...dateMask];\n};\n\nexport interface ParsedRange {\n start: Date;\n end: Date;\n}\n\n/** результат, коли введено лише валідну дату початку (кінець підставляється окремо) */\nexport interface ParsedStart {\n start: Date;\n end: null;\n}\n\ninterface ParseBounds {\n minDate?: Date | null;\n maxDate?: Date | null;\n /** дозволити введення лише дати початку — для режиму endDefaultsToToday */\n allowStartOnly?: boolean;\n}\n\nconst parseToken = (token: string, displayFormat: string): Date | null => {\n const trimmed = token.trim();\n if (trimmed.length !== displayFormat.length) return null;\n const parsed = parse(trimmed, displayFormat, new Date());\n if (!isValid(parsed)) return null;\n // round-trip guard rejects overflow values like 32/13/2025\n if (format(parsed, displayFormat) !== trimmed) return null;\n return parsed;\n};\n\n/**\n * Parses a typed range string.\n * Returns 'empty' for blank input, a full {start, end} range when both dates are\n * valid, and — when `allowStartOnly` is set (endDefaultsToToday) — a {start, end: null}\n * result when only a valid start date has been entered. null otherwise.\n */\nexport const parseRange = (\n text: string,\n displayFormat: string,\n { minDate, maxDate, allowStartOnly = false }: ParseBounds = {},\n): ParsedRange | ParsedStart | 'empty' | null => {\n const trimmed = text.trim();\n if (trimmed === '') return 'empty';\n\n // Split on the spaced range separator ' - ' — the exact literal the mask inserts between\n // the two dates. Using the spaced form (not a bare '-') keeps date-internal dashes intact,\n // so '-'-separated formats like yyyy-MM-dd parse correctly too.\n const parts = trimmed.split(SEPARATOR);\n const startPart = parts[0];\n const start = startPart !== undefined ? parseToken(startPart, displayFormat) : null;\n\n if (parts.length === 2) {\n const endPart = parts[1];\n const end = endPart !== undefined ? parseToken(endPart, displayFormat) : null;\n if (start && end) {\n if (start.getTime() > end.getTime()) return null;\n if (minDate && start.getTime() < minDate.getTime()) return null;\n if (maxDate && end.getTime() > maxDate.getTime()) return null;\n return { start, end };\n }\n }\n\n // start-only: a valid start with the end still blank (or mask placeholders)\n if (allowStartOnly && start) {\n if (minDate && start.getTime() < minDate.getTime()) return null;\n if (maxDate && start.getTime() > maxDate.getTime()) return null;\n return { start, end: null };\n }\n\n return null;\n};\n\n/**\n * Commit-time fallback for the end date.\n * When enabled and the user committed a start but no end, fills the end with `now`.\n * `now` is injected so the whole computation does a single clock read per commit\n * and stays a pure function (the caller passes `new Date()` at Save).\n *\n * Returns the tuple unchanged when disabled, when both are empty / end is already\n * set, or when start is in the future relative to `now` (would yield a reversed\n * range). When `maxDate` precedes `now`, the filled end is clamped down to it.\n */\nexport const applyEndFallback = (\n start: Date | null,\n end: Date | null,\n enabled: boolean,\n now: Date,\n maxDate?: Date | null,\n): [Date | null, Date | null] => {\n if (!enabled) return [start, end];\n if (!start || end) return [start, end];\n if (start.getTime() > now.getTime()) return [start, end]; // reversed-range guard\n // Clamp DOWN to maxDate only — mirrors parseRange's instant comparison above\n // (end.getTime() > maxDate.getTime()); may no-op against a day-granular maxDate.\n const filledEnd = maxDate && maxDate.getTime() < now.getTime() ? maxDate : now;\n if (start.getTime() > filledEnd.getTime()) return [start, end]; // post-clamp guard\n return [start, filledEnd];\n};\n"],"names":["formatRange","start","end","displayFormat","startStr","format","endStr","matchPresetLabel","presets","sameInstant","a","b","getTime","match","find","p","range","label","buildDateMask","map","char","test","buildRangeMask","dateMask","parseToken","token","trimmed","trim","length","parsed","parse","Date","isValid","parseRange","text","minDate","maxDate","allowStartOnly","parts","split","startPart","undefined","endPart","applyEndFallback","enabled","now","filledEnd"],"mappings":"0DAIaA,IAAAA,EAAc,CACvBC,EACAC,EACAC,KAEA,IAAMC,EAAWH,EAAQI,EAAOJ,EAAOE,GAAiB,GAClDG,EAASJ,EAAMG,EAAOH,EAAKC,GAAiB,UAClD,AAAIC,GAAYE,EAAe,GAAGF,OAAuBE,GAAQ,CAC7DF,GACG,EACX,EAQaG,EAAmB,CAC5BN,EACAC,EACAM,KAEA,IAAMC,EAAc,CAACC,EAAgBC,IACjCD,AAAM,OAANA,EAAaC,AAAM,OAANA,EAAaA,AAAM,OAANA,GAAcD,EAAEE,OAAO,KAAOD,EAAEC,OAAO,GAC/DC,EAAQL,EAAQM,IAAI,CACtB,AAACC,GAAMN,EAAYR,EAAOc,EAAEC,KAAK,CAAC,EAAE,GAAKP,EAAYP,EAAKa,EAAEC,KAAK,CAAC,EAAE,GAExE,OAAOH,EAAQA,EAAMI,KAAK,CAAG,IACjC,EAOMC,EAAgB,AAACf,GACnB,IAAIA,EAAc,CAACgB,GAAG,CAAC,AAACC,GAAU,WAAWC,IAAI,CAACD,GAAQ,KAAOA,GAGxDE,EAAiB,AAACnB,IAC3B,IAAMoB,EAAWL,EAAcf,GAC/B,MAAO,IAAIoB,EAAU,IAAK,IAAK,OAAQA,EAAS,AACpD,EAoBMC,EAAa,CAACC,EAAetB,KAC/B,IAAMuB,EAAUD,EAAME,IAAI,GAC1B,GAAID,EAAQE,MAAM,GAAKzB,EAAcyB,MAAM,CAAE,OAAO,KACpD,IAAMC,EAASC,EAAMJ,EAASvB,EAAe,IAAI4B,aACjD,AAAKC,EAAQH,IAETxB,EAAOwB,EAAQ1B,KAAmBuB,EAC/BG,EAHsB,IAIjC,EAQaI,EAAa,CACtBC,EACA/B,EACA,CAAEgC,QAAAA,CAAO,CAAEC,QAAAA,CAAO,CAAEC,eAAAA,EAAiB,CAAA,CAAK,CAAe,CAAG,EAAE,IAE9D,IAAMX,EAAUQ,EAAKP,IAAI,GACzB,GAAID,AAAY,KAAZA,EAAgB,MAAO,QAK3B,IAAMY,EAAQZ,EAAQa,KAAK,CA5Fb,OA6FRC,EAAYF,CAAK,CAAC,EAAE,CACpBrC,EAAQuC,AAAcC,KAAAA,IAAdD,EAA0BhB,EAAWgB,EAAWrC,GAAiB,KAE/E,GAAImC,AAAiB,IAAjBA,EAAMV,MAAM,CAAQ,CACpB,IAAMc,EAAUJ,CAAK,CAAC,EAAE,CAClBpC,EAAMwC,AAAYD,KAAAA,IAAZC,EAAwBlB,EAAWkB,EAASvC,GAAiB,KACzE,GAAIF,GAASC,SACT,AAAID,EAAMW,OAAO,GAAKV,EAAIU,OAAO,IAC7BuB,GAAWlC,EAAMW,OAAO,GAAKuB,EAAQvB,OAAO,IAC5CwB,GAAWlC,EAAIU,OAAO,GAAKwB,EAAQxB,OAAO,GAFF,KAGrC,CAAEX,MAAAA,EAAOC,IAAAA,CAAI,CAE5B,QAGA,AAAImC,GAAkBpC,EAClB,AAAIkC,GAAWlC,EAAMW,OAAO,GAAKuB,EAAQvB,OAAO,IAC5CwB,GAAWnC,EAAMW,OAAO,GAAKwB,EAAQxB,OAAO,GADW,KAEpD,CAAEX,MAAAA,EAAOC,IAAK,IAAK,EAGvB,IACX,EAYayC,EAAmB,CAC5B1C,EACAC,EACA0C,EACAC,EACAT,KAEA,GAAI,CAACQ,GACD,CAAC3C,GAASC,GACVD,EAAMW,OAAO,GAAKiC,EAAIjC,OAAO,GAFnB,MAAO,CAACX,EAAOC,EAAI,CAKjC,IAAM4C,EAAYV,GAAWA,EAAQxB,OAAO,GAAKiC,EAAIjC,OAAO,GAAKwB,EAAUS,SAC3E,AAAI5C,EAAMW,OAAO,GAAKkC,EAAUlC,OAAO,GAAW,CAACX,EAAOC,EAAI,CACvD,CAACD,EAAO6C,EAAU,AAC7B"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/components/Datepicker/DateRangePicker/utils.ts"],"sourcesContent":["import { format, isValid, parse } from 'date-fns';\n\nconst SEPARATOR = ' - ';\n\nexport const formatRange = (\n start: Date | null,\n end: Date | null,\n displayFormat: string,\n): string => {\n const startStr = start ? format(start, displayFormat) : '';\n const endStr = end ? format(end, displayFormat) : '';\n if (startStr && endStr) return `${startStr}${SEPARATOR}${endStr}`;\n if (startStr) return startStr;\n return '';\n};\n\ntype PresetEntry = { label: string; range: [Date, Date] };\n\n/**\n * Якщо діапазон точно збігається з діапазоном іменованого пресету — повертає його підпис,\n * інакше null. Порівняння за getTime() з урахуванням null; за колізії — перший збіг.\n */\nexport const matchPresetLabel = (\n start: Date | null,\n end: Date | null,\n presets: ReadonlyArray<PresetEntry>,\n): string | null => {\n const sameInstant = (a: Date | null, b: Date | null): boolean =>\n a === null ? b === null : b !== null && a.getTime() === b.getTime();\n const match = presets.find(\n (p) => sameInstant(start, p.range[0]) && sameInstant(end, p.range[1]),\n );\n return match ? match.label : null;\n};\n\n/**\n * Builds a react-text-mask mask for a single date from a date-fns format string:\n * every pattern letter becomes a digit slot, every other character stays a literal.\n * Targets numeric date formats (dd/MM/yyyy, dd.MM.yyyy, yyyy-MM-dd, …).\n */\nconst buildDateMask = (displayFormat: string): (string | RegExp)[] =>\n [...displayFormat].map((char) => (/[a-zA-Z]/.test(char) ? /\\d/ : char));\n\n/** Builds the full range mask (`<date> - <date>`) derived from the given format. */\nexport const buildRangeMask = (displayFormat: string): (string | RegExp)[] => {\n const dateMask = buildDateMask(displayFormat);\n return [...dateMask, ' ', '-', ' ', ...dateMask];\n};\n\nexport interface ParsedRange {\n start: Date;\n end: Date;\n}\n\n/** результат, коли введено лише валідну дату початку (кінець підставляється окремо) */\nexport interface ParsedStart {\n start: Date;\n end: null;\n}\n\ninterface ParseBounds {\n minDate?: Date | null;\n maxDate?: Date | null;\n /** дозволити введення лише дати початку — для режиму endDefaultsToToday */\n allowStartOnly?: boolean;\n}\n\nconst parseToken = (token: string, displayFormat: string): Date | null => {\n const trimmed = token.trim();\n if (trimmed.length !== displayFormat.length) return null;\n const parsed = parse(trimmed, displayFormat, new Date());\n if (!isValid(parsed)) return null;\n // round-trip guard rejects overflow values like 32/13/2025\n if (format(parsed, displayFormat) !== trimmed) return null;\n return parsed;\n};\n\n/**\n * Parses a typed range string.\n * Returns 'empty' for blank input, a full {start, end} range when both dates are\n * valid, and — when `allowStartOnly` is set (endDefaultsToToday) — a {start, end: null}\n * result when only a valid start date has been entered. null otherwise.\n */\nexport const parseRange = (\n text: string,\n displayFormat: string,\n { minDate, maxDate, allowStartOnly = false }: ParseBounds = {},\n): ParsedRange | ParsedStart | 'empty' | null => {\n const trimmed = text.trim();\n if (trimmed === '') return 'empty';\n\n // Split on the spaced range separator ' - ' — the exact literal the mask inserts between\n // the two dates. Using the spaced form (not a bare '-') keeps date-internal dashes intact,\n // so '-'-separated formats like yyyy-MM-dd parse correctly too.\n const parts = trimmed.split(SEPARATOR);\n const startPart = parts[0];\n const start = startPart !== undefined ? parseToken(startPart, displayFormat) : null;\n\n if (parts.length === 2) {\n const endPart = parts[1];\n const end = endPart !== undefined ? parseToken(endPart, displayFormat) : null;\n if (start && end) {\n if (start.getTime() > end.getTime()) return null;\n if (minDate && start.getTime() < minDate.getTime()) return null;\n if (maxDate && end.getTime() > maxDate.getTime()) return null;\n return { start, end };\n }\n }\n\n // start-only: a valid start with the end still blank (or mask placeholders)\n if (allowStartOnly && start) {\n if (minDate && start.getTime() < minDate.getTime()) return null;\n if (maxDate && start.getTime() > maxDate.getTime()) return null;\n return { start, end: null };\n }\n\n return null;\n};\n\n/**\n * Commit-time fallback for the end date.\n * When enabled and the user committed a start but no end, fills the end with `now`.\n * `now` is injected so the whole computation does a single clock read per commit\n * and stays a pure function (the caller passes `new Date()` at Save).\n *\n * Returns the tuple unchanged when disabled, when both are empty / end is already\n * set, or when start is in the future relative to `now` (would yield a reversed\n * range). When `maxDate` precedes `now`, the filled end is clamped down to it.\n */\nexport const applyEndFallback = (\n start: Date | null,\n end: Date | null,\n enabled: boolean,\n now: Date,\n maxDate?: Date | null,\n): [Date | null, Date | null] => {\n if (!enabled) return [start, end];\n if (!start || end) return [start, end];\n if (start.getTime() > now.getTime()) return [start, end]; // reversed-range guard\n // Clamp DOWN to maxDate only — mirrors parseRange's instant comparison above\n // (end.getTime() > maxDate.getTime()); may no-op against a day-granular maxDate.\n const filledEnd = maxDate && maxDate.getTime() < now.getTime() ? maxDate : now;\n if (start.getTime() > filledEnd.getTime()) return [start, end]; // post-clamp guard\n return [start, filledEnd];\n};\n\n/**\n * Гарантує порядок діапазону: якщо обидві дати не null і start пізніше за end —\n * міняє їх місцями. Єдина дата (null) або рівні дати лишаються без змін.\n * Парність із гардом ручного вводу `parseRange` (start.getTime() > end.getTime()).\n */\nexport const normalizeOrder = (\n start: Date | null,\n end: Date | null,\n): [Date | null, Date | null] => {\n if (start && end && start.getTime() > end.getTime()) return [end, start];\n return [start, end];\n};\n"],"names":["formatRange","start","end","displayFormat","startStr","format","endStr","matchPresetLabel","presets","sameInstant","a","b","getTime","match","find","p","range","label","buildDateMask","map","char","test","buildRangeMask","dateMask","parseToken","token","trimmed","trim","length","parsed","parse","Date","isValid","parseRange","text","minDate","maxDate","allowStartOnly","parts","split","startPart","undefined","endPart","applyEndFallback","enabled","now","filledEnd","normalizeOrder"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { VchasnoProduct } from '../types.js';
2
2
 
3
- type Product = Exclude<VchasnoProduct, 'edi' | 'ttn' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'profile'>;
3
+ type Product = Exclude<VchasnoProduct, 'edi' | 'ttn' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'account' | 'business'>;
4
4
 
5
5
  export type { Product };
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../../src/components/FollowUs/config.ts"],"sourcesContent":["import type { VchasnoProduct } from '../types';\nimport type { Social } from './types';\n\nexport type Product = Exclude<VchasnoProduct, 'edi' | 'ttn' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'profile'>;\n\nexport const config: Record<Product, Partial<Record<Social, string>>> = {\n edo: {\n fb: 'https://www.facebook.com/vchasno',\n telegram: 'https://t.me/vchasnoservice',\n youtube: 'https://www.youtube.com/channel/UCE0jekYQINP_h5uHRpugwxw',\n inst: 'https://www.instagram.com/vchasno.service/',\n },\n kasa: {\n inst: 'https://www.instagram.com/vchasno.service',\n tiktok: 'https://www.tiktok.com/@vchasno.kasa',\n fb: 'https://www.facebook.com/vchasno',\n youtube: 'https://www.youtube.com/channel/UCE0jekYQINP_h5uHRpugwxw',\n },\n};\n"],"names":["config","edo","fb","telegram","youtube","inst","kasa","tiktok"],"mappings":"IAKaA,EAA2D,CACpEC,IAAK,CACDC,GAAI,mCACJC,SAAU,8BACVC,QAAS,2DACTC,KAAM,4CACV,EACAC,KAAM,CACFD,KAAM,4CACNE,OAAQ,uCACRL,GAAI,mCACJE,QAAS,0DACb,CACJ"}
1
+ {"version":3,"file":"config.js","sources":["../../../src/components/FollowUs/config.ts"],"sourcesContent":["import type { VchasnoProduct } from '../types';\nimport type { Social } from './types';\n\nexport type Product = Exclude<\n VchasnoProduct,\n 'edi' | 'ttn' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'account' | 'business'\n>;\n\nexport const config: Record<Product, Partial<Record<Social, string>>> = {\n edo: {\n fb: 'https://www.facebook.com/vchasno',\n telegram: 'https://t.me/vchasnoservice',\n youtube: 'https://www.youtube.com/channel/UCE0jekYQINP_h5uHRpugwxw',\n inst: 'https://www.instagram.com/vchasno.service/',\n },\n kasa: {\n inst: 'https://www.instagram.com/vchasno.service',\n tiktok: 'https://www.tiktok.com/@vchasno.kasa',\n fb: 'https://www.facebook.com/vchasno',\n youtube: 'https://www.youtube.com/channel/UCE0jekYQINP_h5uHRpugwxw',\n },\n};\n"],"names":["config","edo","fb","telegram","youtube","inst","kasa","tiktok"],"mappings":"IAQaA,EAA2D,CACpEC,IAAK,CACDC,GAAI,mCACJC,SAAU,8BACVC,QAAS,2DACTC,KAAM,4CACV,EACAC,KAAM,CACFD,KAAM,4CACNE,OAAQ,uCACRL,GAAI,mCACJE,QAAS,0DACb,CACJ"}
@@ -1,5 +1,5 @@
1
1
  import { VchasnoProduct } from '../types.js';
2
2
 
3
- type Product = Exclude<VchasnoProduct, 'edi' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'profile'>;
3
+ type Product = Exclude<VchasnoProduct, 'edi' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'account' | 'business'>;
4
4
 
5
5
  export type { Product };
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../../src/components/MobileAppLinks/config.ts"],"sourcesContent":["import type { VchasnoProduct } from '../types';\nimport type { LinkConfig } from './types';\n\nexport type Product = Exclude<VchasnoProduct, 'edi' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'profile'>;\n\nexport const config: Record<Product, LinkConfig> = {\n edo: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.edo',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D0%B5%D0%B4%D0%BE/id6462861848',\n },\n kasa: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.kasa',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D0%BA%D0%B0%D1%81%D0%B0/id6444186091',\n },\n ttn: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.ttn.mobile',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D1%82%D1%82%D0%BD/id6550909392',\n },\n};\n"],"names":["config","edo","android","ios","kasa","ttn"],"mappings":"IAKaA,EAAsC,CAC/CC,IAAK,CACDC,QAAS,+DACTC,IAAK,oGACT,EACAC,KAAM,CACFF,QAAS,gEACTC,IAAK,0GACT,EACAE,IAAK,CACDH,QAAS,sEACTC,IAAK,oGACT,CACJ"}
1
+ {"version":3,"file":"config.js","sources":["../../../src/components/MobileAppLinks/config.ts"],"sourcesContent":["import type { VchasnoProduct } from '../types';\nimport type { LinkConfig } from './types';\n\nexport type Product = Exclude<\n VchasnoProduct,\n 'edi' | 'dm' | 'kep' | 'hrs' | 'zvit' | 'account' | 'business'\n>;\n\nexport const config: Record<Product, LinkConfig> = {\n edo: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.edo',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D0%B5%D0%B4%D0%BE/id6462861848',\n },\n kasa: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.kasa',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D0%BA%D0%B0%D1%81%D0%B0/id6444186091',\n },\n ttn: {\n android: 'https://play.google.com/store/apps/details?id=ua.vchasno.ttn.mobile',\n ios: 'https://apps.apple.com/ua/app/%D0%B2%D1%87%D0%B0%D1%81%D0%BD%D0%BE-%D1%82%D1%82%D0%BD/id6550909392',\n },\n};\n"],"names":["config","edo","android","ios","kasa","ttn"],"mappings":"IAQaA,EAAsC,CAC/CC,IAAK,CACDC,QAAS,+DACTC,IAAK,oGACT,EACAC,KAAM,CACFF,QAAS,gEACTC,IAAK,0GACT,EACAE,IAAK,CACDH,QAAS,sEACTC,IAAK,oGACT,CACJ"}