@hellboy/ds 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +111 -0
  2. package/dist/index.css +3699 -0
  3. package/dist/index.css.map +1 -0
  4. package/dist/index.d.mts +1087 -0
  5. package/dist/index.d.ts +1087 -0
  6. package/dist/index.js +3391 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +3287 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/dist/theme.css +55 -0
  11. package/hellboy-ds-0.1.2.tgz +0 -0
  12. package/package.json +42 -0
  13. package/src/components/badge/Badge.tsx +29 -0
  14. package/src/components/badge/index.ts +1 -0
  15. package/src/components/banner/Banner.tsx +48 -0
  16. package/src/components/banner/banner.css +44 -0
  17. package/src/components/banner/index.ts +1 -0
  18. package/src/components/button/button.tsx +127 -0
  19. package/src/components/button/index.ts +1 -0
  20. package/src/components/card/card.tsx +57 -0
  21. package/src/components/card/index.ts +1 -0
  22. package/src/components/checkbox/Checkbox.tsx +98 -0
  23. package/src/components/checkbox/index.ts +1 -0
  24. package/src/components/code-block/code-block.tsx +44 -0
  25. package/src/components/code-block/index.ts +1 -0
  26. package/src/components/color-control/color-control.tsx +322 -0
  27. package/src/components/color-control/index.ts +1 -0
  28. package/src/components/drag-handle/DragHandle.tsx +78 -0
  29. package/src/components/drag-handle/index.ts +1 -0
  30. package/src/components/drawer/drawer.tsx +82 -0
  31. package/src/components/drawer/index.ts +1 -0
  32. package/src/components/floating-bar/floating-bar.tsx +52 -0
  33. package/src/components/floating-bar/index.ts +2 -0
  34. package/src/components/footer/footer.tsx +28 -0
  35. package/src/components/footer/index.ts +1 -0
  36. package/src/components/grid/Grid.tsx +53 -0
  37. package/src/components/grid/index.ts +1 -0
  38. package/src/components/header/header.tsx +57 -0
  39. package/src/components/header/index.ts +1 -0
  40. package/src/components/icons/icons.tsx +44 -0
  41. package/src/components/icons/index.ts +1 -0
  42. package/src/components/index.ts +29 -0
  43. package/src/components/input/DatePicker.tsx +133 -0
  44. package/src/components/input/Input.tsx +220 -0
  45. package/src/components/input/InputDate.tsx +10 -0
  46. package/src/components/input/InputDateTime.tsx +10 -0
  47. package/src/components/input/InputEmail.tsx +10 -0
  48. package/src/components/input/InputField.tsx +137 -0
  49. package/src/components/input/InputNumber.tsx +10 -0
  50. package/src/components/input/InputPassword.tsx +10 -0
  51. package/src/components/input/InputSearch.tsx +10 -0
  52. package/src/components/input/InputTel.tsx +10 -0
  53. package/src/components/input/InputText.tsx +10 -0
  54. package/src/components/input/InputTime.tsx +10 -0
  55. package/src/components/input/InputUrl.tsx +10 -0
  56. package/src/components/input/TimePicker.tsx +151 -0
  57. package/src/components/input/index.ts +11 -0
  58. package/src/components/layout/Layout.tsx +244 -0
  59. package/src/components/layout/index.ts +1 -0
  60. package/src/components/list/List.tsx +159 -0
  61. package/src/components/list/index.ts +1 -0
  62. package/src/components/navbar/MenuCategory.tsx +20 -0
  63. package/src/components/navbar/MenuGroup.tsx +288 -0
  64. package/src/components/navbar/MenuItem.tsx +65 -0
  65. package/src/components/navbar/Navbar.tsx +23 -0
  66. package/src/components/navbar/index.ts +4 -0
  67. package/src/components/page/index.ts +1 -0
  68. package/src/components/page/page.tsx +46 -0
  69. package/src/components/page-index/PageIndex.tsx +275 -0
  70. package/src/components/page-index/index.ts +1 -0
  71. package/src/components/popover/index.ts +1 -0
  72. package/src/components/popover/popover.tsx +199 -0
  73. package/src/components/radio/Radio.tsx +176 -0
  74. package/src/components/radio/index.ts +1 -0
  75. package/src/components/section/index.ts +1 -0
  76. package/src/components/section/section.tsx +66 -0
  77. package/src/components/select/Select.tsx +212 -0
  78. package/src/components/select/index.ts +1 -0
  79. package/src/components/slider/Slider.tsx +267 -0
  80. package/src/components/slider/index.ts +1 -0
  81. package/src/components/switch/index.ts +1 -0
  82. package/src/components/switch/switch.tsx +99 -0
  83. package/src/components/table/Table.tsx +147 -0
  84. package/src/components/table/index.ts +1 -0
  85. package/src/components/theme-control/index.ts +1 -0
  86. package/src/components/theme-control/theme-control.tsx +78 -0
  87. package/src/components/tooltip/index.ts +1 -0
  88. package/src/components/tooltip/tooltip.tsx +207 -0
  89. package/src/contexts/NavbarTooltipContext.tsx +48 -0
  90. package/src/contexts/index.ts +1 -0
  91. package/src/foundations/motion.md +136 -0
  92. package/src/index.ts +40 -0
  93. package/src/style/_shared/field.css +69 -0
  94. package/src/style/components/badge/badge.css +74 -0
  95. package/src/style/components/button/button.css +244 -0
  96. package/src/style/components/card/card.css +69 -0
  97. package/src/style/components/checkbox.css +142 -0
  98. package/src/style/components/code-block/code-block.css +34 -0
  99. package/src/style/components/color-control/color-control.css +126 -0
  100. package/src/style/components/drag-handle/drag-handle.css +68 -0
  101. package/src/style/components/drawer/drawer.css +210 -0
  102. package/src/style/components/floating-bar/floating-bar.css +39 -0
  103. package/src/style/components/footer/footer.css +108 -0
  104. package/src/style/components/grid/grid.css +33 -0
  105. package/src/style/components/header/header.css +44 -0
  106. package/src/style/components/icons/icons.css +44 -0
  107. package/src/style/components/input/input.css +393 -0
  108. package/src/style/components/layout/layout.css +205 -0
  109. package/src/style/components/list/list.css +140 -0
  110. package/src/style/components/navbar/navbar.css +342 -0
  111. package/src/style/components/page/page.css +46 -0
  112. package/src/style/components/page-index/page-index.css +158 -0
  113. package/src/style/components/popover/popover.css +44 -0
  114. package/src/style/components/radio.css +178 -0
  115. package/src/style/components/section/section.css +67 -0
  116. package/src/style/components/select/select.css +143 -0
  117. package/src/style/components/slider/slider.css +159 -0
  118. package/src/style/components/switch/switch.css +267 -0
  119. package/src/style/components/table/table.css +108 -0
  120. package/src/style/components/theme-control/theme-control.css +35 -0
  121. package/src/style/components/tooltip/tooltip.css +52 -0
  122. package/src/style/foundations/global.css +316 -0
  123. package/src/style/foundations/motion.css +164 -0
  124. package/src/style/foundations/spacing.css +51 -0
  125. package/src/style/foundations/typography.css +39 -0
  126. package/src/style/foundations/z-index.css +81 -0
  127. package/src/style/modes/dark.css +146 -0
  128. package/src/style/modes/light.css +147 -0
  129. package/src/style/semantic.css +52 -0
  130. package/src/style/styles.css +51 -0
  131. package/src/style/themes/theme.json +37 -0
  132. package/src/utils/README.md +305 -0
  133. package/src/utils/USER_PREFERENCES.md +558 -0
  134. package/src/utils/theme.ts +127 -0
  135. package/src/utils/user-preferences.ts +577 -0
  136. package/tsconfig.json +25 -0
  137. package/tsup.config.ts +52 -0
