@flowtomic/logic 0.1.7 → 0.1.8

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 (38) hide show
  1. package/dist/hooks/useDashboardLayout/index.d.ts +2 -2
  2. package/dist/hooks/useDashboardLayout/index.d.ts.map +1 -1
  3. package/dist/hooks/useDashboardLayout/useDashboardLayout.d.ts +21 -0
  4. package/dist/hooks/useDashboardLayout/useDashboardLayout.d.ts.map +1 -1
  5. package/dist/hooks/useResizable/index.d.ts +1 -1
  6. package/dist/hooks/useResizable/index.d.ts.map +1 -1
  7. package/dist/hooks/useResizable/useResizable.d.ts +5 -0
  8. package/dist/hooks/useResizable/useResizable.d.ts.map +1 -1
  9. package/dist/index.js +2 -2
  10. package/package.json +3 -3
  11. package/dist/hooks/useAnimatedIndicator/index.js +0 -1
  12. package/dist/hooks/useAnimatedIndicator/useAnimatedIndicator.js +0 -242
  13. package/dist/hooks/useAutocomplete/index.js +0 -1
  14. package/dist/hooks/useAutocomplete/useAutocomplete.js +0 -380
  15. package/dist/hooks/useDashboardLayout/index.js +0 -1
  16. package/dist/hooks/useDashboardLayout/useDashboardLayout.js +0 -175
  17. package/dist/hooks/useGenealogy/index.js +0 -1
  18. package/dist/hooks/useGenealogy/useGenealogy.js +0 -341
  19. package/dist/hooks/useMoblile/index.js +0 -1
  20. package/dist/hooks/useMoblile/useMobile.js +0 -15
  21. package/dist/hooks/useProjectProgress/index.js +0 -1
  22. package/dist/hooks/useProjectProgress/useProjectProgress.js +0 -124
  23. package/dist/hooks/useProjectStats/index.js +0 -1
  24. package/dist/hooks/useProjectStats/useProjectStats.js +0 -87
  25. package/dist/hooks/useReactTableBack/index.js +0 -1
  26. package/dist/hooks/useReactTableBack/useReactTableBack.js +0 -124
  27. package/dist/hooks/useReactTableFront/index.js +0 -1
  28. package/dist/hooks/useReactTableFront/useReactTableFront.js +0 -112
  29. package/dist/hooks/useResizable/index.js +0 -1
  30. package/dist/hooks/useResizable/useResizable.js +0 -129
  31. package/dist/hooks/useScriptEditor/index.js +0 -1
  32. package/dist/hooks/useScriptEditor/useScriptEditor.js +0 -247
  33. package/dist/hooks/useStatCard/index.js +0 -1
  34. package/dist/hooks/useStatCard/useStatCard.js +0 -187
  35. package/dist/hooks/useThemeTransition/index.js +0 -1
  36. package/dist/hooks/useThemeTransition/useThemeTransition.js +0 -35
  37. package/dist/hooks/useTimeTracker/index.js +0 -1
  38. package/dist/hooks/useTimeTracker/useTimeTracker.js +0 -143
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowtomic/logic",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Hooks headless e lógica reutilizável para React",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -27,9 +27,9 @@
27
27
  "license": "MIT",
