@udixio/ui-react 2.5.2 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/index.cjs +2 -2
  3. package/dist/index.js +2566 -2264
  4. package/dist/lib/components/Button.d.ts.map +1 -1
  5. package/dist/lib/components/Card.d.ts.map +1 -1
  6. package/dist/lib/components/Carousel.d.ts +0 -2
  7. package/dist/lib/components/Carousel.d.ts.map +1 -1
  8. package/dist/lib/components/Fab.d.ts +1 -1
  9. package/dist/lib/components/Fab.d.ts.map +1 -1
  10. package/dist/lib/components/FabMenu.d.ts +9 -0
  11. package/dist/lib/components/FabMenu.d.ts.map +1 -0
  12. package/dist/lib/components/IconButton.d.ts.map +1 -1
  13. package/dist/lib/components/NavigationRail.d.ts.map +1 -1
  14. package/dist/lib/components/NavigationRailItem.d.ts.map +1 -1
  15. package/dist/lib/components/Tab.d.ts.map +1 -1
  16. package/dist/lib/components/ToolTip.d.ts.map +1 -1
  17. package/dist/lib/components/index.d.ts +1 -0
  18. package/dist/lib/components/index.d.ts.map +1 -1
  19. package/dist/lib/effects/AnimateOnScroll.d.ts.map +1 -1
  20. package/dist/lib/effects/State.d.ts +26 -0
  21. package/dist/lib/effects/State.d.ts.map +1 -0
  22. package/dist/lib/effects/index.d.ts +1 -0
  23. package/dist/lib/effects/index.d.ts.map +1 -1
  24. package/dist/lib/effects/ripple/RippleEffect.d.ts.map +1 -1
  25. package/dist/lib/interfaces/button.interface.d.ts +4 -1
  26. package/dist/lib/interfaces/button.interface.d.ts.map +1 -1
  27. package/dist/lib/interfaces/fab-menu.interface.d.ts +12 -0
  28. package/dist/lib/interfaces/fab-menu.interface.d.ts.map +1 -0
  29. package/dist/lib/interfaces/fab.interface.d.ts +2 -2
  30. package/dist/lib/interfaces/fab.interface.d.ts.map +1 -1
  31. package/dist/lib/interfaces/index.d.ts +1 -0
  32. package/dist/lib/interfaces/index.d.ts.map +1 -1
  33. package/dist/lib/interfaces/side-sheet.interface.d.ts +1 -1
  34. package/dist/lib/interfaces/side-sheet.interface.d.ts.map +1 -1
  35. package/dist/lib/styles/button.style.d.ts +43 -3
  36. package/dist/lib/styles/button.style.d.ts.map +1 -1
  37. package/dist/lib/styles/card.style.d.ts +9 -1
  38. package/dist/lib/styles/card.style.d.ts.map +1 -1
  39. package/dist/lib/styles/carousel-item.style.d.ts +11 -1
  40. package/dist/lib/styles/carousel-item.style.d.ts.map +1 -1
  41. package/dist/lib/styles/carousel.style.d.ts +16 -1
  42. package/dist/lib/styles/carousel.style.d.ts.map +1 -1
  43. package/dist/lib/styles/divider.style.d.ts +8 -2
  44. package/dist/lib/styles/divider.style.d.ts.map +1 -1
  45. package/dist/lib/styles/fab-menu.style.d.ts +83 -0
  46. package/dist/lib/styles/fab-menu.style.d.ts.map +1 -0
  47. package/dist/lib/styles/fab.style.d.ts +29 -5
  48. package/dist/lib/styles/fab.style.d.ts.map +1 -1
  49. package/dist/lib/styles/icon-button.style.d.ts +37 -1
  50. package/dist/lib/styles/icon-button.style.d.ts.map +1 -1
  51. package/dist/lib/styles/index.d.ts +2 -0
  52. package/dist/lib/styles/index.d.ts.map +1 -1
  53. package/dist/lib/styles/navigation-rail-item.style.d.ts +11 -1
  54. package/dist/lib/styles/navigation-rail-item.style.d.ts.map +1 -1
  55. package/dist/lib/styles/navigation-rail.style.d.ts +31 -1
  56. package/dist/lib/styles/navigation-rail.style.d.ts.map +1 -1
  57. package/dist/lib/styles/progress-indicator.style.d.ts +12 -1
  58. package/dist/lib/styles/progress-indicator.style.d.ts.map +1 -1
  59. package/dist/lib/styles/side-sheet.style.d.ts +20 -3
  60. package/dist/lib/styles/side-sheet.style.d.ts.map +1 -1
  61. package/dist/lib/styles/slider.style.d.ts +21 -2
  62. package/dist/lib/styles/slider.style.d.ts.map +1 -1
  63. package/dist/lib/styles/snackbar.style.d.ts +14 -3
  64. package/dist/lib/styles/snackbar.style.d.ts.map +1 -1
  65. package/dist/lib/styles/switch.style.d.ts +14 -2
  66. package/dist/lib/styles/switch.style.d.ts.map +1 -1
  67. package/dist/lib/styles/tab.style.d.ts +12 -2
  68. package/dist/lib/styles/tab.style.d.ts.map +1 -1
  69. package/dist/lib/styles/tabs.style.d.ts +17 -2
  70. package/dist/lib/styles/tabs.style.d.ts.map +1 -1
  71. package/dist/lib/styles/text-field.style.d.ts +23 -2
  72. package/dist/lib/styles/text-field.style.d.ts.map +1 -1
  73. package/dist/lib/styles/tooltip.style.d.ts +20 -3
  74. package/dist/lib/styles/tooltip.style.d.ts.map +1 -1
  75. package/dist/lib/utils/styles/get-classname.d.ts +3 -0
  76. package/dist/lib/utils/styles/get-classname.d.ts.map +1 -1
  77. package/dist/lib/utils/styles/index.d.ts +1 -0
  78. package/dist/lib/utils/styles/index.d.ts.map +1 -1
  79. package/dist/lib/utils/styles/use-classnames.d.ts +6 -0
  80. package/dist/lib/utils/styles/use-classnames.d.ts.map +1 -0
  81. package/package.json +3 -3
  82. package/src/lib/components/Button.tsx +54 -20
  83. package/src/lib/components/Card.tsx +11 -9
  84. package/src/lib/components/Carousel.tsx +70 -205
  85. package/src/lib/components/CarouselItem.tsx +2 -2
  86. package/src/lib/components/Divider.tsx +2 -2
  87. package/src/lib/components/Fab.tsx +22 -21
  88. package/src/lib/components/FabMenu.tsx +229 -0
  89. package/src/lib/components/IconButton.tsx +24 -30
  90. package/src/lib/components/NavigationRail.tsx +7 -4
  91. package/src/lib/components/NavigationRailItem.tsx +13 -4
  92. package/src/lib/components/ProgressIndicator.tsx +2 -2
  93. package/src/lib/components/SideSheet.tsx +2 -2
  94. package/src/lib/components/Slider.tsx +2 -2
  95. package/src/lib/components/Snackbar.tsx +2 -2
  96. package/src/lib/components/Switch.tsx +2 -2
  97. package/src/lib/components/Tab.tsx +11 -11
  98. package/src/lib/components/Tabs.tsx +2 -2
  99. package/src/lib/components/TextField.tsx +2 -2
  100. package/src/lib/components/ToolTip.tsx +9 -3
  101. package/src/lib/components/index.ts +1 -0
  102. package/src/lib/effects/AnimateOnScroll.ts +51 -18
  103. package/src/lib/effects/State.tsx +83 -0
  104. package/src/lib/effects/index.ts +1 -0
  105. package/src/lib/effects/ripple/RippleEffect.tsx +40 -27
  106. package/src/lib/interfaces/button.interface.ts +5 -1
  107. package/src/lib/interfaces/fab-menu.interface.ts +12 -0
  108. package/src/lib/interfaces/fab.interface.ts +8 -2
  109. package/src/lib/interfaces/index.ts +1 -0
  110. package/src/lib/interfaces/side-sheet.interface.tsx +1 -1
  111. package/src/lib/styles/button.style.ts +127 -136
  112. package/src/lib/styles/card.style.ts +22 -17
  113. package/src/lib/styles/carousel-item.style.ts +23 -9
  114. package/src/lib/styles/carousel.style.ts +17 -5
  115. package/src/lib/styles/divider.style.ts +27 -13
  116. package/src/lib/styles/fab-menu.style.ts +28 -0
  117. package/src/lib/styles/fab.style.ts +41 -43
  118. package/src/lib/styles/icon-button.style.ts +160 -149
  119. package/src/lib/styles/index.ts +2 -0
  120. package/src/lib/styles/navigation-rail-item.style.ts +49 -40
  121. package/src/lib/styles/navigation-rail.style.ts +31 -15
  122. package/src/lib/styles/progress-indicator.style.ts +49 -36
  123. package/src/lib/styles/side-sheet.style.ts +41 -27
  124. package/src/lib/styles/slider.style.ts +37 -23
  125. package/src/lib/styles/snackbar.style.ts +22 -10
  126. package/src/lib/styles/switch.style.ts +61 -45
  127. package/src/lib/styles/tab.style.ts +76 -66
  128. package/src/lib/styles/tabs.style.ts +19 -10
  129. package/src/lib/styles/text-field.style.ts +108 -97
  130. package/src/lib/styles/tooltip.style.ts +42 -33
  131. package/src/lib/utils/styles/get-classname.ts +23 -0
  132. package/src/lib/utils/styles/index.ts +1 -0
  133. package/src/lib/utils/styles/use-classnames.ts +25 -0
  134. package/src/tests/useClassNames.spec.tsx +82 -0
