@digital-b2c/coreui-kit 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Luxottica
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luxottica
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,52 +1,52 @@
1
- # CoreUI Kit
2
-
3
- A React‑based design system and component library.
4
-
5
- ## 🚀 Getting Started
6
-
7
- Install
8
-
9
- ```bash
10
- npm install
11
- ```
12
-
13
- Development
14
-
15
- - Run the build in watch mode
16
-
17
- ```bash
18
- npm run dev
19
- ```
20
-
21
- Start Storybook
22
-
23
- ```bash
24
- npm run storybook
25
- ```
26
-
27
- Run tests
28
-
29
- ```bash
30
- npm test
31
- ```
32
-
33
- Lint/format
34
-
35
- ```bash
36
- npm run lint
37
- ```
38
-
39
- ## 🛠️ Usage
40
-
41
- Import components in other projects:
42
-
43
- ```ts
44
- import '@digital-b2c/coreui-kit/styles.css'
45
-
46
- import { MiniSectionCta } from '@digital-b2c/coreui-kit'
47
-
48
- <MiniSectionCta>
49
- <MiniSectionCta.Title>Header</MiniSectionCta.Title>
50
- <MiniSectionCta.Subtitle>Description</MiniSectionCta.Subtitle>
51
- </MiniSectionCta>
52
- ```
1
+ # CoreUI Kit
2
+
3
+ A React‑based design system and component library.
4
+
5
+ ## 🚀 Getting Started
6
+
7
+ Install
8
+
9
+ ```bash
10
+ npm install
11
+ ```
12
+
13
+ Development
14
+
15
+ - Run the build in watch mode
16
+
17
+ ```bash
18
+ npm run dev
19
+ ```
20
+
21
+ Start Storybook
22
+
23
+ ```bash
24
+ npm run storybook
25
+ ```
26
+
27
+ Run tests
28
+
29
+ ```bash
30
+ npm test
31
+ ```
32
+
33
+ Lint/format
34
+
35
+ ```bash
36
+ npm run lint
37
+ ```
38
+
39
+ ## 🛠️ Usage
40
+
41
+ Import components in other projects:
42
+
43
+ ```ts
44
+ import '@digital-b2c/coreui-kit/styles.css'
45
+
46
+ import { MiniSectionCta } from '@digital-b2c/coreui-kit'
47
+
48
+ <MiniSectionCta>
49
+ <MiniSectionCta.Title>Header</MiniSectionCta.Title>
50
+ <MiniSectionCta.Subtitle>Description</MiniSectionCta.Subtitle>
51
+ </MiniSectionCta>
52
+ ```
package/dist/index.cjs CHANGED
@@ -2572,7 +2572,9 @@ var ResourcesGridList_module_default = {
2572
2572
  searchCollapse: "ResourcesGridList_module_searchCollapse",
2573
2573
  searchIconInner: "ResourcesGridList_module_searchIconInner",
2574
2574
  searchInput: "ResourcesGridList_module_searchInput",
2575
+ searchClear: "ResourcesGridList_module_searchClear",
2575
2576
  dropdownPanel: "ResourcesGridList_module_dropdownPanel",
2577
+ searchPanel: "ResourcesGridList_module_searchPanel",
2576
2578
  dropdownOption: "ResourcesGridList_module_dropdownOption",
2577
2579
  selected: "ResourcesGridList_module_selected",
2578
2580
  content: "ResourcesGridList_module_content",
@@ -2589,6 +2591,7 @@ var ResourcesGridList_module_default = {
2589
2591
  cardsArea: "ResourcesGridList_module_cardsArea",
2590
2592
  grid: "ResourcesGridList_module_grid",
2591
2593
  list: "ResourcesGridList_module_list",
2594
+ cardLink: "ResourcesGridList_module_cardLink",
2592
2595
  cardGrid: "ResourcesGridList_module_cardGrid",
2593
2596
  cardBody: "ResourcesGridList_module_cardBody",
2594
2597
  cardIconTitle: "ResourcesGridList_module_cardIconTitle",
@@ -2622,23 +2625,31 @@ function FilterBar({
2622
2625
  filterValue,
2623
2626
  onFilterChange,
2624
2627
  sortValue,
2625
- onSortChange
2628
+ onSortChange,
2629
+ searchValue,
2630
+ onSearchChange
2626
2631
  }) {
2627
2632
  const [openDropdown, setOpenDropdown] = React62.useState(null);
2628
2633
  const [searchState, setSearchState] = React62.useState("closed");
2629
- const [searchQuery, setSearchQuery] = React62.useState("");
2630
2634
  const filterRef = React62.useRef(null);
2631
2635
  const sortRef = React62.useRef(null);
2636
+ const searchRef = React62.useRef(null);
2632
2637
  const searchInputRef = React62.useRef(null);
2633
2638
  const closeSearch = () => {
2634
2639
  setSearchState("closing");
2635
- setSearchQuery("");
2640
+ onSearchChange("");
2641
+ };
2642
+ const clearSearch = () => {
2643
+ var _a;
2644
+ onSearchChange("");
2645
+ (_a = searchInputRef.current) == null ? void 0 : _a.focus();
2636
2646
  };
2637
2647
  React62.useEffect(() => {
2638
2648
  const handleMouseDown = (e) => {
2639
- var _a, _b;
2649
+ var _a, _b, _c;
2640
2650
  const target = e.target;
2641
- if (((_a = filterRef.current) == null ? void 0 : _a.contains(target)) || ((_b = sortRef.current) == null ? void 0 : _b.contains(target))) return;
2651
+ if (((_a = filterRef.current) == null ? void 0 : _a.contains(target)) || ((_b = sortRef.current) == null ? void 0 : _b.contains(target)) || ((_c = searchRef.current) == null ? void 0 : _c.contains(target)))
2652
+ return;
2642
2653
  setOpenDropdown(null);
2643
2654
  };
2644
2655
  document.addEventListener("mousedown", handleMouseDown);
@@ -2648,6 +2659,10 @@ function FilterBar({
2648
2659
  var _a;
2649
2660
  if (searchState === "open") (_a = searchInputRef.current) == null ? void 0 : _a.focus();
2650
2661
  }, [searchState]);
2662
+ React62.useEffect(() => {
2663
+ var _a;
2664
+ if (openDropdown === "search") (_a = searchInputRef.current) == null ? void 0 : _a.focus();
2665
+ }, [openDropdown]);
2651
2666
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.filterBar, children: [
2652
2667
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.viewToggle, children: [
2653
2668
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2747,17 +2762,21 @@ function FilterBar({
2747
2762
  opt.value
2748
2763
  )) })
2749
2764
  ] }),
2750
- searchState !== "closed" ? /* @__PURE__ */ jsxRuntime.jsxs(
2751
- "div",
2752
- {
2753
- className: clsx23__default.default(
2754
- ResourcesGridList_module_default.searchExpanded,
2755
- searchState === "closing" && ResourcesGridList_module_default.searchCollapsing
2765
+ isMobile ? (
2766
+ /* Mobile — popup panel, mirroring the Filter/Sort dropdowns */
2767
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.dropdownWrapper, ref: searchRef, children: [
2768
+ /* @__PURE__ */ jsxRuntime.jsx(
2769
+ "button",
2770
+ {
2771
+ type: "button",
2772
+ className: clsx23__default.default(ResourcesGridList_module_default.chip, searchValue !== "" && ResourcesGridList_module_default.active),
2773
+ onClick: () => setOpenDropdown(openDropdown === "search" ? null : "search"),
2774
+ "aria-expanded": openDropdown === "search",
2775
+ "aria-label": "Search",
2776
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "search", size: 20, "aria-hidden": "true" })
2777
+ }
2756
2778
  ),
2757
- onAnimationEnd: () => {
2758
- if (searchState === "closing") setSearchState("closed");
2759
- },
2760
- children: [
2779
+ openDropdown === "search" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.searchPanel, children: [
2761
2780
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.searchIconInner, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "search", size: 20, "aria-hidden": "true" }) }),
2762
2781
  /* @__PURE__ */ jsxRuntime.jsx(
2763
2782
  "input",
@@ -2766,24 +2785,90 @@ function FilterBar({
2766
2785
  type: "text",
2767
2786
  className: ResourcesGridList_module_default.searchInput,
2768
2787
  placeholder: "Search\u2026",
2769
- value: searchQuery,
2770
- onChange: (e) => setSearchQuery(e.target.value),
2788
+ value: searchValue,
2789
+ onChange: (e) => onSearchChange(e.target.value),
2771
2790
  onKeyDown: (e) => {
2772
- if (e.key === "Escape") closeSearch();
2773
- },
2774
- onBlur: closeSearch
2791
+ if (e.key === "Escape") {
2792
+ if (searchValue) clearSearch();
2793
+ else setOpenDropdown(null);
2794
+ }
2795
+ }
2796
+ }
2797
+ ),
2798
+ searchValue && /* @__PURE__ */ jsxRuntime.jsx(
2799
+ "button",
2800
+ {
2801
+ type: "button",
2802
+ className: ResourcesGridList_module_default.searchClear,
2803
+ "aria-label": "Clear search",
2804
+ onClick: clearSearch,
2805
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "xBlack", size: 16, "aria-hidden": "true" })
2775
2806
  }
2776
2807
  )
2777
- ]
2778
- }
2808
+ ] })
2809
+ ] })
2810
+ ) : searchState !== "closed" ? (
2811
+ /* Desktop — animated inline expand */
2812
+ /* @__PURE__ */ jsxRuntime.jsxs(
2813
+ "div",
2814
+ {
2815
+ className: clsx23__default.default(
2816
+ ResourcesGridList_module_default.searchExpanded,
2817
+ searchState === "closing" && ResourcesGridList_module_default.searchCollapsing
2818
+ ),
2819
+ onAnimationEnd: () => {
2820
+ if (searchState === "closing") setSearchState("closed");
2821
+ },
2822
+ children: [
2823
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.searchIconInner, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "search", size: 20, "aria-hidden": "true" }) }),
2824
+ /* @__PURE__ */ jsxRuntime.jsx(
2825
+ "input",
2826
+ {
2827
+ ref: searchInputRef,
2828
+ type: "text",
2829
+ className: ResourcesGridList_module_default.searchInput,
2830
+ placeholder: "Search\u2026",
2831
+ value: searchValue,
2832
+ onChange: (e) => onSearchChange(e.target.value),
2833
+ onKeyDown: (e) => {
2834
+ if (e.key === "Escape") {
2835
+ if (searchValue) clearSearch();
2836
+ else closeSearch();
2837
+ }
2838
+ },
2839
+ onBlur: () => {
2840
+ if (!searchValue) closeSearch();
2841
+ }
2842
+ }
2843
+ ),
2844
+ searchValue && /* @__PURE__ */ jsxRuntime.jsx(
2845
+ "button",
2846
+ {
2847
+ type: "button",
2848
+ className: ResourcesGridList_module_default.searchClear,
2849
+ "aria-label": "Clear search",
2850
+ onMouseDown: (e) => e.preventDefault(),
2851
+ onClick: clearSearch,
2852
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "xBlack", size: 16, "aria-hidden": "true" })
2853
+ }
2854
+ )
2855
+ ]
2856
+ }
2857
+ )
2779
2858
  ) : /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: ResourcesGridList_module_default.chip, onClick: () => setSearchState("open"), children: [
2780
2859
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "search", size: 20, "aria-hidden": "true" }),
2781
- !isMobile && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.chipLabel, children: "Search" })
2860
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.chipLabel, children: "Search" })
2782
2861
  ] })