28
28
  "scripts": {
29
29
  "dev": "bun run --watch src/index.ts",
30
- "build": "biome check . && tsc --emitDeclarationOnly && bun build ./src/index.ts --outdir ./dist --target browser --format esm --minify --external react --external react/jsx-runtime",
30
+ "build": "biome check . && tsc --emitDeclarationOnly && bun build --production ./src/index.ts --outdir ./dist --target browser --format esm --minify --external react --external react/jsx-runtime",
31
31
  "type-check": "tsc --noEmit",
32
- "clean": "rm -rf dist",
32
+ "clean": "rm -rf dist *.tsbuildinfo",
33
33
  "lint": "biome check .",
34
34
  "lint:fix": "biome check --write .",
35
35
  "format": "biome format --write .",
@@ -1 +0,0 @@
1
- export { useAnimatedIndicator } from "./useAnimatedIndicator";
@@ -1,242 +0,0 @@
1
- /**
2
- * useAnimatedIndicator - Headless UI Hook
3
- *
4
- * Hook reutilizável para animação de indicador que se move entre elementos
5
- * Fornece apenas: lógica, estado e cálculos de posição
6
- * NÃO fornece: markup, styles ou implementações pré-construídas
7
- *
8
- * Padrão Headless UI: você controla o markup e styles
9
- */
10
- import { useCallback, useEffect, useRef, useState } from "react";
11
- /**
12
- * Hook headless para animação de indicador
13
- *
14
- * @example
15
- * ```tsx
16
- * const containerRef = useRef<HTMLDivElement>(null);
17
- * const { indicatorStyle, registerElement, unregisterElement } = useAnimatedIndicator({
18
- * containerRef,
19
- * activeSelector: '[data-state="active"]',
20
- * });
21
- *
22
- * return (
23
- * <div ref={containerRef}>
24
- * {items.map((item) => (
25
- * <button
26
- * ref={(el) => registerElement(el, item.id)}
27
- * data-state={isActive ? "active" : "inactive"}
28
- * >
29
- * {item.label}
30
- * </button>
31
- * ))}
32
- * <motion.div
33
- * style={{
34
- * left: `${indicatorStyle.left}px`,
35
- * top: `${indicatorStyle.top}px`,
36
- * width: indicatorStyle.width,
37
- * height: indicatorStyle.height,
38
- * }}
39
- * />
40
- * </div>
41
- * );
42
- * ```
43
- */
44
- export function useAnimatedIndicator(options) {
45
- const { containerRef, activeSelector = '[data-state="active"]', getElementValue, updateOnResize = true, value: controlledValue, } = options;
46
- const elementsRef = useRef(new Map());
47
- const updateTimeoutRef = useRef(null);
48
- const activeValueRef = useRef(undefined);
49
- const [indicatorStyle, setIndicatorStyle] = useState({
50
- left: 0,
51
- width: 0,
52
- height: 0,
53
- top: 0,
54
- opacity: 0,
55
- });
56
- const [activeValue, setActiveValue] = useState();
57
- // Sincronizar ref com state
58
- useEffect(() => {
59
- activeValueRef.current = activeValue;
60
- }, [activeValue]);
61
- // Sincronizar valor controlado
62
- useEffect(() => {
63
- if (controlledValue !== undefined) {
64
- setActiveValue(controlledValue);
65
- }
66
- }, [controlledValue]);
67
- const updateIndicator = useCallback(() => {
68
- const currentActiveValue = activeValueRef.current;
69
- if (!currentActiveValue) {
70
- setIndicatorStyle((prev) => {
71
- if (prev.opacity === 0)
72
- return prev;
73
- return { left: 0, width: 0, height: 0, top: 0, opacity: 0 };
74
- });
75
- return;
76
- }
77
- const activeElement = elementsRef.current.get(currentActiveValue);
78
- const container = containerRef.current;
79
- if (activeElement && container) {
80
- const elementRect = activeElement.getBoundingClientRect();
81
- const containerRect = container.getBoundingClientRect();
82
- // Calcular posição relativa ao container
83
- const left = elementRect.left - containerRect.left;
84
- const width = elementRect.width;
85
- const height = elementRect.height;
86
- const top = elementRect.top - containerRect.top;
87
- setIndicatorStyle((prev) => {
88
- // Evitar atualização se os valores não mudaram
89
- if (prev.left === left &&
90
- prev.width === width &&
91
- prev.height === height &&
92
- prev.top === top &&
93
- prev.opacity === 1) {
94
- return prev;
95
- }
96
- return {
97
- left,
98
- width,
99
- height,
100
- top,
101
- opacity: 1,
102
- };
103
- });
104
- }
105
- }, [containerRef]);
106
- // Função para agendar atualização (debounce) - estável
107
- const scheduleUpdateRef = useRef(undefined);
108
- // Atualizar a função no ref sempre que updateIndicator mudar
109
- useEffect(() => {
110
- scheduleUpdateRef.current = () => {
111
- if (updateTimeoutRef.current !== null) {
112
- cancelAnimationFrame(updateTimeoutRef.current);
113
- }
114
- updateTimeoutRef.current = requestAnimationFrame(() => {
115
- updateIndicator();
116
- updateTimeoutRef.current = null;
117
- });
118
- };
119
- }, [updateIndicator]);
120
- const scheduleUpdate = useCallback(() => {
121
- scheduleUpdateRef.current?.();
122
- }, []);
123
- // Atualizar quando activeValue mudar
124
- useEffect(() => {
125
- scheduleUpdate();
126
- }, [scheduleUpdate]);
127
- // Listener de resize
128
- useEffect(() => {
129
- if (!updateOnResize)
130
- return;
131
- const handleResize = () => scheduleUpdate();
132
- window.addEventListener("resize", handleResize);
133
- return () => {
134
- window.removeEventListener("resize", handleResize);
135
- if (updateTimeoutRef.current !== null) {
136
- cancelAnimationFrame(updateTimeoutRef.current);
137
- }
138
- };
139
- }, [scheduleUpdate, updateOnResize]);
140
- const registerElement = useCallback((element, value) => {
141
- const previousElement = elementsRef.current.get(value);
142
- // Só atualizar se o elemento realmente mudou
143
- if (element === previousElement) {
144
- return;
145
- }
146
- if (element) {
147
- elementsRef.current.set(value, element);
148
- }
149
- else {
150
- // Só remover se o elemento existia antes
151
- if (previousElement) {
152
- elementsRef.current.delete(value);
153
- }
154
- else {
155
- return; // Elemento já não existe, não precisa atualizar
156
- }
157
- }
158
- // Agendar atualização de forma assíncrona para evitar loops
159
- // Só atualizar se temos um elemento válido
160
- if (element) {
161
- scheduleUpdate();
162
- }
163
- }, [scheduleUpdate]);
164
- const unregisterElement = useCallback((value) => {
165
- elementsRef.current.delete(value);
166
- scheduleUpdate();
167
- }, [scheduleUpdate]);
168
- // Refs para opções estáveis
169
- const activeSelectorRef = useRef(activeSelector);
170
- const getElementValueRef = useRef(getElementValue);
171
- useEffect(() => {
172
- activeSelectorRef.current = activeSelector;
173
- getElementValueRef.current = getElementValue;
174
- }, [activeSelector, getElementValue]);
175
- // Ref para valor controlado
176
- const controlledValueRef = useRef(controlledValue);
177
- useEffect(() => {
178
- controlledValueRef.current = controlledValue;
179
- }, [controlledValue]);
180
- // Observar mudanças no elemento ativo
181
- useEffect(() => {
182
- const container = containerRef.current;
183
- if (!container)
184
- return;
185
- const findActiveValue = () => {
186
- // Se estiver em modo controlado, ignorar detecção DOM
187
- if (controlledValueRef.current !== undefined)
188
- return;
189
- const activeElement = container.querySelector(activeSelectorRef.current);
190
- if (activeElement) {
191
- let value;
192
- if (getElementValueRef.current) {
193
- value = getElementValueRef.current(activeElement);
194
- }
195
- else {
196
- // Tentar obter do atributo data-value
197
- value = activeElement.getAttribute("data-value") || undefined;
198
- // Se não tiver data-value, buscar no Map pelo elemento
199
- if (!value) {
200
- for (const [mapValue, mapElement] of elementsRef.current.entries()) {
201
- if (mapElement === activeElement) {
202
- value = mapValue;
203
- break;
204
- }
205
- }
206
- }
207
- }
208
- if (value) {
209
- setActiveValue((prev) => {
210
- // Só atualizar se o valor realmente mudou
211
- if (prev !== value) {
212
- return value;
213
- }
214
- return prev;
215
- });
216
- }
217
- }
218
- };
219
- const observer = new MutationObserver(() => {
220
- // Usar requestAnimationFrame para evitar chamadas síncronas
221
- requestAnimationFrame(findActiveValue);
222
- });
223
- observer.observe(container, {
224
- attributes: true,
225
- attributeFilter: ["data-state", "data-active", "aria-selected"],
226
- subtree: true,
227
- });
228
- // Verificar estado inicial com delay para evitar loop
229
- const timeoutId = setTimeout(findActiveValue, 0);
230
- return () => {
231
- observer.disconnect();
232
- clearTimeout(timeoutId);
233
- };
234
- }, [containerRef]);
235
- return {
236
- indicatorStyle,
237
- registerElement,
238
- unregisterElement,
239
- updateIndicator,
240
- activeValue,
241
- };
242
- }
@@ -1 +0,0 @@
1
- export { useAutocomplete } from "./useAutocomplete";
@@ -1,380 +0,0 @@
1
- /**
2
- * useAutocomplete - Headless UI Hook
3
- *
4
- * Fornece apenas: lógica, estado, processamento e API
5
- * NÃO fornece: markup, styles ou implementações pré-construídas
6
- *
7
- * Padrão Headless UI: você controla o markup e styles
8
- *
9
- * @example
10
- * ```tsx
11
- * function MyCustomAutocomplete() {
12
- * const {
13
- * inputValue,
14
- * selectedValue,
15
- * isOpen,
16
- * filteredItems,
17
- * getInputProps,
18
- * getPopoverProps,
19
- * getListProps,
20
- * getItemProps,
21
- * open,
22
- * close,
23
- * select,
24
- * clear,
25
- * } = useAutocomplete({
26
- * options: [
27
- * { value: "1", label: "Option 1" },
28
- * { value: "2", label: "Option 2" },
29
- * ],
30
- * });
31
- *
32
- * return (
33
- * <div>
34
- * <input {...getInputProps()} />
35
- * {isOpen && (
36
- * <div {...getPopoverProps()}>
37
- * <ul {...getListProps()}>
38
- * {filteredItems.map((item) => (
39
- * <li key={item.value} {...getItemProps(item)}>
40
- * {item.label}
41
- * </li>
42
- * ))}
43
- * </ul>
44
- * </div>
45
- * )}
46
- * </div>
47
- * );
48
- * }
49
- * ```
50
- */
51
- import * as React from "react";
52
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
53
- /**
54
- * Função de filtro padrão (case-insensitive)
55
- */
56
- function defaultFilter(option, searchTerm) {
57
- return option.label.toLowerCase().includes(searchTerm.toLowerCase());
58
- }
59
- /**
60
- * Extrai items dos children em modo composição
61
- */
62
- function extractItemsFromChildren(children) {
63
- const items = [];
64
- const processChild = (child) => {
65
- if (!React.isValidElement(child)) {
66
- return;
67
- }
68
- const props = child.props;
69
- // Se tiver prop 'value', é um Autocomplete.Item
70
- if (props.value !== undefined) {
71
- const value = String(props.value);
72
- let label = value;
73
- // Extrair o texto dos children
74
- if (props.children !== undefined && props.children !== null) {
75
- if (typeof props.children === "string") {
76
- label = props.children;
77
- }
78
- else if (typeof props.children === "number") {
79
- label = String(props.children);
80
- }
81
- else if (React.isValidElement(props.children)) {
82
- const childProps = props.children.props;
83
- if (typeof childProps?.children === "string") {
84
- label = childProps.children;
85
- }
86
- else {
87
- label = String(props.children);
88
- }
89
- }
90
- else if (Array.isArray(props.children)) {
91
- React.Children.forEach(props.children, (c) => {
92
- if (typeof c === "string" && label === value) {
93
- label = c;
94
- }
95
- });
96
- }
97
- else {
98
- label = String(props.children);
99
- }
100
- }
101
- items.push({
102
- value,
103
- label,
104
- disabled: props.disabled,
105
- });
106
- return;
107
- }
108
- // Se tiver prop 'title', é um AutocompleteSection - processar seus children
109
- if (props.title !== undefined) {
110
- if (props.children) {
111
- React.Children.forEach(props.children, processChild);
112
- }
113
- return;
114
- }
115
- // Se tiver children mas não é Item nem Section, processar recursivamente
116
- if (props.children !== undefined && props.children !== null) {
117
- if (typeof props.children === "string" ||
118
- typeof props.children === "number" ||
119
- typeof props.children === "boolean") {
120
- return;
121
- }
122
- if (Array.isArray(props.children) || React.isValidElement(props.children)) {
123
- React.Children.forEach(props.children, processChild);
124
- }
125
- else if (typeof props.children === "object") {
126
- React.Children.forEach(props.children, processChild);
127
- }
128
- }
129
- };
130
- React.Children.forEach(children, processChild);
131
- return items;
132
- }
133
- /**
134
- * Hook Headless UI para Autocomplete
135
- *
136
- * Fornece apenas a lógica e API, sem markup ou styles.
137
- * Você é responsável por criar o visual.
138
- */
139
- export function useAutocomplete(options = {}) {
140
- const { options: providedOptions = [], value: controlledValue, defaultValue, onValueChange, filterFunction = defaultFilter, allowCustomValue = false, isLoading = false, emptyMessage: _emptyMessage = "Nenhum resultado encontrado.", children, } = options;
141
- // Determinar se está usando composição ou API antiga
142
- const useComposition = children !== undefined;
143
- // Estado interno
144
- const [inputValue, setInputValueState] = useState("");
145
- const [selectedValue, setSelectedValue] = useState(controlledValue ?? defaultValue);
146
- const [isOpen, setIsOpen] = useState(false);
147
- const [highlightedIndex, setHighlightedIndex] = useState(-1);
148
- // Determinar se é controlado
149
- const isControlled = controlledValue !== undefined;
150
- // Extrair items dos children se em modo composição
151
- const itemsFromChildren = useMemo(() => {
152
- if (!useComposition)
153
- return [];
154
- return extractItemsFromChildren(children);
155
- }, [useComposition, children]);
156
- // Items disponíveis (API antiga ou composição)
157
- const allItems = useMemo(() => {
158
- if (useComposition) {
159
- return itemsFromChildren;
160
- }
161
- return providedOptions;
162
- }, [useComposition, itemsFromChildren, providedOptions]);
163
- // Filtrar items baseado no inputValue
164
- const filteredItems = useMemo(() => {
165
- if (!inputValue.trim()) {
166
- return allItems;
167
- }
168
- return allItems.filter((item) => filterFunction(item, inputValue));
169
- }, [allItems, inputValue, filterFunction]);
170
- // Estado derivado
171
- const isEmpty = filteredItems.length === 0 && !isLoading;
172
- // IDs para acessibilidade
173
- const listIdRef = useRef(`autocomplete-list-${React.useId()}`);
174
- const listId = listIdRef.current;
175
- // Sincronizar com valor controlado
176
- useEffect(() => {
177
- if (isControlled && controlledValue !== undefined) {
178
- const option = allItems.find((opt) => opt.value === controlledValue);
179
- if (option) {
180
- setSelectedValue(controlledValue);
181
- setInputValueState(option.label);
182
- }
183
- else {
184
- setSelectedValue(undefined);
185
- setInputValueState(controlledValue);
186
- }
187
- }
188
- }, [isControlled, controlledValue, allItems]);
189
- // Sincronizar inputValue quando seleção muda (apenas para API antiga)
190
- useEffect(() => {
191
- if (!useComposition && selectedValue) {
192
- const option = allItems.find((opt) => opt.value === selectedValue);
193
- if (option && inputValue !== option.label) {
194
- setInputValueState(option.label);
195
- }
196
- }
197
- }, [selectedValue, allItems, useComposition, inputValue]);
198
- // Controles
199
- const open = useCallback(() => {
200
- if (filteredItems.length > 0 || isLoading) {
201
- setIsOpen(true);
202
- }
203
- }, [filteredItems.length, isLoading]);
204
- const close = useCallback(() => {
205
- setIsOpen(false);
206
- setHighlightedIndex(-1);
207
- }, []);
208
- const select = useCallback((value) => {
209
- const option = allItems.find((opt) => opt.value === value);
210
- if (option) {
211
- setSelectedValue(value);
212
- setInputValueState(option.label);
213
- onValueChange?.(value);
214
- close();
215
- }
216
- else if (allowCustomValue) {
217
- setSelectedValue(value);
218
- setInputValueState(value);
219
- onValueChange?.(value);
220
- close();
221
- }
222
- }, [allItems, allowCustomValue, onValueChange, close]);
223
- const clear = useCallback(() => {
224
- setSelectedValue(undefined);
225
- setInputValueState("");
226
- onValueChange?.(undefined);
227
- close();
228
- }, [onValueChange, close]);
229
- const setInputValue = useCallback((value) => {
230
- setInputValueState(value);
231
- if (value.trim() && (filteredItems.length > 0 || isLoading)) {
232
- setIsOpen(true);
233
- }
234
- else if (!value.trim()) {
235
- setIsOpen(false);
236
- }
237
- }, [filteredItems.length, isLoading]);
238
- // Helpers de props
239
- const getInputProps = useCallback((props = {}) => {
240
- const highlightedItem = filteredItems[highlightedIndex];
241
- const activeDescendant = highlightedItem
242
- ? `${listId}-item-${highlightedItem.value}`
243
- : undefined;
244
- const handleFocus = (e) => {
245
- open();
246
- props.onFocus?.(e);
247
- };
248
- const handleBlur = (e) => {
249
- // Delay para permitir cliques nos items
250
- setTimeout(() => {
251
- // Não fechar o popover no onBlur - deixar o Popover gerenciar o fechamento
252
- // O Popover do Radix UI já gerencia o fechamento quando você clica fora
253
- // via onOpenChange. Fechar aqui causa conflito e comportamento inconsistente.
254
- props.onBlur?.(e);
255
- }, 200);
256
- };
257
- return {
258
- ...props,
259
- value: inputValue,
260
- onChange: (e) => {
261
- setInputValue(e.target.value);
262
- props.onChange?.(e);
263
- },
264
- onFocus: handleFocus,
265
- onBlur: handleBlur,
266
- onKeyDown: (e) => {
267
- if (e.key === "ArrowDown") {
268
- e.preventDefault();
269
- if (isOpen) {
270
- setHighlightedIndex((prev) => (prev < filteredItems.length - 1 ? prev + 1 : prev));
271
- }
272
- else {
273
- open();
274
- }
275
- }
276
- else if (e.key === "ArrowUp") {
277
- e.preventDefault();
278
- if (isOpen) {
279
- setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : -1));
280
- }
281
- }
282
- else if (e.key === "Enter") {
283
- e.preventDefault();
284
- if (isOpen && highlightedItem) {
285
- select(highlightedItem.value);
286
- }
287
- else if (isOpen && filteredItems.length === 1) {
288
- select(filteredItems[0].value);
289
- }
290
- else if (allowCustomValue && inputValue.trim()) {
291
- select(inputValue);
292
- }
293
- }
294
- else if (e.key === "Escape") {
295
- e.preventDefault();
296
- close();
297
- }
298
- props.onKeyDown?.(e);
299
- },
300
- "aria-expanded": isOpen,
301
- "aria-autocomplete": "list",
302
- "aria-controls": listId,
303
- "aria-activedescendant": activeDescendant,
304
- role: "combobox",
305
- };
306
- }, [
307
- inputValue,
308
- isOpen,
309
- filteredItems,
310
- highlightedIndex,
311
- listId,
312
- open,
313
- close,
314
- select,
315
- allowCustomValue,
316
- setInputValue,
317
- ]);
318
- const getPopoverProps = useCallback((props = {}) => {
319
- return {
320
- ...props,
321
- "aria-label": "Lista de opções",
322
- role: "listbox",
323
- };
324
- }, []);
325
- const getListProps = useCallback((props = {}) => {
326
- return {
327
- ...props,
328
- id: listId,
329
- role: "listbox",
330
- "aria-label": "Opções disponíveis",
331
- };
332
- }, [listId]);
333
- const getItemProps = useCallback((item, props = {}) => {
334
- const itemId = `${listId}-item-${item.value}`;
335
- const isSelected = selectedValue === item.value;
336
- const isHighlighted = filteredItems[highlightedIndex]?.value === item.value;
337
- const handleClick = (e) => {
338
- if (!item.disabled) {
339
- select(item.value);
340
- }
341
- props.onClick?.(e);
342
- };
343
- const handleMouseEnter = (e) => {
344
- const index = filteredItems.findIndex((i) => i.value === item.value);
345
- if (index >= 0) {
346
- setHighlightedIndex(index);
347
- }
348
- props.onMouseEnter?.(e);
349
- };
350
- return {
351
- ...props,
352
- role: "option",
353
- "aria-selected": isSelected,
354
- "aria-disabled": item.disabled ?? false,
355
- id: itemId,
356
- onClick: handleClick,
357
- onMouseEnter: handleMouseEnter,
358
- className: `${props.className || ""} ${isHighlighted ? "bg-accent" : ""} ${isSelected ? "font-semibold" : ""}`.trim(),
359
- };
360
- }, [listId, selectedValue, filteredItems, highlightedIndex, select]);
361
- return {
362
- inputValue,
363
- selectedValue,
364
- isOpen,
365
- filteredItems,
366
- highlightedIndex,
367
- isLoading,
368
- isEmpty,
369
- open,
370
- close,
371
- select,
372
- clear,
373
- setInputValue,
374
- getInputProps,
375
- getPopoverProps,
376
- getListProps,
377
- getItemProps,
378
- extractItemsFromChildren,
379
- };
380
- }
@@ -1 +0,0 @@
1
- export { useDashboardLayout } from "./useDashboardLayout";