@@ -0,0 +1,147 @@
1
+ import * as React from "react";
2
+ import "../../style/components/table/table.css";
3
+
4
+ export interface TableProps extends React.TableHTMLAttributes<HTMLTableElement> {
5
+ /**
6
+ * Whether the table should have a border
7
+ */
8
+ bordered?: boolean;
9
+ /**
10
+ * Whether the table should have striped rows
11
+ */
12
+ striped?: boolean;
13
+ /**
14
+ * Whether the table should have hover effects
15
+ */
16
+ hover?: boolean;
17
+ /**
18
+ * Size variant for the table
19
+ */
20
+ size?: "sm" | "md" | "lg";
21
+ }
22
+
23
+ export interface TableHeadProps extends React.HTMLAttributes<HTMLTableSectionElement> {}
24
+
25
+ export interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}
26
+
27
+ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {}
28
+
29
+ export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
30
+ /**
31
+ * Whether this is a header cell
32
+ */
33
+ header?: boolean;
34
+ }
35
+
36
+ export interface TableContainerProps extends React.HTMLAttributes<HTMLDivElement> {}
37
+
38
+ export const Table: React.FC<TableProps> = ({
39
+ bordered = false,
40
+ striped = true,
41
+ hover = true,
42
+ size = "md",
43
+ className = "",
44
+ children,
45
+ ...props
46
+ }) => {
47
+ const classes = [
48
+ "table",
49
+ bordered && "table--bordered",
50
+ striped && "table--striped",
51
+ hover && "table--hover",
52
+ size && `table--${size}`,
53
+ className,
54
+ ]
55
+ .filter(Boolean)
56
+ .join(" ");
57
+
58
+ return (
59
+ <table className={classes} {...props}>
60
+ {children}
61
+ </table>
62
+ );
63
+ };
64
+
65
+ export const TableHead: React.FC<TableHeadProps> = ({
66
+ className = "",
67
+ children,
68
+ ...props
69
+ }) => {
70
+ const classes = ["table__head", className].filter(Boolean).join(" ");
71
+
72
+ return (
73
+ <thead className={classes} {...props}>
74
+ {children}
75
+ </thead>
76
+ );
77
+ };
78
+
79
+ export const TableBody: React.FC<TableBodyProps> = ({
80
+ className = "",
81
+ children,
82
+ ...props
83
+ }) => {
84
+ const classes = ["table__body", className].filter(Boolean).join(" ");
85
+
86
+ return (
87
+ <tbody className={classes} {...props}>
88
+ {children}
89
+ </tbody>
90
+ );
91
+ };
92
+
93
+ export const TableRow: React.FC<TableRowProps> = ({
94
+ className = "",
95
+ children,
96
+ ...props
97
+ }) => {
98
+ const classes = ["table__row", className].filter(Boolean).join(" ");
99
+
100
+ return (
101
+ <tr className={classes} {...props}>
102
+ {children}
103
+ </tr>
104
+ );
105
+ };
106
+
107
+ export const TableCell: React.FC<TableCellProps> = ({
108
+ header = false,
109
+ className = "",
110
+ children,
111
+ ...props
112
+ }) => {
113
+ const classes = [
114
+ header ? "table__cell--header" : "table__cell",
115
+ className,
116
+ ]
117
+ .filter(Boolean)
118
+ .join(" ");
119
+
120
+ if (header) {
121
+ return (
122
+ <th className={classes} {...props}>
123
+ {children}
124
+ </th>
125
+ );
126
+ }
127
+
128
+ return (
129
+ <td className={classes} {...props}>
130
+ {children}
131
+ </td>
132
+ );
133
+ };
134
+
135
+ export const TableContainer: React.FC<TableContainerProps> = ({
136
+ className = "",
137
+ children,
138
+ ...props
139
+ }) => {
140
+ const classes = ["table-container", className].filter(Boolean).join(" ");
141
+
142
+ return (
143
+ <div className={classes} {...props}>
144
+ {children}
145
+ </div>
146
+ );
147
+ };
@@ -0,0 +1 @@
1
+ export * from "./Table";
@@ -0,0 +1 @@
1
+ export * from './theme-control';
@@ -0,0 +1,78 @@
1
+ import * as React from "react";
2
+ import { getSavedTheme, setTheme } from "../../utils/theme";
3
+ import "../../style/components/theme-control/theme-control.css";
4
+
5
+ type Theme = 'light' | 'dark';
6
+
7
+ interface ThemeOption {
8
+ value: Theme;
9
+ label: string;
10
+ icon: React.ReactNode;
11
+ }
12
+
13
+ const themeOptions: ThemeOption[] = [
14
+ {
15
+ value: 'light',
16
+ label: 'Light',
17
+ icon: (
18
+ <svg className="theme-control__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
19
+ <circle cx="12" cy="12" r="5"/>
20
+ <line x1="12" y1="1" x2="12" y2="3"/>
21
+ <line x1="12" y1="21" x2="12" y2="23"/>
22
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
23
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
24
+ <line x1="1" y1="12" x2="3" y2="12"/>
25
+ <line x1="21" y1="12" x2="23" y2="12"/>
26
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
27
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
28
+ </svg>
29
+ ),
30
+ },
31
+ {
32
+ value: 'dark',
33
+ label: 'Dark',
34
+ icon: (
35
+ <svg className="theme-control__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
36
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
37
+ </svg>
38
+ ),
39
+ },
40
+ ];
41
+
42
+ export interface ThemeControlProps {
43
+ onThemeChange?: (theme: Theme) => void;
44
+ }
45
+
46
+ export const ThemeControl: React.FC<ThemeControlProps> = ({ onThemeChange }) => {
47
+ const [currentTheme, setCurrentTheme] = React.useState<Theme>(() => {
48
+ // Get initial theme from localStorage or default to light
49
+ return getSavedTheme();
50
+ });
51
+
52
+ React.useEffect(() => {
53
+ // Apply theme to document and save to localStorage
54
+ setTheme(currentTheme);
55
+ onThemeChange?.(currentTheme);
56
+ }, [currentTheme, onThemeChange]);
57
+
58
+ const handleThemeSelect = (theme: Theme) => {
59
+ setCurrentTheme(theme);
60
+ };
61
+
62
+ return (
63
+ <div className="theme-control">
64
+ {themeOptions.map((option) => (
65
+ <div
66
+ key={option.value}
67
+ className={`theme-control__option ${
68
+ currentTheme === option.value ? 'theme-control__option--active' : ''
69
+ }`}
70
+ onClick={() => handleThemeSelect(option.value)}
71
+ >
72
+ {option.icon}
73
+ <span>{option.label}</span>
74
+ </div>
75
+ ))}
76
+ </div>
77
+ );
78
+ };
@@ -0,0 +1 @@
1
+ export * from "./tooltip";
@@ -0,0 +1,207 @@
1
+ import * as React from "react";
2
+ import * as ReactDOM from "react-dom";
3
+ import "../../style/components/tooltip/tooltip.css";
4
+
5
+ export interface TooltipProps {
6
+ content: React.ReactNode;
7
+ children: React.ReactNode;
8
+ placement?: 'top' | 'bottom' | 'left' | 'right';
9
+ delay?: number;
10
+ disabled?: boolean;
11
+ }
12
+
13
+ type ResolvedPlacement = 'top' | 'bottom' | 'left' | 'right';
14
+
15
+ export const Tooltip: React.FC<TooltipProps> = ({
16
+ content,
17
+ children,
18
+ placement = 'top',
19
+ delay = 0,
20
+ disabled = false
21
+ }) => {
22
+ const [isVisible, setIsVisible] = React.useState(false);
23
+ const [tooltipStyle, setTooltipStyle] = React.useState<React.CSSProperties>({});
24
+ const [resolvedPlacement, setResolvedPlacement] = React.useState<ResolvedPlacement>(placement);
25
+
26
+ const triggerRef = React.useRef<HTMLDivElement>(null);
27
+ const tooltipRef = React.useRef<HTMLDivElement>(null);
28
+ const timeoutRef = React.useRef<number>();
29
+
30
+ // Calcula posição com ajuste automático baseado no espaço disponível
31
+ React.useEffect(() => {
32
+ if (!isVisible || !triggerRef.current || !tooltipRef.current) {
33
+ return;
34
+ }
35
+
36
+ const updatePosition = () => {
37
+ if (!triggerRef.current || !tooltipRef.current) {
38
+ console.log('Tooltip refs not ready:', { trigger: !!triggerRef.current, tooltip: !!tooltipRef.current });
39
+ return;
40
+ }
41
+
42
+ const triggerRect = triggerRef.current.getBoundingClientRect();
43
+ const tooltipRect = tooltipRef.current.getBoundingClientRect();
44
+
45
+ // Verifica se o tooltip tem dimensões válidas
46
+ if (tooltipRect.width === 0 || tooltipRect.height === 0) {
47
+ // Tenta novamente após um pequeno delay
48
+ setTimeout(updatePosition, 10);
49
+ return;
50
+ }
51
+ const gap = 8;
52
+ const viewportWidth = window.innerWidth;
53
+ const viewportHeight = window.innerHeight;
54
+
55
+ // Calcula espaço disponível em cada direção
56
+ const spaceTop = triggerRect.top;
57
+ const spaceBottom = viewportHeight - triggerRect.bottom;
58
+ const spaceLeft = triggerRect.left;
59
+ const spaceRight = viewportWidth - triggerRect.right;
60
+
61
+ // Determina o melhor placement baseado no espaço disponível
62
+ let finalPlacement: ResolvedPlacement = placement as ResolvedPlacement;
63
+
64
+ if (placement === 'right' && spaceRight < tooltipRect.width + gap) {
65
+ finalPlacement = spaceLeft >= tooltipRect.width + gap ? 'left' : 'bottom';
66
+ } else if (placement === 'left' && spaceLeft < tooltipRect.width + gap) {
67
+ finalPlacement = spaceRight >= tooltipRect.width + gap ? 'right' : 'bottom';
68
+ } else if (placement === 'bottom' && spaceBottom < tooltipRect.height + gap) {
69
+ finalPlacement = spaceTop >= tooltipRect.height + gap ? 'top' : 'bottom';
70
+ } else if (placement === 'top' && spaceTop < tooltipRect.height + gap) {
71
+ finalPlacement = spaceBottom >= tooltipRect.height + gap ? 'bottom' : 'top';
72
+ }
73
+
74
+ setResolvedPlacement(finalPlacement);
75
+
76
+ const newStyle: React.CSSProperties = {
77
+ position: 'fixed',
78
+ zIndex: 10000,
79
+ opacity: 1,
80
+ visibility: 'visible',
81
+ pointerEvents: 'auto',
82
+ };
83
+
84
+ // Calcula posição baseada no placement final
85
+ switch (finalPlacement) {
86
+ case 'right':
87
+ newStyle.top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
88
+ newStyle.left = triggerRect.right + gap;
89
+ break;
90
+ case 'left':
91
+ newStyle.top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
92
+ newStyle.left = triggerRect.left - tooltipRect.width - gap;
93
+ break;
94
+ case 'top':
95
+ newStyle.top = triggerRect.top - tooltipRect.height - gap;
96
+ newStyle.left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
97
+ break;
98
+ case 'bottom':
99
+ default:
100
+ newStyle.top = triggerRect.bottom + gap;
101
+ newStyle.left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
102
+ }
103
+
104
+ // Ajuste para não sair da viewport horizontalmente
105
+ if (newStyle.left! < 0) {
106
+ newStyle.left = 0;
107
+ } else if (newStyle.left! + tooltipRect.width > viewportWidth) {
108
+ newStyle.left = viewportWidth - tooltipRect.width;
109
+ }
110
+
111
+ // Ajuste para não sair da viewport verticalmente
112
+ if (newStyle.top! < 0) {
113
+ newStyle.top = 0;
114
+ } else if (newStyle.top! + tooltipRect.height > viewportHeight) {
115
+ newStyle.top = viewportHeight - tooltipRect.height;
116
+ }
117
+
118
+ setTooltipStyle(newStyle);
119
+ console.log('Calculated position:', newStyle);
120
+ };
121
+
122
+ console.log('Tooltip isVisible:', isVisible, 'tooltipStyle:', tooltipStyle);
123
+
124
+ // Usa requestAnimationFrame para garantir que o tooltip foi renderizado
125
+ requestAnimationFrame(updatePosition);
126
+
127
+ window.addEventListener('resize', updatePosition);
128
+ window.addEventListener('scroll', updatePosition, true);
129
+
130
+ return () => {
131
+ window.removeEventListener('resize', updatePosition);
132
+ window.removeEventListener('scroll', updatePosition, true);
133
+ };
134
+ }, [isVisible, placement]);
135
+
136
+ const handleMouseEnter = () => {
137
+ if (disabled) return;
138
+ console.log('Tooltip mouse enter');
139
+
140
+ if (timeoutRef.current) {
141
+ clearTimeout(timeoutRef.current);
142
+ }
143
+ timeoutRef.current = setTimeout(() => {
144
+ console.log('Tooltip setting visible');
145
+ setIsVisible(true);
146
+ }, delay);
147
+ };
148
+
149
+ const handleMouseLeave = () => {
150
+ console.log('Tooltip mouse leave');
151
+ if (timeoutRef.current) {
152
+ clearTimeout(timeoutRef.current);
153
+ }
154
+ timeoutRef.current = setTimeout(() => {
155
+ console.log('Tooltip setting invisible');
156
+ setIsVisible(false);
157
+ }, 150); // Delay menor para esconder
158
+ };
159
+
160
+ const handleClick = () => {
161
+ // Ocultar tooltip imediatamente quando clicar
162
+ if (timeoutRef.current) {
163
+ clearTimeout(timeoutRef.current);
164
+ }
165
+ setIsVisible(false);
166
+ };
167
+
168
+ return (
169
+ <>
170
+ <div
171
+ ref={triggerRef}
172
+ onMouseEnter={handleMouseEnter}
173
+ onMouseLeave={handleMouseLeave}
174
+ onClick={handleClick}
175
+ style={{ display: 'inline-block' }}
176
+ >
177
+ {children}
178
+ </div>
179
+ {isVisible && !disabled &&
180
+ ReactDOM.createPortal(
181
+ <div
182
+ ref={tooltipRef}
183
+ className={`tooltip tooltip--${resolvedPlacement}`}
184
+ style={{
185
+ ...tooltipStyle,
186
+ // Start with opacity 0 and visibility hidden to prevent initial flash
187
+ opacity: tooltipStyle.top !== undefined ? 1 : 0,
188
+ visibility: tooltipStyle.top !== undefined ? 'visible' : 'hidden',
189
+ }}
190
+ onMouseEnter={() => {
191
+ console.log('Tooltip mouse enter on tooltip');
192
+ if (timeoutRef.current) {
193
+ clearTimeout(timeoutRef.current);
194
+ }
195
+ }}
196
+ onMouseLeave={handleMouseLeave}
197
+ >
198
+ <div className="tooltip__content">
199
+ {content}
200
+ </div>
201
+ </div>,
202
+ document.body
203
+ )
204
+ }
205
+ </>
206
+ );
207
+ };
@@ -0,0 +1,48 @@
1
+ import * as React from "react";
2
+
3
+ interface NavbarTooltipContextType {
4
+ hasOpenPopover: boolean;
5
+ setHasOpenPopover: (open: boolean) => void;
6
+ openPopover: (id: string) => void;
7
+ closePopover: (id: string) => void;
8
+ activePopoverId: string | null;
9
+ }
10
+
11
+ const NavbarTooltipContext = React.createContext<NavbarTooltipContextType | undefined>(undefined);
12
+
13
+ export const NavbarTooltipProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
14
+ const [hasOpenPopover, setHasOpenPopover] = React.useState(false);
15
+ const [activePopoverId, setActivePopoverId] = React.useState<string | null>(null);
16
+
17
+ const openPopover = React.useCallback((id: string) => {
18
+ setActivePopoverId(id);
19
+ setHasOpenPopover(true);
20
+ }, []);
21
+
22
+ const closePopover = React.useCallback((id: string) => {
23
+ if (activePopoverId === id) {
24
+ setActivePopoverId(null);
25
+ setHasOpenPopover(false);
26
+ }
27
+ }, [activePopoverId]);
28
+
29
+ return (
30
+ <NavbarTooltipContext.Provider value={{
31
+ hasOpenPopover,
32
+ setHasOpenPopover,
33
+ openPopover,
34
+ closePopover,
35
+ activePopoverId
36
+ }}>
37
+ {children}
38
+ </NavbarTooltipContext.Provider>
39
+ );
40
+ };
41
+
42
+ export const useNavbarTooltip = () => {
43
+ const context = React.useContext(NavbarTooltipContext);
44
+ if (!context) {
45
+ throw new Error('useNavbarTooltip must be used within a NavbarTooltipProvider');
46
+ }
47
+ return context;
48
+ };
@@ -0,0 +1 @@
1
+ export * from './NavbarTooltipContext';
@@ -0,0 +1,136 @@
1
+ # Motion & Animation
2
+
3
+ O sistema de motion do Hellboy Design System define padrões consistentes para transições, animações e interações, garantindo uma experiência fluida e acessível.
4
+
5
+ ## Princípios
6
+
7
+ ### 1. Propósito
8
+ - **Funcional**: Animações devem ter propósito claro e melhorar a usabilidade
9
+ - **Consistente**: Padrões uniformes em todos os componentes
10
+ - **Acessível**: Respeito às preferências do usuário (prefers-reduced-motion)
11
+
12
+ ### 2. Performance
13
+ - **GPU-accelerated**: Uso de transform e opacity para animações suaves
14
+ - **Otimizado**: Durações apropriadas para evitar distração
15
+
16
+ ## Tokens de Motion
17
+
18
+ ### Durações
19
+ ```css
20
+ --motion-duration-fast: 0.15s /* Interações rápidas (hover, feedback) */
21
+ --motion-duration-base: 0.2s /* Interações padrão */
22
+ --motion-duration-slow: 0.3s /* Transições maiores */
23
+ --motion-duration-slower: 0.5s /* Animações de entrada/saída */
24
+ ```
25
+
26
+ ### Funções de Easing
27
+ ```css
28
+ --motion-easing-standard: cubic-bezier(0.4, 0.0, 0.2, 1) /* Padrão */
29
+ --motion-easing-decelerate: cubic-bezier(0.0, 0.0, 0.2, 1) /* Entrada */
30
+ --motion-easing-accelerate: cubic-bezier(0.4, 0.0, 1, 1) /* Saída */
31
+ --motion-easing-sharp: cubic-bezier(0.4, 0.0, 0.6, 1) /* Ênfase */
32
+ ```
33
+
34
+ ### Transições Combinadas
35
+ ```css
36
+ --motion-transition-fast: var(--motion-duration-fast) var(--motion-easing-standard)
37
+ --motion-transition-base: var(--motion-duration-base) var(--motion-easing-standard)
38
+ --motion-transition-slow: var(--motion-duration-slow) var(--motion-easing-standard)
39
+ ```
40
+
41
+ ### Transições Específicas
42
+ ```css
43
+ --motion-transition-color: color var(--motion-transition-base)
44
+ --motion-transition-background: background-color var(--motion-transition-base)
45
+ --motion-transition-transform: transform var(--motion-transition-base)
46
+ --motion-transition-opacity: opacity var(--motion-transition-base)
47
+ ```
48
+
49
+ ## Padrões de Uso
50
+
51
+ ### Estados Interativos
52
+ - **Hover**: Use `--motion-transition-fast` para feedback imediato
53
+ - **Active/Pressed**: Use `--motion-transition-fast` com transform scale
54
+ - **Focus**: Use `--motion-transition-base` para indicadores visuais
55
+
56
+ ### Entrada e Saída
57
+ - **Fade In/Out**: Use `--motion-transition-fade-in` / `--motion-transition-fade-out`
58
+ - **Slide**: Use animações específicas por direção (slideInRight, slideOutLeft, etc.)
59
+ - **Scale**: Use `--motion-keyframes-scale-in` para elementos emergentes
60
+
61
+ ### Componentes
62
+ - **Buttons**: Transições suaves em hover/active states
63
+ - **Form Controls**: Feedback visual consistente em focus/interaction
64
+ - **Navigation**: Transições fluidas entre estados
65
+ - **Overlays/Dialogs**: Animações de entrada/saída apropriadas
66
+
67
+ ## Acessibilidade
68
+
69
+ ### Reduced Motion
70
+ O sistema automaticamente respeita a preferência `prefers-reduced-motion: reduce`, reduzindo durações para 0.01ms quando ativada.
71
+
72
+ ```css
73
+ @media (prefers-reduced-motion: reduce) {
74
+ :root {
75
+ --motion-duration-fast: 0.01s;
76
+ --motion-duration-base: 0.01s;
77
+ --motion-duration-slow: 0.01s;
78
+ --motion-duration-slower: 0.01s;
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### Boas Práticas
84
+ - Evite animações que causem enjoo (vertigo)
85
+ - Mantenha durações entre 0.15s - 0.5s
86
+ - Use easing functions apropriadas para o contexto
87
+ - Teste em diferentes dispositivos e velocidades
88
+
89
+ ## Exemplos de Implementação
90
+
91
+ ### Button Hover
92
+ ```css
93
+ .btn {
94
+ transition: var(--motion-transition-background), var(--motion-transition-transform);
95
+ }
96
+
97
+ .btn:hover {
98
+ background-color: var(--color-primary-hover);
99
+ transform: translateY(-1px);
100
+ }
101
+ ```
102
+
103
+ ### Modal Entrance
104
+ ```css
105
+ .modal[data-enter] {
106
+ animation: var(--motion-keyframes-scale-in);
107
+ }
108
+
109
+ .modal[data-leave] {
110
+ animation: var(--motion-keyframes-scale-out);
111
+ }
112
+ ```
113
+
114
+ ### Drawer Slide
115
+ ```css
116
+ .drawer--right[data-enter] {
117
+ animation: var(--motion-keyframes-slide-in-right);
118
+ }
119
+
120
+ .drawer--right[data-leave] {
121
+ animation: var(--motion-keyframes-slide-out-right);
122
+ }
123
+ ```
124
+
125
+ ## Ferramentas de Desenvolvimento
126
+
127
+ ### Testando Motion
128
+ - Use `prefers-reduced-motion: reduce` no DevTools
129
+ - Teste em dispositivos móveis
130
+ - Verifique performance com Chrome DevTools
131
+ - Considere usuários com sensibilidade a motion
132
+
133
+ ### Debugging
134
+ - Adicione `animation-play-state: paused` para inspeção
135
+ - Use `animation-fill-mode: forwards` para estados finais
136
+ - Monitore performance com `will-change` property
package/src/index.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Hellboy Design System
3
+ * Core package with foundational components and tokens
4
+ */
5
+
6
+ // Styles
7
+ import './style/styles.css';
8
+
9
+ // Contexts
10
+ export * from './contexts';
11
+
12
+ // Components
13
+ export * from './components';
14
+
15
+ // Direct exports for new components
16
+ export { Popover } from './components/popover/popover';
17
+ export { Tooltip } from './components/tooltip/tooltip';
18
+ export { ThemeControl } from './components/theme-control/theme-control';
19
+ export { Drawer } from './components/drawer/drawer';
20
+ export { Table, TableHead, TableBody, TableRow, TableCell, TableContainer } from './components/table/Table';
21
+ export { PageIndex } from './components/page-index/PageIndex';
22
+ // Individual input components for tree-shaking
23
+ export { InputText } from './components/input/InputText';
24
+ export { InputEmail } from './components/input/InputEmail';
25
+ export { InputPassword } from './components/input/InputPassword';
26
+ export { InputSearch } from './components/input/InputSearch';
27
+ export { InputTel } from './components/input/InputTel';
28
+ export { InputUrl } from './components/input/InputUrl';
29
+ export { InputNumber } from './components/input/InputNumber';
30
+ export { InputDate } from './components/input/InputDate';
31
+ export { InputTime } from './components/input/InputTime';
32
+ export { InputDateTime } from './components/input/InputDateTime';
33
+ export { List, ListItem } from './components/list/List';
34
+ export { Select } from './components/select/Select';
35
+
36
+ // Theme utilities
37
+ export * from './utils/theme';
38
+
39
+ // User preferences utilities
40
+ export * from './utils/user-preferences';