2783
2862
  ] })
2784
2863
  ] });
2785
2864
  }
2786
- var Sidebar = ({ categories, isMobile, onToggle }) => {
2865
+ var Sidebar = ({
2866
+ categories,
2867
+ isMobile,
2868
+ onToggle,
2869
+ selectedIndex,
2870
+ onSelect
2871
+ }) => {
2787
2872
  if (isMobile) {
2788
2873
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ResourcesGridList_module_default.sidebarMobile, children: /* @__PURE__ */ jsxRuntime.jsx(
2789
2874
  "button",
@@ -2801,7 +2886,17 @@ var Sidebar = ({ categories, isMobile, onToggle }) => {
2801
2886
  return /* @__PURE__ */ jsxRuntime.jsxs(
2802
2887
  "li",
2803
2888
  {
2804
- className: clsx23__default.default(ResourcesGridList_module_default.sidebarItem, cat.active && ResourcesGridList_module_default.active),
2889
+ className: clsx23__default.default(ResourcesGridList_module_default.sidebarItem, i === selectedIndex && ResourcesGridList_module_default.active),
2890
+ role: "button",
2891
+ tabIndex: 0,
2892
+ "aria-pressed": i === selectedIndex,
2893
+ onClick: () => onSelect(i),
2894
+ onKeyDown: (e) => {
2895
+ if (e.key === "Enter" || e.key === " ") {
2896
+ e.preventDefault();
2897
+ onSelect(i);
2898
+ }
2899
+ },
2805
2900
  children: [
2806
2901
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: cat.label }),
2807
2902
  cat.hasNotification && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.notificationDot, "aria-label": "New" })
@@ -2811,14 +2906,19 @@ var Sidebar = ({ categories, isMobile, onToggle }) => {
2811
2906
  );
2812
2907
  }) }) });
