@ahrowe/ui 0.19.0 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -1
  2. package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
  3. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
  4. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  5. package/dist/esm/common/datePicker/dateFunctions.mjs +1 -1
  6. package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -1
  7. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  8. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  9. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  10. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +1 -1
  11. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -1
  12. package/dist/esm/common/hooks/useVisualViewportSize.mjs +2 -0
  13. package/dist/esm/common/hooks/useVisualViewportSize.mjs.map +1 -0
  14. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  15. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  16. package/dist/esm/common/iconPicker/iconPicker.module.mjs.map +1 -1
  17. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +1 -1
  18. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -1
  19. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +1 -1
  20. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs.map +1 -1
  21. package/dist/esm/common/input/input.module.mjs.map +1 -1
  22. package/dist/esm/common/modal/modal.mjs +1 -1
  23. package/dist/esm/common/modal/modal.mjs.map +1 -1
  24. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  25. package/dist/esm/common/optionPicker/optionPicker.mjs +1 -1
  26. package/dist/esm/common/optionPicker/optionPicker.mjs.map +1 -1
  27. package/dist/esm/common/optionPicker/optionPicker.module.mjs.map +1 -1
  28. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  29. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  30. package/dist/esm/common/radioGroup/radioGroup.module.mjs.map +1 -1
  31. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs.map +1 -1
  32. package/dist/esm/common/switch/switch.module.mjs.map +1 -1
  33. package/dist/esm/common/themeProvider/defaultTheme.mjs +1 -1
  34. package/dist/esm/common/themeProvider/defaultTheme.mjs.map +1 -1
  35. package/dist/esm/common/timeline/timeline.module.mjs.map +1 -1
  36. package/dist/esm/common/utils/visualViewport.mjs +2 -0
  37. package/dist/esm/common/utils/visualViewport.mjs.map +1 -0
  38. package/dist/index.cjs +6 -6
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/style.css +1 -1
  41. package/dist/types/package/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +3 -1
  42. package/dist/types/package/common/datePicker/dateFunctions.d.ts +11 -0
  43. package/dist/types/package/common/hooks/useVisualViewportSize.d.ts +13 -0
  44. package/dist/types/package/common/themeProvider/theme.types.d.ts +2 -0
  45. package/dist/types/package/common/utils/visualViewport.d.ts +7 -0
  46. package/docs/DatePicker.md +2 -0
  47. package/docs/IconPicker.md +2 -0
  48. package/docs/OptionPicker.md +4 -0
  49. package/docs/ThemeProvider.md +1 -0
  50. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.module.mjs","names":[],"sources":["../../../../package/common/checkbox/checkbox.module.pcss"],"sourcesContent":["\n.checkbox {\n user-select: none;\n display: flex;\n align-items: center;\n column-gap: 10px;\n margin: -1px;\n border: 1px solid transparent;\n width: fit-content;\n /* The visible checkmark box (below) is nested inside this root, not directly on it — see\n input.module.pcss for why this variable exists: a wrapping ButtonGroup sets --group-radius-*\n per corner on the position this occupies, and unlike border-radius itself, custom properties\n inherit through any nesting depth, reaching descendants a plain ancestor selector can't. */\n --checkmark-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n\n &-icon {\n color: #a3a9b9;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background-color: var(--light-background-color);\n width: fit-content;\n height: fit-content;\n /* width: 16px;\n height: 16px; */\n }\n\n &-loading {\n background: transparent;\n\n &-spinner {\n width: 100%;\n height: 100%;\n }\n }\n\n &-pointer {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &:focus-visible {\n outline: none;\n border: 1px solid var(--primary-color);\n border-radius: 6px;\n }\n\n &-disabled {\n filter: brightness(0.8);\n cursor: not-allowed;\n }\n\n &-checkmark {\n border: 1.8px solid var(--border-color);\n border-radius: var(--checkmark-radius);\n position: relative;\n\n svg {\n stroke: var(--text-on-primary);\n stroke-dasharray: 5;\n stroke-dashoffset: 5;\n transition:\n transform 0.1s,\n stroke-dashoffset 0.4s;\n transition-delay: 0s, 0.2s;\n background: var(--primary-color);\n transform: scale(0);\n box-sizing: content-box;\n padding: 2px;\n border-radius: var(--default-border-radius);\n }\n\n &-checked {\n svg {\n stroke-dashoffset: 0;\n transform: scale(1) translate(-3px, -3px);\n }\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"checkbox.module.mjs","names":[],"sources":["../../../../package/common/checkbox/checkbox.module.pcss"],"sourcesContent":["\n.checkbox {\n user-select: none;\n display: flex;\n align-items: center;\n column-gap: 10px;\n margin: -1px;\n border: 1px solid transparent;\n width: fit-content;\n /* The visible checkmark box (below) is nested inside this root, not directly on it — see\n input.module.pcss for why this variable exists: a wrapping ButtonGroup sets --group-radius-*\n per corner on the position this occupies, and unlike border-radius itself, custom properties\n inherit through any nesting depth, reaching descendants a plain ancestor selector can't. */\n --checkmark-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n\n &-icon {\n color: #a3a9b9;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background-color: var(--light-background-color);\n width: fit-content;\n height: fit-content;\n /* width: 16px;\n height: 16px; */\n }\n\n &-loading {\n background: transparent;\n\n &-spinner {\n width: 100%;\n height: 100%;\n }\n }\n\n &-pointer {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &:focus-visible {\n outline: none;\n border: 1px solid var(--focus-border-color, var(--primary-color));\n border-radius: 6px;\n }\n\n &-disabled {\n filter: brightness(0.8);\n cursor: not-allowed;\n }\n\n &-checkmark {\n border: 1.8px solid var(--border-color);\n border-radius: var(--checkmark-radius);\n position: relative;\n\n svg {\n stroke: var(--text-on-primary);\n stroke-dasharray: 5;\n stroke-dashoffset: 5;\n transition:\n transform 0.1s,\n stroke-dashoffset 0.4s;\n transition-delay: 0s, 0.2s;\n background: var(--primary-color);\n transform: scale(0);\n box-sizing: content-box;\n padding: 2px;\n border-radius: var(--default-border-radius);\n }\n\n &-checked {\n svg {\n stroke-dashoffset: 0;\n transform: scale(1) translate(-3px, -3px);\n }\n }\n }\n}\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"colorPicker.module.mjs","names":[],"sources":["../../../../package/common/colorPicker/colorPicker.module.pcss"],"sourcesContent":[".colorPicker {\n display: flex;\n align-items: center;\n gap: 8px;\n /* The visible swatch (below) is nested inside a FloatingMenu trigger, not this root — see\n input.module.pcss for why this variable exists: a wrapping ButtonGroup sets --group-radius-*\n per corner on the position this occupies, and unlike border-radius itself, custom properties\n inherit through any nesting depth, reaching descendants a plain ancestor selector can't. */\n --swatch-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n}\n\n.swatch {\n width: 32px;\n height: 32px;\n border-radius: var(--swatch-radius);\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n flex-shrink: 0;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);\n /* checkerboard so transparency is visible */\n background-image:\n linear-gradient(45deg, #bbb 25%, transparent 25%),\n linear-gradient(-45deg, #bbb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #bbb 75%),\n linear-gradient(-45deg, transparent 75%, #bbb 75%);\n background-size: 8px 8px;\n background-position: 0 0, 0 4px, 4px -4px, -4px 0;\n background-color: white;\n\n &:hover {\n & .swatchHex {\n opacity: 1;\n }\n }\n}\n\n.swatchFill {\n position: absolute;\n inset: 0;\n border-radius: inherit;\n}\n\n.swatchHex {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 8px;\n font-family: monospace;\n background: rgba(0, 0, 0, 0.55);\n color: white;\n border-radius: inherit;\n opacity: 0;\n transition: opacity 0.15s;\n user-select: none;\n pointer-events: none;\n z-index: 1;\n}\n\n.panel {\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 224px;\n}\n\n.gradientArea {\n width: 200px;\n height: 160px;\n position: relative;\n cursor: crosshair;\n border-radius: 4px;\n overflow: hidden;\n touch-action: none;\n background: linear-gradient(to right, white, hsl(calc(var(--hue) * 1deg), 100%, 50%));\n}\n\n.gradientOverlay {\n position: absolute;\n inset: 0;\n background: linear-gradient(to bottom, transparent, black);\n}\n\n.cursor {\n position: absolute;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n border: 2px solid white;\n box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);\n transform: translate(-50%, -50%);\n pointer-events: none;\n z-index: 1;\n}\n\n.hueSlider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 10px;\n border-radius: var(--default-border-radius);\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background: linear-gradient(\n to right,\n hsl(0, 100%, 50%),\n hsl(60, 100%, 50%),\n hsl(120, 100%, 50%),\n hsl(180, 100%, 50%),\n hsl(240, 100%, 50%),\n hsl(300, 100%, 50%),\n hsl(360, 100%, 50%)\n );\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &::-moz-range-thumb {\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n}\n\n.alphaSlider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 10px;\n border-radius: var(--default-border-radius);\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n /* checkerboard base so transparency is visible under the gradient */\n background-image:\n linear-gradient(to right, transparent, var(--alpha-color)),\n linear-gradient(45deg, #bbb 25%, transparent 25%),\n linear-gradient(-45deg, #bbb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #bbb 75%),\n linear-gradient(-45deg, transparent 75%, #bbb 75%);\n background-size: 100% 100%, 8px 8px, 8px 8px, 8px 8px, 8px 8px;\n background-position: 0 0, 0 0, 0 4px, 4px -4px, -4px 0;\n background-color: white;\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &::-moz-range-thumb {\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n}\n\n.hexRow {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.hexInput {\n width: 100%;\n padding: 5px 8px;\n border-radius: var(--default-border-radius);\n border: 1px solid var(--border-color);\n background: var(--input-background);\n color: var(--text-color);\n font-size: 13px;\n font-family: monospace;\n box-sizing: border-box;\n outline: none;\n\n &:focus {\n border-color: var(--primary-color);\n }\n}\n\n.eyeDropperButton {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 28px;\n height: 28px;\n padding: 0;\n border-radius: var(--default-border-radius);\n border: 1px solid var(--border-color);\n background: var(--input-background);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:hover {\n border-color: var(--primary-color);\n color: var(--primary-color);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"colorPicker.module.mjs","names":[],"sources":["../../../../package/common/colorPicker/colorPicker.module.pcss"],"sourcesContent":[".colorPicker {\n display: flex;\n align-items: center;\n gap: 8px;\n /* The visible swatch (below) is nested inside a FloatingMenu trigger, not this root — see\n input.module.pcss for why this variable exists: a wrapping ButtonGroup sets --group-radius-*\n per corner on the position this occupies, and unlike border-radius itself, custom properties\n inherit through any nesting depth, reaching descendants a plain ancestor selector can't. */\n --swatch-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n}\n\n.swatch {\n width: 32px;\n height: 32px;\n border-radius: var(--swatch-radius);\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n flex-shrink: 0;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);\n /* checkerboard so transparency is visible */\n background-image:\n linear-gradient(45deg, #bbb 25%, transparent 25%),\n linear-gradient(-45deg, #bbb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #bbb 75%),\n linear-gradient(-45deg, transparent 75%, #bbb 75%);\n background-size: 8px 8px;\n background-position: 0 0, 0 4px, 4px -4px, -4px 0;\n background-color: white;\n\n &:hover {\n & .swatchHex {\n opacity: 1;\n }\n }\n}\n\n.swatchFill {\n position: absolute;\n inset: 0;\n border-radius: inherit;\n}\n\n.swatchHex {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 8px;\n font-family: monospace;\n background: rgba(0, 0, 0, 0.55);\n color: white;\n border-radius: inherit;\n opacity: 0;\n transition: opacity 0.15s;\n user-select: none;\n pointer-events: none;\n z-index: 1;\n}\n\n.panel {\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 224px;\n}\n\n.gradientArea {\n width: 200px;\n height: 160px;\n position: relative;\n cursor: crosshair;\n border-radius: 4px;\n overflow: hidden;\n touch-action: none;\n background: linear-gradient(to right, white, hsl(calc(var(--hue) * 1deg), 100%, 50%));\n}\n\n.gradientOverlay {\n position: absolute;\n inset: 0;\n background: linear-gradient(to bottom, transparent, black);\n}\n\n.cursor {\n position: absolute;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n border: 2px solid white;\n box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);\n transform: translate(-50%, -50%);\n pointer-events: none;\n z-index: 1;\n}\n\n.hueSlider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 10px;\n border-radius: var(--default-border-radius);\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background: linear-gradient(\n to right,\n hsl(0, 100%, 50%),\n hsl(60, 100%, 50%),\n hsl(120, 100%, 50%),\n hsl(180, 100%, 50%),\n hsl(240, 100%, 50%),\n hsl(300, 100%, 50%),\n hsl(360, 100%, 50%)\n );\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &::-moz-range-thumb {\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n}\n\n.alphaSlider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 10px;\n border-radius: var(--default-border-radius);\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n /* checkerboard base so transparency is visible under the gradient */\n background-image:\n linear-gradient(to right, transparent, var(--alpha-color)),\n linear-gradient(45deg, #bbb 25%, transparent 25%),\n linear-gradient(-45deg, #bbb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #bbb 75%),\n linear-gradient(-45deg, transparent 75%, #bbb 75%);\n background-size: 100% 100%, 8px 8px, 8px 8px, 8px 8px, 8px 8px;\n background-position: 0 0, 0 0, 0 4px, 4px -4px, -4px 0;\n background-color: white;\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &::-moz-range-thumb {\n width: 6px;\n height: 20px;\n border-radius: var(--default-border-radius);\n background: var(--primary-color);\n box-shadow: var(--card-shadow);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n}\n\n.hexRow {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.hexInput {\n width: 100%;\n padding: 5px 8px;\n border-radius: var(--default-border-radius);\n border: 1px solid var(--border-color);\n background: var(--input-background);\n color: var(--text-color);\n font-size: var(--default-font-size);\n font-family: monospace;\n box-sizing: border-box;\n outline: none;\n\n &:focus {\n border-color: var(--focus-border-color, var(--primary-color));\n }\n}\n\n.eyeDropperButton {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 28px;\n height: 28px;\n padding: 0;\n border-radius: var(--default-border-radius);\n border: 1px solid var(--border-color);\n background: var(--input-background);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:hover {\n border-color: var(--primary-color);\n color: var(--primary-color);\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- import e from"../../../interactableDiv/index.mjs";import t from"./datePickerMonth.module.mjs";import{getLocale as n}from"../../../../services/localization.mjs";import{getDateFromDayMonthAndYear as r,getDayMonthAndYearOfDate as i,getDaysInMonth as a,getStartWeekDayOfMonth as o,getWeekDays as s}from"../../dateFunctions.mjs";import c from"classnames";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d(e,t,n,a,o){let{day:s,month:c,year:l}=a?i(a):{day:void 0,month:void 0,year:void 0},{day:u,month:d,year:f}=o?i(o):{day:void 0,month:void 0,year:void 0},p=r(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=r(s,c,l),t=r(u,d,f);g=p.getTime()>=e.getTime()&&p.getTime()<=t.getTime()}return{isStartDate:m,isInRange:g,isEndDate:h}}function f(e,t,n,a,o){let s=r(e,t,n);if(a){let{day:e,month:t,year:n}=i(a);if(s<r(e,t,n))return!0}if(o){let{day:e,month:t,year:n}=i(o);if(s>r(e,t,n))return!0}return!1}function p(e,t,n){let{day:r,month:a,year:o}=i(new Date);return e===r&&t===a&&n===o}function m({className:i=``,month:m=new Date().getMonth()+1,year:h=new Date().getFullYear(),onSelect:g=()=>null,selectionStart:_,selectionEnd:v,minDate:y=null,maxDate:b=null}){let x=n(`-`),S=a(m,h),C=o(m,h);return l(`div`,{className:c(t.datePickerMonth,i),children:u(`div`,{className:c(t.datePickerMonthContent),children:[s(x).map((e,t)=>l(`div`,{children:e},t)),Array.from(Array(C-1).keys()).map(e=>l(`div`,{className:c(t.datePickerMonthItem,t.datePickerMonthPlaceholder)},e)),Array.from(Array(S).keys()).map(n=>{let i=n+1,a=d(i,m,h,_,v),o=f(i,m,h,y,b),s=p(i,m,h);return l(e,{onClick:()=>o?null:g(r(i,m,h)),className:c(t.datePickerMonthDay,t.datePickerMonthItem,{[t.datePickerMonthDaySelected]:a.isInRange,[t.datePickerMonthDaySelectedStart]:a.isStartDate,[t.datePickerMonthDaySelectedEnd]:a.isEndDate,[t.datePickerMonthDayDisabled]:o,[t.datePickerMonthDayToday]:s}),children:i},i)}),Array.from(Array(42-(C+S-1)).keys()).map(e=>l(`div`,{className:c(t.datePickerMonthItem,t.datePickerMonthPlaceholder),children:`\xA0`},e))]})})}export{m as default};
1
+ 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({className:a=``,month:y=new Date().getMonth()+1,year:b=new Date().getFullYear(),onSelect:x=()=>null,selectionStart:S,selectionEnd:C,minDate:w=null,maxDate:T=null,onNavigateMonth:E}){let D=n(`-`),O=o(y,b),k=s(y,b),A=u({}),[j,M]=d(()=>h(y,b,S)),N=u(null);l(()=>{if(N.current!=null){let e=N.current;N.current=null,M(e),A.current[e]?.focus()}else M(h(y,b,S))},[y,b]);function P(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,y,b,n);i.month!==y||i.year!==b?(N.current=i.day,E?.(i.month>y||i.year>b?1:-1)):(M(i.day),A.current[i.day]?.focus())}return p(`div`,{className:f(t.datePickerMonth,a),children:m(`div`,{className:f(t.datePickerMonthContent),children:[c(D).map((e,t)=>p(`div`,{children:e},t)),Array.from(Array(k-1).keys()).map(e=>p(`div`,{className:f(t.datePickerMonthItem,t.datePickerMonthPlaceholder)},e)),Array.from(Array(O).keys()).map(n=>{let r=n+1,a=g(r,y,b,S,C),o=_(r,y,b,w,T),s=v(r,y,b);return p(e,{ref:e=>{A.current[r]=e},tabIndex:r===j?0:-1,onKeyDown:e=>P(e,r),onClick:()=>o?null:x(i(r,y,b)),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-(k+O-1)).keys()).map(e=>p(`div`,{className:f(t.datePickerMonthItem,t.datePickerMonthPlaceholder),children:`\xA0`},e))]})})}export{y 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 cx from 'classnames';\n\nimport styles from './datePickerMonth.module.pcss';\nimport { getLocale } from 'services/localization';\nimport InteractableDiv from 'components/common/interactableDiv';\nimport {\n getDateFromDayMonthAndYear,\n getDayMonthAndYearOfDate,\n getDaysInMonth,\n getStartWeekDayOfMonth,\n getWeekDays,\n} from '../../dateFunctions';\n\ninterface DatePickerMonthProps {\n className?: string;\n month?: number;\n year?: number;\n onSelect?: (date: Date) => void;\n selectionStart?: Date;\n selectionEnd?: Date;\n minDate?: Date | null;\n maxDate?: Date | null;\n}\n\nfunction checkSelected(\n day: number,\n month: number,\n year: number,\n selectionStart: Date | undefined,\n selectionEnd: Date | undefined,\n) {\n const { day: startDay, month: startMonth, year: startYear } = selectionStart\n ? getDayMonthAndYearOfDate(selectionStart)\n : { day: undefined, month: undefined, year: undefined };\n const { day: endDay, month: endMonth, year: endYear } = selectionEnd\n ? getDayMonthAndYearOfDate(selectionEnd)\n : { 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 (startDay !== undefined && startMonth !== undefined && startYear !== undefined &&\n endDay !== undefined && endMonth !== undefined && endYear !== undefined) {\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 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}: DatePickerMonthProps) {\n const locale = getLocale('-');\n const daysInMonth = getDaysInMonth(month, year);\n const startWeekDayOfMonth = getStartWeekDayOfMonth(month, year);\n\n return (\n <div className={cx(styles.datePickerMonth, className)}>\n <div className={cx(styles.datePickerMonthContent)}>\n {getWeekDays(locale).map((weekDay, index) => <div key={index}>{weekDay}</div>)}\n {Array.from(Array(startWeekDayOfMonth - 1).keys()).map((index) => (\n <div\n key={index}\n className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}\n />\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 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\n key={index}\n className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}\n >\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 {\n addDays,\n getDateFromDayMonthAndYear,\n getDayMonthAndYearOfDate,\n getDaysInMonth,\n getStartWeekDayOfMonth,\n getWeekDays,\n} from '../../dateFunctions';\n\ninterface DatePickerMonthProps {\n className?: string;\n month?: number;\n year?: number;\n onSelect?: (date: Date) => void;\n selectionStart?: Date;\n selectionEnd?: Date;\n minDate?: Date | null;\n maxDate?: Date | null;\n /** Called to shift the displayed month by ±1 when arrow navigation runs past its edge. */\n onNavigateMonth?: (delta: 1 | -1) => void;\n}\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(\n month: number,\n year: number,\n selectionStart: Date | undefined,\n): 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 { day: startDay, month: startMonth, year: startYear } = selectionStart\n ? getDayMonthAndYearOfDate(selectionStart)\n : { day: undefined, month: undefined, year: undefined };\n const { day: endDay, month: endMonth, year: endYear } = selectionEnd\n ? getDayMonthAndYearOfDate(selectionEnd)\n : { 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 (startDay !== undefined && startMonth !== undefined && startYear !== undefined &&\n endDay !== undefined && endMonth !== undefined && endYear !== undefined) {\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 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)}>\n <div className={cx(styles.datePickerMonthContent)}>\n {getWeekDays(locale).map((weekDay, index) => <div key={index}>{weekDay}</div>)}\n {Array.from(Array(startWeekDayOfMonth - 1).keys()).map((index) => (\n <div\n key={index}\n className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}\n />\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) => { dayRefs.current[day] = el; }}\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\n key={index}\n className={cx(styles.datePickerMonthItem, styles.datePickerMonthPlaceholder)}\n >\n &nbsp;\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- 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){return{day:e.getDate(),month:e.getMonth()+1,year:e.getFullYear()}}function c(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 l(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{l as correctDateMaskValue,n as getDateFromDayMonthAndYear,c as getDateString,s as getDayMonthAndYearOfDate,t as getDaysInMonth,r as getMonthName,i as getMonthNames,o as getStartWeekDayOfMonth,a as getWeekDays};
1
+ 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};
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\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":"4DAEA,SAAgB,EAAe,EAAe,EAAsB,CAClE,OAAO,IAAI,KAAK,EAAM,EAAO,CAAC,EAAE,QAAQ,CAC1C,CAEA,SAAgB,EAA2B,EAAa,EAAe,EAAoB,CACzF,OAAO,IAAI,KAAK,KAAK,IAAI,EAAM,EAAQ,EAAG,CAAG,CAAC,CAChD,CAEA,SAAgB,EAAa,EAAgB,EAAc,EAAe,EAAa,EAAQ,GAAe,CAE5G,OAAO,IADc,KAAK,KAAK,IAAI,EAAM,EAAQ,EAAG,CAAG,CAChD,EAAS,mBAAmB,EAAQ,CAAE,MAAO,EAAQ,QAAU,MAAO,CAAC,CAChF,CAEA,SAAgB,EAAc,EAAS,EAAU,GAAG,EAAa,CAC/D,OAAO,MAAM,KAAK,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,IAAK,GAAU,EAAa,EAAQ,KAAM,EAAQ,EAAG,CAAC,CAAC,CAC7F,CAEA,SAAgB,EAAY,EAAgB,EAAQ,GAAgB,CAClE,IAAM,EAAW,IAAI,KAAK,KAAK,IAAI,KAAM,EAAG,EAAE,CAAC,EACzC,EAAqB,CAAC,EAC5B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,IACrB,EAAS,KAAK,EAAS,mBAAmB,EAAQ,CAAE,QAAS,EAAQ,QAAU,MAAO,CAAC,CAAC,EACxF,EAAS,QAAQ,EAAS,QAAQ,EAAI,CAAC,EAEzC,OAAO,CACT,CAEA,SAAgB,EAAuB,EAAe,EAAsB,CAE1E,OADc,IAAI,KAAK,KAAK,IAAI,EAAM,EAAQ,EAAG,CAAC,CAAC,EAAE,OAC9C,GAAS,CAClB,CAEA,SAAgB,EAAyB,EAA0D,CACjG,MAAO,CACL,IAAK,EAAK,QAAQ,EAClB,MAAO,EAAK,SAAS,EAAI,EACzB,KAAM,EAAK,YAAY,CACzB,CACF,CAEA,SAAgB,EAAc,EAAoB,CAChD,IAAM,EAAM,EAAK,QAAQ,EACnB,EAAQ,EAAK,SAAS,EAAI,EAC1B,EAAO,EAAK,YAAY,EAE9B,MAAO,GAAG,EAAM,GAAK,IAAI,IAAQ,EAAI,GAAG,EAAQ,GAAK,IAAI,IAAU,EAAM,GAAG,GAC9E,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
+ {"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(day: number, month: number, year: number, delta: number): { 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) { m = 12; y -= 1; }\n d += getDaysInMonth(m, y);\n }\n while (d > getDaysInMonth(m, y)) {\n d -= getDaysInMonth(m, y);\n m += 1;\n if (m > 12) { m = 1; y += 1; }\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,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{Align as r}from"../floatingMenu/floatingMenu.types.mjs";import i from"../floatingMenu/floatingMenu.mjs";import a from"../tooltip/tooltip.mjs";import o from"../input/input.mjs";import s from"../modal/modal.mjs";import{getLocale as ee}from"../../services/localization.mjs";import{correctDateMaskValue as te,getDateFromDayMonthAndYear as c,getDateString as l,getMonthName as ne,getMonthNames as re}from"./dateFunctions.mjs";import ie from"./components/datePickerMonth/datePickerMonth.mjs";import u from"../dropdown/dropdown.mjs";import d from"./datePicker.module.mjs";import{useEffect as f,useRef as p,useState as m}from"react";import h from"classnames";import{faChevronLeft as ae,faChevronRight as oe}from"@fortawesome/free-solid-svg-icons";import{Fragment as se,jsx as g,jsxs as _}from"react/jsx-runtime";import v from"@mona-health/react-input-mask";function y(y){let{className:ce=``,selected:b,onSelect:x=()=>null,formValidator:S=null,noInput:C=!1,noHeader:le=!1,isModal:w=!1,isInline:T=!1,onChange:ue=()=>null,minDate:E=null,maxDate:D=null,children:de=null,showClearButton:fe=!1,label:pe=``,isValid:O=!0,errorMessage:k=``,isRequired:A=!1,startDate:j,endDate:M}=e(`DatePicker`,y),N=()=>S?S.value:b,P=N()??new Date,[F,I]=m(P.getMonth()+1),[L,R]=m(P.getFullYear()),[z,B]=m(!1),[V,H]=m(()=>N()?l(P):``),[me,U]=m(!1),[he,W]=m(!1),[,ge]=m(0),[_e,ve]=m(b),G=p(S);if(_e!==b){ve(b);let e=b??new Date;I(e.getMonth()+1),R(e.getFullYear()),H(b?l(b):``)}f(()=>{if(G.current=S,!S)return;let e=()=>{let e=S.value;e?(I(e.getMonth()+1),R(e.getFullYear()),H(l(e))):H(``),ge(e=>e+1)};return S.registerOnUpdateListener(e),()=>S.removeOnUpdateListener(e)},[S]);let ye=()=>S?S.touched&&S.hasError():!O||!!k,be=()=>!!(A||S?.validators.find(e=>e.validatorId===`required`)),K=e=>{H(e?l(e):``),S&&S.set(e),ue(e)},q=e=>{K(e),x(e),B(!1)},J=e=>{I(t=>{let n=t+e;return n<1?(n=12,R(e=>e-1)):n>12&&(n=1,R(e=>e+1)),n})},Y=e=>{if(e.match(/\d{2}\.\d{2}\.\d{4}/gi)){let[t,n,r]=e.split(`.`),i=c(Number(t),Number(n),Number(r));if(i&&i.toString()!==`Invalid Date`&&(!D||i<=D)&&(!E||i>=E))return i}return null},xe=({previousState:e,nextState:t})=>{if(!e||t.value===e.value)return t;let n=te(t.value,e.value,t.selection??null),r=Y(n.value);return r&&K(r),n},Se=()=>{let e=400,t=new Date().getFullYear()-200;return E&&(t=E.getFullYear()),D&&(e=D.getFullYear()-t+1),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},X=N(),Z=ye(),Q=_(se,{children:[le?null:_(`div`,{className:d.datePickerHeader,children:[g(n,{icon:ae,onClick:()=>J(-1)}),g(`div`,{className:d.datePickerHeaderMonthAndYearContainer,children:_(`div`,{className:d.datePickerHeaderMonthAndYear,children:[g(u,{plainStyle:!0,scrollToSelected:!0,onChange:e=>I(e),className:d.datePickerHeaderMonth,value:ne(ee(`-`),L,F,1),items:re().map((e,t)=>({key:t+1,label:e}))}),g(u,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:d.datePickerHeaderYear,onChange:e=>R(e),value:L,items:Se()})]})}),g(n,{icon:oe,onClick:()=>J(1)})]}),g(ie,{className:d.datePickerMonth,month:F,year:L,onSelect:q,selectionStart:j??X,selectionEnd:M??X,minDate:E,maxDate:D}),fe&&g(t,{onClick:()=>q(null),children:`Clear`}),de]}),$=C?null:g(o,{readOnly:w,classNames:w?{input:d.datePickerModalInput}:void 0,label:`${pe}${be()?` *`:``}`,value:V,onChange:e=>H(e),onClick:()=>B(!0),customInput:g(v,{mask:`99.99.9999`,maskPlaceholder:`_`,beforeMaskedStateChange:xe}),onBlur:()=>{G.current&&(G.current.touched=!0),U(!1),K(Y(V))},onFocus:()=>U(!0),onMouseEnter:()=>W(!0),onMouseLeave:()=>W(!1),isValid:!Z}),Ce=T?Q:w?g(s,{hideHeader:!0,isOpen:z,onClose:()=>B(!1),children:Q}):g(i,{isOpen:z,onOpenChange:e=>B(e),content:Q,align:r.Left,dontCloseOnChildClick:!0,children:$});return _(`div`,{className:h(d.datePicker,ce),children:[(w||T)&&$,Ce,g(a,{variant:`error`,message:S?S.getCurrentErrorMessage():k||``,isVisible:Z&&(me||he)})]})}export{y as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{Align as r}from"../floatingMenu/floatingMenu.types.mjs";import i from"../floatingMenu/floatingMenu.mjs";import a from"../tooltip/tooltip.mjs";import o from"../input/input.mjs";import s from"../modal/modal.mjs";import{getLocale as c}from"../../services/localization.mjs";import{correctDateMaskValue as ee,getDateFromDayMonthAndYear as te,getDateString as l,getMonthName as ne,getMonthNames as re}from"./dateFunctions.mjs";import ie from"./components/datePickerMonth/datePickerMonth.mjs";import u from"../dropdown/dropdown.mjs";import d from"./datePicker.module.mjs";import{useEffect as f,useRef as p,useState as m}from"react";import h from"classnames";import{faChevronLeft as ae,faChevronRight as oe}from"@fortawesome/free-solid-svg-icons";import{Fragment as se,jsx as g,jsxs as _}from"react/jsx-runtime";import ce from"@mona-health/react-input-mask";function v(v){let{className:le=``,selected:y,onSelect:b=()=>null,formValidator:x=null,noInput:S=!1,noHeader:C=!1,isModal:w=!1,isInline:T=!1,onChange:ue=()=>null,minDate:E=null,maxDate:D=null,children:de=null,showClearButton:fe=!1,label:pe=``,isValid:O=!0,errorMessage:k=``,isRequired:A=!1,startDate:j,endDate:M}=e(`DatePicker`,v),N=()=>x?x.value:y,P=N()??new Date,[F,I]=m(P.getMonth()+1),[L,R]=m(P.getFullYear()),[z,B]=m(!1),[V,H]=m(()=>N()?l(P):``),[me,U]=m(!1),[he,W]=m(!1),[,ge]=m(0),[_e,ve]=m(y),G=p(x);if(_e!==y){ve(y);let e=y??new Date;I(e.getMonth()+1),R(e.getFullYear()),H(y?l(y):``)}f(()=>{if(G.current=x,!x)return;let e=()=>{let e=x.value;e?(I(e.getMonth()+1),R(e.getFullYear()),H(l(e))):H(``),ge(e=>e+1)};return x.registerOnUpdateListener(e),()=>x.removeOnUpdateListener(e)},[x]);let ye=()=>x?x.touched&&x.hasError():!O||!!k,be=()=>!!(A||x?.validators.find(e=>e.validatorId===`required`)),K=e=>{H(e?l(e):``),x&&x.set(e),ue(e)},q=e=>{K(e),b(e),B(!1)},J=e=>{I(t=>{let n=t+e;return n<1?(n=12,R(e=>e-1)):n>12&&(n=1,R(e=>e+1)),n})},Y=e=>{if(e.match(/\d{2}\.\d{2}\.\d{4}/gi)){let[t,n,r]=e.split(`.`),i=te(Number(t),Number(n),Number(r));if(i&&i.toString()!==`Invalid Date`&&(!D||i<=D)&&(!E||i>=E))return i}return null},xe=({previousState:e,nextState:t})=>{if(!e||t.value===e.value)return t;let n=ee(t.value,e.value,t.selection??null),r=Y(n.value);return r&&K(r),n},Se=()=>{let e=400,t=new Date().getFullYear()-200;return E&&(t=E.getFullYear()),D&&(e=D.getFullYear()-t+1),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},X=N(),Z=ye(),Q=_(se,{children:[C?null:_(`div`,{className:d.datePickerHeader,children:[g(n,{icon:ae,onClick:()=>J(-1)}),g(`div`,{className:d.datePickerHeaderMonthAndYearContainer,children:_(`div`,{className:d.datePickerHeaderMonthAndYear,children:[g(u,{plainStyle:!0,scrollToSelected:!0,onChange:e=>I(e),className:d.datePickerHeaderMonth,value:ne(c(`-`),L,F,1),items:re().map((e,t)=>({key:t+1,label:e}))}),g(u,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:d.datePickerHeaderYear,onChange:e=>R(e),value:L,items:Se()})]})}),g(n,{icon:oe,onClick:()=>J(1)})]}),g(ie,{className:d.datePickerMonth,month:F,year:L,onSelect:q,selectionStart:j??X,selectionEnd:M??X,minDate:E,maxDate:D,onNavigateMonth:J}),fe&&g(t,{onClick:()=>q(null),children:`Clear`}),de]}),$=S?null:g(o,{readOnly:w,classNames:w?{input:d.datePickerModalInput}:void 0,label:`${pe}${be()?` *`:``}`,value:V,onChange:e=>H(e),onClick:()=>B(!0),customInput:g(ce,{mask:`99.99.9999`,maskPlaceholder:`_`,beforeMaskedStateChange:xe}),onBlur:()=>{G.current&&(G.current.touched=!0),U(!1),K(Y(V))},onFocus:()=>U(!0),onMouseEnter:()=>W(!0),onMouseLeave:()=>W(!1),isValid:!Z}),Ce=T?Q:w?g(s,{hideHeader:!0,isOpen:z,onClose:()=>B(!1),children:Q}):g(i,{isOpen:z,onOpenChange:e=>B(e),content:Q,align:r.Left,dontCloseOnChildClick:!0,children:$});return _(`div`,{className:h(d.datePicker,le),children:[(w||T)&&$,Ce,g(a,{variant:`error`,message:x?x.getCurrentErrorMessage():k||``,isVisible:Z&&(me||he)})]})}export{v 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 FloatingMenu from '../floatingMenu';\nimport Dropdown from '../dropdown';\nimport { Align } from '../floatingMenu/floatingMenu.types';\nimport InputMask, { InputState, BeforeMaskedStateChangeStates } from '@mona-health/react-input-mask';\nimport { getDateFromDayMonthAndYear, getMonthName, getMonthNames, getDateString, correctDateMaskValue } from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { FormValidator } from 'services/formValidation';\n\nimport styles from './datePicker.module.pcss';\n\nexport interface DatePickerProps {\n className?: string;\n selected?: Date;\n onSelect?: (date: Date | null) => void;\n formValidator?: FormValidator | null;\n noInput?: boolean;\n noHeader?: boolean;\n isModal?: boolean;\n isInline?: boolean;\n onChange?: (date: Date | null) => void;\n minDate?: Date | null;\n maxDate?: Date | null;\n children?: React.ReactNode;\n showClearButton?: boolean;\n label?: string;\n isValid?: boolean;\n errorMessage?: string;\n isRequired?: boolean;\n startDate?: Date;\n endDate?: Date;\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 } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): Date | undefined =>\n 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(() =>\n getCurrValue() ? getDateString(initialDate) : ''\n );\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\n ? (formValidator.touched && formValidator.hasError())\n : (!isValid || !!errorMessage);\n };\n\n const computedIsRequired = (): boolean => {\n return !!(isRequired || formValidator?.validators.find(\n (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) { next = 12; setCurrentYear((y) => y - 1); }\n else if (next > 12) { next = 1; setCurrentYear((y) => y + 1); }\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): InputState => {\n // previousState is only supplied on user-driven change events; on mount/focus/blur\n // there is nothing to auto-correct, so the next state passes through unchanged.\n if (!previousState || 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={styles.datePickerHeader}>\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={styles.datePickerHeaderMonth}\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={styles.datePickerHeaderYear}\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={styles.datePickerMonth}\n month={currentMonth}\n year={currentYear}\n onSelect={handleSelect}\n selectionStart={startDate ?? currValue}\n selectionEnd={endDate ?? currValue}\n minDate={minDate}\n maxDate={maxDate}\n />\n {showClearButton && <Button onClick={() => handleSelect(null)}>Clear</Button>}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <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={\n <InputMask mask=\"99.99.9999\" maskPlaceholder=\"_\" beforeMaskedStateChange={beforeMaskedStateChange} />\n }\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 <FloatingMenu\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n align={Align.Left}\n dontCloseOnChildClick\n >\n {input}\n </FloatingMenu>\n );\n })();\n\n return (\n <div className={cx(styles.datePicker, className)}>\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 FloatingMenu from '../floatingMenu';\nimport Dropdown from '../dropdown';\nimport { Align } from '../floatingMenu/floatingMenu.types';\nimport InputMask, { InputState, BeforeMaskedStateChangeStates } from '@mona-health/react-input-mask';\nimport { getDateFromDayMonthAndYear, getMonthName, getMonthNames, getDateString, correctDateMaskValue } from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { FormValidator } from 'services/formValidation';\n\nimport styles from './datePicker.module.pcss';\n\nexport interface DatePickerProps {\n className?: string;\n selected?: Date;\n onSelect?: (date: Date | null) => void;\n formValidator?: FormValidator | null;\n noInput?: boolean;\n noHeader?: boolean;\n isModal?: boolean;\n isInline?: boolean;\n onChange?: (date: Date | null) => void;\n minDate?: Date | null;\n maxDate?: Date | null;\n children?: React.ReactNode;\n showClearButton?: boolean;\n label?: string;\n isValid?: boolean;\n errorMessage?: string;\n isRequired?: boolean;\n startDate?: Date;\n endDate?: Date;\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 } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): Date | undefined =>\n 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(() =>\n getCurrValue() ? getDateString(initialDate) : ''\n );\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\n ? (formValidator.touched && formValidator.hasError())\n : (!isValid || !!errorMessage);\n };\n\n const computedIsRequired = (): boolean => {\n return !!(isRequired || formValidator?.validators.find(\n (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) { next = 12; setCurrentYear((y) => y - 1); }\n else if (next > 12) { next = 1; setCurrentYear((y) => y + 1); }\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): InputState => {\n // previousState is only supplied on user-driven change events; on mount/focus/blur\n // there is nothing to auto-correct, so the next state passes through unchanged.\n if (!previousState || 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={styles.datePickerHeader}>\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={styles.datePickerHeaderMonth}\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={styles.datePickerHeaderYear}\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={styles.datePickerMonth}\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 && <Button onClick={() => handleSelect(null)}>Clear</Button>}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <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={\n <InputMask mask=\"99.99.9999\" maskPlaceholder=\"_\" beforeMaskedStateChange={beforeMaskedStateChange} />\n }\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 <FloatingMenu\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n align={Align.Left}\n dontCloseOnChildClick\n >\n {input}\n </FloatingMenu>\n );\n })();\n\n return (\n <div className={cx(styles.datePicker, className)}>\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 +1 @@
1
- {"version":3,"file":"dropdown.module.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.module.pcss"],"sourcesContent":["\n.required-mark {\n padding: 0px 0px 0px 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.dropdown {\n position: relative;\n /* See input.module.pcss for why this exists: the visible border lives on `-input`/`-fieldset`\n below, not this root, so a wrapping ButtonGroup's --group-radius-* custom properties (which\n inherit through any nesting depth, unlike border-radius itself) are what let this component\n flatten correctly when it sits inside a ButtonGroup. */\n --dropdown-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n\n &-label {\n display: flex;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n white-space: nowrap;\n margin-right: 5px;\n margin-bottom: 5px;\n display: flex;\n align-items: center;\n color: var(--text-color);\n font-size: 12px;\n position: absolute;\n top: -15px;\n }\n }\n\n &-input {\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--input-background);\n border-radius: var(--dropdown-radius);\n\n &-plain {\n background: transparent;\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus-within {\n outline: none;\n }\n\n &-button {\n padding: 7px 20% 7px 7.5px !important;\n background-color: transparent;\n border: none;\n font-family: inherit;\n font-size: inherit;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n text-align: left;\n width: 100%;\n line-height: 1.25;\n color: var(--text-color);\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n border-radius: var(--dropdown-radius);\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus {\n outline: none;\n }\n\n &-icon {\n float: right;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--spacing-s);\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &-arrow {\n transition: transform 0.25s;\n pointer-events: none;\n\n &-open {\n transform: rotate(180deg);\n }\n }\n }\n }\n\n &-list-anim {\n position: fixed;\n z-index: 1;\n color: var(--text-color);\n background: var(--background-modal);\n box-shadow: var(--card-shadow);\n border-radius: var(--default-border-radius);\n overflow: hidden;\n transform: scaleY(1);\n transition: transform 0.25s;\n transform-origin: right top;\n\n &-flip {\n transform-origin: right bottom;\n }\n\n &-wider {\n width: max-content !important;\n }\n }\n\n &-list {\n width: 100%;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n max-height: 160px;\n list-style-type: none;\n\n &-item {\n border: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--background-modal);\n padding: 8px;\n text-align: left;\n border-radius: 0;\n transition: all 0.3s;\n\n &-active {\n background-color: var(--background-accent);\n }\n\n &-selected {\n font-weight: 500;\n }\n\n &:focus {\n outline: none;\n }\n\n &:hover {\n background-color: var(--background-accent);\n }\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n cursor: not-allowed;\n\n &:hover {\n background-color: var(--disabled-input-color);\n }\n }\n }\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n box-sizing: border-box;\n border-radius: var(--dropdown-radius);\n inset: -10px 0 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-legend {\n display: block;\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n font-size: 13px;\n padding: 5px;\n opacity: 0;\n }\n\n /* With an empty label the span would still reserve its padding, leaving a gap in\n the fieldset's top border. Collapse it so the notch closes when there's no label. */\n span:empty {\n padding: 0.000001px;\n }\n }\n }\n\n &-placeholder {\n position: absolute;\n top: 8px;\n left: 7px;\n transition: all 0.2s;\n opacity: 0;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n inset: 9px 0 0 7px;\n font-size: 16px;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: -9px 0 0 14px;\n font-size: 13px;\n color: var(--input-label-floating-color, var(--text-color));\n }\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 0.5;\n }\n }\n\n &-border {\n &-focused {\n outline-color: var(--primary-color);\n border-color: var(--primary-color);\n }\n\n &-plain {\n border-color: transparent;\n outline-color: transparent;\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"dropdown.module.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.module.pcss"],"sourcesContent":["\n.required-mark {\n padding: 0px 0px 0px 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.dropdown {\n position: relative;\n /* See input.module.pcss for why this exists: the visible border lives on `-input`/`-fieldset`\n below, not this root, so a wrapping ButtonGroup's --group-radius-* custom properties (which\n inherit through any nesting depth, unlike border-radius itself) are what let this component\n flatten correctly when it sits inside a ButtonGroup. */\n --dropdown-radius: var(--group-radius-tl, var(--default-border-radius)) var(--group-radius-tr, var(--default-border-radius))\n var(--group-radius-br, var(--default-border-radius)) var(--group-radius-bl, var(--default-border-radius));\n\n &-label {\n display: flex;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n white-space: nowrap;\n margin-right: 5px;\n margin-bottom: 5px;\n display: flex;\n align-items: center;\n color: var(--text-color);\n font-size: 12px;\n position: absolute;\n top: -15px;\n }\n }\n\n &-input {\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--input-background);\n border-radius: var(--dropdown-radius);\n\n &-plain {\n background: transparent;\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus-within {\n outline: none;\n }\n\n &-button {\n padding: 7px 20% 7px 7.5px !important;\n background-color: transparent;\n border: none;\n font-family: inherit;\n font-size: inherit;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n text-align: left;\n width: 100%;\n line-height: 1.25;\n color: var(--text-color);\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n border-radius: var(--dropdown-radius);\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus {\n outline: none;\n }\n\n &-icon {\n float: right;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--spacing-s);\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &-arrow {\n transition: transform 0.25s;\n pointer-events: none;\n\n &-open {\n transform: rotate(180deg);\n }\n }\n }\n }\n\n &-list-anim {\n position: fixed;\n z-index: 1;\n color: var(--text-color);\n background: var(--background-modal);\n box-shadow: var(--card-shadow);\n border-radius: var(--default-border-radius);\n overflow: hidden;\n transform: scaleY(1);\n transition: transform 0.25s;\n transform-origin: right top;\n\n &-flip {\n transform-origin: right bottom;\n }\n\n &-wider {\n width: max-content !important;\n }\n }\n\n &-list {\n width: 100%;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n max-height: 160px;\n list-style-type: none;\n\n &-item {\n border: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--background-modal);\n padding: 8px;\n text-align: left;\n border-radius: 0;\n transition: all 0.3s;\n\n &-active {\n background-color: var(--background-accent);\n }\n\n &-selected {\n font-weight: 500;\n }\n\n &:focus {\n outline: none;\n }\n\n &:hover {\n background-color: var(--background-accent);\n }\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n cursor: not-allowed;\n\n &:hover {\n background-color: var(--disabled-input-color);\n }\n }\n }\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n box-sizing: border-box;\n border-radius: var(--dropdown-radius);\n inset: -10px 0 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-legend {\n display: block;\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n font-size: 13px;\n padding: 5px;\n opacity: 0;\n }\n\n /* With an empty label the span would still reserve its padding, leaving a gap in\n the fieldset's top border. Collapse it so the notch closes when there's no label. */\n span:empty {\n padding: 0.000001px;\n }\n }\n }\n\n &-placeholder {\n position: absolute;\n top: 8px;\n left: 7px;\n transition: all 0.2s;\n opacity: 0;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n inset: 9px 0 0 7px;\n font-size: 16px;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: -9px 0 0 14px;\n font-size: 13px;\n color: var(--input-label-floating-color, var(--text-color));\n }\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 0.5;\n }\n }\n\n &-border {\n &-focused {\n outline-color: var(--focus-border-color, var(--primary-color));\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-plain:not(&-focused) {\n border-color: transparent;\n outline-color: transparent;\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{useLayoutEffect as n}from"react";var r=8;function i({isOpen:i,triggerRef:a,anchorRef:o,panelRef:s,flipClassName:c,placement:l=`bottom`}){n(()=>{if(!i)return;let n,u;function d(){let i=a.current,f=o.current;if(!i||!f){n=requestAnimationFrame(d);return}let p=e(i);function m(){let e=i.getBoundingClientRect(),n=s.current?.offsetHeight??0,a=window.innerHeight-e.bottom,o=e.top,u=l===`top`?o:a,d=u<n&&(l===`top`?a:o)>u,m=l===`top`?!d:d;f.classList.toggle(c,d),f.style.top=`${m?e.top-f.offsetHeight:e.bottom}px`,f.style.left=`${e.left}px`;let h=s.current;if(h){let t=h===f?0:h.offsetLeft,n=e.left+t,i=n+h.offsetWidth-(window.innerWidth-r),a=r-n;i>0?f.style.left=`${e.left-i}px`:a>0&&(f.style.left=`${e.left+a}px`)}f.style.visibility=t(e,p)?`hidden`:``;let v=s.current;v&&!g.has(v)&&_()}let h=new ResizeObserver(()=>m()),g=new Set;function _(){[f,s.current].forEach(e=>{!e||g.has(e)||(g.add(e),h.observe(e))})}m();let v=[window,...p];v.forEach(e=>e.addEventListener(`scroll`,m,{passive:!0})),window.addEventListener(`resize`,m),u=()=>{v.forEach(e=>e.removeEventListener(`scroll`,m)),window.removeEventListener(`resize`,m),h.disconnect()}}return d(),()=>{n!==void 0&&cancelAnimationFrame(n),u?.()}},[i,a,o,s,c,l])}export{i as useFloatingPosition};
1
+ import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{getVisualViewportRect as n}from"../utils/visualViewport.mjs";import{useLayoutEffect as r}from"react";var i=8;function a({isOpen:a,triggerRef:o,anchorRef:s,panelRef:c,flipClassName:l,placement:u=`bottom`}){r(()=>{if(!a)return;let r,d;function f(){let a=o.current,p=s.current;if(!a||!p){r=requestAnimationFrame(f);return}let m=e(a);function h(){let e=a.getBoundingClientRect(),r=c.current?.offsetHeight??0,o=n(),s=o.top+o.height-e.bottom,d=e.top-o.top,f=u===`top`?d:s,h=f<r&&(u===`top`?s:d)>f,g=u===`top`?!h:h;p.classList.toggle(l,h),p.style.top=`${g?e.top-p.offsetHeight:e.bottom}px`,p.style.left=`${e.left}px`;let y=c.current;if(y){let t=y===p?0:y.offsetLeft,n=e.left+t,r=n+y.offsetWidth-(o.left+o.width-i),a=o.left+i-n;r>0?p.style.left=`${e.left-r}px`:a>0&&(p.style.left=`${e.left+a}px`)}p.style.visibility=t(e,m)?`hidden`:``;let b=c.current;b&&!_.has(b)&&v()}let g=new ResizeObserver(()=>h()),_=new Set;function v(){[p,c.current].forEach(e=>{!e||_.has(e)||(_.add(e),g.observe(e))})}h();let y=[window,...m];y.forEach(e=>e.addEventListener(`scroll`,h,{passive:!0})),window.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`scroll`,h),d=()=>{y.forEach(e=>e.removeEventListener(`scroll`,h)),window.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`scroll`,h),g.disconnect()}}return f(),()=>{r!==void 0&&cancelAnimationFrame(r),d?.()}},[a,o,s,c,l,u])}export{a as useFloatingPosition};
2
2
  //# sourceMappingURL=useFloatingPosition.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: tracks the\n * trigger across scroll/resize on every real scrolling ancestor, flips above the trigger\n * when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * Position/visibility are written straight to the DOM via refs, not through React state:\n * going through setState -> re-render -> commit adds a round-trip that lags behind the\n * browser's own scroll painting by at least a frame.\n */\nexport function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement = 'bottom' }: UseFloatingPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The anchor/trigger may not be mounted yet on the very first invocation of this\n // effect: a portal target (e.g. BodyEnd's `#bodyEnd` div) can still be missing on\n // the initial render, in which case the portaled content — and this ref — commits\n // one render later. Since refs never change identity, that later commit doesn't\n // re-trigger this effect on its own, so retry on the next frame until it's there.\n function trySetup() {\n const trigger = triggerRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !anchor) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const rect = trigger!.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor!.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor!.style.top = `${renderAbove ? rect.top - anchor!.offsetHeight : rect.bottom}px`;\n anchor!.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (window.innerWidth - EDGE_MARGIN);\n const overflowLeft = EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor!.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor!.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor!.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n // The panel can mount a commit later than the anchor; once it's observed this\n // is a single Set lookup, so it costs nothing on the scroll path.\n const panel = panelRef.current;\n if (panel && !observed.has(panel)) observeSizeTargets();\n }\n\n // The panel's own height feeds both the flip decision and, when rendering above,\n // the top offset — so a popup whose content changes size while open (a filtered\n // list shrinking, an async list loading in) has to be re-measured, or it keeps a\n // top computed for its old height and ends up detached from the trigger.\n const resizeObserver = new ResizeObserver(() => updatePos());\n const observed = new Set<Element>();\n function observeSizeTargets() {\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown)\n // but not for a zero-height wrapper whose content sits inside it (FloatingMenu).\n // Called from updatePos too: the panel can mount a commit later than the anchor.\n [anchor, panelRef.current].forEach((el) => {\n if (!el || observed.has(el)) return;\n observed.add(el);\n resizeObserver.observe(el);\n });\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((t) => t.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n teardown = () => {\n scrollTargets.forEach((t) => t.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n resizeObserver.disconnect();\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement]);\n}"],"mappings":"yIAkBA,IAAM,EAAc,EAgBpB,SAAgB,EAAoB,CAAE,SAAQ,aAAY,YAAW,WAAU,gBAAe,YAAY,UAAqC,CAC7I,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAOJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAS,EAAU,QACzB,GAAI,CAAC,GAAW,CAAC,EAAQ,CACvB,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAO,EAAS,sBAAsB,EACtC,EAAc,EAAS,SAAS,cAAgB,EAChD,EAAa,OAAO,YAAc,EAAK,OACvC,EAAa,EAAK,IAClB,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAQ,UAAU,OAAO,EAAe,CAAI,EAK5C,EAAQ,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAQ,aAAe,EAAK,OAAO,IACnF,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAK,IAQlC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,OAAO,WAAa,GAClD,EAAe,EAAc,EAC/B,EAAgB,EAClB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACzC,EAAe,IACxB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAErD,CAEA,EAAQ,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,GAG/E,IAAM,EAAQ,EAAS,QACnB,GAAS,CAAC,EAAS,IAAI,CAAK,GAAG,EAAmB,CACxD,CAMA,IAAM,EAAiB,IAAI,mBAAqB,EAAU,CAAC,EACrD,EAAW,IAAI,IACrB,SAAS,GAAqB,CAI5B,CAAC,EAAQ,EAAS,OAAO,EAAE,QAAS,GAAO,CACrC,CAAC,GAAM,EAAS,IAAI,CAAE,IAC1B,EAAS,IAAI,CAAE,EACf,EAAe,QAAQ,CAAE,EAC3B,CAAC,CACH,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAM,EAAE,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACvF,OAAO,iBAAiB,SAAU,CAAS,EAC3C,MAAiB,CACf,EAAc,QAAS,GAAM,EAAE,oBAAoB,SAAU,CAAS,CAAC,EACvE,OAAO,oBAAoB,SAAU,CAAS,EAC9C,EAAe,WAAW,CAC5B,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAY,EAAW,EAAU,EAAe,CAAS,CAAC,CACxE"}
1
+ {"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: tracks the\n * trigger across scroll/resize on every real scrolling ancestor, flips above the trigger\n * when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * Position/visibility are written straight to the DOM via refs, not through React state:\n * going through setState -> re-render -> commit adds a round-trip that lags behind the\n * browser's own scroll painting by at least a frame.\n */\nexport function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement = 'bottom' }: UseFloatingPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The anchor/trigger may not be mounted yet on the very first invocation of this\n // effect: a portal target (e.g. BodyEnd's `#bodyEnd` div) can still be missing on\n // the initial render, in which case the portaled content — and this ref — commits\n // one render later. Since refs never change identity, that later commit doesn't\n // re-trigger this effect on its own, so retry on the next frame until it's there.\n function trySetup() {\n const trigger = triggerRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !anchor) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const rect = trigger!.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n // open, so flip/clamp react to what's actually on screen instead of the keyboard hiding\n // a panel that \"fit\" against the unshrunk layout viewport.\n const vv = getVisualViewportRect();\n const spaceBelow = vv.top + vv.height - rect.bottom;\n const spaceAbove = rect.top - vv.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor!.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor!.style.top = `${renderAbove ? rect.top - anchor!.offsetHeight : rect.bottom}px`;\n anchor!.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (vv.left + vv.width - EDGE_MARGIN);\n const overflowLeft = vv.left + EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor!.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor!.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor!.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n // The panel can mount a commit later than the anchor; once it's observed this\n // is a single Set lookup, so it costs nothing on the scroll path.\n const panel = panelRef.current;\n if (panel && !observed.has(panel)) observeSizeTargets();\n }\n\n // The panel's own height feeds both the flip decision and, when rendering above,\n // the top offset — so a popup whose content changes size while open (a filtered\n // list shrinking, an async list loading in) has to be re-measured, or it keeps a\n // top computed for its old height and ends up detached from the trigger.\n const resizeObserver = new ResizeObserver(() => updatePos());\n const observed = new Set<Element>();\n function observeSizeTargets() {\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown)\n // but not for a zero-height wrapper whose content sits inside it (FloatingMenu).\n // Called from updatePos too: the panel can mount a commit later than the anchor.\n [anchor, panelRef.current].forEach((el) => {\n if (!el || observed.has(el)) return;\n observed.add(el);\n resizeObserver.observe(el);\n });\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((t) => t.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n // `window.resize` doesn't reliably fire when a mobile keyboard opens/closes — visualViewport\n // does, and is what the space/clamp math above is measured against.\n window.visualViewport?.addEventListener('resize', updatePos);\n window.visualViewport?.addEventListener('scroll', updatePos);\n teardown = () => {\n scrollTargets.forEach((t) => t.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('scroll', updatePos);\n resizeObserver.disconnect();\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement]);\n}"],"mappings":"6MAmBA,IAAM,EAAc,EAgBpB,SAAgB,EAAoB,CAAE,SAAQ,aAAY,YAAW,WAAU,gBAAe,YAAY,UAAqC,CAC7I,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAOJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAS,EAAU,QACzB,GAAI,CAAC,GAAW,CAAC,EAAQ,CACvB,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAO,EAAS,sBAAsB,EACtC,EAAc,EAAS,SAAS,cAAgB,EAIhD,EAAK,EAAsB,EAC3B,EAAa,EAAG,IAAM,EAAG,OAAS,EAAK,OACvC,EAAa,EAAK,IAAM,EAAG,IAC3B,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAQ,UAAU,OAAO,EAAe,CAAI,EAK5C,EAAQ,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAQ,aAAe,EAAK,OAAO,IACnF,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAK,IAQlC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,EAAG,KAAO,EAAG,MAAQ,GACnD,EAAe,EAAG,KAAO,EAAc,EACzC,EAAgB,EAClB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACzC,EAAe,IACxB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAErD,CAEA,EAAQ,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,GAG/E,IAAM,EAAQ,EAAS,QACnB,GAAS,CAAC,EAAS,IAAI,CAAK,GAAG,EAAmB,CACxD,CAMA,IAAM,EAAiB,IAAI,mBAAqB,EAAU,CAAC,EACrD,EAAW,IAAI,IACrB,SAAS,GAAqB,CAI5B,CAAC,EAAQ,EAAS,OAAO,EAAE,QAAS,GAAO,CACrC,CAAC,GAAM,EAAS,IAAI,CAAE,IAC1B,EAAS,IAAI,CAAE,EACf,EAAe,QAAQ,CAAE,EAC3B,CAAC,CACH,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAM,EAAE,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACvF,OAAO,iBAAiB,SAAU,CAAS,EAG3C,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,MAAiB,CACf,EAAc,QAAS,GAAM,EAAE,oBAAoB,SAAU,CAAS,CAAC,EACvE,OAAO,oBAAoB,SAAU,CAAS,EAC9C,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,EAAe,WAAW,CAC5B,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAY,EAAW,EAAU,EAAe,CAAS,CAAC,CACxE"}
@@ -0,0 +1,2 @@
1
+ import{getVisualViewportRect as e}from"../utils/visualViewport.mjs";import{useEffect as t,useState as n}from"react";function r(){let[r,i]=n(()=>{let t=e();return{height:t.height,offsetTop:t.top}});return t(()=>{let t=window.visualViewport;if(!t)return;function n(){let t=e();i({height:t.height,offsetTop:t.top})}return n(),t.addEventListener(`resize`,n),t.addEventListener(`scroll`,n),()=>{t.removeEventListener(`resize`,n),t.removeEventListener(`scroll`,n)}},[]),r}export{r as useVisualViewportSize};
2
+ //# sourceMappingURL=useVisualViewportSize.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVisualViewportSize.mjs","names":[],"sources":["../../../../package/common/hooks/useVisualViewportSize.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\n\nexport interface VisualViewportSize {\n /** Height of the actually-visible viewport in px — shrinks when a mobile on-screen keyboard\n * opens, unlike `window.innerHeight` / CSS `vh`, which stay pinned to the full layout viewport. */\n height: number;\n /** Vertical offset of the visible viewport's top edge within the layout viewport — non-zero once\n * the page has scrolled to keep a focused field above the keyboard. */\n offsetTop: number;\n}\n\n/**\n * Tracks `window.visualViewport` so layout can react to the on-screen keyboard opening/closing.\n * Falls back to `window.innerHeight`/0 in browsers without the API.\n */\nexport function useVisualViewportSize(): VisualViewportSize {\n const [size, setSize] = useState<VisualViewportSize>(() => {\n const rect = getVisualViewportRect();\n return { height: rect.height, offsetTop: rect.top };\n });\n\n useEffect(() => {\n const vv = window.visualViewport;\n if (!vv) return;\n\n function update() {\n const rect = getVisualViewportRect();\n setSize({ height: rect.height, offsetTop: rect.top });\n }\n\n update();\n vv.addEventListener('resize', update);\n vv.addEventListener('scroll', update);\n return () => {\n vv.removeEventListener('resize', update);\n vv.removeEventListener('scroll', update);\n };\n }, []);\n\n return size;\n}\n"],"mappings":"oHAgBA,SAAgB,GAA4C,CAC1D,GAAM,CAAC,EAAM,GAAW,MAAmC,CACzD,IAAM,EAAO,EAAsB,EACnC,MAAO,CAAE,OAAQ,EAAK,OAAQ,UAAW,EAAK,GAAI,CACpD,CAAC,EAoBD,OAlBA,MAAgB,CACd,IAAM,EAAK,OAAO,eAClB,GAAI,CAAC,EAAI,OAET,SAAS,GAAS,CAChB,IAAM,EAAO,EAAsB,EACnC,EAAQ,CAAE,OAAQ,EAAK,OAAQ,UAAW,EAAK,GAAI,CAAC,CACtD,CAKA,OAHA,EAAO,EACP,EAAG,iBAAiB,SAAU,CAAM,EACpC,EAAG,iBAAiB,SAAU,CAAM,MACvB,CACX,EAAG,oBAAoB,SAAU,CAAM,EACvC,EAAG,oBAAoB,SAAU,CAAM,CACzC,CACF,EAAG,CAAC,CAAC,EAEE,CACT"}
@@ -1,2 +1,2 @@
1
- import e from"../ripple/ripple.mjs";import t from"./iconPicker.module.mjs";import"react";import n from"classnames";import{FontAwesomeIcon as r}from"@fortawesome/react-fontawesome";import{jsx as i,jsxs as a}from"react/jsx-runtime";function o(e){let{formValidator:t}=e;return t?t.touched&&t.hasError():!1}function s(e){let{isRequired:t,formValidator:n}=e;return!!(t||n?.validators.find(e=>e.validatorId===`required`))}function c({data:c=[],selectedId:l=null,label:u=``,onChange:d,formValidator:f=null,isRequired:p,className:m,style:h,classNames:g,styles:_,...v}){let y=f?f.value??null:l,b=o({formValidator:f,isRequired:p}),x=s({formValidator:f,isRequired:p});function S(e){f&&f.set(e),d?.(e)}return a(`div`,{...v,className:n(t.iconPicker,{[t.iconPickerError]:b},g?.root,m),style:{..._?.root,...h},children:[u&&a(`div`,{className:n(t.iconPickerLabel,g?.label),style:_?.label,children:[u,x&&` *`]}),i(`div`,{className:n(t.iconPickerItemContainer,g?.itemContainer),style:_?.itemContainer,children:c.map(({id:o,label:s,icon:c,customIcon:l})=>a(`div`,{className:n(t.iconPickerItem,{[t.iconPickerItemSelected]:y===o},g?.item),style:_?.item,title:s,tabIndex:0,role:`button`,onClick:()=>S(o),onKeyDown:({key:e})=>{e===`Enter`&&S(o)},children:[c&&i(r,{icon:c}),l??null,i(e,{})]},o))})]})}export{c as default};
1
+ import e from"../ripple/ripple.mjs";import t from"./iconPicker.module.mjs";import{useRef as n}from"react";import r from"classnames";import{FontAwesomeIcon as i}from"@fortawesome/react-fontawesome";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s(e){let{formValidator:t}=e;return t?t.touched&&t.hasError():!1}function c(e){let{isRequired:t,formValidator:n}=e;return!!(t||n?.validators.find(e=>e.validatorId===`required`))}function l({data:l=[],selectedId:u=null,label:d=``,onChange:f,formValidator:p=null,isRequired:m,className:h,style:g,classNames:_,styles:v,...y}){let b=p?p.value??null:u,x=s({formValidator:p,isRequired:m}),S=c({formValidator:p,isRequired:m}),C=n([]),w=l.findIndex(e=>e.id===b),T=w>=0?w:0;function E(e){p&&p.set(e),f?.(e)}function D(e,t){if(l.length===0)return;let n=(t+e+l.length)%l.length;C.current[n]?.focus(),E(l[n].id)}function O(e,t,n){switch(e.key){case`ArrowDown`:case`ArrowRight`:e.preventDefault(),D(1,t);break;case`ArrowUp`:case`ArrowLeft`:e.preventDefault(),D(-1,t);break;case` `:case`Enter`:e.preventDefault(),E(n);break;default:break}}return o(`div`,{...y,className:r(t.iconPicker,{[t.iconPickerError]:x},_?.root,h),style:{...v?.root,...g},children:[d&&o(`div`,{className:r(t.iconPickerLabel,_?.label),style:v?.label,children:[d,S&&` *`]}),a(`div`,{role:`radiogroup`,"aria-label":d||void 0,className:r(t.iconPickerItemContainer,_?.itemContainer),style:v?.itemContainer,children:l.map(({id:n,label:s,icon:c,customIcon:l},u)=>{let d=b===n;return o(`div`,{ref:e=>{C.current[u]=e},className:r(t.iconPickerItem,{[t.iconPickerItemSelected]:d},_?.item),style:v?.item,title:s,tabIndex:u===T?0:-1,role:`radio`,"aria-checked":d,onClick:()=>E(n),onKeyDown:e=>O(e,u,n),children:[c&&a(i,{icon:c}),l??null,a(e,{})]},n)})})]})}export{l as default};
2
2
  //# sourceMappingURL=iconPicker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"iconPicker.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.tsx"],"sourcesContent":["import React from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport styles from './iconPicker.module.pcss';\nimport Ripple from '../ripple';\nimport type { IconPickerItem, IconPickerProps } from './iconPicker.types';\n\nfunction hasError(props: IconPickerProps): boolean {\n const { formValidator } = props;\n return formValidator ? (formValidator.touched && formValidator.hasError()) : false;\n}\n\nfunction isRequired(props: IconPickerProps): boolean {\n const { isRequired: reqProp, formValidator } = props;\n return !!(reqProp || formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n ));\n}\n\nexport default function IconPicker({\n data = [],\n selectedId = null,\n label = '',\n onChange,\n formValidator = null,\n isRequired: _isRequired,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: IconPickerProps) {\n const currentValue = formValidator ? (formValidator.value as string) ?? null : selectedId;\n const showError = hasError({ formValidator, isRequired: _isRequired });\n const required = isRequired({ formValidator, isRequired: _isRequired });\n\n function handleSelect(id: string) {\n if (formValidator) formValidator.set(id);\n onChange?.(id);\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.iconPicker, { [styles.iconPickerError]: showError }, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n >\n {label && (\n <div className={cx(styles.iconPickerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {required && ' *'}\n </div>\n )}\n <div\n className={cx(styles.iconPickerItemContainer, classNames?.itemContainer)}\n style={slotStyles?.itemContainer}\n >\n {data.map(({ id, label: itemLabel, icon, customIcon }: IconPickerItem) => (\n <div\n key={id}\n className={cx(\n styles.iconPickerItem,\n { [styles.iconPickerItemSelected]: currentValue === id },\n classNames?.item\n )}\n style={slotStyles?.item}\n title={itemLabel}\n tabIndex={0}\n role=\"button\"\n onClick={() => handleSelect(id)}\n onKeyDown={({ key }) => { if (key === 'Enter') handleSelect(id); }}\n >\n {icon && <FontAwesomeIcon icon={icon} />}\n {customIcon ?? null}\n <Ripple />\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"sOAOA,SAAS,EAAS,EAAiC,CACjD,GAAM,CAAE,iBAAkB,EAC1B,OAAO,EAAiB,EAAc,SAAW,EAAc,SAAS,EAAK,EAC/E,CAEA,SAAS,EAAW,EAAiC,CACnD,GAAM,CAAE,WAAY,EAAS,iBAAkB,EAC/C,MAAO,CAAC,EAAE,GAAW,GAAe,WAAW,KAC5C,GAAO,EAA+B,cAAgB,UACzD,EACF,CAEA,SAAwB,EAAW,CACjC,OAAO,CAAC,EACR,aAAa,KACb,QAAQ,GACR,WACA,gBAAgB,KAChB,WAAY,EACZ,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACe,CAClB,IAAM,EAAe,EAAiB,EAAc,OAAoB,KAAO,EACzE,EAAY,EAAS,CAAE,gBAAe,WAAY,CAAY,CAAC,EAC/D,EAAW,EAAW,CAAE,gBAAe,WAAY,CAAY,CAAC,EAEtE,SAAS,EAAa,EAAY,CAC5B,GAAe,EAAc,IAAI,CAAE,EACvC,IAAW,CAAE,CACf,CAEA,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,WAAY,EAAG,EAAO,iBAAkB,CAAU,EAAG,GAAY,KAAM,CAAS,EACrG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,CAAM,WAHzC,CAKG,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,gBAAiB,GAAY,KAAK,EAAG,MAAO,GAAY,eAAlF,CACG,EACA,GAAY,IACV,IAEP,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,wBAAyB,GAAY,aAAa,EACvE,MAAO,GAAY,uBAElB,EAAK,KAAK,CAAE,KAAI,MAAO,EAAW,OAAM,gBACvC,EAAC,MAAD,CAEE,UAAW,EACT,EAAO,eACP,EAAG,EAAO,wBAAyB,IAAiB,CAAG,EACvD,GAAY,IACd,EACA,MAAO,GAAY,KACnB,MAAO,EACP,SAAU,EACV,KAAK,SACL,YAAe,EAAa,CAAE,EAC9B,WAAY,CAAE,SAAU,CAAM,IAAQ,SAAS,EAAa,CAAE,CAAG,WAZnE,CAcG,GAAQ,EAAC,EAAD,CAAuB,MAAO,CAAA,EACtC,GAAc,KACf,EAAC,EAAD,CAAS,CAAA,CACN,GAhBE,CAgBF,CACN,CACE,CAAA,CACF,GAET"}
1
+ {"version":3,"file":"iconPicker.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport styles from './iconPicker.module.pcss';\nimport Ripple from '../ripple';\nimport type { IconPickerItem, IconPickerProps } from './iconPicker.types';\n\nfunction hasError(props: IconPickerProps): boolean {\n const { formValidator } = props;\n return formValidator ? (formValidator.touched && formValidator.hasError()) : false;\n}\n\nfunction isRequired(props: IconPickerProps): boolean {\n const { isRequired: reqProp, formValidator } = props;\n return !!(reqProp || formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n ));\n}\n\nexport default function IconPicker({\n data = [],\n selectedId = null,\n label = '',\n onChange,\n formValidator = null,\n isRequired: _isRequired,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: IconPickerProps) {\n const currentValue = formValidator ? (formValidator.value as string) ?? null : selectedId;\n const showError = hasError({ formValidator, isRequired: _isRequired });\n const required = isRequired({ formValidator, isRequired: _isRequired });\n\n const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n const selectedIndex = data.findIndex((item) => item.id === currentValue);\n const rovingIndex = selectedIndex >= 0 ? selectedIndex : 0;\n\n function handleSelect(id: string) {\n if (formValidator) formValidator.set(id);\n onChange?.(id);\n }\n\n function moveTo(step: 1 | -1, fromIndex: number) {\n if (data.length === 0) return;\n const next = (fromIndex + step + data.length) % data.length;\n itemRefs.current[next]?.focus();\n handleSelect(data[next].id);\n }\n\n function handleKeyDown(event: React.KeyboardEvent, index: number, id: string) {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight':\n event.preventDefault();\n moveTo(1, index);\n break;\n case 'ArrowUp':\n case 'ArrowLeft':\n event.preventDefault();\n moveTo(-1, index);\n break;\n case ' ':\n case 'Enter':\n event.preventDefault();\n handleSelect(id);\n break;\n default:\n break;\n }\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.iconPicker, { [styles.iconPickerError]: showError }, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n >\n {label && (\n <div className={cx(styles.iconPickerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {required && ' *'}\n </div>\n )}\n <div\n role=\"radiogroup\"\n aria-label={label || undefined}\n className={cx(styles.iconPickerItemContainer, classNames?.itemContainer)}\n style={slotStyles?.itemContainer}\n >\n {data.map(({ id, label: itemLabel, icon, customIcon }: IconPickerItem, index) => {\n const checked = currentValue === id;\n return (\n <div\n key={id}\n ref={(el) => { itemRefs.current[index] = el; }}\n className={cx(\n styles.iconPickerItem,\n { [styles.iconPickerItemSelected]: checked },\n classNames?.item\n )}\n style={slotStyles?.item}\n title={itemLabel}\n tabIndex={index === rovingIndex ? 0 : -1}\n role=\"radio\"\n aria-checked={checked}\n onClick={() => handleSelect(id)}\n onKeyDown={(event) => handleKeyDown(event, index, id)}\n >\n {icon && <FontAwesomeIcon icon={icon} />}\n {customIcon ?? null}\n <Ripple />\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"uPAOA,SAAS,EAAS,EAAiC,CACjD,GAAM,CAAE,iBAAkB,EAC1B,OAAO,EAAiB,EAAc,SAAW,EAAc,SAAS,EAAK,EAC/E,CAEA,SAAS,EAAW,EAAiC,CACnD,GAAM,CAAE,WAAY,EAAS,iBAAkB,EAC/C,MAAO,CAAC,EAAE,GAAW,GAAe,WAAW,KAC5C,GAAO,EAA+B,cAAgB,UACzD,EACF,CAEA,SAAwB,EAAW,CACjC,OAAO,CAAC,EACR,aAAa,KACb,QAAQ,GACR,WACA,gBAAgB,KAChB,WAAY,EACZ,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACe,CAClB,IAAM,EAAe,EAAiB,EAAc,OAAoB,KAAO,EACzE,EAAY,EAAS,CAAE,gBAAe,WAAY,CAAY,CAAC,EAC/D,EAAW,EAAW,CAAE,gBAAe,WAAY,CAAY,CAAC,EAEhE,EAAW,EAAkC,CAAC,CAAC,EAC/C,EAAgB,EAAK,UAAW,GAAS,EAAK,KAAO,CAAY,EACjE,EAAc,GAAiB,EAAI,EAAgB,EAEzD,SAAS,EAAa,EAAY,CAC5B,GAAe,EAAc,IAAI,CAAE,EACvC,IAAW,CAAE,CACf,CAEA,SAAS,EAAO,EAAc,EAAmB,CAC/C,GAAI,EAAK,SAAW,EAAG,OACvB,IAAM,GAAQ,EAAY,EAAO,EAAK,QAAU,EAAK,OACrD,EAAS,QAAQ,IAAO,MAAM,EAC9B,EAAa,EAAK,GAAM,EAAE,CAC5B,CAEA,SAAS,EAAc,EAA4B,EAAe,EAAY,CAC5E,OAAQ,EAAM,IAAd,CACE,IAAK,YACL,IAAK,aACH,EAAM,eAAe,EACrB,EAAO,EAAG,CAAK,EACf,MACF,IAAK,UACL,IAAK,YACH,EAAM,eAAe,EACrB,EAAO,GAAI,CAAK,EAChB,MACF,IAAK,IACL,IAAK,QACH,EAAM,eAAe,EACrB,EAAa,CAAE,EACf,MACF,QACE,KACJ,CACF,CAEA,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,WAAY,EAAG,EAAO,iBAAkB,CAAU,EAAG,GAAY,KAAM,CAAS,EACrG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,CAAM,WAHzC,CAKG,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,gBAAiB,GAAY,KAAK,EAAG,MAAO,GAAY,eAAlF,CACG,EACA,GAAY,IACV,IAEP,EAAC,MAAD,CACE,KAAK,aACL,aAAY,GAAS,IAAA,GACrB,UAAW,EAAG,EAAO,wBAAyB,GAAY,aAAa,EACvE,MAAO,GAAY,uBAElB,EAAK,KAAK,CAAE,KAAI,MAAO,EAAW,OAAM,cAA8B,IAAU,CAC/E,IAAM,EAAU,IAAiB,EACjC,OACE,EAAC,MAAD,CAEE,IAAM,GAAO,CAAE,EAAS,QAAQ,GAAS,CAAI,EAC7C,UAAW,EACT,EAAO,eACP,EAAG,EAAO,wBAAyB,CAAQ,EAC3C,GAAY,IACd,EACA,MAAO,GAAY,KACnB,MAAO,EACP,SAAU,IAAU,EAAc,EAAI,GACtC,KAAK,QACL,eAAc,EACd,YAAe,EAAa,CAAE,EAC9B,UAAY,GAAU,EAAc,EAAO,EAAO,CAAE,WAdtD,CAgBG,GAAQ,EAAC,EAAD,CAAuB,MAAO,CAAA,EACtC,GAAc,KACf,EAAC,EAAD,CAAS,CAAA,CACN,GAlBE,CAkBF,CAET,CAAC,CACE,CAAA,CACF,GAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"iconPicker.module.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.module.pcss"],"sourcesContent":[".iconPicker {\n border-width: 1px;\n border-radius: var(--default-border-radius);\n border-color: transparent;\n border-style: solid;\n\n &-label {\n font-size: var(--text-small-font-size);\n margin-bottom: 8px;\n }\n\n &-item {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 8px;\n width: 24px;\n height: 24px;\n background: var(--background-accent);\n border-radius: 200px;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n stroke: var(--text-color);\n position: relative;\n\n &:focus-visible {\n outline: 1px solid var(--primary-color);\n }\n\n &-container {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-around;\n gap: 8px 14px;\n }\n\n &-selected {\n background: var(--primary-color);\n }\n }\n\n &-error {\n border-color: red;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"iconPicker.module.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.module.pcss"],"sourcesContent":[".iconPicker {\n border-width: 1px;\n border-radius: var(--default-border-radius);\n border-color: transparent;\n border-style: solid;\n\n &-label {\n font-size: var(--text-small-font-size);\n margin-bottom: 8px;\n }\n\n &-item {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 8px;\n width: 24px;\n height: 24px;\n background: var(--background-accent);\n border-radius: 200px;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n stroke: var(--text-color);\n position: relative;\n\n &:focus-visible {\n outline: 1px solid var(--focus-border-color, var(--primary-color));\n }\n\n &-container {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-around;\n gap: 8px 14px;\n }\n\n &-selected {\n background: var(--primary-color);\n\n /* The selected item's own background is --primary-color, which is also the\n default --focus-border-color — use the on-primary color instead so the ring\n stays visible on whichever item roving tabindex focuses by default. */\n &:focus-visible {\n outline-color: var(--text-on-primary);\n }\n }\n }\n\n &-error {\n border-color: red;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- import e from"../loading/spinnerLoading/index.mjs";import t from"./infiniteBlock.module.mjs";import n,{useCallback as r,useRef as i,useState as a}from"react";import o from"classnames";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l(e,t){let n=e;for(;n.props.children!==null&&typeof n.props.children==`object`&&!Array.isArray(n.props.children);)n=n.props.children;let r=n.props.children;if(Array.isArray(r)){let e=r;if(!e[0]?.props?.children){for(let n of e)if(typeof n==`string`&&n.trim().length>0)return n.toLowerCase().startsWith(t)}return String(e[0].props.children).toLowerCase().startsWith(t)}return String(r).toLowerCase().startsWith(t)}function u(e,t,n){let r=e+t;return r===n?0:r<-1?n-1:r}function d({children:d,onScroll:f,className:p=``,isDataLoading:m=!1,setHighlightedIndex:h=()=>null}){let g=i(null),_=i(!1),[v,y]=a(!1),b=i(-1),x=i(null),S=r(()=>{let e=g.current;if(!e)return;let{scrollTop:t,offsetHeight:n,scrollHeight:r}=e;Math.abs(t+n-r)>5||_.current||(_.current=!0,y(!0),f().then(()=>{_.current=!1,y(!1)}))},[f]),C=r(e=>{let t=g.current;if(!t)return;let r=n.Children.toArray(d),i=b.current;switch(e.key){case`ArrowDown`:i=u(i,1,r.length);break;case`ArrowUp`:i=u(i,-1,r.length);break;default:for(let t=0;t<r.length;t++)if(l(r[t],e.key)){if(i>=t&&x.current===e.key)continue;i=t;break}}if(b.current=i,x.current=e.key,i>=0){let e=t.children[i];if(e){let n=e.offsetTop,r=n+e.offsetHeight;n<t.scrollTop?t.scrollTop=n:r>t.scrollTop+t.clientHeight&&(t.scrollTop=r-t.clientHeight)}h(i)}},[d,h]);return c(`div`,{className:o(t.infiniteBlock,p),onScroll:S,onKeyDown:C,tabIndex:0,ref:g,children:[m?s(`div`,{className:t.spinnerWrapper,children:s(e,{className:t.spinner})}):d,v&&s(`div`,{className:t.spinnerWrapper,children:s(e,{className:t.spinner})})]})}export{d as default};
1
+ import e from"../loading/spinnerLoading/index.mjs";import t from"./infiniteBlock.module.mjs";import n,{useCallback as r,useEffect as i,useRef as a,useState as o}from"react";import s from"classnames";import{Fragment as c,jsx as l,jsxs as u}from"react/jsx-runtime";function d(e){return e==null||typeof e==`boolean`?``:typeof e==`string`||typeof e==`number`?String(e):Array.isArray(e)?e.map(d).join(``):n.isValidElement(e)?d(e.props.children):``}function f(e,t,n){return e===-1?t>0?0:n-1:(e+t+n)%n}function p(e,t,n){let[r,s]=o(!1),c=a(!1),l=a(null),u=a(t);return i(()=>{u.current=t}),i(()=>{let t=e.current,r=l.current;if(n||!t||!r)return;let i=!1,a=()=>{c.current||(c.current=!0,s(!0),u.current().catch(()=>null).finally(()=>{i||(c.current=!1,s(!1),o.unobserve(r),o.observe(r))}))},o=new IntersectionObserver(([e])=>{e.isIntersecting&&a()},{root:t});return o.observe(r),()=>{i=!0,o.disconnect()}},[e,n]),{isLoading:r,sentinelRef:l}}function m(e,t){let i=a(null),o=a(-1),s=a(null);return{containerRef:i,onKeyDown:r(r=>{let a=i.current;if(!a)return;let c=n.Children.toArray(e);if(c.length===0)return;let l=o.current;if(r.key===`ArrowDown`)r.preventDefault(),l=f(l,1,c.length);else if(r.key===`ArrowUp`)r.preventDefault(),l=f(l,-1,c.length);else if(r.key.length===1){let e=r.key.toLowerCase(),t=s.current===r.key?l+1:0,n=t=>d(t).toLowerCase().startsWith(e),i=c.slice(t).findIndex(n),a=i===-1?c.slice(0,t).findIndex(n):t+i;if(s.current=r.key,a===-1)return;l=a}else return;s.current=r.key,o.current=l;let u=a.children[l];if(u){let e=u.offsetTop,t=e+u.offsetHeight;e<a.scrollTop?a.scrollTop=e:t>a.scrollTop+a.clientHeight&&(a.scrollTop=t-a.clientHeight)}t(l)},[e,t])}}function h({children:n,onScroll:r,className:i=``,isDataLoading:a=!1,setHighlightedIndex:o=()=>null}){let{containerRef:d,onKeyDown:f}=m(n,o),{isLoading:h,sentinelRef:g}=p(d,r,a);return l(`div`,{className:s(t.infiniteBlock,i),onKeyDown:f,tabIndex:0,ref:d,children:a?l(`div`,{className:t.spinnerWrapper,children:l(e,{className:t.spinner})}):u(c,{children:[n,l(`div`,{ref:g,className:t.sentinel,"aria-hidden":`true`}),h&&l(`div`,{className:t.spinnerWrapper,children:l(e,{className:t.spinner})})]})})}export{h as default};
2
2
  //# sourceMappingURL=infiniteBlock.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"infiniteBlock.mjs","names":[],"sources":["../../../../package/common/infiniteBlock/infiniteBlock.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback } from 'react';\nimport cx from 'classnames';\n\nimport styles from './infiniteBlock.module.pcss';\nimport SpinnerLoading from '../loading/spinnerLoading';\nimport type { InfiniteBlockProps } from './infiniteBlock.types';\n\n// Walk down a React element tree until we reach a string leaf or an array of children.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction childStartsWithKey(child: React.ReactElement<any>, key: string): boolean {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let node: React.ReactElement<any> = child;\n\n while (\n node.props.children !== null &&\n typeof node.props.children === 'object' &&\n !Array.isArray(node.props.children)\n ) {\n node = node.props.children as typeof node;\n }\n\n const content: unknown = node.props.children;\n\n if (Array.isArray(content)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = content as any[];\n // If the first element has no children of its own, scan for a raw string\n if (!arr[0]?.props?.children) {\n for (const item of arr) {\n if (typeof item === 'string' && item.trim().length > 0) {\n return item.toLowerCase().startsWith(key);\n }\n }\n }\n return String(arr[0].props.children).toLowerCase().startsWith(key);\n }\n\n return String(content).toLowerCase().startsWith(key);\n}\n\nfunction clampIndex(index: number, change: number, length: number): number {\n const next = index + change;\n if (next === length) return 0;\n if (next < -1) return length - 1;\n return next;\n}\n\nfunction InfiniteBlock({\n children,\n onScroll,\n className = '',\n isDataLoading = false,\n setHighlightedIndex = () => null,\n}: InfiniteBlockProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Use a ref (not state) for the scroll-guard so reads are always synchronous,\n // avoiding the React-batching race where two scroll events fire before the\n // first setState call has been committed.\n const isScrollLoadingRef = useRef(false);\n const [showScrollSpinner, setShowScrollSpinner] = useState(false);\n\n // Keyboard nav state lives in refs — it doesn't affect rendering.\n const indexRef = useRef(-1);\n const lastKeyRef = useRef<string | null>(null);\n\n const handleScroll = useCallback(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const { scrollTop, offsetHeight, scrollHeight } = el;\n\n // Browsers calculate scrollTop with a small floating-point error under zoom,\n // so we allow up to 5px of slack before deciding we are at the bottom.\n if (Math.abs(scrollTop + offsetHeight - scrollHeight) > 5) return;\n if (isScrollLoadingRef.current) return;\n\n isScrollLoadingRef.current = true;\n setShowScrollSpinner(true);\n onScroll().then(() => {\n isScrollLoadingRef.current = false;\n setShowScrollSpinner(false);\n });\n }, [onScroll]);\n\n const respondToUserInput = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const el = containerRef.current;\n if (!el) return;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const childArray = React.Children.toArray(children) as React.ReactElement<any>[];\n let index = indexRef.current;\n\n switch (event.key) {\n case 'ArrowDown':\n index = clampIndex(index, 1, childArray.length);\n break;\n case 'ArrowUp':\n index = clampIndex(index, -1, childArray.length);\n break;\n default:\n for (let i = 0; i < childArray.length; i++) {\n if (childStartsWithKey(childArray[i], event.key)) {\n if (index >= i && lastKeyRef.current === event.key) {\n continue;\n }\n index = i;\n break;\n }\n }\n }\n\n indexRef.current = index;\n lastKeyRef.current = event.key;\n\n if (index >= 0) {\n const child = el.children[index] as HTMLElement | undefined;\n if (child) {\n const childTop = child.offsetTop;\n const childBottom = childTop + child.offsetHeight;\n if (childTop < el.scrollTop) {\n el.scrollTop = childTop;\n } else if (childBottom > el.scrollTop + el.clientHeight) {\n el.scrollTop = childBottom - el.clientHeight;\n }\n }\n setHighlightedIndex(index);\n }\n },\n [children, setHighlightedIndex]\n );\n\n return (\n <div\n className={cx(styles.infiniteBlock, className)}\n onScroll={handleScroll}\n onKeyDown={respondToUserInput}\n tabIndex={0}\n ref={containerRef}\n >\n {isDataLoading ? (\n <div className={styles.spinnerWrapper}>\n <SpinnerLoading className={styles.spinner} />\n </div>\n ) : children}\n {showScrollSpinner && (\n <div className={styles.spinnerWrapper}>\n <SpinnerLoading className={styles.spinner} />\n </div>\n )}\n </div>\n );\n}\n\nexport default InfiniteBlock;\n"],"mappings":"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"}
1
+ {"version":3,"file":"infiniteBlock.mjs","names":[],"sources":["../../../../package/common/infiniteBlock/infiniteBlock.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport styles from './infiniteBlock.module.pcss';\nimport SpinnerLoading from '../loading/spinnerLoading';\nimport type { InfiniteBlockProps } from './infiniteBlock.types';\n\n// Flattens a React node down to the text it renders, so keyboard type-ahead can match\n// against whatever a child actually displays — a plain string, a number, or something\n// wrapped in nested elements/fragments/arrays (e.g. an icon + label pair).\nfunction getNodeText(node: React.ReactNode): string {\n if (node === null || node === undefined || typeof node === 'boolean') return '';\n if (typeof node === 'string' || typeof node === 'number') return String(node);\n if (Array.isArray(node)) return node.map(getNodeText).join('');\n if (React.isValidElement<{ children?: React.ReactNode }>(node)) {\n return getNodeText(node.props.children);\n }\n return '';\n}\n\n// Cycles the index by `change`, wrapping directly from last to first (and first to last) —\n// no \"nothing highlighted\" stop in between, in either direction. `-1` means nothing is\n// highlighted yet: ArrowDown from there starts at the first item, ArrowUp at the last.\nfunction clampIndex(index: number, change: number, length: number): number {\n if (index === -1) return change > 0 ? 0 : length - 1;\n return (index + change + length) % length;\n}\n\n// Loads more items once a sentinel element at the end of the list scrolls into view.\n// IntersectionObserver only fires on a change of intersection state, so if a page of\n// freshly-loaded items still doesn't fill the container, the sentinel stays visible and\n// we have to re-arm the observer ourselves to pick up the next page.\nfunction useInfiniteScroll(\n containerRef: React.RefObject<HTMLDivElement | null>,\n onScroll: () => Promise<void>,\n disabled: boolean\n) {\n const [isLoading, setIsLoading] = useState(false);\n const isLoadingRef = useRef(false);\n const sentinelRef = useRef<HTMLDivElement>(null);\n\n // Kept in a ref so a caller passing a fresh onScroll function each render doesn't\n // tear down and recreate the observer every time.\n const onScrollRef = useRef(onScroll);\n useEffect(() => {\n onScrollRef.current = onScroll;\n });\n\n useEffect(() => {\n const root = containerRef.current;\n const sentinel = sentinelRef.current;\n if (disabled || !root || !sentinel) return undefined;\n\n let cancelled = false;\n\n const loadMore = () => {\n if (isLoadingRef.current) return;\n isLoadingRef.current = true;\n setIsLoading(true);\n\n onScrollRef\n .current()\n .catch(() => null)\n .finally(() => {\n if (cancelled) return;\n isLoadingRef.current = false;\n setIsLoading(false);\n observer.unobserve(sentinel);\n observer.observe(sentinel);\n });\n };\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) loadMore();\n },\n { root }\n );\n\n observer.observe(sentinel);\n\n return () => {\n cancelled = true;\n observer.disconnect();\n };\n }, [containerRef, disabled]);\n\n return { isLoading, sentinelRef };\n}\n\n// Arrow-key navigation plus type-ahead: pressing a character key jumps to the next child\n// whose text starts with it, cycling through repeats and wrapping at the end of the list.\nfunction useTypeaheadNav(\n children: React.ReactNode,\n setHighlightedIndex: (index: number) => void\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const indexRef = useRef(-1);\n const lastKeyRef = useRef<string | null>(null);\n\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const container = containerRef.current;\n if (!container) return;\n\n const childArray = React.Children.toArray(children);\n if (childArray.length === 0) return;\n\n let index = indexRef.current;\n\n if (event.key === 'ArrowDown') {\n // Without this, the browser's own native \"scroll a focused scrollable element on\n // arrow keys\" behavior fires alongside our scrollIntoView math below, stacking an\n // extra native scroll on top of ours on every press until the highlighted item is\n // pushed out of view entirely.\n event.preventDefault();\n index = clampIndex(index, 1, childArray.length);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n index = clampIndex(index, -1, childArray.length);\n } else if (event.key.length === 1) {\n const key = event.key.toLowerCase();\n const repeatingKey = lastKeyRef.current === event.key;\n const searchStart = repeatingKey ? index + 1 : 0;\n const startsWithKey = (child: React.ReactNode) =>\n getNodeText(child).toLowerCase().startsWith(key);\n\n const afterCurrent = childArray.slice(searchStart).findIndex(startsWithKey);\n const match =\n afterCurrent !== -1\n ? searchStart + afterCurrent\n : childArray.slice(0, searchStart).findIndex(startsWithKey);\n\n lastKeyRef.current = event.key;\n if (match === -1) return;\n index = match;\n } else {\n return;\n }\n\n lastKeyRef.current = event.key;\n indexRef.current = index;\n\n const child = container.children[index] as HTMLElement | undefined;\n if (child) {\n const childTop = child.offsetTop;\n const childBottom = childTop + child.offsetHeight;\n if (childTop < container.scrollTop) {\n container.scrollTop = childTop;\n } else if (childBottom > container.scrollTop + container.clientHeight) {\n container.scrollTop = childBottom - container.clientHeight;\n }\n }\n setHighlightedIndex(index);\n },\n [children, setHighlightedIndex]\n );\n\n return { containerRef, onKeyDown };\n}\n\nfunction InfiniteBlock({\n children,\n onScroll,\n className = '',\n isDataLoading = false,\n setHighlightedIndex = () => null,\n}: InfiniteBlockProps) {\n const { containerRef, onKeyDown } = useTypeaheadNav(children, setHighlightedIndex);\n const { isLoading: showScrollSpinner, sentinelRef } = useInfiniteScroll(\n containerRef,\n onScroll,\n isDataLoading\n );\n\n return (\n <div\n className={cx(styles.infiniteBlock, className)}\n onKeyDown={onKeyDown}\n tabIndex={0}\n ref={containerRef}\n >\n {isDataLoading ? (\n <div className={styles.spinnerWrapper}>\n <SpinnerLoading className={styles.spinner} />\n </div>\n ) : (\n <>\n {children}\n <div ref={sentinelRef} className={styles.sentinel} aria-hidden=\"true\" />\n {showScrollSpinner && (\n <div className={styles.spinnerWrapper}>\n <SpinnerLoading className={styles.spinner} />\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport default InfiniteBlock;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e={infiniteBlock:`infiniteBlock_dFv-h`,"spinner-wrapper":`spinner-wrapper_hsgWz`,spinnerWrapper:`spinner-wrapper_hsgWz`,spinner:`spinner_VjUS2`};export{e as default};
1
+ var e={infiniteBlock:`infiniteBlock_dFv-h`,sentinel:`sentinel_n-Zie`,"spinner-wrapper":`spinner-wrapper_hsgWz`,spinnerWrapper:`spinner-wrapper_hsgWz`,spinner:`spinner_VjUS2`};export{e as default};
2
2
  //# sourceMappingURL=infiniteBlock.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"infiniteBlock.module.mjs","names":[],"sources":["../../../../package/common/infiniteBlock/infiniteBlock.module.pcss"],"sourcesContent":[".infiniteBlock {\n max-height: none;\n}\n\n.spinner-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 0;\n}\n\n.spinner {\n width: 32px;\n height: 32px;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"infiniteBlock.module.mjs","names":[],"sources":["../../../../package/common/infiniteBlock/infiniteBlock.module.pcss"],"sourcesContent":[".infiniteBlock {\n position: relative;\n max-height: none;\n}\n\n.sentinel {\n height: 1px;\n}\n\n.spinner-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 0;\n}\n\n.spinner {\n width: 32px;\n height: 32px;\n}\n"],"mappings":""}