@rio-cloud/rio-uikit 2.3.0-beta.2 → 2.3.0-beta.3

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 (102) hide show
  1. package/Marker.js +9 -5
  2. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisBanner.d.ts +38 -3
  3. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisBanner.js +104 -109
  4. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisBanner.js.map +1 -1
  5. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisOverlay.d.ts +24 -5
  6. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisOverlay.js +60 -56
  7. package/components/analyticsAnalysisOverlay/AnalyticsAnalysisOverlay.js.map +1 -1
  8. package/components/datepicker/DayPicker.js +72 -70
  9. package/components/datepicker/DayPicker.js.map +1 -1
  10. package/components/datepicker/DayPickerDropdown.d.ts +1 -0
  11. package/components/datepicker/DayPickerDropdown.js +61 -48
  12. package/components/datepicker/DayPickerDropdown.js.map +1 -1
  13. package/components/datepicker/useStackedDayPickerCalendars.js +26 -26
  14. package/components/datepicker/useStackedDayPickerCalendars.js.map +1 -1
  15. package/components/listMenu/ListMenu.d.ts +8 -0
  16. package/components/listMenu/ListMenu.js +74 -66
  17. package/components/listMenu/ListMenu.js.map +1 -1
  18. package/components/map/components/Map.js +189 -157
  19. package/components/map/components/Map.js.map +1 -1
  20. package/components/map/components/MapContext.d.ts +1 -0
  21. package/components/map/components/MapContext.js +8 -7
  22. package/components/map/components/MapContext.js.map +1 -1
  23. package/components/map/components/features/Route.d.ts +65 -1
  24. package/components/map/components/features/Route.js +184 -98
  25. package/components/map/components/features/Route.js.map +1 -1
  26. package/components/map/components/features/basics/Marker.d.ts +21 -1
  27. package/components/map/components/features/basics/Marker.js +99 -40
  28. package/components/map/components/features/basics/Marker.js.map +1 -1
  29. package/components/map/components/features/basics/Polygon.d.ts +24 -1
  30. package/components/map/components/features/basics/Polygon.js +72 -19
  31. package/components/map/components/features/basics/Polygon.js.map +1 -1
  32. package/components/map/components/features/basics/Polyline.d.ts +29 -0
  33. package/components/map/components/features/basics/Polyline.js +69 -39
  34. package/components/map/components/features/basics/Polyline.js.map +1 -1
  35. package/components/map/components/features/layers/MarkerLayer.js +8 -8
  36. package/components/map/components/features/layers/MarkerLayer.js.map +1 -1
  37. package/components/map/components/features/layers/clustering/SimpleClusterLayer.js +13 -6
  38. package/components/map/components/features/layers/clustering/SimpleClusterLayer.js.map +1 -1
  39. package/components/map/utils/clustering.d.ts +1 -1
  40. package/components/map/utils/clustering.js +30 -30
  41. package/components/map/utils/clustering.js.map +1 -1
  42. package/components/map/utils/mapTypes.d.ts +135 -0
  43. package/components/map/utils/mapTypes.js.map +1 -1
  44. package/components/mapMarker/ClusterMapMarker.d.ts +2 -0
  45. package/components/mapMarker/ClusterMapMarker.js.map +1 -1
  46. package/components/mapMarker/SingleMapMarker.d.ts +2 -0
  47. package/components/mapMarker/SingleMapMarker.js.map +1 -1
  48. package/components/selects/ClearButton.js +9 -7
  49. package/components/selects/ClearButton.js.map +1 -1
  50. package/components/table/Table.js +208 -205
  51. package/components/table/Table.js.map +1 -1
  52. package/components/table/Table.types.d.ts +13 -4
  53. package/components/table/TableColumn.d.ts +8 -1
  54. package/components/table/TableColumn.js +66 -64
  55. package/components/table/TableColumn.js.map +1 -1
  56. package/components/table/TableExpandedRow.js +11 -11
  57. package/components/table/TableExpandedRow.js.map +1 -1
  58. package/components/table/TableHeader.d.ts +17 -0
  59. package/components/table/TableHeader.js +89 -76
  60. package/components/table/TableHeader.js.map +1 -1
  61. package/components/table/TableHeaderColumn.d.ts +11 -1
  62. package/components/table/TableHeaderColumn.js +63 -58
  63. package/components/table/TableHeaderColumn.js.map +1 -1
  64. package/components/table/TableRow.d.ts +6 -0
  65. package/components/table/TableRow.js +49 -48
  66. package/components/table/TableRow.js.map +1 -1
  67. package/components/table/context/TableLayoutContext.d.ts +1 -0
  68. package/components/table/context/TableLayoutContext.js.map +1 -1
  69. package/components/table/layout/useHorizontalSectionSync.d.ts +2 -1
  70. package/components/table/layout/useHorizontalSectionSync.js +32 -31
  71. package/components/table/layout/useHorizontalSectionSync.js.map +1 -1
  72. package/components/table/layout/useTableLayout.d.ts +2 -1
  73. package/components/table/layout/useTableLayout.js +37 -30
  74. package/components/table/layout/useTableLayout.js.map +1 -1
  75. package/components/table/render/header/TableDraggableHeaderCell.js +38 -36
  76. package/components/table/render/header/TableDraggableHeaderCell.js.map +1 -1
  77. package/components/table/render/header/TableHeader.types.d.ts +2 -0
  78. package/components/table/render/header/TableHeaderCellContent.js +16 -16
  79. package/components/table/render/header/TableHeaderCellContent.js.map +1 -1
  80. package/components/table/render/header/TableStaticHeaderCell.js +31 -29
  81. package/components/table/render/header/TableStaticHeaderCell.js.map +1 -1
  82. package/components/table/render/header/resolveHeaderCellClassName.d.ts +1 -0
  83. package/components/table/render/header/resolveHeaderCellClassName.js +10 -9
  84. package/components/table/render/header/resolveHeaderCellClassName.js.map +1 -1
  85. package/components/table/runtime/useResolvedRenderColumns.d.ts +4 -4
  86. package/components/table/runtime/useResolvedRenderColumns.js +13 -13
  87. package/components/table/runtime/useResolvedRenderColumns.js.map +1 -1
  88. package/components/table/runtime/useResolvedRenderHeader.d.ts +1 -1
  89. package/components/table/runtime/useResolvedRenderHeader.js.map +1 -1
  90. package/hooks/useDraggableElement.d.ts +27 -5
  91. package/hooks/useDraggableElement.js +100 -23
  92. package/hooks/useDraggableElement.js.map +1 -1
  93. package/hooks/usePopperDropdown.d.ts +1 -0
  94. package/hooks/usePopperDropdown.js +15 -12
  95. package/hooks/usePopperDropdown.js.map +1 -1
  96. package/package.json +1 -1
  97. package/utils/analytics/createAnalyticsOverlayTooltip.js.map +1 -1
  98. package/utils/init/initConfig.js +5 -5
  99. package/utils/init/initConfig.js.map +1 -1
  100. package/version.d.ts +1 -1
  101. package/version.js +1 -1
  102. package/version.js.map +1 -1
