@ahrowe/ui 0.38.0 → 0.39.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 (36) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs-types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +6 -6
  3. package/dist/cjs-types/common/datePicker/dateFunctions.d.ts +10 -19
  4. package/dist/cjs-types/common/datePicker/datePicker.types.d.ts +20 -14
  5. package/dist/cjs-types/common/datePicker/index.d.ts +1 -0
  6. package/dist/cjs-types/common/popover/popover.types.d.ts +5 -0
  7. package/dist/cjs-types/common/utils/day.d.ts +16 -0
  8. package/dist/cjs-types/index.d.ts +1 -1
  9. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
  10. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  11. package/dist/esm/common/datePicker/dateFunctions.mjs +1 -1
  12. package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -1
  13. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  14. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  15. package/dist/esm/common/hooks/useFocusBoundary.mjs +1 -1
  16. package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -1
  17. package/dist/esm/common/popover/popover.mjs +1 -1
  18. package/dist/esm/common/popover/popover.mjs.map +1 -1
  19. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  20. package/dist/esm/common/utils/day.mjs +2 -0
  21. package/dist/esm/common/utils/day.mjs.map +1 -0
  22. package/dist/esm/index.mjs +1 -1
  23. package/dist/index.cjs +3 -3
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +6 -6
  26. package/dist/types/common/datePicker/dateFunctions.d.ts +10 -19
  27. package/dist/types/common/datePicker/datePicker.types.d.ts +20 -14
  28. package/dist/types/common/datePicker/index.d.ts +1 -0
  29. package/dist/types/common/popover/popover.types.d.ts +5 -0
  30. package/dist/types/common/utils/day.d.ts +16 -0
  31. package/dist/types/index.d.ts +1 -1
  32. package/docs/CLAUDE.md +5 -1
  33. package/docs/DatePicker.md +72 -45
  34. package/docs/FormValidator.md +3 -3
  35. package/docs/Popover.md +15 -0
  36. package/package.json +2 -2
package/README.md CHANGED
@@ -136,7 +136,7 @@ runs where `@ahrowe/ui` is installed.
136
136
  | `ConfigProvider` | Set global **default props** for library components once, near the root of your app, instead of repeating the same prop on every instance |
137
137
  | `ConfirmModal` | Confirmation dialog before destructive or irreversible actions — delete, archive, send, overwrite |
138
138
  | `CopyButton` | Icon-only button that copies a value to the clipboard: an invoice number, an ID in a table row, an API key or share link inside an `Input` |
139
- | `DatePicker` | Date selection input — booking forms, birth date fields, date range pickers, deadline selectors |
139
+ | `DatePicker`, `dateToDay`, `dayToDate` | Date selection input — booking forms, birth date fields, date range pickers, deadline selectors |
140
140
  | `Divider`, `DividerTextPosition`, `DividerOrientation` | A rule that separates sections of content — horizontal by default, filling the width of its parent |
141
141
  | `Drawer` | Inline horizontal panel that collapses and expands by animating its width — side panels, navigation rails, detail/filter panes that slide open beside the main content |
142
142
  | `DropZone`, `DropZoneReturnType`, `DropZoneStatus` | Drag-and-drop file upload area, optionally click-to-open the native picker |
@@ -8,16 +8,16 @@ export interface DatePickerMonthProps {
8
8
  month?: number;
9
9
  /** Year to display. */
10
10
  year?: number;
11
- /** Called with the day that was picked. */
12
- onSelect?: (date: Date) => void;
11
+ /** Called with the day that was picked, `'YYYY-MM-DD'`. */
12
+ onSelect?: (day: string) => void;
13
13
  /** First day of the highlighted range, and the day that starts with the tab stop. */
14
- selectionStart?: Date;
14
+ selectionStart?: string | null;
15
15
  /** Last day of the highlighted range. */
16
- selectionEnd?: Date;
16
+ selectionEnd?: string | null;
17
17
  /** Days before this are not selectable. */
18
- minDate?: Date | null;
18
+ minDate?: string | null;
19
19
  /** Days after this are not selectable. */
20
- maxDate?: Date | null;
20
+ maxDate?: string | null;
21
21
  /** Called to shift the displayed month by ±1 when arrow navigation runs past its edge. */
22
22
  onNavigateMonth?: (delta: 1 | -1) => void;
23
23
  }
@@ -1,26 +1,17 @@
1
- export declare function getDaysInMonth(month: number, year: number): number;
2
- export declare function getDateFromDayMonthAndYear(day: number, month: number, year: number): Date;
1
+ import { DayParts } from '../utils/day.js';
3
2
  export declare function getMonthName(locale: string, year: number, month: number, day: number, short?: boolean): string;
4
3
  export declare function getMonthNames(locale?: string): string[];
5
4
  export declare function getWeekDays(locale: string, short?: boolean): string[];
5
+ /** 1 (Monday) to 7 (Sunday). */
6
6
  export declare function getStartWeekDayOfMonth(month: number, year: number): number;
