@udixio/ui-react 2.9.5 → 2.9.7

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 (52) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/index.cjs +3 -3
  3. package/dist/index.js +3436 -2702
  4. package/dist/lib/components/Chip.d.ts.map +1 -1
  5. package/dist/lib/components/Chips.d.ts.map +1 -1
  6. package/dist/lib/components/Tab.d.ts +1 -1
  7. package/dist/lib/components/Tab.d.ts.map +1 -1
  8. package/dist/lib/components/TabGroup.d.ts +9 -0
  9. package/dist/lib/components/TabGroup.d.ts.map +1 -0
  10. package/dist/lib/components/TabGroupContext.d.ts +10 -0
  11. package/dist/lib/components/TabGroupContext.d.ts.map +1 -0
  12. package/dist/lib/components/TabPanel.d.ts +10 -0
  13. package/dist/lib/components/TabPanel.d.ts.map +1 -0
  14. package/dist/lib/components/TabPanels.d.ts +10 -0
  15. package/dist/lib/components/TabPanels.d.ts.map +1 -0
  16. package/dist/lib/components/Tabs.d.ts.map +1 -1
  17. package/dist/lib/components/index.d.ts +3 -0
  18. package/dist/lib/components/index.d.ts.map +1 -1
  19. package/dist/lib/effects/smooth-scroll.effect.d.ts +35 -11
  20. package/dist/lib/effects/smooth-scroll.effect.d.ts.map +1 -1
  21. package/dist/lib/interfaces/index.d.ts +2 -0
  22. package/dist/lib/interfaces/index.d.ts.map +1 -1
  23. package/dist/lib/interfaces/tab-group.interface.d.ts +13 -0
  24. package/dist/lib/interfaces/tab-group.interface.d.ts.map +1 -0
  25. package/dist/lib/interfaces/tab-panels.interface.d.ts +20 -0
  26. package/dist/lib/interfaces/tab-panels.interface.d.ts.map +1 -0
  27. package/dist/lib/interfaces/tab.interface.d.ts +2 -1
  28. package/dist/lib/interfaces/tab.interface.d.ts.map +1 -1
  29. package/dist/lib/styles/index.d.ts +1 -0
  30. package/dist/lib/styles/index.d.ts.map +1 -1
  31. package/dist/lib/styles/tab-panels.style.d.ts +31 -0
  32. package/dist/lib/styles/tab-panels.style.d.ts.map +1 -0
  33. package/dist/lib/styles/tab.style.d.ts +2 -0
  34. package/dist/lib/styles/tab.style.d.ts.map +1 -1
  35. package/package.json +4 -3
  36. package/src/lib/components/Chip.tsx +2 -1
  37. package/src/lib/components/Chips.tsx +57 -16
  38. package/src/lib/components/Tab.tsx +5 -1
  39. package/src/lib/components/TabGroup.tsx +60 -0
  40. package/src/lib/components/TabGroupContext.tsx +11 -0
  41. package/src/lib/components/TabPanel.tsx +24 -0
  42. package/src/lib/components/TabPanels.tsx +71 -0
  43. package/src/lib/components/Tabs.tsx +17 -6
  44. package/src/lib/components/index.ts +3 -0
  45. package/src/lib/effects/smooth-scroll.effect.tsx +81 -125
  46. package/src/lib/interfaces/index.ts +2 -0
  47. package/src/lib/interfaces/tab-group.interface.ts +13 -0
  48. package/src/lib/interfaces/tab-panels.interface.ts +21 -0
  49. package/src/lib/interfaces/tab.interface.ts +2 -1
  50. package/src/lib/styles/index.ts +1 -0
  51. package/src/lib/styles/tab-panels.style.ts +35 -0
  52. package/src/stories/effect/smooth-scroll.stories.tsx +34 -25