@@ -1,39 +1,39 @@
1
- import { useState as S, useCallback as E, useEffect as y } from "react";
2
- import R from "../../hooks/useResizeObserver.js";
3
- import W from "../../hooks/useWindowResize.js";
4
- const A = 480, B = (m = []) => {
5
- const [r, , { inlineSize: a }] = R(), [f, n] = S(!1), o = E(() => {
6
- const e = r.current;
7
- if (!e || typeof window > "u")
1
+ import { useState as A, useCallback as b, useEffect as B } from "react";
2
+ import M from "../../hooks/useResizeObserver.js";
3
+ import k from "../../hooks/useWindowResize.js";
4
+ const q = 480, _ = (f = []) => {
5
+ const [l, , { inlineSize: u }] = M(), [g, o] = A(!1), s = b(() => {
6
+ const n = l.current;
7
+ if (!n || typeof window > "u")
8
8
  return;
9
- const t = e.querySelector(".rdp-months"), s = t ? Array.from(t.querySelectorAll(".rdp-month")) : [], d = s[0];
10
- if (!t || !d) {
11
- n(!1);
9
+ const r = n.querySelector(".rdp-months"), d = r ? Array.from(r.querySelectorAll(".rdp-month")) : [], m = d[0];
10
+ if (!r || !m) {
11
+ o(!1);
12
12
  return;
13
13
  }
14
- const l = e.parentElement, i = window.document.documentElement.clientWidth;
15
- if (!l || !a || !i) {
16
- n(!1);
14
+ const i = n.parentElement, a = i?.parentElement, h = a?.parentElement, c = window.document.documentElement.clientWidth;
15
+ if (!i || !a || !h || !u || !c) {
16
+ o(!1);
17
17
  return;
18
18
  }
19
- if (i < A) {
20
- n(!1);
19
+ if (c < q) {
20
+ o(!1);
21
21
  return;
22
22
  }
23
- const h = Number.parseFloat(window.getComputedStyle(t).columnGap || "0") || 0, p = d.getBoundingClientRect().width, w = Math.max(
23
+ const p = Number.parseFloat(window.getComputedStyle(r).columnGap || "0") || 0, w = m.getBoundingClientRect().width, C = Math.max(
24
24
  0,
25
- e.getBoundingClientRect().width - t.getBoundingClientRect().width
26
- ), C = p * s.length + h * (s.length - 1) + w, g = Array.from(l.children).reduce((c, u) => u === e ? c : c + u.getBoundingClientRect().width, 0);
27
- n(C + g > i - 32);
28
- }, [a, r]);
29
- return W(o), y(() => {
30
- o();
31
- }, [o, ...m]), {
32
- calendarsRef: r,
33
- stackCalendars: f
25
+ n.getBoundingClientRect().width - r.getBoundingClientRect().width
26
+ ), E = w * d.length + p * (d.length - 1) + C, S = Array.from(i.children).reduce((e, t) => t === n ? e : e + t.getBoundingClientRect().width, 0), R = Array.from(a.children).reduce((e, t) => t === i ? e : Math.max(e, t.getBoundingClientRect().width), 0), y = Array.from(h.children).reduce((e, t) => t === a ? e : e + t.getBoundingClientRect().width, 0), W = Math.max(E + S, R);
27
+ o(W + y > c - 32);
28
+ }, [u, l]);
29
+ return k(s), B(() => {
30
+ s();
31
+ }, [s, ...f]), {
32
+ calendarsRef: l,
33
+ stackCalendars: g
34
34
  };
35
35
  };
36
36
  export {
37
- B as default
37
+ _ as default
38
38
  };
39
39
  //# sourceMappingURL=useStackedDayPickerCalendars.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStackedDayPickerCalendars.js","sources":["../../../src/components/datepicker/useStackedDayPickerCalendars.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nimport useResizeObserver from '../../hooks/useResizeObserver';\nimport useWindowResize from '../../hooks/useWindowResize';\n\nconst STACKED_CALENDARS_XS_MAX = 480;\n\nconst useStackedDayPickerCalendars = (dependencies: readonly unknown[] = []) => {\n const [calendarsRef, , { inlineSize: calendarsInlineSize }] = useResizeObserver<HTMLDivElement>();\n const [stackCalendars, setStackCalendars] = useState(false);\n\n const updateCalendarLayout = useCallback(() => {\n const calendarsElement = calendarsRef.current;\n if (!calendarsElement || typeof window === 'undefined') {\n return;\n }\n\n const monthsWrapper = calendarsElement.querySelector<HTMLElement>('.rdp-months');\n const monthElements = monthsWrapper\n ? Array.from(monthsWrapper.querySelectorAll<HTMLElement>('.rdp-month'))\n : [];\n const firstMonthElement = monthElements[0];\n\n if (!monthsWrapper || !firstMonthElement) {\n setStackCalendars(false);\n return;\n }\n\n const rowElement = calendarsElement.parentElement;\n const viewportWidth = window.document.documentElement.clientWidth;\n\n if (!rowElement || !calendarsInlineSize || !viewportWidth) {\n setStackCalendars(false);\n return;\n }\n\n // XS layouts are always stacked via CSS so Popper measures the compact layout immediately.\n if (viewportWidth < STACKED_CALENDARS_XS_MAX) {\n setStackCalendars(false);\n return;\n }\n\n const monthsGap = Number.parseFloat(window.getComputedStyle(monthsWrapper).columnGap || '0') || 0;\n const monthWidth = firstMonthElement.getBoundingClientRect().width;\n const calendarsExtraWidth = Math.max(\n 0,\n calendarsElement.getBoundingClientRect().width - monthsWrapper.getBoundingClientRect().width\n );\n const requiredCalendarsWidth =\n monthWidth * monthElements.length + monthsGap * (monthElements.length - 1) + calendarsExtraWidth;\n const siblingWidth = Array.from(rowElement.children).reduce((sum, child) => {\n if (child === calendarsElement) {\n return sum;\n }\n\n return sum + (child as HTMLElement).getBoundingClientRect().width;\n }, 0);\n\n setStackCalendars(requiredCalendarsWidth + siblingWidth > viewportWidth - 32);\n }, [calendarsInlineSize, calendarsRef]);\n\n useWindowResize(updateCalendarLayout);\n\n useEffect(() => {\n updateCalendarLayout();\n }, [updateCalendarLayout, ...dependencies]);\n\n return {\n calendarsRef,\n stackCalendars,\n };\n};\n\nexport default useStackedDayPickerCalendars;\n"],"names":["STACKED_CALENDARS_XS_MAX","useStackedDayPickerCalendars","dependencies","calendarsRef","calendarsInlineSize","useResizeObserver","stackCalendars","setStackCalendars","useState","updateCalendarLayout","useCallback","calendarsElement","monthsWrapper","monthElements","firstMonthElement","rowElement","viewportWidth","monthsGap","monthWidth","calendarsExtraWidth","requiredCalendarsWidth","siblingWidth","sum","child","useWindowResize","useEffect"],"mappings":";;;AAKA,MAAMA,IAA2B,KAE3BC,IAA+B,CAACC,IAAmC,OAAO;AAC5E,QAAM,CAACC,KAAgB,EAAE,YAAYC,EAAA,CAAqB,IAAIC,EAAA,GACxD,CAACC,GAAgBC,CAAiB,IAAIC,EAAS,EAAK,GAEpDC,IAAuBC,EAAY,MAAM;AAC3C,UAAMC,IAAmBR,EAAa;AACtC,QAAI,CAACQ,KAAoB,OAAO,SAAW;AACvC;AAGJ,UAAMC,IAAgBD,EAAiB,cAA2B,aAAa,GACzEE,IAAgBD,IAChB,MAAM,KAAKA,EAAc,iBAA8B,YAAY,CAAC,IACpE,CAAA,GACAE,IAAoBD,EAAc,CAAC;AAEzC,QAAI,CAACD,KAAiB,CAACE,GAAmB;AACtC,MAAAP,EAAkB,EAAK;AACvB;AAAA,IACJ;AAEA,UAAMQ,IAAaJ,EAAiB,eAC9BK,IAAgB,OAAO,SAAS,gBAAgB;AAEtD,QAAI,CAACD,KAAc,CAACX,KAAuB,CAACY,GAAe;AACvD,MAAAT,EAAkB,EAAK;AACvB;AAAA,IACJ;AAGA,QAAIS,IAAgBhB,GAA0B;AAC1C,MAAAO,EAAkB,EAAK;AACvB;AAAA,IACJ;AAEA,UAAMU,IAAY,OAAO,WAAW,OAAO,iBAAiBL,CAAa,EAAE,aAAa,GAAG,KAAK,GAC1FM,IAAaJ,EAAkB,sBAAA,EAAwB,OACvDK,IAAsB,KAAK;AAAA,MAC7B;AAAA,MACAR,EAAiB,sBAAA,EAAwB,QAAQC,EAAc,wBAAwB;AAAA,IAAA,GAErFQ,IACFF,IAAaL,EAAc,SAASI,KAAaJ,EAAc,SAAS,KAAKM,GAC3EE,IAAe,MAAM,KAAKN,EAAW,QAAQ,EAAE,OAAO,CAACO,GAAKC,MAC1DA,MAAUZ,IACHW,IAGJA,IAAOC,EAAsB,sBAAA,EAAwB,OAC7D,CAAC;AAEJ,IAAAhB,EAAkBa,IAAyBC,IAAeL,IAAgB,EAAE;AAAA,EAChF,GAAG,CAACZ,GAAqBD,CAAY,CAAC;AAEtC,SAAAqB,EAAgBf,CAAoB,GAEpCgB,EAAU,MAAM;AACZ,IAAAhB,EAAA;AAAA,EACJ,GAAG,CAACA,GAAsB,GAAGP,CAAY,CAAC,GAEnC;AAAA,IACH,cAAAC;AAAA,IACA,gBAAAG;AAAA,EAAA;AAER;"}
1
+ {"version":3,"file":"useStackedDayPickerCalendars.js","sources":["../../../src/components/datepicker/useStackedDayPickerCalendars.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nimport useResizeObserver from '../../hooks/useResizeObserver';\nimport useWindowResize from '../../hooks/useWindowResize';\n\nconst STACKED_CALENDARS_XS_MAX = 480;\n\nconst useStackedDayPickerCalendars = (dependencies: readonly unknown[] = []) => {\n const [calendarsRef, , { inlineSize: calendarsInlineSize }] = useResizeObserver<HTMLDivElement>();\n const [stackCalendars, setStackCalendars] = useState(false);\n\n const updateCalendarLayout = useCallback(() => {\n const calendarsElement = calendarsRef.current;\n if (!calendarsElement || typeof window === 'undefined') {\n return;\n }\n\n const monthsWrapper = calendarsElement.querySelector<HTMLElement>('.rdp-months');\n const monthElements = monthsWrapper\n ? Array.from(monthsWrapper.querySelectorAll<HTMLElement>('.rdp-month'))\n : [];\n const firstMonthElement = monthElements[0];\n\n if (!monthsWrapper || !firstMonthElement) {\n setStackCalendars(false);\n return;\n }\n\n const rowElement = calendarsElement.parentElement;\n const mainColumnElement = rowElement?.parentElement;\n const outerRowElement = mainColumnElement?.parentElement;\n const viewportWidth = window.document.documentElement.clientWidth;\n\n if (!rowElement || !mainColumnElement || !outerRowElement || !calendarsInlineSize || !viewportWidth) {\n setStackCalendars(false);\n return;\n }\n\n // XS layouts are always stacked via CSS so Popper measures the compact layout immediately.\n if (viewportWidth < STACKED_CALENDARS_XS_MAX) {\n setStackCalendars(false);\n return;\n }\n\n const monthsGap = Number.parseFloat(window.getComputedStyle(monthsWrapper).columnGap || '0') || 0;\n const monthWidth = firstMonthElement.getBoundingClientRect().width;\n\n const calendarsExtraWidth = Math.max(\n 0,\n calendarsElement.getBoundingClientRect().width - monthsWrapper.getBoundingClientRect().width\n );\n\n const requiredCalendarsWidth =\n monthWidth * monthElements.length + monthsGap * (monthElements.length - 1) + calendarsExtraWidth;\n\n const rowSiblingWidth = Array.from(rowElement.children).reduce((sum, child) => {\n if (child === calendarsElement) {\n return sum;\n }\n\n return sum + (child as HTMLElement).getBoundingClientRect().width;\n }, 0);\n\n const mainColumnSiblingWidth = Array.from(mainColumnElement.children).reduce((maxWidth, child) => {\n if (child === rowElement) {\n return maxWidth;\n }\n\n return Math.max(maxWidth, (child as HTMLElement).getBoundingClientRect().width);\n }, 0);\n\n const outerRowSiblingWidth = Array.from(outerRowElement.children).reduce((sum, child) => {\n if (child === mainColumnElement) {\n return sum;\n }\n\n return sum + (child as HTMLElement).getBoundingClientRect().width;\n }, 0);\n\n const requiredMainColumnWidth = Math.max(requiredCalendarsWidth + rowSiblingWidth, mainColumnSiblingWidth);\n\n setStackCalendars(requiredMainColumnWidth + outerRowSiblingWidth > viewportWidth - 32);\n }, [calendarsInlineSize, calendarsRef]);\n\n useWindowResize(updateCalendarLayout);\n\n useEffect(() => {\n updateCalendarLayout();\n }, [updateCalendarLayout, ...dependencies]);\n\n return {\n calendarsRef,\n stackCalendars,\n };\n};\n\nexport default useStackedDayPickerCalendars;\n"],"names":["STACKED_CALENDARS_XS_MAX","useStackedDayPickerCalendars","dependencies","calendarsRef","calendarsInlineSize","useResizeObserver","stackCalendars","setStackCalendars","useState","updateCalendarLayout","useCallback","calendarsElement","monthsWrapper","monthElements","firstMonthElement","rowElement","mainColumnElement","outerRowElement","viewportWidth","monthsGap","monthWidth","calendarsExtraWidth","requiredCalendarsWidth","rowSiblingWidth","sum","child","mainColumnSiblingWidth","maxWidth","outerRowSiblingWidth","requiredMainColumnWidth","useWindowResize","useEffect"],"mappings":";;;AAKA,MAAMA,IAA2B,KAE3BC,IAA+B,CAACC,IAAmC,OAAO;AAC5E,QAAM,CAACC,KAAgB,EAAE,YAAYC,EAAA,CAAqB,IAAIC,EAAA,GACxD,CAACC,GAAgBC,CAAiB,IAAIC,EAAS,EAAK,GAEpDC,IAAuBC,EAAY,MAAM;AAC3C,UAAMC,IAAmBR,EAAa;AACtC,QAAI,CAACQ,KAAoB,OAAO,SAAW;AACvC;AAGJ,UAAMC,IAAgBD,EAAiB,cAA2B,aAAa,GACzEE,IAAgBD,IAChB,MAAM,KAAKA,EAAc,iBAA8B,YAAY,CAAC,IACpE,CAAA,GACAE,IAAoBD,EAAc,CAAC;AAEzC,QAAI,CAACD,KAAiB,CAACE,GAAmB;AACtC,MAAAP,EAAkB,EAAK;AACvB;AAAA,IACJ;AAEA,UAAMQ,IAAaJ,EAAiB,eAC9BK,IAAoBD,GAAY,eAChCE,IAAkBD,GAAmB,eACrCE,IAAgB,OAAO,SAAS,gBAAgB;AAEtD,QAAI,CAACH,KAAc,CAACC,KAAqB,CAACC,KAAmB,CAACb,KAAuB,CAACc,GAAe;AACjG,MAAAX,EAAkB,EAAK;AACvB;AAAA,IACJ;AAGA,QAAIW,IAAgBlB,GAA0B;AAC1C,MAAAO,EAAkB,EAAK;AACvB;AAAA,IACJ;AAEA,UAAMY,IAAY,OAAO,WAAW,OAAO,iBAAiBP,CAAa,EAAE,aAAa,GAAG,KAAK,GAC1FQ,IAAaN,EAAkB,sBAAA,EAAwB,OAEvDO,IAAsB,KAAK;AAAA,MAC7B;AAAA,MACAV,EAAiB,sBAAA,EAAwB,QAAQC,EAAc,wBAAwB;AAAA,IAAA,GAGrFU,IACFF,IAAaP,EAAc,SAASM,KAAaN,EAAc,SAAS,KAAKQ,GAE3EE,IAAkB,MAAM,KAAKR,EAAW,QAAQ,EAAE,OAAO,CAACS,GAAKC,MAC7DA,MAAUd,IACHa,IAGJA,IAAOC,EAAsB,sBAAA,EAAwB,OAC7D,CAAC,GAEEC,IAAyB,MAAM,KAAKV,EAAkB,QAAQ,EAAE,OAAO,CAACW,GAAUF,MAChFA,MAAUV,IACHY,IAGJ,KAAK,IAAIA,GAAWF,EAAsB,sBAAA,EAAwB,KAAK,GAC/E,CAAC,GAEEG,IAAuB,MAAM,KAAKX,EAAgB,QAAQ,EAAE,OAAO,CAACO,GAAKC,MACvEA,MAAUT,IACHQ,IAGJA,IAAOC,EAAsB,sBAAA,EAAwB,OAC7D,CAAC,GAEEI,IAA0B,KAAK,IAAIP,IAAyBC,GAAiBG,CAAsB;AAEzG,IAAAnB,EAAkBsB,IAA0BD,IAAuBV,IAAgB,EAAE;AAAA,EACzF,GAAG,CAACd,GAAqBD,CAAY,CAAC;AAEtC,SAAA2B,EAAgBrB,CAAoB,GAEpCsB,EAAU,MAAM;AACZ,IAAAtB,EAAA;AAAA,EACJ,GAAG,CAACA,GAAsB,GAAGP,CAAY,CAAC,GAEnC;AAAA,IACH,cAAAC;AAAA,IACA,gBAAAG;AAAA,EAAA;AAER;"}
@@ -1,6 +1,7 @@
1
1
  import { default as React, ReactNode } from 'react';
2
2
  import { ListMenuNavItem, ListMenuItem } from './ListMenuGroup';
3
3
  export type { ListMenuNavItem, ListMenuItem } from './ListMenuGroup';
4
+ type ListMenuFilterFn<T extends ListMenuNavItem> = (items: ListMenuItem<T>[], value: string, filterKey: keyof T) => ListMenuItem<T>[];
4
5
  export type ListMenuProps<T extends ListMenuNavItem> = {
5
6
  /**
6
7
  * List of menu item groups to be shown.
@@ -68,6 +69,13 @@ export type ListMenuProps<T extends ListMenuNavItem> = {
68
69
  * Additional classes to be set on the wrapper element.
69
70
  */
70
71
  className?: string;
72
+ /**
73
+ * Optional custom filter function.
74
+ *
75
+ * Use this when filtering should do more than a simple substring match,
76
+ * for example fuzzy ranking or multi-field weighting.
77
+ */
78
+ filterFn?: ListMenuFilterFn<T>;
71
79
  };
72
80
  declare const ListMenu: <T extends ListMenuNavItem>(props: ListMenuProps<T>) => import("react/jsx-runtime").JSX.Element;
73
81
  export default ListMenu;
@@ -1,68 +1,76 @@
1
- import { jsxs as u, jsx as t } from "react/jsx-runtime";
2
- import { useState as i, useRef as b, useEffect as x } from "react";
3
- import { isEmpty as _ } from "es-toolkit/compat";
4
- import j from "../../utils/classNames.js";
5
- import A from "../../hooks/useEffectOnce.js";
6
- import D from "../clearableInput/ClearableInput.js";
7
- import G from "../expander/ExpanderPanel.js";
8
- import V from "./ListMenuGroup.js";
9
- import $ from "../../hooks/useEsc.js";
10
- import X from "../../hooks/useWindowResize.js";
11
- import Z from "../../hooks/useKey.js";
12
- import { debounce as q } from "es-toolkit/function";
13
- const J = 10, Q = 580, U = (n, s, r) => n.map((o) => ({
14
- ...o,
15
- navItems: o.navItems.filter(
16
- (a) => a[r].toLowerCase().includes(s.toLowerCase())
1
+ import { jsxs as f, jsx as t } from "react/jsx-runtime";
2
+ import { useState as l, useRef as x, useEffect as v } from "react";
3
+ import { isEmpty as j } from "es-toolkit/compat";
4
+ import A from "../../utils/classNames.js";
5
+ import D from "../../hooks/useEffectOnce.js";
6
+ import G from "../../hooks/useSearchHighlight.js";
7
+ import V from "../clearableInput/ClearableInput.js";
8
+ import $ from "../expander/ExpanderPanel.js";
9
+ import q from "./ListMenuGroup.js";
10
+ import X from "../../hooks/useEsc.js";
11
+ import Z from "../../hooks/useWindowResize.js";
12
+ import J from "../../hooks/useKey.js";
13
+ import { debounce as Q } from "es-toolkit/function";
14
+ const U = 10, Y = 580, ee = (r, s, o) => r.map((n) => ({
15
+ ...n,
16
+ navItems: n.navItems.filter(
17
+ (c) => c[o].toLowerCase().includes(s.toLowerCase())
17
18
  )
18
- })), Y = (n) => n.find(({ navItems: s }) => !_(s)), pe = (n) => {
19
+ })), te = (r) => r.find(({ navItems: s }) => !j(s)), he = (r) => {
19
20
  const {
20
21
  menuItems: s,
21
- focusFilter: r = !1,
22
- enableFilter: o = !1,
23
- filterPlaceholder: a,
24
- onFilterChange: v = () => {
22
+ focusFilter: o = !1,
23
+ enableFilter: n = !1,
24
+ filterPlaceholder: c,
25
+ onFilterChange: h = () => {
25
26
  },
26
27
  notFoundMessage: L,
27
28
  className: w = "",
28
- groupClassName: k = "",
29
- responsive: f = !0,
30
- autoClose: F = !0,
31
- filterKey: O = "key",
32
- trailingInputAddon: h,
29
+ groupClassName: F = "",
30
+ responsive: g = !0,
31
+ autoClose: k = !0,
32
+ filterKey: H = "key",
33
+ trailingInputAddon: y,
34
+ filterFn: O,
33
35
  ...R
34
- } = n, [l, g] = i(""), [T, H] = i(!1), [y, M] = i(!1), [K, S] = i(""), c = b(null), m = b(null), N = () => {
35
- if (f && m.current) {
36
- const [e] = m.current.getElementsByClassName("active");
37
- S(
38
- /* @__PURE__ */ u("div", { className: "display-flex align-items-center", children: [
36
+ } = r, [i, M] = l(""), [T, S] = l(!1), [N, E] = l(!1), [K, z] = l(""), m = x(null), a = x(null), I = () => {
37
+ if (g && a.current) {
38
+ const [e] = a.current.getElementsByClassName("active");
39
+ z(
40
+ /* @__PURE__ */ f("div", { className: "display-flex align-items-center", children: [
39
41
  /* @__PURE__ */ t("span", { className: "rioglyph rioglyph-menu-hamburger margin-right-10" }),
40
42
  /* @__PURE__ */ t("span", { children: e?.innerText })
41
43
  ] })
42
44
  );
43
45
  }
44
46
  };
45
- $(() => {
46
- o && c.current === document.activeElement && g("");
47
+ X(() => {
48
+ n && m.current === document.activeElement && (M(""), h(""));
47
49
  });
48
- const E = q(() => {
49
- N(), H(window.innerWidth < Q);
50
- }, J);
51
- x(E, []), X(E);
50
+ const C = Q(() => {
51
+ I(), S(window.innerWidth < Y);
52
+ }, U);
53
+ v(C, []), Z(C);
52
54
  const d = () => {
53
- c.current?.focus();
55
+ m.current?.focus();
54
56
  };
55
- Z((e) => {
57
+ J((e) => {
56
58
  (e.metaKey || e.ctrlKey) && e.key === "k" && (e.preventDefault(), d());
57
- }), A(() => {
58
- r && d();
59
- }), x(() => N, [s]);
60
- const z = () => r && d(), B = (e) => {
61
- g(e), v(e);
62
- }, I = U(s, l, O), P = (e) => {
63
- const p = e.target.parentElement?.tagName.toLowerCase() === "li";
64
- F && p && M(!1);
65
- }, W = j(
59
+ }), D(() => {
60
+ o && d();
61
+ }), v(I, [s]);
62
+ const B = () => o && d(), P = (e) => {
63
+ M(e), h(e);
64
+ }, p = n ? (O ?? ee)(s, i, H) : s;
65
+ G({
66
+ ref: a,
67
+ query: n ? i : "",
68
+ deps: [p]
69
+ });
70
+ const W = (e) => {
71
+ const u = e.target.parentElement?.tagName.toLowerCase() === "li";
72
+ k && u && E(!1);
73
+ }, _ = A(
66
74
  "form-group",
67
75
  "margin-bottom-5",
68
76
  "padding-left-15",
@@ -71,38 +79,38 @@ const J = 10, Q = 580, U = (n, s, r) => n.map((o) => ({
71
79
  "position-sticky",
72
80
  "top-0",
73
81
  "z-index-1"
74
- ), C = /* @__PURE__ */ u("div", { ...R, className: `ListMenu ${w} ${l ? "filtered" : ""}`, ref: m, children: [
75
- o && /* @__PURE__ */ t("div", { className: W, children: /* @__PURE__ */ u("div", { className: "input-group width-100pct", children: [
82
+ ), b = /* @__PURE__ */ f("div", { ...R, className: `ListMenu ${w} ${i ? "filtered" : ""}`, ref: a, children: [
83
+ n && /* @__PURE__ */ t("div", { className: _, children: /* @__PURE__ */ f("div", { className: "input-group width-100pct", children: [
76
84
  /* @__PURE__ */ t("span", { className: "input-group-addon", children: /* @__PURE__ */ t("span", { className: "rioglyph rioglyph-search", "aria-hidden": "true" }) }),
77
85
  /* @__PURE__ */ t(
78
- D,
86
+ V,
79
87
  {
80
- value: l,
81
- inputRef: c,
82
- placeholder: a,
83
- onChange: B,
84
- onClear: z
88
+ value: i,
89
+ inputRef: m,
90
+ placeholder: c,
91
+ onChange: P,
92
+ onClear: B
85
93
  }
86
94
  ),
87
- h && h
95
+ y && y
88
96
  ] }) }),
89
- !Y(I) && /* @__PURE__ */ t("div", { className: "padding-top-25 text-center text-color-gray", children: L }),
90
- I.map((e, p) => /* @__PURE__ */ t(V, { className: k, menuGroup: e }, p))
97
+ !te(p) && /* @__PURE__ */ t("div", { className: "padding-top-25 text-center text-color-gray", children: L }),
98
+ p.map((e, u) => /* @__PURE__ */ t(q, { className: F, menuGroup: e }, u))
91
99
  ] });
92
- return f && T ? /* @__PURE__ */ t(
93
- G,
100
+ return g && T ? /* @__PURE__ */ t(
101
+ $,
94
102
  {
95
103
  title: K,
96
104
  bsStyle: "default",
97
- open: y,
98
- onToggle: () => M(!y),
105
+ open: N,
106
+ onToggle: () => E(!N),
99
107
  unmountOnExit: !1,
100
108
  className: "shadow-default",
101
- children: /* @__PURE__ */ t("div", { onClick: P, children: C })
109
+ children: /* @__PURE__ */ t("div", { onClick: W, children: b })
102
110
  }
103
- ) : C;
111
+ ) : b;
104
112
  };
105
113
  export {
106
- pe as default
114
+ he as default
107
115
  };
108
116
  //# sourceMappingURL=ListMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListMenu.js","sources":["../../../src/components/listMenu/ListMenu.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react';\nimport { isEmpty } from 'es-toolkit/compat';\n\nimport classNames from '../../utils/classNames';\nimport useEffectOnce from '../../hooks/useEffectOnce';\nimport ClearableInput from '../clearableInput/ClearableInput';\nimport ExpanderPanel from '../expander/ExpanderPanel';\nimport ListMenuGroup, { type ListMenuNavItem, type ListMenuItem } from './ListMenuGroup';\nimport useEsc from '../../hooks/useEsc';\nimport useWindowResize from '../../hooks/useWindowResize';\nimport useKey from '../../hooks/useKey';\nimport { debounce } from 'es-toolkit/function';\n\nexport type { ListMenuNavItem, ListMenuItem } from './ListMenuGroup';\n\nconst RESIZE_THROTTLING = 10;\nconst MOBILE_MAX_WIDTH = 580;\n\nconst filterMenuItems = <T extends ListMenuNavItem>(\n items: ListMenuItem<T>[],\n value: string,\n filterKey: keyof T\n): ListMenuItem<T>[] =>\n items.map(item => ({\n ...item,\n navItems: item.navItems.filter(navItem =>\n (navItem[filterKey] as string).toLowerCase().includes(value.toLowerCase())\n ),\n }));\n\nconst hasMenuItems = <T extends ListMenuNavItem>(items: ListMenuItem<T>[]) =>\n items.find(({ navItems }) => !isEmpty(navItems));\n\nexport type ListMenuProps<T extends ListMenuNavItem> = {\n /**\n * List of menu item groups to be shown.\n */\n menuItems: ListMenuItem<T>[];\n\n /**\n * Enables the filter.\n *\n * @default false\n */\n enableFilter?: boolean;\n\n /**\n * Focus the filter input.\n *\n * @default false\n */\n focusFilter?: boolean;\n\n /**\n * Define the attribute key for filtering.\n *\n * @default 'key'\n */\n filterKey?: keyof T;\n\n /**\n * The placeholder text for the filter input.\n */\n filterPlaceholder?: string;\n\n /**\n * Gets called when the filter input changes.\n *\n * @param value\n * @returns\n */\n onFilterChange?: (value: string) => void;\n\n /**\n * A localized message to be shown when the filter result is empty.\n */\n notFoundMessage?: string | ReactNode;\n\n /**\n * The menu uses collapses on smaller screens using an expander panel.\n *\n * @default true\n */\n responsive?: boolean;\n\n /**\n * Enables automatic closing of the expander panel.\n *\n * Only relevant when using the `responsive` flag. Note: Make sure to not stop the events from bubbling up when\n * clicking on a list item!\n *\n * Using `event.stopPropagation()` will prevent the panel from closing.\n *\n * @default true\n */\n autoClose?: boolean;\n\n /**\n * Additional classes to be set on the menu group element.\n */\n groupClassName?: string;\n\n /**\n * Additional addon for the input group.\n */\n trailingInputAddon?: React.ReactNode;\n\n /**\n * Additional classes to be set on the wrapper element.\n */\n className?: string;\n};\n\nconst ListMenu = <T extends ListMenuNavItem>(props: ListMenuProps<T>) => {\n const {\n menuItems,\n focusFilter = false,\n enableFilter = false,\n filterPlaceholder,\n onFilterChange = () => {},\n notFoundMessage,\n className = '',\n groupClassName = '',\n responsive = true,\n autoClose = true,\n filterKey = 'key',\n trailingInputAddon,\n ...remainingProps\n } = props;\n\n const [filterValue, setFilterValue] = useState('');\n const [isMobileMode, setIsMobileMode] = useState(false);\n const [isExpanderOpen, setIsExpanderOpen] = useState(false);\n const [mobileHeader, setMobileHeader] = useState<ReactNode>('');\n\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const buildMobileHeader = () => {\n if (responsive && listRef.current) {\n const [activeElement] = listRef.current.getElementsByClassName('active') as HTMLCollectionOf<HTMLElement>;\n setMobileHeader(\n <div className='display-flex align-items-center'>\n <span className='rioglyph rioglyph-menu-hamburger margin-right-10' />\n <span>{activeElement?.innerText}</span>\n </div>\n );\n }\n };\n\n // clear filter input on esc\n useEsc(() => {\n if (enableFilter && inputRef.current === document.activeElement) {\n setFilterValue('');\n }\n });\n\n // Convert the menu to an expandable panel for smaller screens\n const handleMobileSize = debounce(() => {\n buildMobileHeader();\n setIsMobileMode(window.innerWidth < MOBILE_MAX_WIDTH);\n }, RESIZE_THROTTLING);\n\n // Render a dropdown menu on mobile on mount\n useEffect(handleMobileSize, []);\n\n useWindowResize(handleMobileSize);\n\n const focusInput = () => {\n inputRef.current?.focus();\n };\n\n useKey((event: KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'k') {\n event.preventDefault();\n focusInput();\n }\n });\n\n // Focus filter input if requested\n useEffectOnce(() => {\n focusFilter && focusInput();\n });\n\n useEffect(() => buildMobileHeader, [menuItems]);\n\n const handleClear = () => focusFilter && focusInput();\n\n const handleFilterChange = (value: string) => {\n setFilterValue(value);\n onFilterChange(value);\n };\n\n const filteredMenuItems = filterMenuItems(menuItems, filterValue, filterKey);\n\n const handleExpanderBodyClick = (event: MouseEvent) => {\n const isListItem = (event.target as HTMLDivElement).parentElement?.tagName.toLowerCase() === 'li';\n if (autoClose && isListItem) {\n setIsExpanderOpen(false);\n }\n };\n\n const formClassNames = classNames(\n 'form-group',\n 'margin-bottom-5',\n 'padding-left-15',\n 'padding-right-15',\n 'padding-bottom-15',\n 'position-sticky',\n 'top-0',\n 'z-index-1'\n );\n\n const listMenu = (\n <div {...remainingProps} className={`ListMenu ${className} ${filterValue ? 'filtered' : ''}`} ref={listRef}>\n {enableFilter && (\n <div className={formClassNames}>\n <div className='input-group width-100pct'>\n <span className='input-group-addon'>\n <span className='rioglyph rioglyph-search' aria-hidden='true' />\n </span>\n <ClearableInput\n value={filterValue}\n inputRef={inputRef}\n placeholder={filterPlaceholder}\n onChange={handleFilterChange}\n onClear={handleClear}\n />\n {trailingInputAddon && trailingInputAddon}\n </div>\n </div>\n )}\n\n {!hasMenuItems(filteredMenuItems) && (\n <div className='padding-top-25 text-center text-color-gray'>{notFoundMessage}</div>\n )}\n\n {filteredMenuItems.map((menuGroup, index) => (\n <ListMenuGroup key={index} className={groupClassName} menuGroup={menuGroup} />\n ))}\n </div>\n );\n\n if (responsive && isMobileMode) {\n return (\n <ExpanderPanel\n title={mobileHeader}\n bsStyle='default'\n open={isExpanderOpen}\n onToggle={() => setIsExpanderOpen(!isExpanderOpen)}\n unmountOnExit={false}\n className='shadow-default'\n >\n <div onClick={handleExpanderBodyClick}>{listMenu}</div>\n </ExpanderPanel>\n );\n }\n\n return listMenu;\n};\n\nexport default ListMenu;\n"],"names":["RESIZE_THROTTLING","MOBILE_MAX_WIDTH","filterMenuItems","items","value","filterKey","item","navItem","hasMenuItems","navItems","isEmpty","ListMenu","props","menuItems","focusFilter","enableFilter","filterPlaceholder","onFilterChange","notFoundMessage","className","groupClassName","responsive","autoClose","trailingInputAddon","remainingProps","filterValue","setFilterValue","useState","isMobileMode","setIsMobileMode","isExpanderOpen","setIsExpanderOpen","mobileHeader","setMobileHeader","inputRef","useRef","listRef","buildMobileHeader","activeElement","jsxs","jsx","useEsc","handleMobileSize","debounce","useEffect","useWindowResize","focusInput","useKey","event","useEffectOnce","handleClear","handleFilterChange","filteredMenuItems","handleExpanderBodyClick","isListItem","formClassNames","classNames","listMenu","ClearableInput","menuGroup","index","ListMenuGroup","ExpanderPanel"],"mappings":"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"}
1
+ {"version":3,"file":"ListMenu.js","sources":["../../../src/components/listMenu/ListMenu.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react';\nimport { isEmpty } from 'es-toolkit/compat';\n\nimport classNames from '../../utils/classNames';\nimport useEffectOnce from '../../hooks/useEffectOnce';\nimport useSearchHighlight from '../../hooks/useSearchHighlight';\nimport ClearableInput from '../clearableInput/ClearableInput';\nimport ExpanderPanel from '../expander/ExpanderPanel';\nimport ListMenuGroup, { type ListMenuNavItem, type ListMenuItem } from './ListMenuGroup';\nimport useEsc from '../../hooks/useEsc';\nimport useWindowResize from '../../hooks/useWindowResize';\nimport useKey from '../../hooks/useKey';\nimport { debounce } from 'es-toolkit/function';\n\nexport type { ListMenuNavItem, ListMenuItem } from './ListMenuGroup';\n\nconst RESIZE_THROTTLING = 10;\nconst MOBILE_MAX_WIDTH = 580;\n\nconst filterMenuItems = <T extends ListMenuNavItem>(\n items: ListMenuItem<T>[],\n value: string,\n filterKey: keyof T\n): ListMenuItem<T>[] =>\n items.map(item => ({\n ...item,\n navItems: item.navItems.filter(navItem =>\n (navItem[filterKey] as string).toLowerCase().includes(value.toLowerCase())\n ),\n }));\n\nconst hasMenuItems = <T extends ListMenuNavItem>(items: ListMenuItem<T>[]) =>\n items.find(({ navItems }) => !isEmpty(navItems));\n\ntype ListMenuFilterFn<T extends ListMenuNavItem> = (\n items: ListMenuItem<T>[],\n value: string,\n filterKey: keyof T\n) => ListMenuItem<T>[];\n\nexport type ListMenuProps<T extends ListMenuNavItem> = {\n /**\n * List of menu item groups to be shown.\n */\n menuItems: ListMenuItem<T>[];\n\n /**\n * Enables the filter.\n *\n * @default false\n */\n enableFilter?: boolean;\n\n /**\n * Focus the filter input.\n *\n * @default false\n */\n focusFilter?: boolean;\n\n /**\n * Define the attribute key for filtering.\n *\n * @default 'key'\n */\n filterKey?: keyof T;\n\n /**\n * The placeholder text for the filter input.\n */\n filterPlaceholder?: string;\n\n /**\n * Gets called when the filter input changes.\n *\n * @param value\n * @returns\n */\n onFilterChange?: (value: string) => void;\n\n /**\n * A localized message to be shown when the filter result is empty.\n */\n notFoundMessage?: string | ReactNode;\n\n /**\n * The menu uses collapses on smaller screens using an expander panel.\n *\n * @default true\n */\n responsive?: boolean;\n\n /**\n * Enables automatic closing of the expander panel.\n *\n * Only relevant when using the `responsive` flag. Note: Make sure to not stop the events from bubbling up when\n * clicking on a list item!\n *\n * Using `event.stopPropagation()` will prevent the panel from closing.\n *\n * @default true\n */\n autoClose?: boolean;\n\n /**\n * Additional classes to be set on the menu group element.\n */\n groupClassName?: string;\n\n /**\n * Additional addon for the input group.\n */\n trailingInputAddon?: React.ReactNode;\n\n /**\n * Additional classes to be set on the wrapper element.\n */\n className?: string;\n\n /**\n * Optional custom filter function.\n *\n * Use this when filtering should do more than a simple substring match,\n * for example fuzzy ranking or multi-field weighting.\n */\n filterFn?: ListMenuFilterFn<T>;\n};\n\nconst ListMenu = <T extends ListMenuNavItem>(props: ListMenuProps<T>) => {\n const {\n menuItems,\n focusFilter = false,\n enableFilter = false,\n filterPlaceholder,\n onFilterChange = () => {},\n notFoundMessage,\n className = '',\n groupClassName = '',\n responsive = true,\n autoClose = true,\n filterKey = 'key',\n trailingInputAddon,\n filterFn,\n ...remainingProps\n } = props;\n\n const [filterValue, setFilterValue] = useState('');\n const [isMobileMode, setIsMobileMode] = useState(false);\n const [isExpanderOpen, setIsExpanderOpen] = useState(false);\n const [mobileHeader, setMobileHeader] = useState<ReactNode>('');\n\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const buildMobileHeader = () => {\n if (responsive && listRef.current) {\n const [activeElement] = listRef.current.getElementsByClassName('active') as HTMLCollectionOf<HTMLElement>;\n setMobileHeader(\n <div className='display-flex align-items-center'>\n <span className='rioglyph rioglyph-menu-hamburger margin-right-10' />\n <span>{activeElement?.innerText}</span>\n </div>\n );\n }\n };\n\n // clear filter input on esc\n useEsc(() => {\n if (enableFilter && inputRef.current === document.activeElement) {\n setFilterValue('');\n onFilterChange('');\n }\n });\n\n // Convert the menu to an expandable panel for smaller screens\n const handleMobileSize = debounce(() => {\n buildMobileHeader();\n setIsMobileMode(window.innerWidth < MOBILE_MAX_WIDTH);\n }, RESIZE_THROTTLING);\n\n // Render a dropdown menu on mobile on mount\n useEffect(handleMobileSize, []);\n\n useWindowResize(handleMobileSize);\n\n const focusInput = () => {\n inputRef.current?.focus();\n };\n\n useKey((event: KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'k') {\n event.preventDefault();\n focusInput();\n }\n });\n\n // Focus filter input if requested\n useEffectOnce(() => {\n focusFilter && focusInput();\n });\n\n useEffect(buildMobileHeader, [menuItems]);\n\n const handleClear = () => focusFilter && focusInput();\n\n const handleFilterChange = (value: string) => {\n setFilterValue(value);\n onFilterChange(value);\n };\n\n const filteredMenuItems = enableFilter\n ? (filterFn ?? filterMenuItems)(menuItems, filterValue, filterKey)\n : menuItems;\n\n useSearchHighlight({\n ref: listRef,\n query: enableFilter ? filterValue : '',\n deps: [filteredMenuItems],\n });\n\n const handleExpanderBodyClick = (event: MouseEvent) => {\n const isListItem = (event.target as HTMLDivElement).parentElement?.tagName.toLowerCase() === 'li';\n if (autoClose && isListItem) {\n setIsExpanderOpen(false);\n }\n };\n\n const formClassNames = classNames(\n 'form-group',\n 'margin-bottom-5',\n 'padding-left-15',\n 'padding-right-15',\n 'padding-bottom-15',\n 'position-sticky',\n 'top-0',\n 'z-index-1'\n );\n\n const listMenu = (\n <div {...remainingProps} className={`ListMenu ${className} ${filterValue ? 'filtered' : ''}`} ref={listRef}>\n {enableFilter && (\n <div className={formClassNames}>\n <div className='input-group width-100pct'>\n <span className='input-group-addon'>\n <span className='rioglyph rioglyph-search' aria-hidden='true' />\n </span>\n <ClearableInput\n value={filterValue}\n inputRef={inputRef}\n placeholder={filterPlaceholder}\n onChange={handleFilterChange}\n onClear={handleClear}\n />\n {trailingInputAddon && trailingInputAddon}\n </div>\n </div>\n )}\n\n {!hasMenuItems(filteredMenuItems) && (\n <div className='padding-top-25 text-center text-color-gray'>{notFoundMessage}</div>\n )}\n\n {filteredMenuItems.map((menuGroup, index) => (\n <ListMenuGroup key={index} className={groupClassName} menuGroup={menuGroup} />\n ))}\n </div>\n );\n\n if (responsive && isMobileMode) {\n return (\n <ExpanderPanel\n title={mobileHeader}\n bsStyle='default'\n open={isExpanderOpen}\n onToggle={() => setIsExpanderOpen(!isExpanderOpen)}\n unmountOnExit={false}\n className='shadow-default'\n >\n <div onClick={handleExpanderBodyClick}>{listMenu}</div>\n </ExpanderPanel>\n );\n }\n\n return listMenu;\n};\n\nexport default ListMenu;\n"],"names":["RESIZE_THROTTLING","MOBILE_MAX_WIDTH","filterMenuItems","items","value","filterKey","item","navItem","hasMenuItems","navItems","isEmpty","ListMenu","props","menuItems","focusFilter","enableFilter","filterPlaceholder","onFilterChange","notFoundMessage","className","groupClassName","responsive","autoClose","trailingInputAddon","filterFn","remainingProps","filterValue","setFilterValue","useState","isMobileMode","setIsMobileMode","isExpanderOpen","setIsExpanderOpen","mobileHeader","setMobileHeader","inputRef","useRef","listRef","buildMobileHeader","activeElement","jsxs","jsx","useEsc","handleMobileSize","debounce","useEffect","useWindowResize","focusInput","useKey","event","useEffectOnce","handleClear","handleFilterChange","filteredMenuItems","useSearchHighlight","handleExpanderBodyClick","isListItem","formClassNames","classNames","listMenu","ClearableInput","menuGroup","index","ListMenuGroup","ExpanderPanel"],"mappings":"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"}