7
- /**
8
- * Adds `delta` days to a day/month/year triple, rolling over into adjacent months/years as
9
- * needed. Pure integer arithmetic over `getDaysInMonth` rather than a `Date` object, so it
10
- * can't drift a day from local-vs-UTC ambiguity the way mutating a UTC-constructed `Date`
11
- * with its local `setDate` would.
12
- */
13
- export declare function addDays(day: number, month: number, year: number, delta: number): {
14
- day: number;
15
- month: number;
16
- year: number;
17
- };
18
- export declare function getDayMonthAndYearOfDate(date: Date): {
19
- day: number;
20
- month: number;
21
- year: number;
22
- };
23
- export declare function getDateString(date: Date): string;
7
+ /** `delta` days from a day, rolling over into the months and years around it. */
8
+ export declare function addDays(day: number, month: number, year: number, delta: number): DayParts;
9
+ /** Today in the user's time zone. */
10
+ export declare function getToday(): DayParts;
11
+ /** A `'YYYY-MM-DD'` day as the field shows it, `dd.mm.yyyy`, or `''` for anything else. */
12
+ export declare function getDateString(value: string | null | undefined): string;
13
+ /** What the field holds, `dd.mm.yyyy`, as `'YYYY-MM-DD'`; `null` while incomplete, or for a day that does not exist. */
14
+ export declare function parseDateString(text: string): string | null;
24
15
  export interface DateMaskSelection {
25
16
  start: number;
26
17
  end: number;
@@ -3,8 +3,10 @@ import { FormValidator } from '../../services/formValidation/index.js';
3
3
  import { HtmlProps, SlotClassNames, SlotStyles } from '../types/slots.types.js';
4
4
  export type DatePickerSlots = 'root' | 'input' | 'header' | 'monthDropdown' | 'yearDropdown' | 'calendar' | 'clearButton';
5
5
  /**
6
- * `onChange` and `onSelect` report a date rather than a DOM event, so the native
6
+ * `onChange` and `onSelect` report a day rather than a DOM event, so the native
7
7
  * handlers of those names are dropped instead of being widened to accept both.
8
+ *
9
+ * Every day is a `'YYYY-MM-DD'` string, never a `Date`: see docs/DatePicker.md.
8
10
  */
9
11
  export interface DatePickerProps extends Omit<HtmlProps<HTMLDivElement>, 'onChange' | 'onSelect'> {
10
12
  /** Class on the root element. */
@@ -12,33 +14,37 @@ export interface DatePickerProps extends Omit<HtmlProps<HTMLDivElement>, 'onChan
12
14
  style?: CSSProperties;
13
15
  classNames?: SlotClassNames<DatePickerSlots>;
14
16
  styles?: SlotStyles<DatePickerSlots>;
15
- /** Selected date, controlled. Ignored while a `formValidator` owns the value. */
16
- selected?: Date;
17
+ /** Selected day, `'YYYY-MM-DD'`, controlled. Ignored while a `formValidator` owns the value. */
18
+ selected?: string | null;
17
19
  /** Floating label on the input. */
18
20
  label?: string;
19
21
  /**
20
22
  * Called when a day is picked in the calendar, after `onChange`. Picking also
21
23
  * closes the picker.
22
24
  */
23
- onSelect?: (date: Date | null) => void;
25
+ onSelect?: (day: string | null) => void;
24
26
  /**
25
27
  * Called whenever the value changes, whether picked in the calendar or typed
26
- * into the input. `null` when the field was cleared or holds no valid date.
28
+ * into the input. `null` when the field was cleared or holds no valid day.
27
29
  */
28
- onChange?: (date: Date | null) => void;
29
- /** Hands the value to a validator, which then owns it. See docs/FormValidator.md. */
30
- formValidator?: FormValidator | null;
31
- /** Earliest selectable date. Also bounds the year dropdown. */
32
- minDate?: Date | null;
33
- /** Latest selectable date. Also bounds the year dropdown. */
34
- maxDate?: Date | null;
30
+ onChange?: (day: string | null) => void;
31
+ /**
32
+ * Hands the value to a validator, which then owns it. See docs/FormValidator.md. The three
33
+ * forms are what TypeScript infers for `new FormValidator<string | null>(null)`,
34
+ * `new FormValidator(null)` and `new FormValidator('')`; a `Date` validator fits none of them.
35
+ */
36
+ formValidator?: FormValidator<string | null> | FormValidator<string> | FormValidator<null> | null;
37
+ /** Earliest selectable day, `'YYYY-MM-DD'`. Also bounds the year dropdown. */
38
+ minDate?: string | null;
39
+ /** Latest selectable day, `'YYYY-MM-DD'`. Also bounds the year dropdown. */
40
+ maxDate?: string | null;
35
41
  /**
36
42
  * Start of a highlighted range. Defaults to the selected date, so two pickers
37
43
  * sharing a start and an end highlight the span between them.
38
44
  */
39
- startDate?: Date;
45
+ startDate?: string | null;
40
46
  /** End of the highlighted range. */
41
- endDate?: Date;
47
+ endDate?: string | null;
42
48
  /** Render the calendar in place instead of in a popover. */
43
49
  isInline?: boolean;
44
50
  /** Open the calendar in a modal, with the input read-only. */
@@ -1,2 +1,3 @@
1
1
  export { default } from './datePicker.js';
2
2
  export * from './datePicker.types.js';
3
+ export { dateToDay, dayToDate } from '../utils/day.js';
@@ -24,6 +24,11 @@ export type PopoverSlots = 'root' | 'trigger' | 'floating' | 'panel' | 'arrow' |
24
24
  export interface PopoverProps extends Omit<HtmlProps, 'content'> {
25
25
  /** The trigger element. */
26
26
  children?: ReactNode;
27
+ /**
28
+ * Place the panel against this element instead of `children`, for one Popover does not wrap.
29
+ * Open it with `isOpen`; `null` falls back to `children`.
30
+ */
31
+ anchor?: HTMLElement | null;
27
32
  /** The popover body. */
28
33
  content?: ReactNode;
29
34
  /** Preferred side (default `Bottom`). */
@@ -0,0 +1,16 @@
1
+ export interface DayParts {
2
+ year: number;
3
+ /** 1 to 12. */
4
+ month: number;
5
+ day: number;
6
+ }
7
+ export declare function daysInMonth({ year, month }: Pick<DayParts, 'year' | 'month'>): number;
8
+ /** The parts of a `'YYYY-MM-DD'` string, or `null` for anything else, 31 February included. */
9
+ export declare function parseDay(value: unknown): DayParts | null;
10
+ /** `value` itself when it is a `'YYYY-MM-DD'` day that exists, otherwise `null`. */
11
+ export declare function asDay(value: unknown): string | null;
12
+ export declare function formatDay({ year, month, day }: DayParts): string;
13
+ /** The day `date` falls on in the browser's time zone, as `'YYYY-MM-DD'`; `''` for an Invalid Date. */
14
+ export declare function dateToDay(date: Date): string;
15
+ /** The first moment of a `'YYYY-MM-DD'` day in the browser's time zone. An Invalid Date for anything else. */
16
+ export declare function dayToDate(day: string): Date;
@@ -158,4 +158,4 @@ export * from './common/hooks/index.js';
158
158
  export { FormValidator, FormValidatorGroup, Validators, ValidatableComponent, useFormValidator, useFormValidatorGroup, } from './services/formValidation/index.js';
159
159
  export type { ValidationError, ValidatorFunction, ErrorParser, FormValidatorGroupOptions, InferGroupValues, MergedValues, } from './services/formValidation/index.js';
160
160
  export { mapLocale, setLocale, getLocale } from './services/localization.js';
161
- export { isNumber, isDate, isISODate, isEmail, isBic, isURL, hasEightPasswordChars, hasOnePasswordLetter, hasOnePasswordDigit, isPassword, } from '@ahrowe/form-validation';
161
+ export { isNumber, isDate, isDay, isISODate, isEmail, isBic, isURL, hasEightPasswordChars, hasOnePasswordLetter, hasOnePasswordDigit, isPassword, } from '@ahrowe/form-validation';
@@ -1,2 +1,2 @@
1
- "use client";import e from"../../../interactableDiv/index.mjs";import t from"./datePickerMonth.module.mjs";import{getLocale as n}from"../../../../services/localization.mjs";import{addDays as r,getDateFromDayMonthAndYear as i,getDayMonthAndYearOfDate as a,getDaysInMonth as o,getStartWeekDayOfMonth as s,getWeekDays as c}from"../../dateFunctions.mjs";import{useEffect as l,useRef as u,useState as d}from"react";import f from"classnames";import{jsx as p,jsxs as m}from"react/jsx-runtime";function h(e,t,n){if(n){let r=a(n);if(r.month===e&&r.year===t)return r.day}let r=a(new Date);return r.month===e&&r.year===t?r.day:1}function g(e,t,n,r,o){let{day:s,month:c,year:l}=r?a(r):{day:void 0,month:void 0,year:void 0},{day:u,month:d,year:f}=o?a(o):{day:void 0,month:void 0,year:void 0},p=i(e,t,n),m=e===s&&t===c&&n===l,h=e===u&&t===d&&n===f,g=!1;if(s!==void 0&&c!==void 0&&l!==void 0&&u!==void 0&&d!==void 0&&f!==void 0){let e=i(s,c,l),t=i(u,d,f);g=p.getTime()>=e.getTime()&&p.getTime()<=t.getTime()}return{isStartDate:m,isInRange:g,isEndDate:h}}function _(e,t,n,r,o){let s=i(e,t,n);if(r){let{day:e,month:t,year:n}=a(r);if(s<i(e,t,n))return!0}if(o){let{day:e,month:t,year:n}=a(o);if(s>i(e,t,n))return!0}return!1}function v(e,t,n){let{day:r,month:i,year:o}=a(new Date);return e===r&&t===i&&n===o}function y({style:a,className:y=``,month:b=new Date().getMonth()+1,year:x=new Date().getFullYear(),onSelect:S=()=>null,selectionStart:C,selectionEnd:w,minDate:T=null,maxDate:E=null,onNavigateMonth:D}){let O=n(`-`),k=o(b,x),A=s(b,x),j=u({}),[M,N]=d(()=>h(b,x,C)),P=u(null);l(()=>{if(P.current!=null){let e=P.current;P.current=null,N(e),j.current[e]?.focus()}else N(h(b,x,C))},[b,x]);function F(e,t){let n=0;if(e.key===`ArrowRight`)n=1;else if(e.key===`ArrowLeft`)n=-1;else if(e.key===`ArrowDown`)n=7;else if(e.key===`ArrowUp`)n=-7;else return;e.preventDefault();let i=r(t,b,x,n);i.month!==b||i.year!==x?(P.current=i.day,D?.(i.month>b||i.year>x?1:-1)):(N(i.day),j.current[i.day]?.focus())}return p(`div`,{className:f(t.datePickerMonth,y),style:a,children:m(`div`,{className:f(t.datePickerMonthContent),children:[c(O).map((e,t)=>p(`div`,{children:e},t)),Array.from(Array(A-1).keys()).map(e=>p(`div`,{className:f(t.datePickerMonthItem,t.datePickerMonthPlaceholder)},e)),Array.from(Array(k).keys()).map(n=>{let r=n+1,a=g(r,b,x,C,w),o=_(r,b,x,T,E),s=v(r,b,x);return p(e,{ref:e=>{j.current[r]=e},tabIndex:r===M?0:-1,onKeyDown:e=>F(e,r),onClick:()=>o?null:S(i(r,b,x)),className:f(t.datePickerMonthDay,t.datePickerMonthItem,{[t.datePickerMonthDaySelected]:a.isInRange,[t.datePickerMonthDaySelectedStart]:a.isStartDate,[t.datePickerMonthDaySelectedEnd]:a.isEndDate,[t.datePickerMonthDayDisabled]:o,[t.datePickerMonthDayToday]:s}),children:r},r)}),Array.from(Array(42-(A+k-1)).keys()).map(e=>p(`div`,{className:f(t.datePickerMonthItem,t.datePickerMonthPlaceholder),children:`\xA0`},e))]})})}export{y as default};
1
+ "use client";import e from"../../../interactableDiv/index.mjs";import t from"./datePickerMonth.module.mjs";import{getLocale as n}from"../../../../services/localization.mjs";import{dateToDay as r,daysInMonth as i,formatDay as a,parseDay as o}from"../../../utils/day.mjs";import{addDays as s,getStartWeekDayOfMonth as c,getToday as l,getWeekDays as u}from"../../dateFunctions.mjs";import{useEffect as d,useRef as f,useState as p}from"react";import m from"classnames";import{jsx as h,jsxs as g}from"react/jsx-runtime";function _(e,t,n){let r=o(n);if(r&&r.month===e&&r.year===t)return r.day;let i=l();return i.month===e&&i.year===t?i.day:1}function v(e,t,n){return{isStartDate:e===t,isEndDate:e===n,isInRange:!!t&&!!n&&e>=t&&e<=n}}function y(e,t,n){return!!t&&e<t||!!n&&e>n}function b({style:o,className:b=``,month:x=l().month,year:S=l().year,onSelect:C=()=>null,selectionStart:w,selectionEnd:T,minDate:E=null,maxDate:D=null,onNavigateMonth:O}){let k=n(`-`),A=i({year:S,month:x}),j=c(x,S),M=r(new Date),N=f({}),[P,F]=p(()=>_(x,S,w)),I=f(null);d(()=>{if(I.current!=null){let e=I.current;I.current=null,F(e),N.current[e]?.focus()}else F(_(x,S,w))},[x,S]);function L(e,t){let n=0;if(e.key===`ArrowRight`)n=1;else if(e.key===`ArrowLeft`)n=-1;else if(e.key===`ArrowDown`)n=7;else if(e.key===`ArrowUp`)n=-7;else return;e.preventDefault();let r=s(t,x,S,n);r.month!==x||r.year!==S?(I.current=r.day,O?.(r.month>x||r.year>S?1:-1)):(F(r.day),N.current[r.day]?.focus())}return h(`div`,{className:m(t.datePickerMonth,b),style:o,children:g(`div`,{className:m(t.datePickerMonthContent),children:[u(k).map((e,t)=>h(`div`,{children:e},t)),Array.from(Array(j-1).keys()).map(e=>h(`div`,{className:m(t.datePickerMonthItem,t.datePickerMonthPlaceholder)},e)),Array.from(Array(A).keys()).map(n=>{let r=n+1,i=a({day:r,month:x,year:S}),o=v(i,w,T),s=y(i,E,D),c=i===M;return h(e,{ref:e=>{N.current[r]=e},tabIndex:r===P?0:-1,onKeyDown:e=>L(e,r),onClick:()=>s?null:C(i),className:m(t.datePickerMonthDay,t.datePickerMonthItem,{[t.datePickerMonthDaySelected]:o.isInRange,[t.datePickerMonthDaySelectedStart]:o.isStartDate,[t.datePickerMonthDaySelectedEnd]:o.isEndDate,[t.datePickerMonthDayDisabled]:s,[t.datePickerMonthDayToday]:c}),children:r},r)}),Array.from(Array(42-(j+A-1)).keys()).map(e=>h(`div`,{className:m(t.datePickerMonthItem,t.datePickerMonthPlaceholder),children:`\xA0`},e))]})})}export{b as default};
2
2
  //# sourceMappingURL=datePickerMonth.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"datePickerMonth.mjs","names":[],"sources":["../../../../../../package/common/datePicker/components/datePickerMonth/datePickerMonth.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport styles from './datePickerMonth.module.pcss';\nimport { getLocale } from 'services/localization';\nimport InteractableDiv from 'components/common/interactableDiv';\nimport {\n addDays,\n getDateFromDayMonthAndYear,\n getDayMonthAndYearOfDate,\n getDaysInMonth,\n getStartWeekDayOfMonth,\n getWeekDays,\n} from '../../dateFunctions';\nimport type { DatePickerMonthProps } from './datePickerMonth.types';\n\n// Which day gets the sole tab stop when this month first renders (or when the displayed\n// month changes via the header, not via arrow navigation): the selected day if it falls in\n// this month, else today if it falls in this month, else the 1st.\nfunction getDefaultFocusedDay(month: number, year: number, selectionStart: Date | undefined): number {\n if (selectionStart) {\n const sel = getDayMonthAndYearOfDate(selectionStart);\n if (sel.month === month && sel.year === year) return sel.day;\n }\n const today = getDayMonthAndYearOfDate(new Date());\n if (today.month === month && today.year === year) return today.day;\n return 1;\n}\n\nfunction checkSelected(\n day: number,\n month: number,\n year: number,\n selectionStart: Date | undefined,\n selectionEnd: Date | undefined,\n) {\n const {\n day: startDay,\n month: startMonth,\n year: startYear,\n } = selectionStart ? getDayMonthAndYearOfDate(selectionStart) : { day: undefined, month: undefined, year: undefined };\n const {\n day: endDay,\n month: endMonth,\n year: endYear,\n } = selectionEnd ? getDayMonthAndYearOfDate(selectionEnd) : { day: undefined, month: undefined, year: undefined };\n\n const toCheckNoTime = getDateFromDayMonthAndYear(day, month, year);\n\n const isStartDate = day === startDay && month === startMonth && year === startYear;\n const isEndDate = day === endDay && month === endMonth && year === endYear;\n\n let isInRange = false;\n if (\n startDay !== undefined &&\n startMonth !== undefined &&\n startYear !== undefined &&\n endDay !== undefined &&\n endMonth !== undefined &&\n endYear !== undefined\n ) {\n const selectionStartNoTime = getDateFromDayMonthAndYear(startDay, startMonth, startYear);\n const selectionEndNoTime = getDateFromDayMonthAndYear(endDay, endMonth, endYear);\n isInRange =\n toCheckNoTime.getTime() >= selectionStartNoTime.getTime() &&\n toCheckNoTime.getTime() <= selectionEndNoTime.getTime();\n }\n\n return { isStartDate, isInRange, isEndDate };\n}\n\nfunction checkDisabled(\n day: number,\n month: number,\n year: number,\n minDate: Date | null | undefined,\n maxDate: Date | null | undefined,\n): boolean {\n const toCheckNoTime = getDateFromDayMonthAndYear(day, month, year);\n\n if (minDate) {\n const { day: minDay, month: minMonth, year: minYear } = getDayMonthAndYearOfDate(minDate);\n if (toCheckNoTime < getDateFromDayMonthAndYear(minDay, minMonth, minYear)) return true;\n }\n\n if (maxDate) {\n const { day: maxDay, month: maxMonth, year: maxYear } = getDayMonthAndYearOfDate(maxDate);\n if (toCheckNoTime > getDateFromDayMonthAndYear(maxDay, maxMonth, maxYear)) return true;\n }\n\n return false;\n}\n\nfunction checkIsToday(day: number, month: number, year: number): boolean {\n const { day: currDay, month: currMonth, year: currYear } = getDayMonthAndYearOfDate(new Date());\n return day === currDay && month === currMonth && year === currYear;\n}\n\nexport default function DatePickerMonth({\n style,\n className = '',\n month = new Date().getMonth() + 1,\n year = new Date().getFullYear(),\n onSelect = () => null,\n selectionStart,\n selectionEnd,\n minDate = null,\n maxDate = null,\n onNavigateMonth,\n}: DatePickerMonthProps) {\n const locale = getLocale('-');\n const daysInMonth = getDaysInMonth(month, year);\n const startWeekDayOfMonth = getStartWeekDayOfMonth(month, year);\n\n const dayRefs = useRef<Record<number, HTMLDivElement | null>>({});\n const [focusedDay, setFocusedDay] = useState(() => getDefaultFocusedDay(month, year, selectionStart));\n\n // A day arrowed onto in an adjacent month, waiting for that month's grid to render so it\n // can be focused. `onNavigateMonth` only shifts `month`/`year` — the actual DOM focus has\n // to happen after this component re-renders with the new days, hence the effect below.\n const pendingFocusDayRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (pendingFocusDayRef.current != null) {\n const day = pendingFocusDayRef.current;\n pendingFocusDayRef.current = null;\n setFocusedDay(day);\n dayRefs.current[day]?.focus();\n } else {\n // The displayed month changed some other way (header chevrons, month/year dropdowns) —\n // re-pick a sensible tab stop, but don't steal focus from whatever the user just used.\n setFocusedDay(getDefaultFocusedDay(month, year, selectionStart));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [month, year]);\n\n function handleDayKeyDown(event: React.KeyboardEvent<HTMLDivElement>, day: number) {\n let delta = 0;\n if (event.key === 'ArrowRight') delta = 1;\n else if (event.key === 'ArrowLeft') delta = -1;\n else if (event.key === 'ArrowDown') delta = 7;\n else if (event.key === 'ArrowUp') delta = -7;\n else return;\n\n event.preventDefault();\n const next = addDays(day, month, year, delta);\n\n if (next.month !== month || next.year !== year) {\n pendingFocusDayRef.current = next.day;\n onNavigateMonth?.(next.month > month || next.year > year ? 1 : -1);\n } else {\n setFocusedDay(next.day);\n dayRefs.current[next.day]?.focus();\n }\n }\n\n return (\n <div className={cx(styles.datePickerMonth, className)} style={style}>\n <div className={cx(styles.datePickerMonthContent)}>\n {getWeekDays(locale).map((weekDay, index) => (\n <div key={index}>{weekDay}</div>\n ))}\n {Array.from(Array(startWeekDayOfMonth - 1).keys()).map((index) => (\n <div key={index} className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)} />\n ))}\n {Array.from(Array(daysInMonth).keys()).map((index) => {\n const day = index + 1;\n const selectedRes = checkSelected(day, month, year, selectionStart, selectionEnd);\n const isDisabled = checkDisabled(day, month, year, minDate, maxDate);\n const isToday = checkIsToday(day, month, year);\n\n return (\n <InteractableDiv\n key={day}\n ref={(el) => {\n dayRefs.current[day] = el;\n }}\n tabIndex={day === focusedDay ? 0 : -1}\n onKeyDown={(event) => handleDayKeyDown(event, day)}\n onClick={() => (isDisabled ? null : onSelect(getDateFromDayMonthAndYear(day, month, year)))}\n className={cx(styles.datePickerMonthDay, styles.datePickerMonthItem, {\n [styles.datePickerMonthDaySelected]: selectedRes.isInRange,\n [styles.datePickerMonthDaySelectedStart]: selectedRes.isStartDate,\n [styles.datePickerMonthDaySelectedEnd]: selectedRes.isEndDate,\n [styles.datePickerMonthDayDisabled]: isDisabled,\n [styles.datePickerMonthDayToday]: isToday,\n })}\n >\n {day}\n </InteractableDiv>\n );\n })}\n {Array.from(Array(42 - (startWeekDayOfMonth + daysInMonth - 1)).keys()).map((index) => (\n <div key={index} className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}>\n &nbsp;\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"datePickerMonth.mjs","names":[],"sources":["../../../../../../package/common/datePicker/components/datePickerMonth/datePickerMonth.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport styles from './datePickerMonth.module.pcss';\nimport { getLocale } from 'services/localization';\nimport InteractableDiv from 'components/common/interactableDiv';\nimport { dateToDay, daysInMonth, formatDay, parseDay } from 'components/common/utils/day';\nimport { addDays, getStartWeekDayOfMonth, getToday, getWeekDays } from '../../dateFunctions';\nimport type { DatePickerMonthProps } from './datePickerMonth.types';\n\n// Which day gets the sole tab stop when this month first renders (or when the displayed\n// month changes via the header, not via arrow navigation): the selected day if it falls in\n// this month, else today if it falls in this month, else the 1st.\nfunction getDefaultFocusedDay(month: number, year: number, selectionStart: string | null | undefined): number {\n const selected = parseDay(selectionStart);\n if (selected && selected.month === month && selected.year === year) return selected.day;\n const today = getToday();\n if (today.month === month && today.year === year) return today.day;\n return 1;\n}\n\n// `'YYYY-MM-DD'` sorts as it reads, so days compare as plain strings.\nfunction checkSelected(value: string, start: string | null | undefined, end: string | null | undefined) {\n return {\n isStartDate: value === start,\n isEndDate: value === end,\n isInRange: !!start && !!end && value >= start && value <= end,\n };\n}\n\nfunction checkDisabled(value: string, minDate: string | null | undefined, maxDate: string | null | undefined): boolean {\n return (!!minDate && value < minDate) || (!!maxDate && value > maxDate);\n}\n\nexport default function DatePickerMonth({\n style,\n className = '',\n month = getToday().month,\n year = getToday().year,\n onSelect = () => null,\n selectionStart,\n selectionEnd,\n minDate = null,\n maxDate = null,\n onNavigateMonth,\n}: DatePickerMonthProps) {\n const locale = getLocale('-');\n const dayCount = daysInMonth({ year, month });\n const startWeekDayOfMonth = getStartWeekDayOfMonth(month, year);\n const today = dateToDay(new Date());\n\n const dayRefs = useRef<Record<number, HTMLDivElement | null>>({});\n const [focusedDay, setFocusedDay] = useState(() => getDefaultFocusedDay(month, year, selectionStart));\n\n // A day arrowed onto in an adjacent month, waiting for that month's grid to render so it\n // can be focused. `onNavigateMonth` only shifts `month`/`year` — the actual DOM focus has\n // to happen after this component re-renders with the new days, hence the effect below.\n const pendingFocusDayRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (pendingFocusDayRef.current != null) {\n const day = pendingFocusDayRef.current;\n pendingFocusDayRef.current = null;\n setFocusedDay(day);\n dayRefs.current[day]?.focus();\n } else {\n // The displayed month changed some other way (header chevrons, month/year dropdowns) —\n // re-pick a sensible tab stop, but don't steal focus from whatever the user just used.\n setFocusedDay(getDefaultFocusedDay(month, year, selectionStart));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [month, year]);\n\n function handleDayKeyDown(event: React.KeyboardEvent<HTMLDivElement>, day: number) {\n let delta = 0;\n if (event.key === 'ArrowRight') delta = 1;\n else if (event.key === 'ArrowLeft') delta = -1;\n else if (event.key === 'ArrowDown') delta = 7;\n else if (event.key === 'ArrowUp') delta = -7;\n else return;\n\n event.preventDefault();\n const next = addDays(day, month, year, delta);\n\n if (next.month !== month || next.year !== year) {\n pendingFocusDayRef.current = next.day;\n onNavigateMonth?.(next.month > month || next.year > year ? 1 : -1);\n } else {\n setFocusedDay(next.day);\n dayRefs.current[next.day]?.focus();\n }\n }\n\n return (\n <div className={cx(styles.datePickerMonth, className)} style={style}>\n <div className={cx(styles.datePickerMonthContent)}>\n {getWeekDays(locale).map((weekDay, index) => (\n <div key={index}>{weekDay}</div>\n ))}\n {Array.from(Array(startWeekDayOfMonth - 1).keys()).map((index) => (\n <div key={index} className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)} />\n ))}\n {Array.from(Array(dayCount).keys()).map((index) => {\n const day = index + 1;\n const value = formatDay({ day, month, year });\n const selectedRes = checkSelected(value, selectionStart, selectionEnd);\n const isDisabled = checkDisabled(value, minDate, maxDate);\n const isToday = value === today;\n\n return (\n <InteractableDiv\n key={day}\n ref={(el) => {\n dayRefs.current[day] = el;\n }}\n tabIndex={day === focusedDay ? 0 : -1}\n onKeyDown={(event) => handleDayKeyDown(event, day)}\n onClick={() => (isDisabled ? null : onSelect(value))}\n className={cx(styles.datePickerMonthDay, styles.datePickerMonthItem, {\n [styles.datePickerMonthDaySelected]: selectedRes.isInRange,\n [styles.datePickerMonthDaySelectedStart]: selectedRes.isStartDate,\n [styles.datePickerMonthDaySelectedEnd]: selectedRes.isEndDate,\n [styles.datePickerMonthDayDisabled]: isDisabled,\n [styles.datePickerMonthDayToday]: isToday,\n })}\n >\n {day}\n </InteractableDiv>\n );\n })}\n {Array.from(Array(42 - (startWeekDayOfMonth + dayCount - 1)).keys()).map((index) => (\n <div key={index} className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}>\n &nbsp;\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";import{getLocale as e}from"../../services/localization.mjs";function t(e,t){return new Date(t,e,0).getDate()}function n(e,t,n){return new Date(Date.UTC(n,t-1,e))}function r(e,t,n,r,i=!1){return new Date(Date.UTC(t,n-1,r)).toLocaleDateString(e,{month:i?`short`:`long`})}function i(t=e(`-`)){return Array.from(Array(12).keys()).map(e=>r(t,2023,e+1,1))}function a(e,t=!0){let n=new Date(Date.UTC(2023,3,10)),r=[];for(let i=0;i<7;i++)r.push(n.toLocaleDateString(e,{weekday:t?`short`:`long`})),n.setDate(n.getDate()+1);return r}function o(e,t){return new Date(Date.UTC(t,e-1,1)).getDay()||7}function s(e,n,r,i){let a=e+i,o=n,s=r;for(;a<1;)--o,o<1&&(o=12,--s),a+=t(o,s);for(;a>t(o,s);)a-=t(o,s),o+=1,o>12&&(o=1,s+=1);return{day:a,month:o,year:s}}function c(e){return{day:e.getDate(),month:e.getMonth()+1,year:e.getFullYear()}}function l(e){let t=e.getDate(),n=e.getMonth()+1,r=e.getFullYear();return`${t<10?`0${t}`:t}.${n<10?`0${n}`:n}.${r}`}function u(e,t,n){let r=e,i=n;return r[0]!==`_`&&(r[0]>`3`?(r=`0${r[0]}${t.substring(2)}`,i={start:3,end:3}):r[0]===`3`&&r[1]!==`_`&&r[1]>`1`&&(r=`0${r[1]}${t.substring(2)}`,i={start:3,end:3})),r[3]!==`_`&&r[3]>`1`&&(r=`${r.substring(0,3)}0${r[3]}${t.substring(5)}`,i={start:6,end:6}),r[3]===`1`&&r[4]!==`_`&&r[4]>`2`&&(r=`${r.substring(0,3)}${r[3]}2${t.substring(5)}`),{value:r,selection:i}}export{s as addDays,u as correctDateMaskValue,n as getDateFromDayMonthAndYear,l as getDateString,c as getDayMonthAndYearOfDate,t as getDaysInMonth,r as getMonthName,i as getMonthNames,o as getStartWeekDayOfMonth,a as getWeekDays};
1
+ "use client";import{getLocale as e}from"../../services/localization.mjs";import{dateToDay as t,daysInMonth as n,formatDay as r,parseDay as i}from"../utils/day.mjs";function a(e,t,n){let r=new Date(0);return r.setUTCFullYear(e,t-1,n),r}function o(e,t,n,r,i=!1){return a(t,n,r).toLocaleDateString(e,{month:i?`short`:`long`,timeZone:`UTC`})}function s(t=e(`-`)){return Array.from(Array(12).keys()).map(e=>o(t,2023,e+1,1))}function c(e,t=!0){return Array.from(Array(7).keys()).map(n=>a(2023,4,10+n).toLocaleDateString(e,{weekday:t?`short`:`long`,timeZone:`UTC`}))}function l(e,t){return a(t,e,1).getUTCDay()||7}function u(e,t,r,i){let a=e+i,o=t,s=r;for(;a<1;)--o,o<1&&(o=12,--s),a+=n({year:s,month:o});for(;a>n({year:s,month:o});)a-=n({year:s,month:o}),o+=1,o>12&&(o=1,s+=1);return{day:a,month:o,year:s}}function d(){return i(t(new Date))}function f(e){let t=i(e);return t?`${String(t.day).padStart(2,`0`)}.${String(t.month).padStart(2,`0`)}.${String(t.year).padStart(4,`0`)}`:``}function p(e){let t=/^(\d{2})\.(\d{2})\.(\d{4})$/.exec(e);if(!t)return null;let n=r({day:Number(t[1]),month:Number(t[2]),year:Number(t[3])});return i(n)?n:null}function m(e,t,n){let r=e,i=n;return r[0]!==`_`&&(r[0]>`3`?(r=`0${r[0]}${t.substring(2)}`,i={start:3,end:3}):r[0]===`3`&&r[1]!==`_`&&r[1]>`1`&&(r=`0${r[1]}${t.substring(2)}`,i={start:3,end:3})),r[3]!==`_`&&r[3]>`1`&&(r=`${r.substring(0,3)}0${r[3]}${t.substring(5)}`,i={start:6,end:6}),r[3]===`1`&&r[4]!==`_`&&r[4]>`2`&&(r=`${r.substring(0,3)}${r[3]}2${t.substring(5)}`),{value:r,selection:i}}export{u as addDays,m as correctDateMaskValue,f as getDateString,o as getMonthName,s as getMonthNames,l as getStartWeekDayOfMonth,d as getToday,c as getWeekDays,p as parseDateString};
2
2
  //# sourceMappingURL=dateFunctions.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dateFunctions.mjs","names":[],"sources":["../../../../package/common/datePicker/dateFunctions.ts"],"sourcesContent":["import { getLocale } from 'services/localization';\n\nexport function getDaysInMonth(month: number, year: number): number {\n return new Date(year, month, 0).getDate();\n}\n\nexport function getDateFromDayMonthAndYear(day: number, month: number, year: number): Date {\n return new Date(Date.UTC(year, month - 1, day));\n}\n\nexport function getMonthName(locale: string, year: number, month: number, day: number, short = false): string {\n const currDate = new Date(Date.UTC(year, month - 1, day));\n return currDate.toLocaleDateString(locale, { month: short ? 'short' : 'long' });\n}\n\nexport function getMonthNames(locale = getLocale('-')): string[] {\n return Array.from(Array(12).keys()).map((index) => getMonthName(locale, 2023, index + 1, 1));\n}\n\nexport function getWeekDays(locale: string, short = true): string[] {\n const currDate = new Date(Date.UTC(2023, 3, 10)); // Random Monday - 10.4.2023\n const weekDays: string[] = [];\n for (let i = 0; i < 7; i++) {\n weekDays.push(currDate.toLocaleDateString(locale, { weekday: short ? 'short' : 'long' }));\n currDate.setDate(currDate.getDate() + 1);\n }\n return weekDays;\n}\n\nexport function getStartWeekDayOfMonth(month: number, year: number): number {\n const start = new Date(Date.UTC(year, month - 1, 1)).getDay();\n return start || 7;\n}\n\n/**\n * Adds `delta` days to a day/month/year triple, rolling over into adjacent months/years as\n * needed. Pure integer arithmetic over `getDaysInMonth` rather than a `Date` object, so it\n * can't drift a day from local-vs-UTC ambiguity the way mutating a UTC-constructed `Date`\n * with its local `setDate` would.\n */\nexport function addDays(\n day: number,\n month: number,\n year: number,\n delta: number,\n): { day: number; month: number; year: number } {\n let d = day + delta;\n let m = month;\n let y = year;\n while (d < 1) {\n m -= 1;\n if (m < 1) {\n m = 12;\n y -= 1;\n }\n d += getDaysInMonth(m, y);\n }\n while (d > getDaysInMonth(m, y)) {\n d -= getDaysInMonth(m, y);\n m += 1;\n if (m > 12) {\n m = 1;\n y += 1;\n }\n }\n return { day: d, month: m, year: y };\n}\n\nexport function getDayMonthAndYearOfDate(date: Date): { day: number; month: number; year: number } {\n return {\n day: date.getDate(),\n month: date.getMonth() + 1,\n year: date.getFullYear(),\n };\n}\n\nexport function getDateString(date: Date): string {\n const day = date.getDate();\n const month = date.getMonth() + 1;\n const year = date.getFullYear();\n\n return `${day < 10 ? `0${day}` : day}.${month < 10 ? `0${month}` : month}.${year}`;\n}\n\nexport interface DateMaskSelection {\n start: number;\n end: number;\n}\n\nexport interface DateMaskState {\n value: string;\n selection: DateMaskSelection | null;\n}\n\n/**\n * Auto-corrects a partially typed `dd.mm.yyyy` mask value so a single out-of-range\n * digit doesn't force the user to backtrack:\n * - a day \"tens\" digit > 3 (e.g. typing `4`) becomes `04` and the caret jumps to the month\n * - a day of `3x` where x > 1 (e.g. `35`) becomes `0x`\n * - a month \"tens\" digit > 1 (e.g. `2`) becomes `02` and the caret jumps to the year\n * - a month `1x` where x > 2 (e.g. `13`) is clamped to `12`\n *\n * `previousValue` supplies the digits to retain for the part of the field that isn't\n * being rewritten. The returned `selection` is the adjusted caret position, or the\n * passed-in `selection` when no correction applies.\n */\nexport function correctDateMaskValue(\n nextValue: string,\n previousValue: string,\n selection: DateMaskSelection | null,\n): DateMaskState {\n let value = nextValue;\n let nextSelection = selection;\n\n if (value[0] !== '_') {\n if (value[0] > '3') {\n value = `0${value[0]}${previousValue.substring(2)}`;\n nextSelection = { start: 3, end: 3 };\n } else if (value[0] === '3') {\n if (value[1] !== '_' && value[1] > '1') {\n value = `0${value[1]}${previousValue.substring(2)}`;\n nextSelection = { start: 3, end: 3 };\n }\n }\n }\n if (value[3] !== '_' && value[3] > '1') {\n value = `${value.substring(0, 3)}0${value[3]}${previousValue.substring(5)}`;\n nextSelection = { start: 6, end: 6 };\n }\n if (value[3] === '1' && value[4] !== '_' && value[4] > '2') {\n value = `${value.substring(0, 3)}${value[3]}2${previousValue.substring(5)}`;\n }\n\n return { value, selection: nextSelection };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dateFunctions.mjs","names":[],"sources":["../../../../package/common/datePicker/dateFunctions.ts"],"sourcesContent":["import { getLocale } from 'services/localization';\nimport { dateToDay, daysInMonth, formatDay, parseDay, type DayParts } from '../utils/day';\n\n// Labels are formatted from a UTC date in UTC, so no time zone can move them onto another day.\n// `setUTCFullYear` rather than `Date.UTC`, which reads the years 0 to 99 as 1900 to 1999.\nfunction utcDate(year: number, month: number, day: number): Date {\n const date = new Date(0);\n date.setUTCFullYear(year, month - 1, day);\n return date;\n}\n\nexport function getMonthName(locale: string, year: number, month: number, day: number, short = false): string {\n return utcDate(year, month, day).toLocaleDateString(locale, { month: short ? 'short' : 'long', timeZone: 'UTC' });\n}\n\nexport function getMonthNames(locale = getLocale('-')): string[] {\n return Array.from(Array(12).keys()).map((index) => getMonthName(locale, 2023, index + 1, 1));\n}\n\nexport function getWeekDays(locale: string, short = true): string[] {\n // 10 April 2023 was a Monday.\n return Array.from(Array(7).keys()).map((index) =>\n utcDate(2023, 4, 10 + index).toLocaleDateString(locale, { weekday: short ? 'short' : 'long', timeZone: 'UTC' }),\n );\n}\n\n/** 1 (Monday) to 7 (Sunday). */\nexport function getStartWeekDayOfMonth(month: number, year: number): number {\n return utcDate(year, month, 1).getUTCDay() || 7;\n}\n\n/** `delta` days from a day, rolling over into the months and years around it. */\nexport function addDays(day: number, month: number, year: number, delta: number): DayParts {\n let d = day + delta;\n let m = month;\n let y = year;\n while (d < 1) {\n m -= 1;\n if (m < 1) {\n m = 12;\n y -= 1;\n }\n d += daysInMonth({ year: y, month: m });\n }\n while (d > daysInMonth({ year: y, month: m })) {\n d -= daysInMonth({ year: y, month: m });\n m += 1;\n if (m > 12) {\n m = 1;\n y += 1;\n }\n }\n return { day: d, month: m, year: y };\n}\n\n/** Today in the user's time zone. */\nexport function getToday(): DayParts {\n return parseDay(dateToDay(new Date()))!;\n}\n\n/** A `'YYYY-MM-DD'` day as the field shows it, `dd.mm.yyyy`, or `''` for anything else. */\nexport function getDateString(value: string | null | undefined): string {\n const parts = parseDay(value);\n if (!parts) return '';\n return `${String(parts.day).padStart(2, '0')}.${String(parts.month).padStart(2, '0')}.${String(parts.year).padStart(4, '0')}`;\n}\n\n/** What the field holds, `dd.mm.yyyy`, as `'YYYY-MM-DD'`; `null` while incomplete, or for a day that does not exist. */\nexport function parseDateString(text: string): string | null {\n const match = /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/.exec(text);\n if (!match) return null;\n const value = formatDay({ day: Number(match[1]), month: Number(match[2]), year: Number(match[3]) });\n return parseDay(value) ? value : null;\n}\n\nexport interface DateMaskSelection {\n start: number;\n end: number;\n}\n\nexport interface DateMaskState {\n value: string;\n selection: DateMaskSelection | null;\n}\n\n/**\n * Auto-corrects a partially typed `dd.mm.yyyy` mask value so a single out-of-range\n * digit doesn't force the user to backtrack:\n * - a day \"tens\" digit > 3 (e.g. typing `4`) becomes `04` and the caret jumps to the month\n * - a day of `3x` where x > 1 (e.g. `35`) becomes `0x`\n * - a month \"tens\" digit > 1 (e.g. `2`) becomes `02` and the caret jumps to the year\n * - a month `1x` where x > 2 (e.g. `13`) is clamped to `12`\n *\n * `previousValue` supplies the digits to retain for the part of the field that isn't\n * being rewritten. The returned `selection` is the adjusted caret position, or the\n * passed-in `selection` when no correction applies.\n */\nexport function correctDateMaskValue(\n nextValue: string,\n previousValue: string,\n selection: DateMaskSelection | null,\n): DateMaskState {\n let value = nextValue;\n let nextSelection = selection;\n\n if (value[0] !== '_') {\n if (value[0] > '3') {\n value = `0${value[0]}${previousValue.substring(2)}`;\n nextSelection = { start: 3, end: 3 };\n } else if (value[0] === '3') {\n if (value[1] !== '_' && value[1] > '1') {\n value = `0${value[1]}${previousValue.substring(2)}`;\n nextSelection = { start: 3, end: 3 };\n }\n }\n }\n if (value[3] !== '_' && value[3] > '1') {\n value = `${value.substring(0, 3)}0${value[3]}${previousValue.substring(5)}`;\n nextSelection = { start: 6, end: 6 };\n }\n if (value[3] === '1' && value[4] !== '_' && value[4] > '2') {\n value = `${value.substring(0, 3)}${value[3]}2${previousValue.substring(5)}`;\n }\n\n return { value, selection: nextSelection };\n}\n"],"mappings":"oKAKA,SAAS,EAAQ,EAAc,EAAe,EAAmB,CAC/D,IAAM,EAAO,IAAI,KAAK,CAAC,EAEvB,OADA,EAAK,eAAe,EAAM,EAAQ,EAAG,CAAG,EACjC,CACT,CAEA,SAAgB,EAAa,EAAgB,EAAc,EAAe,EAAa,EAAQ,GAAe,CAC5G,OAAO,EAAQ,EAAM,EAAO,CAAG,CAAC,CAAC,mBAAmB,EAAQ,CAAE,MAAO,EAAQ,QAAU,OAAQ,SAAU,KAAM,CAAC,CAClH,CAEA,SAAgB,EAAc,EAAS,EAAU,GAAG,EAAa,CAC/D,OAAO,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAK,GAAU,EAAa,EAAQ,KAAM,EAAQ,EAAG,CAAC,CAAC,CAC7F,CAEA,SAAgB,EAAY,EAAgB,EAAQ,GAAgB,CAElE,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAK,GACtC,EAAQ,KAAM,EAAG,GAAK,CAAK,CAAC,CAAC,mBAAmB,EAAQ,CAAE,QAAS,EAAQ,QAAU,OAAQ,SAAU,KAAM,CAAC,CAChH,CACF,CAGA,SAAgB,EAAuB,EAAe,EAAsB,CAC1E,OAAO,EAAQ,EAAM,EAAO,CAAC,CAAC,CAAC,UAAU,GAAK,CAChD,CAGA,SAAgB,EAAQ,EAAa,EAAe,EAAc,EAAyB,CACzF,IAAI,EAAI,EAAM,EACV,EAAI,EACJ,EAAI,EACR,KAAO,EAAI,GACT,IACI,EAAI,IACN,EAAI,GACJ,KAEF,GAAK,EAAY,CAAE,KAAM,EAAG,MAAO,CAAE,CAAC,EAExC,KAAO,EAAI,EAAY,CAAE,KAAM,EAAG,MAAO,CAAE,CAAC,GAC1C,GAAK,EAAY,CAAE,KAAM,EAAG,MAAO,CAAE,CAAC,EACtC,GAAK,EACD,EAAI,KACN,EAAI,EACJ,GAAK,GAGT,MAAO,CAAE,IAAK,EAAG,MAAO,EAAG,KAAM,CAAE,CACrC,CAGA,SAAgB,GAAqB,CACnC,OAAO,EAAS,EAAU,IAAI,IAAM,CAAC,CACvC,CAGA,SAAgB,EAAc,EAA0C,CACtE,IAAM,EAAQ,EAAS,CAAK,EAE5B,OADK,EACE,GAAG,OAAO,EAAM,GAAG,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAAG,OAAO,EAAM,KAAK,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAAG,OAAO,EAAM,IAAI,CAAC,CAAC,SAAS,EAAG,GAAG,IADvG,EAErB,CAGA,SAAgB,EAAgB,EAA6B,CAC3D,IAAM,EAAQ,8BAA8B,KAAK,CAAI,EACrD,GAAI,CAAC,EAAO,OAAO,KACnB,IAAM,EAAQ,EAAU,CAAE,IAAK,OAAO,EAAM,EAAE,EAAG,MAAO,OAAO,EAAM,EAAE,EAAG,KAAM,OAAO,EAAM,EAAE,CAAE,CAAC,EAClG,OAAO,EAAS,CAAK,EAAI,EAAQ,IACnC,CAwBA,SAAgB,EACd,EACA,EACA,EACe,CACf,IAAI,EAAQ,EACR,EAAgB,EAqBpB,OAnBI,EAAM,KAAO,MACX,EAAM,GAAK,KACb,EAAQ,IAAI,EAAM,KAAK,EAAc,UAAU,CAAC,IAChD,EAAgB,CAAE,MAAO,EAAG,IAAK,CAAE,GAC1B,EAAM,KAAO,KAClB,EAAM,KAAO,KAAO,EAAM,GAAK,MACjC,EAAQ,IAAI,EAAM,KAAK,EAAc,UAAU,CAAC,IAChD,EAAgB,CAAE,MAAO,EAAG,IAAK,CAAE,IAIrC,EAAM,KAAO,KAAO,EAAM,GAAK,MACjC,EAAQ,GAAG,EAAM,UAAU,EAAG,CAAC,EAAE,GAAG,EAAM,KAAK,EAAc,UAAU,CAAC,IACxE,EAAgB,CAAE,MAAO,EAAG,IAAK,CAAE,GAEjC,EAAM,KAAO,KAAO,EAAM,KAAO,KAAO,EAAM,GAAK,MACrD,EAAQ,GAAG,EAAM,UAAU,EAAG,CAAC,IAAI,EAAM,GAAG,GAAG,EAAc,UAAU,CAAC,KAGnE,CAAE,QAAO,UAAW,CAAc,CAC3C"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{PopoverAlign as r,PopoverPlacement as i}from"../popover/popover.types.mjs";import ee from"../popover/popover.mjs";import te from"../tooltip/tooltip.mjs";import ne from"../input/input.mjs";import a from"../modal/modal.mjs";import{getLocale as o}from"../../services/localization.mjs";import{correctDateMaskValue as re,getDateFromDayMonthAndYear as ie,getDateString as s,getMonthName as ae,getMonthNames as oe}from"./dateFunctions.mjs";import se from"./components/datePickerMonth/datePickerMonth.mjs";import c from"../dropdown/dropdown.mjs";import ce from"../maskedInput/maskedInput.mjs";import l from"./datePicker.module.mjs";import{useEffect as le,useRef as u,useState as d}from"react";import f from"classnames";import{faChevronLeft as p,faChevronRight as m}from"@fortawesome/free-solid-svg-icons";import{Fragment as ue,jsx as h,jsxs as g}from"react/jsx-runtime";function _(_){let{className:de=``,selected:v,onSelect:fe=()=>null,formValidator:y=null,noInput:pe=!1,noHeader:me=!1,isModal:b=!1,isInline:x=!1,onChange:he=()=>null,minDate:S=null,maxDate:C=null,children:ge=null,showClearButton:_e=!1,label:ve=``,isValid:ye=!0,errorMessage:w=``,isRequired:T=!1,startDate:E,endDate:D,style:O,classNames:k,styles:A,...j}=e(`DatePicker`,_),M=()=>y?y.value:v,N=M()??new Date,[P,F]=d(N.getMonth()+1),[I,L]=d(N.getFullYear()),[R,z]=d(!1),[B,V]=d(()=>M()?s(N):``),[be,H]=d(!1),[xe,U]=d(!1),[,Se]=d(0),[Ce,we]=d(v),W=u(y);if(Ce!==v){we(v);let e=v??new Date;F(e.getMonth()+1),L(e.getFullYear()),V(v?s(v):``)}le(()=>{if(W.current=y,!y)return;let e=()=>{let e=y.value;e?(F(e.getMonth()+1),L(e.getFullYear()),V(s(e))):V(``),Se(e=>e+1)};return y.registerOnUpdateListener(e),()=>y.removeOnUpdateListener(e)},[y]);let Te=()=>y?y.touched&&y.hasError():!ye||!!w,Ee=()=>!!(T||y?.validators.find(e=>e.validatorId===`required`)),G=e=>{V(e?s(e):``),y&&y.set(e),he(e)},K=e=>{G(e),fe(e),z(!1)},q=e=>{F(t=>{let n=t+e;return n<1?(n=12,L(e=>e-1)):n>12&&(n=1,L(e=>e+1)),n})},J=e=>{if(e.match(/\d{2}\.\d{2}\.\d{4}/gi)){let[t,n,r]=e.split(`.`),i=ie(Number(t),Number(n),Number(r));if(i&&i.toString()!==`Invalid Date`&&(!C||i<=C)&&(!S||i>=S))return i}return null},De=({previousState:e,nextState:t})=>{if(t.value===e.value)return t;let n=re(t.value,e.value,t.selection??null),r=J(n.value);return r&&G(r),n},Y=()=>{let e=400,t=new Date().getFullYear()-200;return S&&(t=S.getFullYear()),C&&(e=C.getFullYear()-t+1),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},X=M(),Z=Te(),Oe=me?null:g(`div`,{className:f(l.datePickerHeader,k?.header),style:A?.header,children:[h(n,{icon:p,onClick:()=>q(-1)}),h(`div`,{className:l.datePickerHeaderMonthAndYearContainer,children:g(`div`,{className:l.datePickerHeaderMonthAndYear,children:[h(c,{plainStyle:!0,scrollToSelected:!0,onChange:e=>F(e),className:f(l.datePickerHeaderMonth,k?.monthDropdown),style:A?.monthDropdown,value:ae(o(`-`),I,P,1),items:oe().map((e,t)=>({key:t+1,label:e}))}),h(c,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:f(l.datePickerHeaderYear,k?.yearDropdown),style:A?.yearDropdown,onChange:e=>L(e),value:I,items:Y()})]})}),h(n,{icon:m,onClick:()=>q(1)})]}),Q=g(ue,{children:[Oe,h(se,{className:f(l.datePickerMonth,k?.calendar),style:A?.calendar,month:P,year:I,onSelect:K,selectionStart:E??X,selectionEnd:D??X,minDate:S,maxDate:C,onNavigateMonth:q}),_e&&h(t,{onClick:()=>K(null),className:k?.clearButton,style:A?.clearButton,children:`Clear`}),ge]}),$=pe?null:h(ne,{autoComplete:`off`,className:k?.input,style:A?.input,readOnly:b,classNames:b?{input:l.datePickerModalInput}:void 0,label:`${ve}${Ee()?` *`:``}`,value:B,onChange:e=>V(e),onClick:()=>z(!0),customInput:h(ce,{mask:`99.99.9999`,beforeMaskedStateChange:De}),onBlur:()=>{W.current&&(W.current.touched=!0),H(!1),G(J(B))},onFocus:()=>H(!0),onMouseEnter:()=>U(!0),onMouseLeave:()=>U(!1),isValid:!Z}),ke=x?Q:b?h(a,{hideHeader:!0,isOpen:R,onClose:()=>z(!1),children:Q}):h(ee,{isOpen:R,onOpenChange:e=>z(e),content:Q,placement:i.Bottom,align:r.Start,closeOnTriggerClick:!1,constrainWidth:!1,children:$});return g(`div`,{...j,className:f(l.datePicker,de,k?.root),style:{...O,...A?.root},children:[(b||x)&&$,ke,h(te,{variant:`error`,message:y?y.getCurrentErrorMessage():w||``,isVisible:Z&&(be||xe)})]})}export{_ as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{PopoverAlign as r,PopoverPlacement as ee}from"../popover/popover.types.mjs";import te from"../popover/popover.mjs";import ne from"../tooltip/tooltip.mjs";import re from"../input/input.mjs";import ie from"../modal/modal.mjs";import{getLocale as ae}from"../../services/localization.mjs";import{asDay as i,parseDay as a}from"../utils/day.mjs";import{correctDateMaskValue as oe,getDateString as o,getMonthName as se,getMonthNames as ce,getToday as s,parseDateString as le}from"./dateFunctions.mjs";import ue from"./components/datePickerMonth/datePickerMonth.mjs";import c from"../dropdown/dropdown.mjs";import de from"../maskedInput/maskedInput.mjs";import l from"./datePicker.module.mjs";import{useEffect as u,useRef as d,useState as f}from"react";import p from"classnames";import{faChevronLeft as fe,faChevronRight as pe}from"@fortawesome/free-solid-svg-icons";import{Fragment as me,jsx as m,jsxs as h}from"react/jsx-runtime";function he(e){return e==null||e===``||i(e)?null:Object.prototype.toString.call(e)===`[object Date]`?`a Date. Convert it with dateToDay()`:`${JSON.stringify(e)}, which is not a day`}function g(g){let{className:ge=``,selected:_,onSelect:_e=()=>null,formValidator:v=null,noInput:ve=!1,noHeader:ye=!1,isModal:y=!1,isInline:b=!1,onChange:be=()=>null,minDate:x=null,maxDate:S=null,children:xe=null,showClearButton:Se=!1,label:C=``,isValid:Ce=!0,errorMessage:w=``,isRequired:we=!1,startDate:T,endDate:E,style:Te,classNames:D,styles:O,...Ee}=e(`DatePicker`,g),k=()=>i(v?v.value:_),A=i(x),j=i(S),M=k(),N=a(M)??s(),[P,F]=f(N.month),[I,L]=f(N.year),[R,z]=f(!1),[B,V]=f(()=>o(M)),[De,H]=f(!1),[Oe,U]=f(!1),[,ke]=f(0),[Ae,je]=f(_),W=d(v);if(Ae!==_){je(_);let e=a(_)??s();F(e.month),L(e.year),V(o(_))}let G=d(new Set),K=v?.value;u(()=>{let e={selected:_,formValidator:K,minDate:x,maxDate:S,startDate:T,endDate:E};for(let[t,n]of Object.entries(e)){let e=he(n);e&&!G.current.has(t)&&(G.current.add(t),console.warn(`DatePicker: \`${t}\` takes a day as a 'YYYY-MM-DD' string, and got ${e}. See "Migration from Date values" in docs/DatePicker.md.`))}},[_,K,x,S,T,E]),u(()=>{if(W.current=v,!v)return;v.label=C,v.validate();let e=()=>{let e=a(v.value);e&&(F(e.month),L(e.year)),V(o(v.value)),ke(e=>e+1)};return v.registerOnUpdateListener(e),()=>v.removeOnUpdateListener(e)},[v,C]);let Me=()=>v?v.touched&&v.hasError():!Ce||!!w,Ne=()=>!!(we||v?.validators.find(e=>e.validatorId===`required`)),q=e=>{V(o(e)),v&&v.set(e),be(e)},J=e=>{q(e),_e(e),z(!1)},Y=e=>{let t=I*12+P-1+e,n=Math.floor(t/12);n<0||n>9999||(L(n),F(t%12+1))},X=e=>{let t=le(e);return!t||A&&t<A||j&&t>j?null:t},Pe=({previousState:e,nextState:t})=>{if(t.value===e.value)return t;let n=oe(t.value,e.value,t.selection??null),r=X(n.value);return r&&q(r),n},Fe=()=>{let e=400,t=s().year-200,n=a(A),r=a(j);return n&&(t=n.year),r&&(e=Math.max(0,r.year-t+1)),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},Z=k(),Ie=Me(),Le=ye?null:h(`div`,{className:p(l.datePickerHeader,D?.header),style:O?.header,children:[m(n,{icon:fe,onClick:()=>Y(-1)}),m(`div`,{className:l.datePickerHeaderMonthAndYearContainer,children:h(`div`,{className:l.datePickerHeaderMonthAndYear,children:[m(c,{plainStyle:!0,scrollToSelected:!0,onChange:e=>F(e),className:p(l.datePickerHeaderMonth,D?.monthDropdown),style:O?.monthDropdown,value:se(ae(`-`),I,P,1),items:ce().map((e,t)=>({key:t+1,label:e}))}),m(c,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:p(l.datePickerHeaderYear,D?.yearDropdown),style:O?.yearDropdown,onChange:e=>L(e),value:I,items:Fe()})]})}),m(n,{icon:pe,onClick:()=>Y(1)})]}),Q=h(me,{children:[Le,m(ue,{className:p(l.datePickerMonth,D?.calendar),style:O?.calendar,month:P,year:I,onSelect:J,selectionStart:i(T)??Z,selectionEnd:i(E)??Z,minDate:A,maxDate:j,onNavigateMonth:Y}),Se&&m(t,{onClick:()=>J(null),className:D?.clearButton,style:O?.clearButton,children:`Clear`}),xe]}),$=ve?null:m(re,{autoComplete:`off`,className:D?.input,style:O?.input,readOnly:y,classNames:y?{input:l.datePickerModalInput}:void 0,label:`${C}${Ne()?` *`:``}`,value:B,onChange:e=>V(e),onClick:()=>z(!0),customInput:m(de,{mask:`99.99.9999`,beforeMaskedStateChange:Pe}),onBlur:()=>{W.current&&(W.current.touched=!0),H(!1),B!==o(k())&&q(X(B))},onFocus:()=>H(!0),onMouseEnter:()=>U(!0),onMouseLeave:()=>U(!1),isValid:!Ie}),Re=b?Q:y?m(ie,{hideHeader:!0,isOpen:R,onClose:()=>z(!1),children:Q}):m(te,{isOpen:R,onOpenChange:e=>z(e),content:Q,placement:ee.Bottom,align:r.Start,closeOnTriggerClick:!1,constrainWidth:!1,children:$});return h(`div`,{...Ee,className:p(l.datePicker,ge,D?.root),style:{...Te,...O?.root},children:[(y||b)&&$,Re,m(ne,{variant:`error`,message:v?v.getCurrentErrorMessage():w||``,isVisible:Ie&&(De||Oe)})]})}export{g as default};
2
2
  //# sourceMappingURL=datePicker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"datePicker.mjs","names":[],"sources":["../../../../package/common/datePicker/datePicker.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport Input from '../input';\nimport { useComponentDefaults } from '../configProvider';\nimport DatePickerMonth from './components/datePickerMonth';\nimport { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\nimport { getLocale } from 'services/localization';\nimport ActionIcon from '../actionIcon';\nimport Modal from '../modal';\nimport Popover from '../popover';\nimport Dropdown from '../dropdown';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport MaskedInput from '../maskedInput';\nimport type { BeforeMaskedStateChangeStates, MaskState } from '../maskedInput';\nimport {\n getDateFromDayMonthAndYear,\n getMonthName,\n getMonthNames,\n getDateString,\n correctDateMaskValue,\n} from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { DatePickerProps } from './datePicker.types';\n\nimport styles from './datePicker.module.pcss';\n\nexport default function DatePicker(props: DatePickerProps) {\n const {\n className = '',\n selected,\n onSelect = () => null,\n formValidator = null,\n noInput = false,\n noHeader = false,\n isModal = false,\n isInline = false,\n onChange = () => null,\n minDate = null,\n maxDate = null,\n children = null,\n showClearButton = false,\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n startDate,\n endDate,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): Date | undefined => (formValidator ? (formValidator.value as Date) : selected);\n\n const initialDate = getCurrValue() ?? new Date();\n\n const [currentMonth, setCurrentMonth] = useState(initialDate.getMonth() + 1);\n const [currentYear, setCurrentYear] = useState(initialDate.getFullYear());\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [currentDateString, setCurrentDateString] = useState(() => (getCurrValue() ? getDateString(initialDate) : ''));\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const [prevSelected, setPrevSelected] = useState(selected);\n\n const fvRef = useRef(formValidator);\n\n // Sync navigation view when `selected` prop changes externally\n if (prevSelected !== selected) {\n setPrevSelected(selected);\n const d = selected ?? new Date();\n setCurrentMonth(d.getMonth() + 1);\n setCurrentYear(d.getFullYear());\n setCurrentDateString(selected ? getDateString(selected) : '');\n }\n\n // Subscribe to formValidator updates (external system → setState in callback)\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => {\n const val = formValidator.value as Date | undefined;\n if (val) {\n setCurrentMonth(val.getMonth() + 1);\n setCurrentYear(val.getFullYear());\n setCurrentDateString(getDateString(val));\n } else {\n setCurrentDateString('');\n }\n forceUpdate((n: number) => n + 1);\n };\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator]);\n\n const hasError = (): boolean => {\n return formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n };\n\n const handleChange = (date: Date | null) => {\n setCurrentDateString(date ? getDateString(date) : '');\n if (formValidator) formValidator.set(date);\n onChange(date);\n };\n\n const handleSelect = (date: Date | null) => {\n handleChange(date);\n onSelect(date);\n setIsPickerOpen(false);\n };\n\n const changeMonth = (delta: number) => {\n setCurrentMonth((prev) => {\n let next = prev + delta;\n if (next < 1) {\n next = 12;\n setCurrentYear((y) => y - 1);\n } else if (next > 12) {\n next = 1;\n setCurrentYear((y) => y + 1);\n }\n return next;\n });\n };\n\n const tryParseDateString = (dateString: string): Date | null => {\n if (dateString.match(/\\d{2}\\.\\d{2}\\.\\d{4}/gi)) {\n const [day, month, year] = dateString.split('.');\n const parsedDate = getDateFromDayMonthAndYear(Number(day), Number(month), Number(year));\n if (parsedDate && parsedDate.toString() !== 'Invalid Date') {\n const isSmallerThanMaxDate = !maxDate || parsedDate <= maxDate;\n const isBiggerThanMinDate = !minDate || parsedDate >= minDate;\n if (isSmallerThanMaxDate && isBiggerThanMinDate) return parsedDate;\n }\n }\n return null;\n };\n\n const beforeMaskedStateChange = ({ previousState, nextState }: BeforeMaskedStateChangeStates): MaskState => {\n // A change that moved nothing needs no correcting, and re-running the day/month padding on\n // an unchanged value would fight the caret the mask just placed.\n if (nextState.value === previousState.value) return nextState;\n\n const corrected = correctDateMaskValue(nextState.value, previousState.value, nextState.selection ?? null);\n\n const parsedDate = tryParseDateString(corrected.value);\n if (parsedDate) handleChange(parsedDate);\n\n return corrected;\n };\n\n const getYearDropdownOptions = () => {\n let length = 400;\n let zeroOffset = new Date().getFullYear() - 200;\n if (minDate) zeroOffset = minDate.getFullYear();\n if (maxDate) length = maxDate.getFullYear() - zeroOffset + 1;\n return Array.from(Array(length).keys()).map((i) => ({ key: i + zeroOffset, label: i + zeroOffset }));\n };\n\n const currValue = getCurrValue();\n const hasErr = hasError();\n\n const header = noHeader ? null : (\n <div className={cx(styles.datePickerHeader, classNames?.header)} style={slotStyles?.header}>\n <ActionIcon icon={faChevronLeft} onClick={() => changeMonth(-1)} />\n <div className={styles.datePickerHeaderMonthAndYearContainer}>\n <div className={styles.datePickerHeaderMonthAndYear}>\n <Dropdown\n plainStyle\n scrollToSelected\n onChange={(v) => setCurrentMonth(v as number)}\n className={cx(styles.datePickerHeaderMonth, classNames?.monthDropdown)}\n style={slotStyles?.monthDropdown}\n value={getMonthName(getLocale('-'), currentYear, currentMonth, 1)}\n items={getMonthNames().map((month, index) => ({ key: index + 1, label: month }))}\n />\n <Dropdown\n plainStyle\n scrollToSelected\n useMatLabelStyle={false}\n className={cx(styles.datePickerHeaderYear, classNames?.yearDropdown)}\n style={slotStyles?.yearDropdown}\n onChange={(v) => setCurrentYear(v as number)}\n value={currentYear}\n items={getYearDropdownOptions()}\n />\n </div>\n </div>\n <ActionIcon icon={faChevronRight} onClick={() => changeMonth(1)} />\n </div>\n );\n\n const pickerContent = (\n <>\n {header}\n <DatePickerMonth\n className={cx(styles.datePickerMonth, classNames?.calendar)}\n style={slotStyles?.calendar}\n month={currentMonth}\n year={currentYear}\n onSelect={handleSelect}\n selectionStart={startDate ?? currValue}\n selectionEnd={endDate ?? currValue}\n minDate={minDate}\n maxDate={maxDate}\n onNavigateMonth={changeMonth}\n />\n {showClearButton && (\n <Button onClick={() => handleSelect(null)} className={classNames?.clearButton} style={slotStyles?.clearButton}>\n Clear\n </Button>\n )}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <Input\n autoComplete='off'\n className={classNames?.input}\n style={slotStyles?.input}\n readOnly={isModal}\n classNames={isModal ? { input: styles.datePickerModalInput } : undefined}\n label={`${label}${computedIsRequired() ? ' *' : ''}`}\n value={currentDateString}\n onChange={(v) => setCurrentDateString(v as string)}\n onClick={() => setIsPickerOpen(true)}\n customInput={<MaskedInput mask='99.99.9999' beforeMaskedStateChange={beforeMaskedStateChange} />}\n onBlur={() => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n handleChange(tryParseDateString(currentDateString));\n }}\n onFocus={() => setIsFocused(true)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n isValid={!hasErr}\n />\n );\n\n const picker = (() => {\n if (isInline) return pickerContent;\n if (isModal) {\n return (\n <Modal hideHeader isOpen={isPickerOpen} onClose={() => setIsPickerOpen(false)}>\n {pickerContent}\n </Modal>\n );\n }\n return (\n <Popover\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n // A click to place the caret in the field must not take the panel away.\n // The focus stays there on its own: Popover only follows a keyboard open.\n closeOnTriggerClick={false}\n constrainWidth={false}\n >\n {input}\n </Popover>\n );\n })();\n\n return (\n <div\n {...rest}\n className={cx(styles.datePicker, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {(isModal || isInline) && input}\n {picker}\n <Tooltip\n variant='error'\n message={formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || ''}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"datePicker.mjs","names":[],"sources":["../../../../package/common/datePicker/datePicker.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport Input from '../input';\nimport { useComponentDefaults } from '../configProvider';\nimport DatePickerMonth from './components/datePickerMonth';\nimport { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\nimport { getLocale } from 'services/localization';\nimport ActionIcon from '../actionIcon';\nimport Modal from '../modal';\nimport Popover from '../popover';\nimport Dropdown from '../dropdown';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport MaskedInput from '../maskedInput';\nimport type { BeforeMaskedStateChangeStates, MaskState } from '../maskedInput';\nimport { asDay, parseDay } from '../utils/day';\nimport {\n getMonthName,\n getMonthNames,\n getDateString,\n getToday,\n parseDateString,\n correctDateMaskValue,\n} from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { FormValidator } from 'services/formValidation';\nimport type { DatePickerProps } from './datePicker.types';\n\nimport styles from './datePicker.module.pcss';\n\n/**\n * Why `value` is not a day, or `null` when it is one or is empty. Days were `Date`s before 0.39,\n * and stored as their JSON, a timestamp; either still gets through a loosely typed validator or\n * plain JavaScript, and would otherwise just show an empty field.\n */\nfunction notADay(value: unknown): string | null {\n if (value === null || value === undefined || value === '' || asDay(value)) return null;\n if (Object.prototype.toString.call(value) === '[object Date]') return 'a Date. Convert it with dateToDay()';\n return `${JSON.stringify(value)}, which is not a day`;\n}\n\nexport default function DatePicker(props: DatePickerProps) {\n const {\n className = '',\n selected,\n onSelect = () => null,\n formValidator = null,\n noInput = false,\n noHeader = false,\n isModal = false,\n isInline = false,\n onChange = () => null,\n minDate = null,\n maxDate = null,\n children = null,\n showClearButton = false,\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n startDate,\n endDate,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): string | null => asDay(formValidator ? formValidator.value : selected);\n const minDay = asDay(minDate);\n const maxDay = asDay(maxDate);\n\n const initialValue = getCurrValue();\n const initialDay = parseDay(initialValue) ?? getToday();\n\n const [currentMonth, setCurrentMonth] = useState(initialDay.month);\n const [currentYear, setCurrentYear] = useState(initialDay.year);\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [currentDateString, setCurrentDateString] = useState(() => getDateString(initialValue));\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const [prevSelected, setPrevSelected] = useState(selected);\n\n const fvRef = useRef(formValidator);\n\n // Sync navigation view when `selected` prop changes externally\n if (prevSelected !== selected) {\n setPrevSelected(selected);\n const shown = parseDay(selected) ?? getToday();\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n setCurrentDateString(getDateString(selected));\n }\n\n // Once per prop: a `new Date()` written inline is a new object on every render.\n const warned = useRef(new Set<string>());\n const validatorValue: unknown = formValidator?.value;\n useEffect(() => {\n const values = { selected, formValidator: validatorValue, minDate, maxDate, startDate, endDate };\n for (const [name, value] of Object.entries(values)) {\n const problem = notADay(value);\n if (!problem || warned.current.has(name)) continue;\n warned.current.add(name);\n console.warn(\n `DatePicker: \\`${name}\\` takes a day as a 'YYYY-MM-DD' string, and got ${problem}. ` +\n `See \"Migration from Date values\" in docs/DatePicker.md.`,\n );\n }\n }, [selected, validatorValue, minDate, maxDate, startDate, endDate]);\n\n // Subscribe to formValidator updates (external system → setState in callback)\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n formValidator.label = label;\n formValidator.validate();\n const listener = () => {\n const shown = parseDay(formValidator.value);\n if (shown) {\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n }\n setCurrentDateString(getDateString(formValidator.value));\n forceUpdate((n: number) => n + 1);\n };\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator, label]);\n\n const hasError = (): boolean => {\n return formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n };\n\n const handleChange = (day: string | null) => {\n setCurrentDateString(getDateString(day));\n // Typed as a union so each validator TypeScript infers for a day fits; all of them hold one.\n if (formValidator) (formValidator as FormValidator<string | null>).set(day);\n onChange(day);\n };\n\n const handleSelect = (day: string | null) => {\n handleChange(day);\n onSelect(day);\n setIsPickerOpen(false);\n };\n\n const changeMonth = (delta: number) => {\n const index = currentYear * 12 + currentMonth - 1 + delta;\n const year = Math.floor(index / 12);\n // A day is written with four digits, so the calendar stops at the years it can name.\n if (year < 0 || year > 9999) return;\n setCurrentYear(year);\n setCurrentMonth((index % 12) + 1);\n };\n\n const tryParseDateString = (text: string): string | null => {\n const day = parseDateString(text);\n // `'YYYY-MM-DD'` sorts as it reads, so the bounds compare as plain strings.\n if (!day || (minDay && day < minDay) || (maxDay && day > maxDay)) return null;\n return day;\n };\n\n const beforeMaskedStateChange = ({ previousState, nextState }: BeforeMaskedStateChangeStates): MaskState => {\n // A change that moved nothing needs no correcting, and re-running the day/month padding on\n // an unchanged value would fight the caret the mask just placed.\n if (nextState.value === previousState.value) return nextState;\n\n const corrected = correctDateMaskValue(nextState.value, previousState.value, nextState.selection ?? null);\n\n const parsed = tryParseDateString(corrected.value);\n if (parsed) handleChange(parsed);\n\n return corrected;\n };\n\n const getYearDropdownOptions = () => {\n let length = 400;\n let zeroOffset = getToday().year - 200;\n const min = parseDay(minDay);\n const max = parseDay(maxDay);\n if (min) zeroOffset = min.year;\n // Never negative: a `maxDate` before `minDate` made `Array(length)` throw during render.\n if (max) length = Math.max(0, max.year - zeroOffset + 1);\n return Array.from(Array(length).keys()).map((i) => ({ key: i + zeroOffset, label: i + zeroOffset }));\n };\n\n const currValue = getCurrValue();\n const hasErr = hasError();\n\n const header = noHeader ? null : (\n <div className={cx(styles.datePickerHeader, classNames?.header)} style={slotStyles?.header}>\n <ActionIcon icon={faChevronLeft} onClick={() => changeMonth(-1)} />\n <div className={styles.datePickerHeaderMonthAndYearContainer}>\n <div className={styles.datePickerHeaderMonthAndYear}>\n <Dropdown\n plainStyle\n scrollToSelected\n onChange={(v) => setCurrentMonth(v as number)}\n className={cx(styles.datePickerHeaderMonth, classNames?.monthDropdown)}\n style={slotStyles?.monthDropdown}\n value={getMonthName(getLocale('-'), currentYear, currentMonth, 1)}\n items={getMonthNames().map((month, index) => ({ key: index + 1, label: month }))}\n />\n <Dropdown\n plainStyle\n scrollToSelected\n useMatLabelStyle={false}\n className={cx(styles.datePickerHeaderYear, classNames?.yearDropdown)}\n style={slotStyles?.yearDropdown}\n onChange={(v) => setCurrentYear(v as number)}\n value={currentYear}\n items={getYearDropdownOptions()}\n />\n </div>\n </div>\n <ActionIcon icon={faChevronRight} onClick={() => changeMonth(1)} />\n </div>\n );\n\n const pickerContent = (\n <>\n {header}\n <DatePickerMonth\n className={cx(styles.datePickerMonth, classNames?.calendar)}\n style={slotStyles?.calendar}\n month={currentMonth}\n year={currentYear}\n onSelect={handleSelect}\n selectionStart={asDay(startDate) ?? currValue}\n selectionEnd={asDay(endDate) ?? currValue}\n minDate={minDay}\n maxDate={maxDay}\n onNavigateMonth={changeMonth}\n />\n {showClearButton && (\n <Button onClick={() => handleSelect(null)} className={classNames?.clearButton} style={slotStyles?.clearButton}>\n Clear\n </Button>\n )}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <Input\n autoComplete='off'\n className={classNames?.input}\n style={slotStyles?.input}\n readOnly={isModal}\n classNames={isModal ? { input: styles.datePickerModalInput } : undefined}\n label={`${label}${computedIsRequired() ? ' *' : ''}`}\n value={currentDateString}\n onChange={(v) => setCurrentDateString(v as string)}\n onClick={() => setIsPickerOpen(true)}\n customInput={<MaskedInput mask='99.99.9999' beforeMaskedStateChange={beforeMaskedStateChange} />}\n onBlur={() => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n // Only an edit is written back. A value the field cannot show, a leftover Date or a\n // timestamp, shows as empty, and writing that back would erase it on a mere tab-through.\n if (currentDateString !== getDateString(getCurrValue())) handleChange(tryParseDateString(currentDateString));\n }}\n onFocus={() => setIsFocused(true)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n isValid={!hasErr}\n />\n );\n\n const picker = (() => {\n if (isInline) return pickerContent;\n if (isModal) {\n return (\n <Modal hideHeader isOpen={isPickerOpen} onClose={() => setIsPickerOpen(false)}>\n {pickerContent}\n </Modal>\n );\n }\n return (\n <Popover\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n // A click to place the caret in the field must not take the panel away.\n // The focus stays there on its own: Popover only follows a keyboard open.\n closeOnTriggerClick={false}\n constrainWidth={false}\n >\n {input}\n </Popover>\n );\n })();\n\n return (\n <div\n {...rest}\n className={cx(styles.datePicker, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {(isModal || isInline) && input}\n {picker}\n <Tooltip\n variant='error'\n message={formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || ''}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";var e=[`a[href]`,`area[href]`,`button:not([disabled])`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex="-1"])`,`[contenteditable="true"]`].join(`,`);function t(t){return t?Array.from(t.querySelectorAll(e)).filter(e=>e.getAttribute(`tabindex`)!==`-1`):[]}function n({triggerRef:e,contentRef:n}){function r(){return t(e.current)[0]??e.current}function i(){r()?.focus()}function a(){let e=t(document.body).filter(e=>!n.current?.contains(e)),i=r(),a=i?e.indexOf(i):-1;a>=0&&e[a+1]?.focus()}return{firstTriggerFocusable:r,restoreFocusToTrigger:i,focusAfterTrigger:a}}export{t as tabbablesIn,n as useFocusBoundary};
1
+ "use client";var e=[`a[href]`,`area[href]`,`button:not([disabled])`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex="-1"])`,`[contenteditable="true"]`].join(`,`);function t(t){return t?Array.from(t.querySelectorAll(e)).filter(e=>e.getAttribute(`tabindex`)!==`-1`):[]}function n(t){return t.matches(e)&&t.getAttribute(`tabindex`)!==`-1`}function r({triggerRef:e,contentRef:r}){function i(){let r=e.current;return r&&n(r)?r:t(r)[0]??r}function a(){i()?.focus()}function o(){let e=t(document.body).filter(e=>!r.current?.contains(e)),n=i(),a=n?e.indexOf(n):-1;a>=0&&e[a+1]?.focus()}return{firstTriggerFocusable:i,restoreFocusToTrigger:a,focusAfterTrigger:o}}export{t as tabbablesIn,r as useFocusBoundary};
2
2
  //# sourceMappingURL=useFocusBoundary.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFocusBoundary.mjs","names":[],"sources":["../../../../package/common/hooks/useFocusBoundary.ts"],"sourcesContent":["import type { RefObject } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\n/** Tabbable descendants of `root`, in DOM order. */\nexport function tabbablesIn(root: ParentNode | null): HTMLElement[] {\n if (!root) return [];\n return (\n Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n // A button or a link can be taken out of the tab order too, which the\n // selector above only catches for elements whose focusability comes from\n // the attribute. A roving tabindex, where one item of a list is the tab\n // stop and the rest are reachable by arrow key, otherwise reads as a list\n // of tab stops, and the Tab boundary lands on the wrong entry.\n .filter((el) => el.getAttribute('tabindex') !== '-1')\n );\n}\n\nexport interface UseFocusBoundaryArgs {\n /** The trigger element focus returns to on Escape / Shift+Tab out of the content's top. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The portaled content root — tabbables inside it define the Tab boundary. */\n contentRef: RefObject<HTMLElement | null>;\n}\n\n/**\n * Focus helpers for content portaled to the end of the DOM (e.g. via BodyEnd), where Tab can't\n * reach it in visual document order on its own. Used by Popover and by Menu, which both need to\n * hand focus back to the trigger on Escape / Shift+Tab out of the top, and continue focus\n * naturally past the trigger when Tab exits the bottom.\n */\nexport function useFocusBoundary({ triggerRef, contentRef }: UseFocusBoundaryArgs) {\n function firstTriggerFocusable(): HTMLElement | null {\n return tabbablesIn(triggerRef.current)[0] ?? triggerRef.current;\n }\n\n function restoreFocusToTrigger() {\n firstTriggerFocusable()?.focus();\n }\n\n // Move focus to the tabbable element that follows the trigger in the document, skipping the\n // portaled content — the \"natural next\" stop when Tab exits the bottom of the content.\n function focusAfterTrigger() {\n const all = tabbablesIn(document.body).filter((el) => !contentRef.current?.contains(el));\n const trig = firstTriggerFocusable();\n const idx = trig ? all.indexOf(trig) : -1;\n if (idx >= 0) all[idx + 1]?.focus();\n }\n\n return { firstTriggerFocusable, restoreFocusToTrigger, focusAfterTrigger };\n}\n"],"mappings":"aAEA,IAAM,EAAqB,CACzB,UACA,aACA,yBACA,wBACA,yBACA,2BACA,kCACA,0BACF,CAAC,CAAC,KAAK,GAAG,EAGV,SAAgB,EAAY,EAAwC,CAElE,OADK,EAEH,MAAM,KAAK,EAAK,iBAA8B,CAAkB,CAAC,CAAC,CAM/D,OAAQ,GAAO,EAAG,aAAa,UAAU,IAAM,IAAI,EARtC,CAAC,CAUrB,CAeA,SAAgB,EAAiB,CAAE,aAAY,cAAoC,CACjF,SAAS,GAA4C,CACnD,OAAO,EAAY,EAAW,OAAO,CAAC,CAAC,IAAM,EAAW,OAC1D,CAEA,SAAS,GAAwB,CAC/B,EAAsB,CAAC,EAAE,MAAM,CACjC,CAIA,SAAS,GAAoB,CAC3B,IAAM,EAAM,EAAY,SAAS,IAAI,CAAC,CAAC,OAAQ,GAAO,CAAC,EAAW,SAAS,SAAS,CAAE,CAAC,EACjF,EAAO,EAAsB,EAC7B,EAAM,EAAO,EAAI,QAAQ,CAAI,EAAI,GACnC,GAAO,GAAG,EAAI,EAAM,EAAE,EAAE,MAAM,CACpC,CAEA,MAAO,CAAE,wBAAuB,wBAAuB,mBAAkB,CAC3E"}
1
+ {"version":3,"file":"useFocusBoundary.mjs","names":[],"sources":["../../../../package/common/hooks/useFocusBoundary.ts"],"sourcesContent":["import type { RefObject } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\n/** Tabbable descendants of `root`, in DOM order. */\nexport function tabbablesIn(root: ParentNode | null): HTMLElement[] {\n if (!root) return [];\n return (\n Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n // A button or a link can be taken out of the tab order too, which the\n // selector above only catches for elements whose focusability comes from\n // the attribute. A roving tabindex, where one item of a list is the tab\n // stop and the rest are reachable by arrow key, otherwise reads as a list\n // of tab stops, and the Tab boundary lands on the wrong entry.\n .filter((el) => el.getAttribute('tabindex') !== '-1')\n );\n}\n\nfunction isTabbable(element: HTMLElement): boolean {\n return element.matches(FOCUSABLE_SELECTOR) && element.getAttribute('tabindex') !== '-1';\n}\n\nexport interface UseFocusBoundaryArgs {\n /** The trigger element focus returns to on Escape / Shift+Tab out of the content's top. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The portaled content root — tabbables inside it define the Tab boundary. */\n contentRef: RefObject<HTMLElement | null>;\n}\n\n/**\n * Focus helpers for content portaled to the end of the DOM (e.g. via BodyEnd), where Tab can't\n * reach it in visual document order on its own. Used by Popover and by Menu, which both need to\n * hand focus back to the trigger on Escape / Shift+Tab out of the top, and continue focus\n * naturally past the trigger when Tab exits the bottom.\n */\nexport function useFocusBoundary({ triggerRef, contentRef }: UseFocusBoundaryArgs) {\n function firstTriggerFocusable(): HTMLElement | null {\n const trigger = triggerRef.current;\n // The trigger itself where it takes focus, as an element handed to Popover's `anchor` can;\n // else the first element inside it that does, as inside Popover's and Menu's own wrappers.\n if (trigger && isTabbable(trigger)) return trigger;\n return tabbablesIn(trigger)[0] ?? trigger;\n }\n\n function restoreFocusToTrigger() {\n firstTriggerFocusable()?.focus();\n }\n\n // Move focus to the tabbable element that follows the trigger in the document, skipping the\n // portaled content — the \"natural next\" stop when Tab exits the bottom of the content.\n function focusAfterTrigger() {\n const all = tabbablesIn(document.body).filter((el) => !contentRef.current?.contains(el));\n const trig = firstTriggerFocusable();\n const idx = trig ? all.indexOf(trig) : -1;\n if (idx >= 0) all[idx + 1]?.focus();\n }\n\n return { firstTriggerFocusable, restoreFocusToTrigger, focusAfterTrigger };\n}\n"],"mappings":"aAEA,IAAM,EAAqB,CACzB,UACA,aACA,yBACA,wBACA,yBACA,2BACA,kCACA,0BACF,CAAC,CAAC,KAAK,GAAG,EAGV,SAAgB,EAAY,EAAwC,CAElE,OADK,EAEH,MAAM,KAAK,EAAK,iBAA8B,CAAkB,CAAC,CAAC,CAM/D,OAAQ,GAAO,EAAG,aAAa,UAAU,IAAM,IAAI,EARtC,CAAC,CAUrB,CAEA,SAAS,EAAW,EAA+B,CACjD,OAAO,EAAQ,QAAQ,CAAkB,GAAK,EAAQ,aAAa,UAAU,IAAM,IACrF,CAeA,SAAgB,EAAiB,CAAE,aAAY,cAAoC,CACjF,SAAS,GAA4C,CACnD,IAAM,EAAU,EAAW,QAI3B,OADI,GAAW,EAAW,CAAO,EAAU,EACpC,EAAY,CAAO,CAAC,CAAC,IAAM,CACpC,CAEA,SAAS,GAAwB,CAC/B,EAAsB,CAAC,EAAE,MAAM,CACjC,CAIA,SAAS,GAAoB,CAC3B,IAAM,EAAM,EAAY,SAAS,IAAI,CAAC,CAAC,OAAQ,GAAO,CAAC,EAAW,SAAS,SAAS,CAAE,CAAC,EACjF,EAAO,EAAsB,EAC7B,EAAM,EAAO,EAAI,QAAQ,CAAI,EAAI,GACnC,GAAO,GAAG,EAAI,EAAM,EAAE,EAAE,MAAM,CACpC,CAEA,MAAO,CAAE,wBAAuB,wBAAuB,mBAAkB,CAC3E"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import r from"../bodyEnd/bodyEnd.mjs";import i from"./popover.module.mjs";import a from"../styles/sheet.module.mjs";import o from"../sheetBackdrop/sheetBackdrop.mjs";import{PopoverAlign as ee,PopoverPlacement as s,PopoverTrigger as c}from"./popover.types.mjs";import{usePopoverPosition as te}from"./usePopoverPosition.mjs";import{tabbablesIn as l,useFocusBoundary as ne}from"../hooks/useFocusBoundary.mjs";import u from"../hooks/useSheet.mjs";import{useOverlay as d}from"../hooks/useOverlay.mjs";import{useCallback as f,useEffect as p,useRef as m,useState as re}from"react";import h from"classnames";import{jsx as g,jsxs as _}from"react/jsx-runtime";function v(v){let{children:y=null,content:b=null,placement:x=s.Bottom,align:S=ee.Center,trigger:C=c.Click,isOpen:w,defaultOpen:T=!1,onOpenChange:E=()=>{},offset:ie=10,withArrow:D=!0,closeOnOutsideClick:O=!0,closeOnEscape:ae=!0,openDelay:oe=100,closeDelay:se=120,disabled:k=!1,focusOnOpen:A=`keyboard`,closeOnTriggerClick:ce=!0,width:j=`auto`,constrainWidth:M=!0,presentation:N,className:P,style:F,classNames:I,styles:L,...R}=e(`Popover`,v),z=m(null),B=m(null),V=m(null),H=m(null),U=m(void 0),W=m(!1),G=m(!1);function K(){W.current=!0}let q=w!==void 0,[le,ue]=re(T),J=q?w:le,Y=m(E);p(()=>{Y.current=E});let X=f((e,t=!1)=>{k&&e||(e&&(G.current=t),q||ue(e),Y.current(e,{fromKeyboard:t}))},[k,q]),de=t(),fe=N??de??n.Default,{isSheet:pe,sheetStyle:me}=u(fe),Z=pe&&C===c.Click;te({isOpen:!!J&&!Z,placement:x,align:S,offset:ie,triggerRef:z,floatingRef:B,panelRef:V,arrowRef:D?H:{current:null},matchTriggerWidth:j===`trigger`}),d({isActive:!!J,containerRef:V,onEscape:ae?()=>{B.current?.contains(document.activeElement)&&(l(z.current)[0]??z.current)?.focus(),X(!1,!0)}:void 0,trapFocus:!1,lockScroll:Z});let{restoreFocusToTrigger:Q,focusAfterTrigger:he}=ne({triggerRef:z,contentRef:B});p(()=>{if(!J){G.current=!1;return}if(!(A===!0||A===`keyboard`&&G.current)||C!==c.Click)return;let e=l(V.current);e.length!==0&&(B.current?.setAttribute(`role`,`dialog`),e[0].focus())},[J,C,A]);function ge(e){if(e.key!==`Tab`||C!==c.Click)return;let t=l(V.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),he(),X(!1,!0)):e.shiftKey&&n===t[0]&&(e.preventDefault(),Q(),X(!1,!0))}p(()=>{if(!J)return;function e(e){let t=W.current;W.current=!1;let n=e.target,r=B.current?.contains(n),i=z.current?.contains(n);!t&&!r&&!i&&X(!1)}function t(e){let t=W.current;W.current=!1;let n=e.target,r=B.current?.contains(n),i=z.current?.contains(n);!t&&!r&&!i&&X(!1,!0)}return O&&C!==c.Hover&&(window.addEventListener(`mouseup`,e),document.addEventListener(`focusin`,t)),()=>{window.removeEventListener(`mouseup`,e),document.removeEventListener(`focusin`,t)}},[J,O,C,X]),p(()=>()=>clearTimeout(U.current),[]);function $(e){clearTimeout(U.current),U.current=setTimeout(()=>X(e),e?oe:se)}function _e(e){J||e.key!==`ArrowDown`&&e.key!==`ArrowUp`||(e.preventDefault(),X(!0,!0))}let ve=C===c.Click?{onClick:e=>{(!J||ce)&&X(!J,e.detail===0)},onKeyDown:_e}:C===c.Hover?{onMouseEnter:()=>$(!0),onMouseLeave:()=>$(!1)}:{onFocus:()=>X(!0),onBlur:()=>X(!1)},ye=C===c.Hover?{onMouseEnter:()=>$(!0),onMouseLeave:()=>$(!1)}:{};return _(`div`,{...R,className:h(i.popover,P,I?.root),style:{...F,...L?.root},children:[g(`div`,{ref:z,className:h(i.popoverTrigger,I?.trigger),style:L?.trigger,...ve,children:y}),J&&_(r,{children:[Z&&g(o,{onClose:()=>{O&&X(!1)},className:I?.backdrop,style:L?.backdrop}),_(`div`,{ref:B,className:h(Z?a.sheet:i.popoverFloating,I?.floating),style:{...Z?me:void 0,...L?.floating},"data-placement":x,onKeyDown:ge,onMouseUpCapture:K,onFocusCapture:K,...ye,children:[g(`div`,{ref:V,className:h(i.popoverPanel,M&&i.popoverPanelConstrained,Z&&a.sheetPanel,I?.panel),style:L?.panel,children:b}),D&&!Z&&g(`div`,{ref:H,className:h(i.popoverArrow,I?.arrow),style:L?.arrow})]})]})]})}export{v as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import r from"../bodyEnd/bodyEnd.mjs";import i from"./popover.module.mjs";import a from"../styles/sheet.module.mjs";import o from"../sheetBackdrop/sheetBackdrop.mjs";import{PopoverAlign as ee,PopoverPlacement as s,PopoverTrigger as c}from"./popover.types.mjs";import{usePopoverPosition as l}from"./usePopoverPosition.mjs";import{tabbablesIn as u,useFocusBoundary as te}from"../hooks/useFocusBoundary.mjs";import ne from"../hooks/useSheet.mjs";import{useOverlay as re}from"../hooks/useOverlay.mjs";import{useCallback as ie,useEffect as d,useRef as f,useState as p}from"react";import m from"classnames";import{jsx as h,jsxs as g}from"react/jsx-runtime";var ae=1e3;function _(e,t){return e?{current:e}:t}function v(v){let{children:y=null,anchor:b,content:x=null,placement:S=s.Bottom,align:C=ee.Center,trigger:w=c.Click,isOpen:T,defaultOpen:oe=!1,onOpenChange:E=()=>{},offset:se=10,withArrow:D=!0,closeOnOutsideClick:O=!0,closeOnEscape:ce=!0,openDelay:le=100,closeDelay:ue=120,disabled:k=!1,focusOnOpen:A=`keyboard`,closeOnTriggerClick:de=!0,width:fe=`auto`,constrainWidth:pe=!0,presentation:me,className:he,style:ge,classNames:j,styles:M,...N}=e(`Popover`,v),P=f(null),F=f(null),I=f(null),L=f(null),R=f(void 0),z=f(!1),B=f(!1);function V(){z.current=!0}let[H,_e]=p(()=>({anchor:b,ref:_(b,P)}));H.anchor!==b&&_e({anchor:b,ref:_(b,P)});let U=H.ref,W=f(null),G=b!==void 0;d(()=>{if(!G)return;function e(e){W.current={target:e.target,keyboard:e.detail===0,time:performance.now()}}return document.addEventListener(`click`,e,!0),()=>document.removeEventListener(`click`,e,!0)},[G]);let K=T!==void 0,[ve,ye]=p(oe),q=K?T:ve,J=f(E);d(()=>{J.current=E});let Y=ie((e,t=!1)=>{k&&e||(e&&(B.current=t),K||ye(e),J.current(e,{fromKeyboard:t}))},[k,K]),be=t(),xe=me??be??n.Default,{isSheet:Se,sheetStyle:Ce}=ne(xe),X=Se&&w===c.Click;l({isOpen:!!q&&!X,placement:S,align:C,offset:se,triggerRef:U,floatingRef:F,panelRef:I,arrowRef:D?L:{current:null},matchTriggerWidth:fe===`trigger`});let{restoreFocusToTrigger:Z,focusAfterTrigger:we}=te({triggerRef:U,contentRef:F});re({isActive:!!q,containerRef:I,onEscape:ce?()=>{F.current?.contains(document.activeElement)&&Z(),Y(!1,!0)}:void 0,trapFocus:!1,lockScroll:X}),d(()=>{if(!q){B.current=!1;return}let e=W.current;W.current=null;let t=!!b&&!!e?.keyboard&&b.contains(e.target)&&performance.now()-e.time<ae;if(!(A===!0||A===`keyboard`&&(B.current||t))||w!==c.Click)return;let n=u(I.current);n.length!==0&&(F.current?.setAttribute(`role`,`dialog`),n[0].focus())},[q,w,A,b]);function Q(e){if(e.key!==`Tab`||w!==c.Click)return;let t=u(I.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),we(),Y(!1,!0)):e.shiftKey&&n===t[0]&&(e.preventDefault(),Z(),Y(!1,!0))}d(()=>{if(!q)return;z.current=!1;function e(e){let t=z.current;z.current=!1;let n=e.target,r=F.current?.contains(n),i=P.current?.contains(n)||U.current?.contains(n);!t&&!r&&!i&&Y(!1)}function t(e){let t=z.current;z.current=!1;let n=e.target,r=F.current?.contains(n),i=P.current?.contains(n)||U.current?.contains(n);!t&&!r&&!i&&Y(!1,!0)}return O&&w!==c.Hover&&(window.addEventListener(`mouseup`,e),document.addEventListener(`focusin`,t)),()=>{window.removeEventListener(`mouseup`,e),document.removeEventListener(`focusin`,t)}},[q,O,w,Y,U]),d(()=>()=>clearTimeout(R.current),[]);function $(e){clearTimeout(R.current),R.current=setTimeout(()=>Y(e),e?le:ue)}function Te(e){q||e.key!==`ArrowDown`&&e.key!==`ArrowUp`||(e.preventDefault(),Y(!0,!0))}let Ee=w===c.Click?{onClick:e=>{(!q||de)&&Y(!q,e.detail===0)},onKeyDown:Te}:w===c.Hover?{onMouseEnter:()=>$(!0),onMouseLeave:()=>$(!1)}:{onFocus:()=>Y(!0),onBlur:()=>Y(!1)},De=w===c.Hover?{onMouseEnter:()=>$(!0),onMouseLeave:()=>$(!1)}:{};return g(`div`,{...N,className:m(i.popover,he,j?.root),style:{...ge,...M?.root},children:[h(`div`,{ref:P,className:m(i.popoverTrigger,j?.trigger),style:M?.trigger,...Ee,children:y}),q&&g(r,{children:[X&&h(o,{onClose:()=>{O&&Y(!1)},className:j?.backdrop,style:M?.backdrop}),g(`div`,{ref:F,className:m(X?a.sheet:i.popoverFloating,j?.floating),style:{...X?Ce:void 0,...M?.floating},"data-placement":S,onKeyDown:Q,onMouseUpCapture:V,onFocusCapture:V,...De,children:[h(`div`,{ref:I,className:m(i.popoverPanel,pe&&i.popoverPanelConstrained,X&&a.sheetPanel,j?.panel),style:M?.panel,children:x}),D&&!X&&h(`div`,{ref:L,className:m(i.popoverArrow,j?.arrow),style:M?.arrow})]})]})]})}export{v as default};
2
2
  //# sourceMappingURL=popover.mjs.map