@@ -1,37 +1,46 @@
1
- import { classNames, defaultClassNames } from '../utils';
2
- import { ToolTipInterface } from '../interfaces/tooltip.interface';
1
+ import {
2
+ type ClassNameComponent,
3
+ classNames,
4
+ createUseClassNames,
5
+ defaultClassNames,
6
+ } from '../utils';
7
+ import { ToolTipInterface } from '../interfaces';
8
+
9
+ const toolTipConfig: ClassNameComponent<ToolTipInterface> = ({
10
+ position,
11
+ variant,
12
+ }) => ({
13
+ toolTip: classNames(
14
+ ' pointer-events-auto w-max z-10 absolute m-1 w-max-content max-w-[312px]',
15
+ {
16
+ 'bottom-full left-1/2 -translate-x-1/2': position == 'top',
17
+ 'top-full left-1/2 -translate-x-1/2': position == 'bottom',
18
+ 'right-full top-1/2 -translate-y-1/2': position == 'left',
19
+ 'left-full top-1/2 -translate-y-1/2': position == 'right',
20
+ 'bottom-full right-full': position == 'top-left',
21
+ 'bottom-full left-full': position == 'top-right',
22
+ 'top-full right-full': position == 'bottom-left',
23
+ 'top-full left-full': position == 'bottom-right',
24
+ },
25
+ ),
26
+ container: classNames(
27
+ 'pb-2',
28
+ variant == 'rich' &&
29
+ 'bg-surface-container rounded-2xl text-on-surface-container px-4 pt-3 shadow-2',
30
+ variant == 'plain' &&
31
+ 'bg-inverse-surface rounded text-inverse-on-surface px-2 py-1',
32
+ ),
33
+ actions: classNames('flex gap-10 px-1 mt-2', variant == 'plain' && 'hidden'),
34
+ subHead: classNames('text-title-small mb-1', variant == 'plain' && 'hidden'),
35
+ supportingText: classNames(''),
36
+ });
3
37
 