2813
2908
  };
2814
- var ResourceIcon = ({ type }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: ResourcesGridList_module_default.iconWrapper, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: type === "pdf" ? "pdf" : "externalLink", size: 32, "aria-hidden": "true" }) });
2909
+ var ResourceIcon = ({ image, type }) => {
2910
+ if (!image) return null;
2911
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ResourcesGridList_module_default.iconWrapper, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: image, alt: type != null ? type : "", width: 32, height: 32 }) });
2912
+ };
2815
2913
  var ResourceCardItem = ({ item, view }) => {
2914
+ const hasHref = Boolean(item.href);
2915
+ const linkWrapper = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: ResourcesGridList_module_default.cardLink, target: "_blank", rel: "noopener noreferrer", children });
2816
2916
  if (view === "grid") {
2817
2917
  return /* @__PURE__ */ jsxRuntime.jsx("article", { className: ResourcesGridList_module_default.cardGrid, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardBody, children: [
2818
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardIconTitle, children: [
2819
- /* @__PURE__ */ jsxRuntime.jsx(ResourceIcon, { type: item.type }),
2918
+ /* @__PURE__ */ jsxRuntime.jsx(ConditionalWrapper, { condition: hasHref, wrapper: linkWrapper, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardIconTitle, children: [
2919
+ /* @__PURE__ */ jsxRuntime.jsx(ResourceIcon, { image: item.image, type: item.type }),
2820
2920
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.cardTitle, children: item.title })
2821
- ] }),
2921
+ ] }) }),
2822
2922
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardMeta, children: [
2823
2923
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.cardDate, children: item.date }),
2824
2924
  item.hasNotification && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.notificationDot, "aria-label": "New" })