@@ -1 +1 @@
1
- {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAO9C;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,4MAqBlB,UAAU,CAAC,aAAa,CAAC,4CA0S3B,CAAC"}
1
+ {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAO9C;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,4MAqBlB,UAAU,CAAC,aAAa,CAAC,4CA2S3B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Chips.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chips.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAY,cAAc,EAAE,MAAM,eAAe,CAAC;AAMzD,eAAO,MAAM,KAAK,GAAI,sEAOnB,UAAU,CAAC,cAAc,CAAC,4CAwQ5B,CAAC"}
1
+ {"version":3,"file":"Chips.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chips.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAY,cAAc,EAAE,MAAM,eAAe,CAAC;AAMzD,eAAO,MAAM,KAAK,GAAI,sEAOnB,UAAU,CAAC,cAAc,CAAC,4CAiT5B,CAAC"}
@@ -4,5 +4,5 @@ import { ReactProps } from '../utils/component';
4
4
  * @status beta
5
5
  * @parent Tabs
6
6
  */
7
- export declare const Tab: ({ className, onClick, label, variant, href, icon, selectedTab, setSelectedTab, tabsId, index, onTabSelected, scrollable, selected, ref, ...restProps }: ReactProps<TabInterface>) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const Tab: ({ className, onClick, label: labelProp, variant, href, icon, selectedTab, setSelectedTab, tabsId, index, onTabSelected, scrollable, selected, children, ref, ...restProps }: ReactProps<TabInterface>) => import("react/jsx-runtime").JSX.Element;
8
8
  //# sourceMappingURL=Tab.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tab.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Tab.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD;;;GAGG;AACH,eAAO,MAAM,GAAG,GAAI,wJAgBjB,UAAU,CAAC,YAAY,CAAC,4CAoF1B,CAAC"}
1
+ {"version":3,"file":"Tab.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Tab.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD;;;GAGG;AACH,eAAO,MAAM,GAAG,GAAI,6KAiBjB,UAAU,CAAC,YAAY,CAAC,4CAuF1B,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { TabGroupInterface } from '../interfaces/tab-group.interface';
2
+ import { ReactProps } from '../utils/component';
3
+ /**
4
+ * TabGroup provides shared state for Tabs and TabPanels
5
+ * @status beta
6
+ * @category Navigation
7
+ */
8
+ export declare const TabGroup: ({ children, selectedTab: externalSelectedTab, setSelectedTab: externalSetSelectedTab, defaultTab, }: ReactProps<TabGroupInterface>) => import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=TabGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabGroup.d.ts","sourceRoot":"","sources":["../../../src/lib/components/TabGroup.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,qGAKtB,UAAU,CAAC,iBAAiB,CAAC,4CA2C/B,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ export interface TabGroupContextValue {
3
+ selectedTab: number | null;
4
+ setSelectedTab: Dispatch<SetStateAction<number | null>>;
5
+ previousTab: number | null;
6
+ direction: number;
7
+ tabsId: string;
8
+ }
9
+ export declare const TabGroupContext: import('react').Context<TabGroupContextValue | null>;
10
+ //# sourceMappingURL=TabGroupContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabGroupContext.d.ts","sourceRoot":"","sources":["../../../src/lib/components/TabGroupContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACxD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,sDAAmD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { TabPanelInterface } from '../interfaces/tab-panels.interface';
2
+ import { ReactProps } from '../utils/component';
3
+ /**
4
+ * TabPanel contains the content for a single tab
5
+ * Must be used within TabPanels
6
+ * @status beta
7
+ * @category Navigation
8
+ */
9
+ export declare const TabPanel: ({ children, className, isSelected, }: ReactProps<TabPanelInterface>) => import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=TabPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabPanel.d.ts","sourceRoot":"","sources":["../../../src/lib/components/TabPanel.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,sCAItB,UAAU,CAAC,iBAAiB,CAAC,4CAQ/B,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { TabPanelsInterface } from '../interfaces/tab-panels.interface';
2
+ import { ReactProps } from '../utils/component';
3
+ /**
4
+ * TabPanels renders the content panels with slide animation
5
+ * Must be used within a TabGroup
6
+ * @status beta
7
+ * @category Navigation
8
+ */
9
+ export declare const TabPanels: ({ children, className, }: ReactProps<TabPanelsInterface>) => import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=TabPanels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabPanels.d.ts","sourceRoot":"","sources":["../../../src/lib/components/TabPanels.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,0BAGvB,UAAU,CAAC,kBAAkB,CAAC,mDAqDhC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,wIAQlB,UAAU,CAAC,aAAa,CAAC,4CAmE3B,CAAC"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKhD;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,wIAQlB,UAAU,CAAC,aAAa,CAAC,4CA6E3B,CAAC"}
@@ -17,6 +17,9 @@ export * from './Snackbar';
17
17
  export * from './Switch';
18
18
  export * from './Tab';
19
19
  export * from './Tabs';
20
+ export * from './TabGroup';
21
+ export * from './TabPanels';
22
+ export * from './TabPanel';
20
23
  export * from './TextField';
21
24
  export * from './NavigationRailItem';
22
25
  export * from './NavigationRail';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC"}
@@ -1,14 +1,38 @@
1
- import { CustomScrollInterface } from './custom-scroll';
2
- import { ReactProps } from '../utils';
1
+ import { ReactNode } from 'react';
2
+ export type SmoothScrollProps = {
3
+ /**
4
+ * Duration of the scroll animation in seconds or as a CSS string (e.g., '1s', '500ms').
5
+ * Default: 1.2
6
+ */
7
+ transition?: number | string;
8
+ /**
9
+ * Easing function for the scroll animation.
10
+ * Default: easeOutQuint
11
+ */
12
+ easing?: (t: number) => number;
13
+ /**
14
+ * Scroll orientation.
15
+ * Default: 'vertical'
16
+ */
17
+ orientation?: 'vertical' | 'horizontal';
18
+ /**
19
+ * Enable smooth scrolling on touch devices.
20
+ * Default: false (native touch scrolling is usually preferred)
21
+ */
22
+ smoothTouch?: boolean;
23
+ /**
24
+ * Multiplier for touch scroll sensitivity.
25
+ * Default: 2
26
+ */
27
+ touchMultiplier?: number;
28
+ /**
29
+ * Children elements (optional, component works at document level)
30
+ */
31
+ children?: ReactNode;
32
+ };
3
33
  /**
4
- * WARNING: using this component is not recommended for now.
5
- * It may block or alter certain scroll events (wheel/touch/keyboard) depending on the context.
6
- * Rework it later (e.g., via Lenis or another solution) before using it in production.
34
+ * SmoothScroll component using Lenis for smooth scrolling.
35
+ * This component enables smooth scrolling at the document level.
7
36
  */
8
- export declare const SmoothScroll: ({ transition, orientation, throttleDuration, }: {
9
- transition?: {
10
- ease: "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut" | "backIn" | "backOut" | "backInOut" | "anticipate" | ((t: number) => number);
11
- duration?: number;
12
- };
13
- } & ReactProps<CustomScrollInterface>) => import("react/jsx-runtime").JSX.Element | null;
37
+ export declare const SmoothScroll: ({ transition, easing, orientation, smoothTouch, touchMultiplier, children, }: SmoothScrollProps) => import("react/jsx-runtime").JSX.Element | null;
14
38
  //# sourceMappingURL=smooth-scroll.effect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"smooth-scroll.effect.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/smooth-scroll.effect.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,gDAI1B;IACD,UAAU,CAAC,EAAE;QACX,IAAI,EACA,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,YAAY,GACZ,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,GAAG,UAAU,CAAC,qBAAqB,CAAC,mDA6GpC,CAAC"}
1
+ {"version":3,"file":"smooth-scroll.effect.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/smooth-scroll.effect.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,8EAO1B,iBAAiB,mDAmDnB,CAAC"}
@@ -15,6 +15,8 @@ export * from './snackbar.interface';
15
15
  export * from './switch.interface';
16
16
  export * from './tab.interface';
17
17
  export * from './tabs.interface';
18
+ export * from './tab-group.interface';
19
+ export * from './tab-panels.interface';
18
20
  export * from './text-field.interface';
19
21
  export * from './navigation-rail-item.interface';
20
22
  export * from './tooltip.interface';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Dispatch, ReactNode, SetStateAction } from 'react';
2
+ export interface TabGroupInterface {
3
+ type: 'div';
4
+ props: {
5
+ children: ReactNode;
6
+ selectedTab?: number | null;
7
+ setSelectedTab?: Dispatch<SetStateAction<number | null>>;
8
+ defaultTab?: number;
9
+ };
10
+ states: object;
11
+ elements: ['tabGroup'];
12
+ }
13
+ //# sourceMappingURL=tab-group.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-group.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tab-group.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,QAAQ,EAAE,SAAS,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,cAAc,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACzD,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC;CACxB"}
@@ -0,0 +1,20 @@
1
+ import { ReactNode } from 'react';
2
+ export interface TabPanelsInterface {
3
+ type: 'div';
4
+ props: {
5
+ children: ReactNode;
6
+ };
7
+ states: object;
8
+ elements: ['tabPanels'];
9
+ }
10
+ export interface TabPanelInterface {
11
+ type: 'div';
12
+ props: {
13
+ children: ReactNode;
14
+ };
15
+ states: {
16
+ isSelected: boolean;
17
+ };
18
+ elements: ['tabPanel'];
19
+ }
20
+ //# sourceMappingURL=tab-panels.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-panels.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tab-panels.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,QAAQ,EAAE,SAAS,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,WAAW,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,QAAQ,EAAE,SAAS,CAAC;KACrB,CAAC;IACF,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC;CACxB"}
@@ -1,6 +1,6 @@
1
1
  import { ActionOrLink } from '../utils/component';
2
2
  import { TabsVariant } from './tabs.interface';
3
- import { Dispatch, RefObject, SetStateAction } from 'react';
3
+ import { Dispatch, ReactNode, RefObject, SetStateAction } from 'react';
4
4
  import { Icon } from '../icon';
5
5
  export type TabProps = {
6
6
  selected?: boolean;
@@ -17,6 +17,7 @@ export type TabProps = {
17
17
  }) => void;
18
18
  index?: number;
19
19
  scrollable?: boolean;
20
+ children?: ReactNode;
20
21
  };