4
38
  export const toolStyle = defaultClassNames<ToolTipInterface>(
5
39
  'toolTip',
6
- ({ position, variant }) => ({
7
- toolTip: classNames(
8
- ' pointer-events-auto w-max z-10 absolute m-1 w-max-content max-w-[312px]',
9
- {
10
- 'bottom-full left-1/2 -translate-x-1/2': position == 'top',
11
- 'top-full left-1/2 -translate-x-1/2': position == 'bottom',
12
- 'right-full top-1/2 -translate-y-1/2': position == 'left',
13
- 'left-full top-1/2 -translate-y-1/2': position == 'right',
14
- 'bottom-full right-full': position == 'top-left',
15
- 'bottom-full left-full': position == 'top-right',
16
- 'top-full right-full': position == 'bottom-left',
17
- 'top-full left-full': position == 'bottom-right',
18
- }
19
- ),
20
- container: classNames(
21
- 'pb-2',
22
- variant == 'rich' &&
23
- 'bg-surface-container rounded-2xl text-on-surface-container px-4 pt-3 shadow-2',
24
- variant == 'plain' &&
25
- 'bg-inverse-surface rounded text-inverse-on-surface px-2 py-1'
26
- ),
27
- actions: classNames(
28
- 'flex gap-10 px-1 mt-2',
29
- variant == 'plain' && 'hidden'
30
- ),
31
- subHead: classNames(
32
- 'text-title-small mb-1',
33
- variant == 'plain' && 'hidden'
34
- ),
35
- supportingText: classNames(''),
36
- })
40
+ toolTipConfig,
41
+ );
42
+
43
+ export const useToolTipStyle = createUseClassNames<ToolTipInterface>(
44
+ 'toolTip',
45
+ toolTipConfig,
37
46
  );
@@ -1,3 +1,4 @@
1
+ import { useMemo } from 'react';
1
2
  import { ComponentInterface } from '../component';
2
3
  import { convertToKebabCase } from '../string';
3
4
  import { classnames } from './classnames';
@@ -71,3 +72,25 @@ export const defaultClassNames = <T extends ComponentInterface>(
71
72
  states,
72
73
  });
73
74
  };
75
+
76
+ export const createUseClassNames = <T extends ComponentInterface>(
77
+ element: T['elements'][0],
78
+ defaultClassName: ClassNameComponent<T> | string,
79
+ ) => {
80
+ return (
81
+ states: T['states'] & T['props'] & {
82
+ className?: string | ClassNameComponent<T>;
83
+ },
84
+ ): Record<T['elements'][number], string> => {
85
+ // eslint-disable-next-line react-hooks/rules-of-hooks
86
+ return useMemo(
87
+ () =>
88
+ getClassNames<T>({
89
+ classNameList: [states.className, defaultClassName],
90
+ default: element,
91
+ states,
92
+ }),
93
+ [states],
94
+ );
95
+ };
96
+ };
@@ -1,3 +1,4 @@
1
1
  export * from './classnames';