@@ -2827,22 +2927,59 @@ var ResourceCardItem = ({ item, view }) => {
2827
2927
  }
2828
2928
  return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: ResourcesGridList_module_default.cardList, children: [
2829
2929
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardListLeft, children: [
2830
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.cardDate, children: item.date }),
2831
- item.hasNotification && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.notificationDot, "aria-label": "New" })
2930
+ item.hasNotification && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.notificationDot, "aria-label": "New" }),
2931
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.cardDate, children: item.date })
2832
2932
  ] }),
2833
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardListRight, children: [
2834
- /* @__PURE__ */ jsxRuntime.jsx(ResourceIcon, { type: item.type }),
2933
+ /* @__PURE__ */ jsxRuntime.jsx(ConditionalWrapper, { condition: hasHref, wrapper: linkWrapper, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.cardListRight, children: [
2934
+ /* @__PURE__ */ jsxRuntime.jsx(ResourceIcon, { image: item.image, type: item.type }),
2835
2935
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.cardTitle, children: item.title })
2836
- ] })
2936
+ ] }) })
2837
2937
  ] });
2838
2938
  };
2839
- var Pagination3 = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.pagination, "aria-label": "Pagination", children: [
2840
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ResourcesGridList_module_default.pageArrow, "aria-label": "Previous page", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "chevronLeftBlack", size: 32, "aria-hidden": "true" }) }),
2841
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.pageDotActive, "aria-current": "page" }),
2842
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.pageDot }),
2843
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.pageDot }),
2844
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ResourcesGridList_module_default.pageArrow, "aria-label": "Next page", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "chevronRightBlack", size: 32, "aria-hidden": "true" }) })
2845
- ] });
2939
+ var Pagination3 = ({ currentPage, totalPages, onPageChange }) => {
2940
+ const isFirst = currentPage <= 1;
2941
+ const isLast = currentPage >= totalPages;
2942
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.pagination, "aria-label": "Pagination", children: [
2943
+ /* @__PURE__ */ jsxRuntime.jsx(
2944
+ "button",
2945
+ {
2946
+ type: "button",
2947
+ className: ResourcesGridList_module_default.pageArrow,
2948
+ "aria-label": "Previous page",
2949
+ disabled: isFirst,
2950
+ onClick: () => onPageChange(currentPage - 1),
2951
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "chevronLeftBlack", size: 32, "aria-hidden": "true" })
2952
+ }
2953
+ ),
2954
+ Array.from({ length: totalPages }, (_, i) => {
2955
+ const page = i + 1;
2956
+ const isActive = page === currentPage;
2957
+ return /* @__PURE__ */ jsxRuntime.jsx(
2958
+ "button",
2959
+ {
2960
+ type: "button",
2961
+ className: clsx23__default.default(isActive ? ResourcesGridList_module_default.pageDotActive : ResourcesGridList_module_default.pageDot),
2962
+ "aria-label": `Page ${page}`,
2963
+ "aria-current": isActive ? "page" : void 0,
2964
+ onClick: () => onPageChange(page)
2965
+ },
2966
+ page
2967
+ );
2968
+ }),
2969
+ /* @__PURE__ */ jsxRuntime.jsx(
2970
+ "button",
2971
+ {
2972
+ type: "button",
2973
+ className: ResourcesGridList_module_default.pageArrow,
2974
+ "aria-label": "Next page",
2975
+ disabled: isLast,
2976
+ onClick: () => onPageChange(currentPage + 1),
2977
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { type: "chevronRightBlack", size: 32, "aria-hidden": "true" })
2978
+ }
2979
+ )
2980
+ ] });
2981
+ };
2982
+ var ITEMS_PER_PAGE = 12;
2846
2983
  var ResourcesGridList = ({
2847
2984
  className,
2848
2985
  items = [],
@@ -2851,19 +2988,51 @@ var ResourcesGridList = ({
2851
2988
  defaultFilter = "all",
2852
2989
  defaultSort = "latest"
2853
2990
  }) => {
2991
+ var _a;
2854
2992
  const [view, setView] = React62.useState(defaultView);
2855
2993
  const [isSidebarOpen, setIsSidebarOpen] = React62.useState(false);
2856
2994
  const [filterValue, setFilterValue] = React62.useState(defaultFilter);
2857
2995
  const [sortValue, setSortValue] = React62.useState(defaultSort);
2996
+ const [searchQuery, setSearchQuery] = React62.useState("");
2997
+ const [currentPage, setCurrentPage] = React62.useState(1);
2998
+ const [selectedCategory, setSelectedCategory] = React62.useState(() => {
2999
+ const activeIndex = categories.findIndex((cat) => cat.active);
3000
+ return activeIndex === -1 ? 0 : activeIndex;
3001
+ });
2858
3002
  const { is } = useViewPort_default();
2859
3003
  const isMobile = is("tablet", "below");
2860
- const displayedItems = [...items].filter((item) => filterValue === "all" || item.type === filterValue).sort((a, b) => {
3004
+ const selectedValue = (_a = categories[selectedCategory]) == null ? void 0 : _a.value;
3005
+ const handleSelectCategory = (index) => {
3006
+ setSelectedCategory(index);
3007
+ setCurrentPage(1);
3008
+ if (isMobile) setIsSidebarOpen(false);
3009
+ };
3010
+ const handleFilterChange = (value) => {
3011
+ setFilterValue(value);
3012
+ setCurrentPage(1);
3013
+ };
3014
+ const handleSortChange = (value) => {
3015
+ setSortValue(value);
3016
+ setCurrentPage(1);
3017
+ };
3018
+ const handleSearchChange = (value) => {
3019
+ setSearchQuery(value);
3020
+ setCurrentPage(1);
3021
+ };
3022
+ const displayedItems = [...items].filter((item) => filterValue === "all" || item.type === filterValue).filter((item) => selectedValue == null || item.category === selectedValue).filter((item) => {
3023
+ const q = searchQuery.trim().toLowerCase();
3024
+ return q === "" || item.title.toLowerCase().includes(q);
3025
+ }).sort((a, b) => {
2861
3026
  if (sortValue === "latest") return new Date(b.date).getTime() - new Date(a.date).getTime();
2862
3027
  if (sortValue === "oldest") return new Date(a.date).getTime() - new Date(b.date).getTime();
2863
3028
  if (sortValue === "az") return a.title.localeCompare(b.title);
2864
3029
  if (sortValue === "za") return b.title.localeCompare(a.title);
2865
3030
  return 0;
2866
3031
  });
3032
+ const totalPages = Math.max(1, Math.ceil(displayedItems.length / ITEMS_PER_PAGE));
3033
+ const safeCurrentPage = Math.min(currentPage, totalPages);
3034
+ const pageStart = (safeCurrentPage - 1) * ITEMS_PER_PAGE;
3035
+ const paginatedItems = displayedItems.slice(pageStart, pageStart + ITEMS_PER_PAGE);
2867
3036
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx23__default.default(ResourcesGridList_module_default.widget, className), children: [
2868
3037
  /* @__PURE__ */ jsxRuntime.jsx(
2869
3038
  FilterBar,
@@ -2872,9 +3041,11 @@ var ResourcesGridList = ({
2872
3041
  onViewChange: setView,
2873
3042
  isMobile,
2874
3043
  filterValue,
2875
- onFilterChange: setFilterValue,
3044
+ onFilterChange: handleFilterChange,
2876
3045
  sortValue,
2877
- onSortChange: setSortValue
3046
+ onSortChange: handleSortChange,
3047
+ searchValue: searchQuery,
3048
+ onSearchChange: handleSearchChange
2878
3049
  }
2879
3050
  ),
2880
3051
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ResourcesGridList_module_default.content, children: [
@@ -2888,17 +3059,30 @@ var ResourcesGridList = ({
2888
3059
  "aria-hidden": !isSidebarOpen,
2889
3060
  children: [
2890
3061
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: ResourcesGridList_module_default.mobileCategoriesPanel, "aria-label": "Resource categories", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: ResourcesGridList_module_default.mobileCategoriesList, children: categories.map((cat, i) => {
2891
- var _a;
3062
+ var _a2;
2892
3063
  return /* @__PURE__ */ jsxRuntime.jsxs(
2893
3064
  "li",
2894
3065
  {
2895
- className: clsx23__default.default(ResourcesGridList_module_default.mobileSidebarItem, cat.active && ResourcesGridList_module_default.active),
3066
+ className: clsx23__default.default(
3067
+ ResourcesGridList_module_default.mobileSidebarItem,
3068
+ i === selectedCategory && ResourcesGridList_module_default.active
3069
+ ),
3070
+ role: "button",
3071
+ tabIndex: 0,
3072
+ "aria-pressed": i === selectedCategory,
3073
+ onClick: () => handleSelectCategory(i),
3074
+ onKeyDown: (e) => {
3075
+ if (e.key === "Enter" || e.key === " ") {
3076
+ e.preventDefault();
3077
+ handleSelectCategory(i);
3078
+ }
3079
+ },
2896
3080
  children: [
2897
3081
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: cat.label }),
2898
3082
  cat.hasNotification && /* @__PURE__ */ jsxRuntime.jsx("span", { className: ResourcesGridList_module_default.notificationDot, "aria-label": "New" })
2899
3083
  ]
2900
3084
  },
2901
- (_a = cat.label) != null ? _a : i
3085
+ (_a2 = cat.label) != null ? _a2 : i
2902
3086
  );
2903
3087
  }) }) }),
2904
3088
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: ResourcesGridList_module_default.mobileSidebarCloseColumn, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2919,15 +3103,24 @@ var ResourcesGridList = ({
2919
3103
  {
2920
3104
  categories,
2921
3105
  isMobile,
2922
- onToggle: () => setIsSidebarOpen(true)
3106
+ onToggle: () => setIsSidebarOpen(true),
3107
+ selectedIndex: selectedCategory,
3108
+ onSelect: handleSelectCategory
2923
3109
  }
2924
3110
  ),
2925
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx23__default.default(ResourcesGridList_module_default.cardsArea, ResourcesGridList_module_default[view]), children: displayedItems.map((item, i) => {
2926
- var _a;
2927
- return /* @__PURE__ */ jsxRuntime.jsx(ResourceCardItem, { item, view }, (_a = item.title) != null ? _a : i);
3111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx23__default.default(ResourcesGridList_module_default.cardsArea, ResourcesGridList_module_default[view]), children: paginatedItems.map((item, i) => {
3112
+ var _a2;
3113
+ return /* @__PURE__ */ jsxRuntime.jsx(ResourceCardItem, { item, view }, (_a2 = item.title) != null ? _a2 : i);
2928
3114
  }) })
2929
3115
  ] }),
2930
- /* @__PURE__ */ jsxRuntime.jsx(Pagination3, {})
3116
+ totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsx(
3117
+ Pagination3,
3118
+ {
3119
+ currentPage: safeCurrentPage,
3120
+ totalPages,
3121
+ onPageChange: setCurrentPage
3122
+ }
3123
+ )
2931
3124
  ] });
2932
3125
  };
2933
3126
  function useIntersectionObserver({