21
22
  type Elements = ['tab', 'stateLayer', 'icon', 'label', 'content', 'underline'];
22
23
  export type TabInterface = ActionOrLink<TabProps> & {
@@ -1 +1 @@
1
- {"version":3,"file":"tab.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tab.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CACd,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG;QACzD,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;KACrB,KACA,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAE/E,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG;IAClD,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC"}
1
+ {"version":3,"file":"tab.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tab.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CACd,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG;QACzD,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;KACrB,KACA,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAE/E,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG;IAClD,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC"}
@@ -15,6 +15,7 @@ export * from './snackbar.style';
15
15
  export * from './switch.style';
16
16
  export * from './tab.style';
17
17
  export * from './tabs.style';
18
+ export * from './tab-panels.style';
18
19
  export * from './text-field.style';
19
20
  export * from './tooltip.style';
20
21
  export { useButtonStyle } from './button.style';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { TabPanelsInterface, TabPanelInterface } from '../interfaces';
2
+ import { ClassNameComponent } from '../utils';
3
+ export declare const tabPanelsStyle: (states: {
4
+ children: any;
5
+ } & {
6
+ children: import('react').ReactNode;
7
+ } & object & {
8
+ className: string | ClassNameComponent<TabPanelsInterface> | undefined;
9
+ }) => Record<"tabPanels", string>;
10
+ export declare const useTabPanelsStyle: (states: object & {
11
+ children: import('react').ReactNode;
12
+ } & {
13
+ className?: string | ClassNameComponent<TabPanelsInterface> | undefined;
14
+ }) => Record<"tabPanels", string>;
15
+ export declare const tabPanelStyle: (states: {
16
+ children: any;
17
+ } & {
18
+ children: import('react').ReactNode;
19
+ } & {
20
+ isSelected: boolean;
21
+ } & {
22
+ className: string | ClassNameComponent<TabPanelInterface> | undefined;
23
+ }) => Record<"tabPanel", string>;
24
+ export declare const useTabPanelStyle: (states: {
25
+ isSelected: boolean;
26
+ } & {
27
+ children: import('react').ReactNode;
28
+ } & {
29
+ className?: string | ClassNameComponent<TabPanelInterface> | undefined;
30
+ }) => Record<"tabPanel", string>;
31
+ //# sourceMappingURL=tab-panels.style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-panels.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/tab-panels.style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAMlB,eAAO,MAAM,cAAc;;;;;;iCAG1B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;iCAG7B,CAAC;AAMF,eAAO,MAAM,aAAa;;;;;;;;gCAGzB,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;gCAG5B,CAAC"}
@@ -11,6 +11,7 @@ export declare const tabStyle: (states: (({
11
11
  onTabSelected: any;
12
12
  index: any;
13
13
  scrollable: any;
14
+ children: any;
14
15
  href: any;
15
16
  } | {
16
17
  selected: any;
@@ -23,6 +24,7 @@ export declare const tabStyle: (states: (({
23
24
  onTabSelected: any;
24
25
  index: any;
25
26
  scrollable: any;
27
+ children: any;
26
28
  href: any;
27
29
  }) & ((import('..').TabProps & {
28
30
  href?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tab.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/tab.style.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAqE7C,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uFAAoD,CAAC;AAE1E,eAAO,MAAM,WAAW;;;;;;;;wFAAsD,CAAC"}
1
+ {"version":3,"file":"tab.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/tab.style.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAqE7C,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uFAAoD,CAAC;AAE1E,eAAO,MAAM,WAAW;;;;;;;;wFAAsD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@udixio/ui-react",
3
- "version": "2.9.5",
3
+ "version": "2.9.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -28,6 +28,7 @@
28
28
  "motion": "^12.23.0",
29
29
  "tailwind-merge": "^3.3.1",
30
30
  "uuid": "^11.0.3",
31
+ "lenis": "^1.2.3",
31
32
  "@fortawesome/fontawesome-svg-core": "^7.0.0",
32
33
  "@fortawesome/free-regular-svg-icons": "^7.0.0",
33
34
  "@fortawesome/free-solid-svg-icons": "^7.0.0",
@@ -36,8 +37,8 @@
36
37
  "devDependencies": {
37
38
  "react": "^19.1.1",
38
39
  "react-dom": "^19.1.1",
39
- "@udixio/theme": "2.1.8",
40
- "@udixio/tailwind": "2.4.6"
40
+ "@udixio/theme": "2.1.10",
41
+ "@udixio/tailwind": "2.4.8"
41
42
  },
42
43
  "repository": {
43
44
  "type": "git",
@@ -114,7 +114,8 @@ export const Chip = ({
114
114
  }
115
115
  };
116
116
 
117
- const isInteractive = !!onToggle || !!onRemove || !!onClick || !!href;
117
+ const isInteractive =
118
+ !!onToggle || !!onRemove || !!onClick || !!href || !!editable;
118
119
 
119
120
  if (activated) {
120
121
  icon = faCheck;
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { ReactProps } from '../utils';
3
3
  import { ChipItem, ChipsInterface } from '../interfaces';
4
4
  import { useChipsStyle } from '../styles';
@@ -34,12 +34,19 @@ export const Chips = ({
34
34
 
35
35
  React.useEffect(() => {
36
36
  if (isFocused) {
37
- ref.current?.focus();
37
+ if (variant == 'input') {
38
+ ghostChipRef.current?.focus();
39
+ } else {
40
+ ref.current?.focus();
41
+ }
38
42
  }
39
43
  }, [isFocused]);
40
44
 
41
45
  const chipRefs = React.useRef<(HTMLElement | null)[]>([]);
42
46
 
47
+ // Guard to prevent multiple chip creation from fast typing
48
+ const isCreatingRef = React.useRef(false);
49
+
43
50
  const updateItems = React.useCallback(
44
51
  (updater: (prev: ChipItem[]) => ChipItem[]) => {
45
52
  onItemsChange?.(updater(list));
@@ -64,6 +71,10 @@ export const Chips = ({
64
71
  (seedLabel = '') => {
65
72
  if (variant !== 'input') return;
66
73
 
74
+ // Guard against multiple rapid creations
75
+ if (isCreatingRef.current) return;
76
+ isCreatingRef.current = true;
77
+
67
78
  const newItem: ChipItem = {
68
79
  label: seedLabel,
69
80
  } as ChipItem;
@@ -77,6 +88,8 @@ export const Chips = ({
77
88
 
78
89
  requestAnimationFrame(() => {
79
90
  setSelectedChip(newId);
91
+ // Reset guard after chip is selected
92
+ isCreatingRef.current = false;
80
93
  });
81
94
  },
82
95
  [variant, onItemsChange, list, getInternalId],
@@ -102,6 +115,11 @@ export const Chips = ({
102
115
  }, [selectedChip, list, getInternalId]);
103
116
 
104
117
  // MODE ITEMS (source de vérité locale ou contrôlée)
118
+
119
+ const ghostChipRef = useRef<HTMLButtonElement>(null);
120
+
121
+ const isGhostChip = (isFocused || list.length === 0) && variant === 'input';
122
+
105
123
  return (
106
124
  <div
107
125
  ref={ref}
@@ -114,7 +132,9 @@ export const Chips = ({
114
132
  setIsFocused(true);
115
133
  }
116
134
  }}
117
- onBlur={() => setIsFocused(false)}
135
+ onBlur={() => {
136
+ setIsFocused(false);
137
+ }}
118
138
  onKeyDown={(e) => {
119
139
  if (variant !== 'input') return;
120
140
 
@@ -160,13 +180,7 @@ export const Chips = ({
160
180
  setSelectedChip(elId);
161
181
  return;
162
182
  }
163
-
164
183
  if (isContainerFocused) {
165
- if (key === 'Enter') {
166
- e.preventDefault();
167
- createAndStartEdit('');
168
- return;
169
- }
170
184
  if (key === 'Backspace') {
171
185
  e.preventDefault();
172
186
  // Focus last chip if any
@@ -176,12 +190,6 @@ export const Chips = ({
176
190
  }
177
191
  return;
178
192
  }
179
- // Start creation when typing a printable character
180
- if (key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey) {
181
- createAndStartEdit(key);
182
- e.preventDefault();
183
- return;
184
- }
185
193
  }
186
194
  }}
187
195
  >
@@ -203,7 +211,7 @@ export const Chips = ({
203
211
  onEditCancel: () => {
204
212
  setIsFocused(true);
205
213
  },
206
- onChange: (next: ChipItem[]) => {
214
+ onChange: () => {
207
215
  if (chipRefs.current.length == index + 1) {
208
216
  const el = ref.current!;
209
217
  requestAnimationFrame(() => {
@@ -275,6 +283,39 @@ export const Chips = ({
275
283
  </style>
276
284
  </>
277
285
  )}
286
+ {isGhostChip && (
287
+ <Chip
288
+ ref={ghostChipRef}
289
+ className="opacity-0"
290
+ draggable={draggable}
291
+ editable={true}
292
+ editing={true}
293
+ onChange={(v) => {
294
+ v = v.replace(/(&nbsp;)+/g, ' ').trim();
295
+ console.log('Ghost chip onChange', v, !!v);
296
+ if (v) {
297
+ createAndStartEdit(v);
298
+ } else {
299
+ if (list.length > 0) {
300
+ const el = chipRefs.current[list.length - 1] as any;
301
+ el?.focus?.();
302
+ }
303
+ }
304
+ }}
305
+ onEditCommit={() => {
306
+ // Ghost chip doesn't commit - it creates a new chip via onChange
307
+ }}
308
+ onBlur={() => {
309
+ setIsFocused(false);
310
+ }}
311
+ onFocus={(e: React.FocusEvent) => {
312
+ setIsFocused(true);
313
+ e.stopPropagation();
314
+ }}
315
+ >
316
+ &nbsp;
317
+ </Chip>
318
+ )}
278
319
  </div>
279
320
  );
280
321
  };
@@ -14,7 +14,7 @@ import { State } from '../effects';
14
14
  export const Tab = ({
15
15
  className,
16
16
  onClick,
17
- label,
17
+ label: labelProp,
18
18
  variant = 'primary',
19
19
  href,
20
20
  icon,
@@ -25,12 +25,16 @@ export const Tab = ({
25
25
  onTabSelected,
26
26
  scrollable = false,
27
27
  selected = false,
28
+ children,
28
29
  ref,
29
30
  ...restProps
30
31
  }: ReactProps<TabInterface>) => {
31
32
  const defaultRef = useRef(null);
32
33
  const resolvedRef = ref || defaultRef;
33
34
 
35
+ // children (string) peut être utilisé comme alternative à label prop
36
+ const label = labelProp ?? (typeof children === 'string' ? children : undefined);
37
+
34
38
  const [isSelected, setIsSelected] = useState<boolean>(selected);
35
39
 
36
40
  useEffect(() => {
@@ -0,0 +1,60 @@
1
+ import React, { useMemo, useRef, useState } from 'react';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { TabGroupContext, TabGroupContextValue } from './TabGroupContext';
4
+ import { TabGroupInterface } from '../interfaces/tab-group.interface';
5
+ import { ReactProps } from '../utils/component';
6
+
7
+ /**
8
+ * TabGroup provides shared state for Tabs and TabPanels
9
+ * @status beta
10
+ * @category Navigation
11
+ */
12
+ export const TabGroup = ({
13
+ children,
14
+ selectedTab: externalSelectedTab,
15
+ setSelectedTab: externalSetSelectedTab,
16
+ defaultTab = 0,
17
+ }: ReactProps<TabGroupInterface>) => {
18
+ const [internalSelectedTab, internalSetSelectedTab] = useState<number | null>(
19
+ defaultTab,
20
+ );
21
+ const previousTabRef = useRef<number | null>(null);
22
+
23
+ // Priorité : props externes > état interne
24
+ const selectedTab =
25
+ externalSelectedTab !== undefined ? externalSelectedTab : internalSelectedTab;
26
+
27
+ const setSelectedTab = externalSetSelectedTab ?? internalSetSelectedTab;
28
+
29
+ // Calculer la direction du slide
30
+ const direction =
31
+ previousTabRef.current !== null && selectedTab !== null
32
+ ? selectedTab > previousTabRef.current
33
+ ? 1
34
+ : -1
35
+ : 0;
36
+
37
+ // Mettre à jour la référence précédente
38
+ if (selectedTab !== previousTabRef.current) {
39
+ previousTabRef.current = selectedTab;
40
+ }
41
+
42
+ const tabsId = useMemo(() => uuidv4(), []);
43
+
44
+ const contextValue: TabGroupContextValue = useMemo(
45
+ () => ({
46
+ selectedTab,
47
+ setSelectedTab,
48
+ previousTab: previousTabRef.current,
49
+ direction,
50
+ tabsId,
51
+ }),
52
+ [selectedTab, setSelectedTab, direction, tabsId],
53
+ );
54
+
55
+ return (
56
+ <TabGroupContext.Provider value={contextValue}>
57
+ {children}
58
+ </TabGroupContext.Provider>
59
+ );
60
+ };
@@ -0,0 +1,11 @@
1
+ import { createContext, Dispatch, SetStateAction } from 'react';
2
+
3
+ export interface TabGroupContextValue {
4
+ selectedTab: number | null;
5
+ setSelectedTab: Dispatch<SetStateAction<number | null>>;
6
+ previousTab: number | null;
7
+ direction: number;
8
+ tabsId: string;
9
+ }
10
+
11
+ export const TabGroupContext = createContext<TabGroupContextValue | null>(null);
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { TabPanelInterface } from '../interfaces/tab-panels.interface';
3
+ import { ReactProps } from '../utils/component';
4
+ import { useTabPanelStyle } from '../styles/tab-panels.style';
5
+
6
+ /**
7
+ * TabPanel contains the content for a single tab
8
+ * Must be used within TabPanels
9
+ * @status beta
10
+ * @category Navigation
11
+ */
12
+ export const TabPanel = ({
13
+ children,
14
+ className,
15
+ isSelected = false,
16
+ }: ReactProps<TabPanelInterface>) => {
17
+ const styles = useTabPanelStyle({
18
+ children,
19
+ className,
20
+ isSelected,
21
+ });
22
+
23
+ return <div className={styles.tabPanel}>{children}</div>;
24
+ };