2
2
  export * from './classnames';
3
3
  export * from './get-classname';
4
+ export * from './use-classnames';
@@ -0,0 +1,25 @@
1
+ import { useMemo } from 'react';
2
+ import { ComponentInterface } from '../component';
3
+ import { ClassNameComponent, getClassNames } from './get-classname';
4
+
5
+ export function useClassNames<T extends ComponentInterface>(
6
+ element: T['elements'][0],
7
+ defaultClassName: ClassNameComponent<T> | string,
8
+ states: (T['states'] & T['props']) & { className?: string | ClassNameComponent<T> },
9
+ ): Record<T['elements'][number], string> {
10
+ return useMemo(
11
+ () =>
12
+ getClassNames<T>({
13
+ classNameList: [states?.className, defaultClassName],
14
+ default: element,
15
+ states: states as any,
16
+ }),
17
+ [element, defaultClassName, states],
18
+ );
19
+ }
20
+
21
+ // Documentation note:
22
+ // - This hook centralizes class name merging logic (string or function),
23
+ // prefixes each element key with its kebab-case name, and adds `relative` on the root element by default.
24
+ // - It preserves current order/priority where consumer overrides take precedence over defaults.
25
+ // - Pass overrides via props.className (string or function) — see Button for example usage.
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { renderHook } from '@testing-library/react';
4
+ import { useClassNames } from '../lib/utils/styles/use-classnames';
5
+ import type { ComponentInterface } from '../lib/utils/component';
6
+ import type { ClassNameComponent } from '../lib/utils/styles/get-classname';
7
+
8
+ // Minimal fake component interface for testing the hook
9
+ interface TestComp extends ComponentInterface {
10
+ type: 'div';
11
+ elements: ['root', 'label'];
12
+ props: { label?: string };
13
+ states: { active?: boolean };
14
+ }
15
+
16
+ const defaultConfig: ClassNameComponent<TestComp> = (s) => ({
17
+ root: 'bg-default',
18
+ label: s.active ? 'text-active' : 'text-inactive',
19
+ });
20
+
21
+ describe('useClassNames', () => {
22
+ it('merges string default with function override; override wins', () => {
23
+ const override: ClassNameComponent<TestComp> = () => ({
24
+ root: 'px-2 custom-override',
25
+ label: 'text-red-500',
26
+ });
27
+
28
+ const { result, rerender } = renderHook(
29
+ (props: any) =>
30
+ useClassNames<TestComp>('root', 'bg-default-root', {
31
+ ...props,
32
+ className: override,
33
+ }),
34
+ { initialProps: { active: false } },
35
+ );
36
+
37
+ expect(result.current.root).toContain('root'); // kebab-case prefix
38
+ expect(result.current.root).toContain('relative'); // default relative
39
+ // override precedence should keep both but allow override to win on conflicts; here no conflict
40
+ expect(result.current.root).toContain('custom-override');
41
+
42
+ // label from default function should be present and overridden by override
43
+ // default for inactive: text-inactive, but override sets text-red-500
44
+ // since we didn't include defaultConfig, this ensures hook handles function override w/ string default
45
+
46
+ rerender({ active: true });
47
+ // Memo invalidated due to states change; new value produced
48
+ expect(result.current.root).toContain('custom-override');
49
+ });
50
+
51
+ it('merges function default with string override on default element', () => {
52
+ const { result } = renderHook(() =>
53
+ useClassNames<TestComp>('root', defaultConfig, {
54
+ active: true,
55
+ className: 'p-4',
56
+ }),
57
+ );
58
+ expect(result.current.root).toContain('root');
59
+ expect(result.current.root).toContain('relative');
60
+ expect(result.current.root).toContain('p-4');
61
+ expect(result.current.label).toContain('label');
62
+ expect(result.current.label).toContain('text-active');
63
+ });
64
+
65
+ it('memoizes: same inputs => stable reference', () => {
66
+ const states = { active: false, className: 'm-1' } as any;
67
+ const { result, rerender } = renderHook(
68
+ (p: any) => useClassNames<TestComp>('root', defaultConfig, p.states),
69
+ { initialProps: { states } },
70
+ );
71
+
72
+ const first = result.current;
73
+ rerender({ states }); // same reference
74
+ const second = result.current;
75
+ expect(second).toBe(first);
76
+
77
+ // change shallow reference -> new object allocated
78
+ rerender({ states: { ...states } });
79
+ const third = result.current;
80
+ expect(third).not.toBe(first);
81
+ });
82
+ });