analytica-frontend-lib 1.1.93 → 1.1.95

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 (41) hide show
  1. package/dist/BreadcrumbMenu/breadcrumbStore/index.d.mts +77 -0
  2. package/dist/BreadcrumbMenu/breadcrumbStore/index.d.ts +77 -0
  3. package/dist/BreadcrumbMenu/breadcrumbStore/index.js +146 -0
  4. package/dist/BreadcrumbMenu/breadcrumbStore/index.js.map +1 -0
  5. package/dist/BreadcrumbMenu/breadcrumbStore/index.mjs +120 -0
  6. package/dist/BreadcrumbMenu/breadcrumbStore/index.mjs.map +1 -0
  7. package/dist/BreadcrumbMenu/index.d.mts +31 -0
  8. package/dist/BreadcrumbMenu/index.d.ts +31 -0
  9. package/dist/BreadcrumbMenu/index.js +308 -0
  10. package/dist/BreadcrumbMenu/index.js.map +1 -0
  11. package/dist/BreadcrumbMenu/index.mjs +289 -0
  12. package/dist/BreadcrumbMenu/index.mjs.map +1 -0
  13. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.d.mts +48 -0
  14. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.d.ts +48 -0
  15. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.js +189 -0
  16. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.js.map +1 -0
  17. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.mjs +164 -0
  18. package/dist/BreadcrumbMenu/useBreadcrumbBuilder/index.mjs.map +1 -0
  19. package/dist/BreadcrumbMenu/useUrlParams/index.d.mts +28 -0
  20. package/dist/BreadcrumbMenu/useUrlParams/index.d.ts +28 -0
  21. package/dist/BreadcrumbMenu/useUrlParams/index.js +43 -0
  22. package/dist/BreadcrumbMenu/useUrlParams/index.js.map +1 -0
  23. package/dist/BreadcrumbMenu/useUrlParams/index.mjs +18 -0
  24. package/dist/BreadcrumbMenu/useUrlParams/index.mjs.map +1 -0
  25. package/dist/StatisticsCard/index.d.mts +77 -0
  26. package/dist/StatisticsCard/index.d.ts +77 -0
  27. package/dist/StatisticsCard/index.js +608 -0
  28. package/dist/StatisticsCard/index.js.map +1 -0
  29. package/dist/StatisticsCard/index.mjs +589 -0
  30. package/dist/StatisticsCard/index.mjs.map +1 -0
  31. package/dist/index.css +41 -0
  32. package/dist/index.css.map +1 -1
  33. package/dist/index.d.mts +5 -0
  34. package/dist/index.d.ts +5 -0
  35. package/dist/index.js +699 -354
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.mjs +679 -339
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/styles.css +41 -0
  40. package/dist/styles.css.map +1 -1
  41. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Menu/Menu.tsx","../../src/utils/utils.ts","../../src/components/BreadcrumbMenu/BreadcrumbMenu.tsx"],"sourcesContent":["import { create, StoreApi, useStore } from 'zustand';\nimport {\n ReactNode,\n useEffect,\n useRef,\n forwardRef,\n HTMLAttributes,\n KeyboardEvent,\n MouseEvent,\n ReactElement,\n isValidElement,\n Children,\n cloneElement,\n useState,\n} from 'react';\nimport { CaretLeft, CaretRight } from 'phosphor-react';\nimport { cn } from '../../utils/utils';\n\ntype MenuVariant = 'menu' | 'menu2' | 'menu-overflow' | 'breadcrumb';\n\ninterface MenuStore {\n value: string;\n setValue: (value: string) => void;\n onValueChange?: (value: string) => void;\n}\n\ntype MenuStoreApi = StoreApi<MenuStore>;\n\nconst createMenuStore = (\n onValueChange?: (value: string) => void\n): MenuStoreApi =>\n create<MenuStore>((set) => ({\n value: '',\n setValue: (value) => {\n set({ value });\n onValueChange?.(value);\n },\n onValueChange,\n }));\n\nexport const useMenuStore = (externalStore?: MenuStoreApi) => {\n if (!externalStore) throw new Error('MenuItem must be inside Menu');\n return externalStore;\n};\n\ninterface MenuProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n defaultValue: string;\n value?: string;\n variant?: MenuVariant;\n onValueChange?: (value: string) => void;\n}\n\nconst VARIANT_CLASSES = {\n menu: 'bg-background shadow-soft-shadow-1 px-6',\n menu2: '',\n 'menu-overflow': '',\n breadcrumb: 'bg-transparent shadow-none !px-0',\n};\n\nconst Menu = forwardRef<HTMLDivElement, MenuProps>(\n (\n {\n className,\n children,\n defaultValue,\n value: propValue,\n variant = 'menu',\n onValueChange,\n ...props\n },\n ref\n ) => {\n const storeRef = useRef<MenuStoreApi>(null);\n storeRef.current ??= createMenuStore(onValueChange);\n const store = storeRef.current;\n const { setValue } = useStore(store, (s) => s);\n\n useEffect(() => {\n setValue(propValue ?? defaultValue);\n }, [defaultValue, propValue, setValue]);\n\n const baseClasses =\n variant === 'menu-overflow'\n ? 'w-fit py-2 flex flex-row items-center justify-center'\n : 'w-full py-2 flex flex-row items-center justify-center';\n const variantClasses = VARIANT_CLASSES[variant];\n\n return (\n <div\n ref={ref}\n className={`\n ${baseClasses}\n ${variantClasses}\n ${className ?? ''}\n `}\n {...props}\n >\n {injectStore(children, store)}\n </div>\n );\n }\n);\nMenu.displayName = 'Menu';\n\ninterface MenuContentProps extends HTMLAttributes<HTMLUListElement> {\n children: ReactNode;\n variant?: MenuVariant;\n}\n\nconst MenuContent = forwardRef<HTMLUListElement, MenuContentProps>(\n ({ className, children, variant = 'menu', ...props }, ref) => {\n const baseClasses = 'w-full flex flex-row items-center gap-2';\n\n const variantClasses =\n variant === 'menu2' || variant === 'menu-overflow'\n ? 'overflow-x-auto scroll-smooth'\n : '';\n\n return (\n <ul\n ref={ref}\n className={`\n ${baseClasses}\n ${variantClasses}\n ${variant == 'breadcrumb' ? 'flex-wrap' : ''}\n ${className ?? ''}\n `}\n style={\n variant === 'menu2' || variant === 'menu-overflow'\n ? { scrollbarWidth: 'none', msOverflowStyle: 'none' }\n : undefined\n }\n {...props}\n >\n {children}\n </ul>\n );\n }\n);\nMenuContent.displayName = 'MenuContent';\n\ninterface MenuItemProps extends HTMLAttributes<HTMLLIElement> {\n value: string;\n disabled?: boolean;\n store?: MenuStoreApi;\n variant?: MenuVariant;\n separator?: boolean;\n}\n\nconst MenuItem = forwardRef<HTMLLIElement, MenuItemProps>(\n (\n {\n className,\n children,\n value,\n disabled = false,\n store: externalStore,\n variant = 'menu',\n separator = false,\n ...props\n },\n ref\n ) => {\n const store = useMenuStore(externalStore);\n const { value: selectedValue, setValue } = useStore(store, (s) => s);\n\n const handleClick = (\n e: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>\n ) => {\n if (!disabled) {\n setValue(value);\n }\n props.onClick?.(e as MouseEvent<HTMLLIElement>);\n };\n\n const commonProps = {\n role: 'menuitem',\n 'aria-disabled': disabled,\n ref,\n onClick: handleClick,\n onKeyDown: (e: KeyboardEvent<HTMLLIElement>) => {\n if (['Enter', ' '].includes(e.key)) handleClick(e);\n },\n tabIndex: disabled ? -1 : 0,\n onMouseDown: (e: MouseEvent<HTMLLIElement>) => {\n e.preventDefault();\n },\n ...props,\n };\n\n const variants: Record<string, ReactNode> = {\n menu: (\n <li\n data-variant=\"menu\"\n className={`\n w-full flex flex-col items-center justify-center gap-0.5 py-1 px-2 rounded-sm font-medium text-xs\n [&>svg]:size-6 cursor-pointer hover:bg-primary-600 hover:text-text\n focus:outline-none focus:border-indicator-info focus:border-2\n ${selectedValue === value ? 'bg-primary-50 text-primary-950' : 'text-text-950'}\n ${className ?? ''}\n `}\n {...commonProps}\n >\n {children}\n </li>\n ),\n menu2: (\n <li\n data-variant=\"menu2\"\n className={`\n w-full flex flex-col items-center px-2 pt-4 gap-3 cursor-pointer focus:rounded-sm justify-center hover:bg-background-100 rounded-lg\n focus:outline-none focus:border-indicator-info focus:border-2\n ${selectedValue === value ? '' : 'pb-4'}\n `}\n {...commonProps}\n >\n <span\n className={cn(\n 'flex flex-row items-center gap-2 px-4 text-text-950 text-xs font-bold',\n className\n )}\n >\n {children}\n </span>\n {selectedValue === value && (\n <div className=\"h-1 w-full bg-primary-950 rounded-lg\" />\n )}\n </li>\n ),\n 'menu-overflow': (\n <li\n data-variant=\"menu-overflow\"\n className={`\n w-fit flex flex-col items-center px-2 pt-4 gap-3 cursor-pointer focus:rounded-sm justify-center hover:bg-background-100 rounded-lg\n focus:outline-none focus:border-indicator-info focus:border-2\n ${selectedValue === value ? '' : 'pb-4'}\n `}\n {...commonProps}\n >\n <span\n className={cn(\n 'flex flex-row items-center gap-2 px-4 text-text-950 text-xs font-bold',\n className\n )}\n >\n {children}\n </span>\n {selectedValue === value && (\n <div className=\"h-1 w-full bg-primary-950 rounded-lg\" />\n )}\n </li>\n ),\n breadcrumb: (\n <li\n data-variant=\"breadcrumb\"\n className={`\n flex flex-row gap-2 items-center w-fit p-2 rounded-lg hover:text-primary-600 cursor-pointer font-bold text-xs\n focus:outline-none focus:border-indicator-info focus:border-2\n ${selectedValue === value ? 'text-text-950' : 'text-text-600'}\n ${className ?? ''}\n `}\n {...commonProps}\n >\n <span\n className={cn(\n 'border-b border-text-600 hover:border-primary-600 text-inherit text-xs',\n selectedValue === value\n ? 'border-b-0 font-bold'\n : 'border-b-text-600'\n )}\n >\n {children}\n </span>\n\n {separator && (\n <CaretRight\n size={16}\n className=\"text-text-600\"\n data-testid=\"separator\"\n />\n )}\n </li>\n ),\n };\n\n return variants[variant] ?? variants['menu'];\n }\n);\nMenuItem.displayName = 'MenuItem';\n\nconst MenuItemIcon = ({\n className,\n icon,\n ...props\n}: HTMLAttributes<HTMLSpanElement> & { icon: ReactNode }) => (\n <span\n className={cn(\n 'bg-background-500 w-[21px] h-[21px] flex items-center justify-center [&>svg]:w-[17px] [&>svg]:h-[17px] rounded-sm',\n className\n )}\n {...props}\n >\n {icon}\n </span>\n);\n\nexport const internalScroll = (\n container: HTMLUListElement | null,\n direction: 'left' | 'right'\n) => {\n if (!container) return;\n container.scrollBy({\n left: direction === 'left' ? -150 : 150,\n behavior: 'smooth',\n });\n};\n\nexport const internalCheckScroll = (\n container: HTMLUListElement | null,\n setShowLeftArrow: (v: boolean) => void,\n setShowRightArrow: (v: boolean) => void\n) => {\n if (!container) return;\n const { scrollLeft, scrollWidth, clientWidth } = container;\n setShowLeftArrow(scrollLeft > 0);\n setShowRightArrow(scrollLeft + clientWidth < scrollWidth);\n};\n\ninterface MenuOverflowProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n defaultValue: string;\n value?: string;\n onValueChange?: (value: string) => void;\n}\n\nconst MenuOverflow = ({\n children,\n className,\n defaultValue,\n value,\n onValueChange,\n ...props\n}: MenuOverflowProps) => {\n const containerRef = useRef<HTMLUListElement>(null);\n const [showLeftArrow, setShowLeftArrow] = useState(false);\n const [showRightArrow, setShowRightArrow] = useState(false);\n\n useEffect(() => {\n const checkScroll = () =>\n internalCheckScroll(\n containerRef.current,\n setShowLeftArrow,\n setShowRightArrow\n );\n checkScroll();\n const container = containerRef.current;\n container?.addEventListener('scroll', checkScroll);\n window.addEventListener('resize', checkScroll);\n return () => {\n container?.removeEventListener('scroll', checkScroll);\n window.removeEventListener('resize', checkScroll);\n };\n }, []);\n\n return (\n <div\n data-testid=\"menu-overflow-wrapper\"\n className={cn('relative w-full overflow-hidden', className)}\n >\n {showLeftArrow && (\n <button\n onClick={() => internalScroll(containerRef.current, 'left')}\n className=\"absolute left-0 top-1/2 -translate-y-1/2 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white shadow-md cursor-pointer\"\n data-testid=\"scroll-left-button\"\n >\n <CaretLeft size={16} />\n <span className=\"sr-only\">Scroll left</span>\n </button>\n )}\n\n <Menu\n defaultValue={defaultValue}\n onValueChange={onValueChange}\n value={value}\n variant=\"menu2\"\n {...props}\n >\n <MenuContent ref={containerRef} variant=\"menu2\">\n {children}\n </MenuContent>\n </Menu>\n\n {showRightArrow && (\n <button\n onClick={() => internalScroll(containerRef.current, 'right')}\n className=\"absolute right-0 top-1/2 -translate-y-1/2 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white shadow-md cursor-pointer\"\n data-testid=\"scroll-right-button\"\n >\n <CaretRight size={16} />\n <span className=\"sr-only\">Scroll right</span>\n </button>\n )}\n </div>\n );\n};\n\nconst injectStore = (children: ReactNode, store: MenuStoreApi): ReactNode =>\n Children.map(children, (child) => {\n if (!isValidElement(child)) return child;\n /* eslint-disable-next-line @typescript-eslint/no-explicit-any */\n const typedChild = child as ReactElement<any>;\n const shouldInject = typedChild.type === MenuItem;\n return cloneElement(typedChild, {\n ...(shouldInject ? { store } : {}),\n ...(typedChild.props.children\n ? { children: injectStore(typedChild.props.children, store) }\n : {}),\n });\n });\n\nexport default Menu;\nexport { Menu, MenuContent, MenuItem, MenuOverflow, MenuItemIcon };\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { Menu, MenuContent, MenuItem } from '../Menu/Menu';\nimport { useNavigate } from 'react-router-dom';\nimport { type BreadcrumbItem } from './breadcrumbStore';\n\n/**\n * Props do componente BreadcrumbMenu\n */\nexport interface BreadcrumbMenuProps {\n /** Lista de breadcrumbs a serem exibidos */\n breadcrumbs: BreadcrumbItem[];\n /** Callback quando um breadcrumb é clicado */\n onBreadcrumbClick?: (breadcrumb: BreadcrumbItem, index: number) => void;\n /** Classes CSS adicionais */\n className?: string;\n}\n\n/**\n * Componente reutilizável para renderizar um menu de breadcrumbs\n *\n * @example\n * ```tsx\n * <BreadcrumbMenu\n * breadcrumbs={breadcrumbs}\n * onBreadcrumbClick={(breadcrumb, index) => {\n * console.log('Clicked:', breadcrumb, 'at index:', index);\n * }}\n * />\n * ```\n */\nexport const BreadcrumbMenu = ({\n breadcrumbs,\n onBreadcrumbClick,\n className = '!px-0 py-4 flex-wrap w-full',\n}: BreadcrumbMenuProps) => {\n const navigate = useNavigate();\n\n const handleClick = (breadcrumb: BreadcrumbItem, index: number) => {\n if (onBreadcrumbClick) {\n onBreadcrumbClick(breadcrumb, index);\n }\n navigate(breadcrumb.url);\n };\n\n return (\n <Menu\n value={`breadcrumb-${breadcrumbs.length - 1}`}\n defaultValue=\"breadcrumb-0\"\n variant=\"breadcrumb\"\n className={className}\n >\n <MenuContent className=\"w-full flex flex-row flex-wrap gap-2 !px-0\">\n {breadcrumbs.map((breadcrumb, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const hasSeparator = !isLast;\n\n return (\n <MenuItem\n key={breadcrumb.id}\n variant=\"breadcrumb\"\n value={`breadcrumb-${index}`}\n className=\"!p-0 whitespace-nowrap\"\n onClick={() => handleClick(breadcrumb, index)}\n separator={hasSeparator}\n >\n {breadcrumb.name}\n </MenuItem>\n );\n })}\n </MenuContent>\n </Menu>\n );\n};\n"],"mappings":"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","names":["jsx"]}
@@ -0,0 +1,48 @@
1
+ import { BreadcrumbItem } from '../breadcrumbStore/index.mjs';
2
+ import 'zustand';
3
+
4
+ /**
5
+ * Interface para configuração de um nível de breadcrumb dinâmico (com dados)
6
+ */
7
+ interface BreadcrumbLevelWithData<T = any> {
8
+ /** Dados do nível atual */
9
+ data: T | null;
10
+ /** ID extraído da URL para comparação */
11
+ urlId?: string;
12
+ /** Função para obter o ID dos dados */
13
+ getId: (data: T) => string;
14
+ /** Função para obter o nome dos dados */
15
+ getName: (data: T) => string;
16
+ /** Função para construir a URL do breadcrumb */
17
+ getUrl: (data: T, previousIds: string[]) => string;
18
+ }
19
+ /**
20
+ * Interface para configuração de um nível de breadcrumb estático (sem dados)
21
+ */
22
+ interface BreadcrumbLevelStatic {
23
+ /** Breadcrumb estático */
24
+ breadcrumb: BreadcrumbItem;
25
+ /** ID extraído da URL para validação (se não estiver na URL, não mostra) */
26
+ urlId?: string;
27
+ }
28
+ /**
29
+ * Union type para aceitar ambos os tipos de breadcrumb
30
+ */
31
+ type BreadcrumbLevel<T = any> = BreadcrumbLevelWithData<T> | BreadcrumbLevelStatic;
32
+ /**
33
+ * Configuração do builder de breadcrumbs
34
+ */
35
+ interface BreadcrumbBuilderConfig {
36
+ /** Namespace único para este breadcrumb */
37
+ namespace: string;
38
+ /** Breadcrumb inicial (raiz) */
39
+ root: BreadcrumbItem;
40
+ /** Níveis hierárquicos de breadcrumbs (cada um pode ter tipo diferente) */
41
+ levels: BreadcrumbLevel<any>[];
42
+ }
43
+ declare const useBreadcrumbBuilder: (config: BreadcrumbBuilderConfig) => {
44
+ breadcrumbs: BreadcrumbItem[];
45
+ sliceBreadcrumbs: (index: number) => void;
46
+ };
47
+
48
+ export { type BreadcrumbBuilderConfig, type BreadcrumbLevel, type BreadcrumbLevelStatic, type BreadcrumbLevelWithData, useBreadcrumbBuilder };
@@ -0,0 +1,48 @@
1
+ import { BreadcrumbItem } from '../breadcrumbStore/index.js';
2
+ import 'zustand';
3
+
4
+ /**
5
+ * Interface para configuração de um nível de breadcrumb dinâmico (com dados)
6
+ */
7
+ interface BreadcrumbLevelWithData<T = any> {
8
+ /** Dados do nível atual */
9
+ data: T | null;
10
+ /** ID extraído da URL para comparação */
11
+ urlId?: string;
12
+ /** Função para obter o ID dos dados */
13
+ getId: (data: T) => string;
14
+ /** Função para obter o nome dos dados */
15
+ getName: (data: T) => string;
16
+ /** Função para construir a URL do breadcrumb */
17
+ getUrl: (data: T, previousIds: string[]) => string;
18
+ }
19
+ /**
20
+ * Interface para configuração de um nível de breadcrumb estático (sem dados)
21
+ */
22
+ interface BreadcrumbLevelStatic {
23
+ /** Breadcrumb estático */
24
+ breadcrumb: BreadcrumbItem;
25
+ /** ID extraído da URL para validação (se não estiver na URL, não mostra) */
26
+ urlId?: string;
27
+ }
28
+ /**
29
+ * Union type para aceitar ambos os tipos de breadcrumb
30
+ */
31
+ type BreadcrumbLevel<T = any> = BreadcrumbLevelWithData<T> | BreadcrumbLevelStatic;
32
+ /**
33
+ * Configuração do builder de breadcrumbs
34
+ */
35
+ interface BreadcrumbBuilderConfig {
36
+ /** Namespace único para este breadcrumb */
37
+ namespace: string;
38
+ /** Breadcrumb inicial (raiz) */
39
+ root: BreadcrumbItem;
40
+ /** Níveis hierárquicos de breadcrumbs (cada um pode ter tipo diferente) */
41
+ levels: BreadcrumbLevel<any>[];
42
+ }
43
+ declare const useBreadcrumbBuilder: (config: BreadcrumbBuilderConfig) => {
44
+ breadcrumbs: BreadcrumbItem[];
45
+ sliceBreadcrumbs: (index: number) => void;
46
+ };
47
+
48
+ export { type BreadcrumbBuilderConfig, type BreadcrumbLevel, type BreadcrumbLevelStatic, type BreadcrumbLevelWithData, useBreadcrumbBuilder };
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts
21
+ var useBreadcrumbBuilder_exports = {};
22
+ __export(useBreadcrumbBuilder_exports, {
23
+ useBreadcrumbBuilder: () => useBreadcrumbBuilder
24
+ });
25
+ module.exports = __toCommonJS(useBreadcrumbBuilder_exports);
26
+ var import_react = require("react");
27
+
28
+ // src/components/BreadcrumbMenu/breadcrumbStore.ts
29
+ var import_zustand = require("zustand");
30
+ var useBreadcrumbStore = (0, import_zustand.create)((set, get) => ({
31
+ breadcrumbs: {},
32
+ setBreadcrumbs: (namespace, items) => {
33
+ set((state) => ({
34
+ breadcrumbs: {
35
+ ...state.breadcrumbs,
36
+ [namespace]: items
37
+ }
38
+ }));
39
+ },
40
+ addBreadcrumb: (namespace, item) => {
41
+ set((state) => {
42
+ const current = state.breadcrumbs[namespace] || [];
43
+ return {
44
+ breadcrumbs: {
45
+ ...state.breadcrumbs,
46
+ [namespace]: [...current, item]
47
+ }
48
+ };
49
+ });
50
+ },
51
+ updateBreadcrumb: (namespace, itemId, updates) => {
52
+ set((state) => {
53
+ const current = state.breadcrumbs[namespace] || [];
54
+ return {
55
+ breadcrumbs: {
56
+ ...state.breadcrumbs,
57
+ [namespace]: current.map(
58
+ (item) => item.id === itemId ? { ...item, ...updates } : item
59
+ )
60
+ }
61
+ };
62
+ });
63
+ },
64
+ removeBreadcrumbFrom: (namespace, itemId) => {
65
+ set((state) => {
66
+ const current = state.breadcrumbs[namespace] || [];
67
+ const index = current.findIndex((item) => item.id === itemId);
68
+ if (index === -1) return state;
69
+ return {
70
+ breadcrumbs: {
71
+ ...state.breadcrumbs,
72
+ [namespace]: current.slice(0, index)
73
+ }
74
+ };
75
+ });
76
+ },
77
+ sliceBreadcrumbs: (namespace, index) => {
78
+ set((state) => {
79
+ const current = state.breadcrumbs[namespace] || [];
80
+ return {
81
+ breadcrumbs: {
82
+ ...state.breadcrumbs,
83
+ [namespace]: current.slice(0, index + 1)
84
+ }
85
+ };
86
+ });
87
+ },
88
+ clearBreadcrumbs: (namespace) => {
89
+ set((state) => {
90
+ const { [namespace]: _, ...rest } = state.breadcrumbs;
91
+ return {
92
+ breadcrumbs: rest
93
+ };
94
+ });
95
+ },
96
+ getBreadcrumbs: (namespace) => {
97
+ return get().breadcrumbs[namespace] || [];
98
+ }
99
+ }));
100
+ var useBreadcrumb = (namespace) => {
101
+ const store = useBreadcrumbStore();
102
+ const breadcrumbs = store.breadcrumbs[namespace] || [];
103
+ return {
104
+ breadcrumbs,
105
+ /**
106
+ * Define todos os breadcrumbs de uma vez
107
+ */
108
+ setBreadcrumbs: (items) => {
109
+ store.setBreadcrumbs(namespace, items);
110
+ },
111
+ /**
112
+ * Adiciona um novo breadcrumb ao final
113
+ */
114
+ addBreadcrumb: (item) => {
115
+ store.addBreadcrumb(namespace, item);
116
+ },
117
+ /**
118
+ * Atualiza um breadcrumb existente
119
+ */
120
+ updateBreadcrumb: (itemId, updates) => {
121
+ store.updateBreadcrumb(namespace, itemId, updates);
122
+ },
123
+ /**
124
+ * Remove um breadcrumb e todos os seguintes
125
+ */
126
+ removeBreadcrumbFrom: (itemId) => {
127
+ store.removeBreadcrumbFrom(namespace, itemId);
128
+ },
129
+ /**
130
+ * Mantém apenas os breadcrumbs até o índice especificado (inclusivo)
131
+ */
132
+ sliceBreadcrumbs: (index) => {
133
+ store.sliceBreadcrumbs(namespace, index);
134
+ },
135
+ /**
136
+ * Limpa todos os breadcrumbs
137
+ */
138
+ clearBreadcrumbs: () => {
139
+ store.clearBreadcrumbs(namespace);
140
+ }
141
+ };
142
+ };
143
+
144
+ // src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts
145
+ var isBreadcrumbWithData = (level) => {
146
+ return "data" in level;
147
+ };
148
+ var useBreadcrumbBuilder = (config) => {
149
+ const { namespace, root, levels } = config;
150
+ const { breadcrumbs, setBreadcrumbs, sliceBreadcrumbs } = useBreadcrumb(namespace);
151
+ const levelDependencies = levels.map(
152
+ (level) => isBreadcrumbWithData(level) ? level.data : null
153
+ );
154
+ const levelUrlIds = levels.map((level) => level.urlId);
155
+ (0, import_react.useEffect)(() => {
156
+ const newBreadcrumbs = [root];
157
+ const previousIds = [];
158
+ for (const level of levels) {
159
+ const { urlId } = level;
160
+ if (isBreadcrumbWithData(level)) {
161
+ const { data, getId, getName, getUrl } = level;
162
+ if (!data) break;
163
+ const dataId = getId(data);
164
+ if (urlId === void 0 || dataId !== urlId) break;
165
+ newBreadcrumbs.push({
166
+ id: dataId,
167
+ name: getName(data),
168
+ url: getUrl(data, previousIds)
169
+ });
170
+ previousIds.push(dataId);
171
+ } else {
172
+ const { breadcrumb } = level;
173
+ if (urlId === void 0) break;
174
+ newBreadcrumbs.push(breadcrumb);
175
+ previousIds.push(breadcrumb.id);
176
+ }
177
+ }
178
+ setBreadcrumbs(newBreadcrumbs);
179
+ }, [namespace, ...levelDependencies, ...levelUrlIds, root.id]);
180
+ return {
181
+ breadcrumbs,
182
+ sliceBreadcrumbs
183
+ };
184
+ };
185
+ // Annotate the CommonJS export names for ESM import in node:
186
+ 0 && (module.exports = {
187
+ useBreadcrumbBuilder
188
+ });
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts","../../../src/components/BreadcrumbMenu/breadcrumbStore.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { useBreadcrumb, type BreadcrumbItem } from './breadcrumbStore';\n\n/**\n * Interface para configuração de um nível de breadcrumb dinâmico (com dados)\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface BreadcrumbLevelWithData<T = any> {\n /** Dados do nível atual */\n data: T | null;\n /** ID extraído da URL para comparação */\n urlId?: string;\n /** Função para obter o ID dos dados */\n getId: (data: T) => string;\n /** Função para obter o nome dos dados */\n getName: (data: T) => string;\n /** Função para construir a URL do breadcrumb */\n getUrl: (data: T, previousIds: string[]) => string;\n}\n\n/**\n * Interface para configuração de um nível de breadcrumb estático (sem dados)\n */\nexport interface BreadcrumbLevelStatic {\n /** Breadcrumb estático */\n breadcrumb: BreadcrumbItem;\n /** ID extraído da URL para validação (se não estiver na URL, não mostra) */\n urlId?: string;\n}\n\n/**\n * Union type para aceitar ambos os tipos de breadcrumb\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BreadcrumbLevel<T = any> =\n | BreadcrumbLevelWithData<T>\n | BreadcrumbLevelStatic;\n\n/**\n * Configuração do builder de breadcrumbs\n */\nexport interface BreadcrumbBuilderConfig {\n /** Namespace único para este breadcrumb */\n namespace: string;\n /** Breadcrumb inicial (raiz) */\n root: BreadcrumbItem;\n /** Níveis hierárquicos de breadcrumbs (cada um pode ter tipo diferente) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n levels: BreadcrumbLevel<any>[];\n}\n\n/**\n * Hook para construir breadcrumbs hierárquicos automaticamente\n *\n * Suporta dois tipos de breadcrumbs:\n * 1. Dinâmico (com dados): Requer dados carregados do backend\n * 2. Estático: Breadcrumb fixo que aparece baseado na URL\n *\n * @param config - Configuração do builder\n * @returns Breadcrumbs e métodos para manipulá-los\n *\n * @example\n * // Breadcrumb dinâmico (com dados do backend)\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'performance',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * {\n * data: subjectData,\n * urlId: subjectId,\n * getId: (data) => data.subjectId,\n * getName: (data) => data.subjectName,\n * getUrl: (data) => `/subjects/${data.subjectId}`,\n * },\n * ],\n * });\n * ```\n *\n * @example\n * // Breadcrumb estático (sem dados)\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'settings',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * {\n * breadcrumb: { id: 'settings', name: 'Configurações', url: '/settings' },\n * urlId: 'settings', // Mostra apenas se 'settings' estiver na URL\n * },\n * {\n * breadcrumb: { id: 'profile', name: 'Perfil', url: '/settings/profile' },\n * urlId: 'profile',\n * },\n * ],\n * });\n * ```\n *\n * @example\n * // Misturar estático e dinâmico\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'mixed',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * // Estático\n * {\n * breadcrumb: { id: 'products', name: 'Produtos', url: '/products' },\n * urlId: 'products',\n * },\n * // Dinâmico\n * {\n * data: categoryData,\n * urlId: categoryId,\n * getId: (data) => data.id,\n * getName: (data) => data.name,\n * getUrl: (data) => `/products/${data.id}`,\n * },\n * ],\n * });\n * ```\n */\n/**\n * Type guard para verificar se é um breadcrumb com dados\n */\nconst isBreadcrumbWithData = (\n level: BreadcrumbLevel\n): level is BreadcrumbLevelWithData => {\n return 'data' in level;\n};\n\nexport const useBreadcrumbBuilder = (config: BreadcrumbBuilderConfig) => {\n const { namespace, root, levels } = config;\n const { breadcrumbs, setBreadcrumbs, sliceBreadcrumbs } =\n useBreadcrumb(namespace);\n\n // Extrair apenas os dados dos levels que são as verdadeiras dependências\n const levelDependencies = levels.map((level) =>\n isBreadcrumbWithData(level) ? level.data : null\n );\n const levelUrlIds = levels.map((level) => level.urlId);\n\n useEffect(() => {\n const newBreadcrumbs: BreadcrumbItem[] = [root];\n const previousIds: string[] = [];\n\n // Construir breadcrumbs hierarquicamente\n for (const level of levels) {\n const { urlId } = level;\n\n // Verificar se é breadcrumb com dados ou estático\n if (isBreadcrumbWithData(level)) {\n // Breadcrumb dinâmico (com dados)\n const { data, getId, getName, getUrl } = level;\n\n // Parar se não temos dados\n if (!data) break;\n\n const dataId = getId(data);\n\n // Se urlId está definido, deve corresponder ao dataId\n // Se urlId é undefined, significa que estamos em nível superior, então parar\n if (urlId === undefined || dataId !== urlId) break;\n\n // Adicionar breadcrumb\n newBreadcrumbs.push({\n id: dataId,\n name: getName(data),\n url: getUrl(data, previousIds),\n });\n\n previousIds.push(dataId);\n } else {\n // Breadcrumb estático\n const { breadcrumb } = level;\n\n // Se urlId é undefined, parar (não estamos neste nível)\n if (urlId === undefined) break;\n\n // Adicionar breadcrumb estático\n newBreadcrumbs.push(breadcrumb);\n previousIds.push(breadcrumb.id);\n }\n }\n\n setBreadcrumbs(newBreadcrumbs);\n }, [namespace, ...levelDependencies, ...levelUrlIds, root.id]);\n\n return {\n breadcrumbs,\n sliceBreadcrumbs,\n };\n};\n","import { create } from 'zustand';\n\n/**\n * Interface para um item de breadcrumb\n */\nexport interface BreadcrumbItem {\n id: string;\n name: string;\n url: string;\n}\n\n/**\n * Interface para o estado do store de breadcrumbs\n */\ninterface BreadcrumbStore {\n // Múltiplas instâncias de breadcrumbs identificadas por namespace\n breadcrumbs: Record<string, BreadcrumbItem[]>;\n\n // Define todos os breadcrumbs de uma instância\n setBreadcrumbs: (namespace: string, items: BreadcrumbItem[]) => void;\n\n // Adiciona um breadcrumb ao final da lista\n addBreadcrumb: (namespace: string, item: BreadcrumbItem) => void;\n\n // Atualiza um breadcrumb existente\n updateBreadcrumb: (\n namespace: string,\n itemId: string,\n updates: Partial<BreadcrumbItem>\n ) => void;\n\n // Remove um breadcrumb e todos os seguintes\n removeBreadcrumbFrom: (namespace: string, itemId: string) => void;\n\n // Mantém apenas os breadcrumbs até o índice especificado\n sliceBreadcrumbs: (namespace: string, index: number) => void;\n\n // Limpa todos os breadcrumbs de uma instância\n clearBreadcrumbs: (namespace: string) => void;\n\n // Obtém os breadcrumbs de uma instância\n getBreadcrumbs: (namespace: string) => BreadcrumbItem[];\n}\n\n/**\n * Store Zustand para gerenciar breadcrumbs\n * Suporta múltiplas instâncias através de namespaces\n */\nexport const useBreadcrumbStore = create<BreadcrumbStore>((set, get) => ({\n breadcrumbs: {},\n\n setBreadcrumbs: (namespace: string, items: BreadcrumbItem[]) => {\n set((state) => ({\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: items,\n },\n }));\n },\n\n addBreadcrumb: (namespace: string, item: BreadcrumbItem) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: [...current, item],\n },\n };\n });\n },\n\n updateBreadcrumb: (\n namespace: string,\n itemId: string,\n updates: Partial<BreadcrumbItem>\n ) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.map((item) =>\n item.id === itemId ? { ...item, ...updates } : item\n ),\n },\n };\n });\n },\n\n removeBreadcrumbFrom: (namespace: string, itemId: string) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n const index = current.findIndex((item) => item.id === itemId);\n if (index === -1) return state;\n\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.slice(0, index),\n },\n };\n });\n },\n\n sliceBreadcrumbs: (namespace: string, index: number) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.slice(0, index + 1),\n },\n };\n });\n },\n\n clearBreadcrumbs: (namespace: string) => {\n set((state) => {\n const { [namespace]: _, ...rest } = state.breadcrumbs;\n return {\n breadcrumbs: rest,\n };\n });\n },\n\n getBreadcrumbs: (namespace: string) => {\n return get().breadcrumbs[namespace] || [];\n },\n}));\n\n/**\n * Hook customizado para facilitar o uso de breadcrumbs\n *\n * @param namespace - Identificador único para esta instância de breadcrumbs\n * @returns Objeto com breadcrumbs e métodos para manipulá-los\n *\n * @example\n * ```tsx\n * const { breadcrumbs, setBreadcrumbs, addBreadcrumb } = useBreadcrumb('performance');\n *\n * // Definir breadcrumbs iniciais\n * setBreadcrumbs([\n * { id: 'home', name: 'Home', url: '/' },\n * { id: 'page', name: 'Page', url: '/page' }\n * ]);\n *\n * // Adicionar novo breadcrumb\n * addBreadcrumb({ id: 'detail', name: 'Detail', url: '/page/detail' });\n * ```\n */\nexport const useBreadcrumb = (namespace: string) => {\n const store = useBreadcrumbStore();\n const breadcrumbs = store.breadcrumbs[namespace] || [];\n\n return {\n breadcrumbs,\n\n /**\n * Define todos os breadcrumbs de uma vez\n */\n setBreadcrumbs: (items: BreadcrumbItem[]) => {\n store.setBreadcrumbs(namespace, items);\n },\n\n /**\n * Adiciona um novo breadcrumb ao final\n */\n addBreadcrumb: (item: BreadcrumbItem) => {\n store.addBreadcrumb(namespace, item);\n },\n\n /**\n * Atualiza um breadcrumb existente\n */\n updateBreadcrumb: (itemId: string, updates: Partial<BreadcrumbItem>) => {\n store.updateBreadcrumb(namespace, itemId, updates);\n },\n\n /**\n * Remove um breadcrumb e todos os seguintes\n */\n removeBreadcrumbFrom: (itemId: string) => {\n store.removeBreadcrumbFrom(namespace, itemId);\n },\n\n /**\n * Mantém apenas os breadcrumbs até o índice especificado (inclusivo)\n */\n sliceBreadcrumbs: (index: number) => {\n store.sliceBreadcrumbs(namespace, index);\n },\n\n /**\n * Limpa todos os breadcrumbs\n */\n clearBreadcrumbs: () => {\n store.clearBreadcrumbs(namespace);\n },\n };\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,164 @@
1
+ // src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts
2
+ import { useEffect } from "react";
3
+
4
+ // src/components/BreadcrumbMenu/breadcrumbStore.ts
5
+ import { create } from "zustand";
6
+ var useBreadcrumbStore = create((set, get) => ({
7
+ breadcrumbs: {},
8
+ setBreadcrumbs: (namespace, items) => {
9
+ set((state) => ({
10
+ breadcrumbs: {
11
+ ...state.breadcrumbs,
12
+ [namespace]: items
13
+ }
14
+ }));
15
+ },
16
+ addBreadcrumb: (namespace, item) => {
17
+ set((state) => {
18
+ const current = state.breadcrumbs[namespace] || [];
19
+ return {
20
+ breadcrumbs: {
21
+ ...state.breadcrumbs,
22
+ [namespace]: [...current, item]
23
+ }
24
+ };
25
+ });
26
+ },
27
+ updateBreadcrumb: (namespace, itemId, updates) => {
28
+ set((state) => {
29
+ const current = state.breadcrumbs[namespace] || [];
30
+ return {
31
+ breadcrumbs: {
32
+ ...state.breadcrumbs,
33
+ [namespace]: current.map(
34
+ (item) => item.id === itemId ? { ...item, ...updates } : item
35
+ )
36
+ }
37
+ };
38
+ });
39
+ },
40
+ removeBreadcrumbFrom: (namespace, itemId) => {
41
+ set((state) => {
42
+ const current = state.breadcrumbs[namespace] || [];
43
+ const index = current.findIndex((item) => item.id === itemId);
44
+ if (index === -1) return state;
45
+ return {
46
+ breadcrumbs: {
47
+ ...state.breadcrumbs,
48
+ [namespace]: current.slice(0, index)
49
+ }
50
+ };
51
+ });
52
+ },
53
+ sliceBreadcrumbs: (namespace, index) => {
54
+ set((state) => {
55
+ const current = state.breadcrumbs[namespace] || [];
56
+ return {
57
+ breadcrumbs: {
58
+ ...state.breadcrumbs,
59
+ [namespace]: current.slice(0, index + 1)
60
+ }
61
+ };
62
+ });
63
+ },
64
+ clearBreadcrumbs: (namespace) => {
65
+ set((state) => {
66
+ const { [namespace]: _, ...rest } = state.breadcrumbs;
67
+ return {
68
+ breadcrumbs: rest
69
+ };
70
+ });
71
+ },
72
+ getBreadcrumbs: (namespace) => {
73
+ return get().breadcrumbs[namespace] || [];
74
+ }
75
+ }));
76
+ var useBreadcrumb = (namespace) => {
77
+ const store = useBreadcrumbStore();
78
+ const breadcrumbs = store.breadcrumbs[namespace] || [];
79
+ return {
80
+ breadcrumbs,
81
+ /**
82
+ * Define todos os breadcrumbs de uma vez
83
+ */
84
+ setBreadcrumbs: (items) => {
85
+ store.setBreadcrumbs(namespace, items);
86
+ },
87
+ /**
88
+ * Adiciona um novo breadcrumb ao final
89
+ */
90
+ addBreadcrumb: (item) => {
91
+ store.addBreadcrumb(namespace, item);
92
+ },
93
+ /**
94
+ * Atualiza um breadcrumb existente
95
+ */
96
+ updateBreadcrumb: (itemId, updates) => {
97
+ store.updateBreadcrumb(namespace, itemId, updates);
98
+ },
99
+ /**
100
+ * Remove um breadcrumb e todos os seguintes
101
+ */
102
+ removeBreadcrumbFrom: (itemId) => {
103
+ store.removeBreadcrumbFrom(namespace, itemId);
104
+ },
105
+ /**
106
+ * Mantém apenas os breadcrumbs até o índice especificado (inclusivo)
107
+ */
108
+ sliceBreadcrumbs: (index) => {
109
+ store.sliceBreadcrumbs(namespace, index);
110
+ },
111
+ /**
112
+ * Limpa todos os breadcrumbs
113
+ */
114
+ clearBreadcrumbs: () => {
115
+ store.clearBreadcrumbs(namespace);
116
+ }
117
+ };
118
+ };
119
+
120
+ // src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts
121
+ var isBreadcrumbWithData = (level) => {
122
+ return "data" in level;
123
+ };
124
+ var useBreadcrumbBuilder = (config) => {
125
+ const { namespace, root, levels } = config;
126
+ const { breadcrumbs, setBreadcrumbs, sliceBreadcrumbs } = useBreadcrumb(namespace);
127
+ const levelDependencies = levels.map(
128
+ (level) => isBreadcrumbWithData(level) ? level.data : null
129
+ );
130
+ const levelUrlIds = levels.map((level) => level.urlId);
131
+ useEffect(() => {
132
+ const newBreadcrumbs = [root];
133
+ const previousIds = [];
134
+ for (const level of levels) {
135
+ const { urlId } = level;
136
+ if (isBreadcrumbWithData(level)) {
137
+ const { data, getId, getName, getUrl } = level;
138
+ if (!data) break;
139
+ const dataId = getId(data);
140
+ if (urlId === void 0 || dataId !== urlId) break;
141
+ newBreadcrumbs.push({
142
+ id: dataId,
143
+ name: getName(data),
144
+ url: getUrl(data, previousIds)
145
+ });
146
+ previousIds.push(dataId);
147
+ } else {
148
+ const { breadcrumb } = level;
149
+ if (urlId === void 0) break;
150
+ newBreadcrumbs.push(breadcrumb);
151
+ previousIds.push(breadcrumb.id);
152
+ }
153
+ }
154
+ setBreadcrumbs(newBreadcrumbs);
155
+ }, [namespace, ...levelDependencies, ...levelUrlIds, root.id]);
156
+ return {
157
+ breadcrumbs,
158
+ sliceBreadcrumbs
159
+ };
160
+ };
161
+ export {
162
+ useBreadcrumbBuilder
163
+ };
164
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/BreadcrumbMenu/useBreadcrumbBuilder.ts","../../../src/components/BreadcrumbMenu/breadcrumbStore.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { useBreadcrumb, type BreadcrumbItem } from './breadcrumbStore';\n\n/**\n * Interface para configuração de um nível de breadcrumb dinâmico (com dados)\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface BreadcrumbLevelWithData<T = any> {\n /** Dados do nível atual */\n data: T | null;\n /** ID extraído da URL para comparação */\n urlId?: string;\n /** Função para obter o ID dos dados */\n getId: (data: T) => string;\n /** Função para obter o nome dos dados */\n getName: (data: T) => string;\n /** Função para construir a URL do breadcrumb */\n getUrl: (data: T, previousIds: string[]) => string;\n}\n\n/**\n * Interface para configuração de um nível de breadcrumb estático (sem dados)\n */\nexport interface BreadcrumbLevelStatic {\n /** Breadcrumb estático */\n breadcrumb: BreadcrumbItem;\n /** ID extraído da URL para validação (se não estiver na URL, não mostra) */\n urlId?: string;\n}\n\n/**\n * Union type para aceitar ambos os tipos de breadcrumb\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BreadcrumbLevel<T = any> =\n | BreadcrumbLevelWithData<T>\n | BreadcrumbLevelStatic;\n\n/**\n * Configuração do builder de breadcrumbs\n */\nexport interface BreadcrumbBuilderConfig {\n /** Namespace único para este breadcrumb */\n namespace: string;\n /** Breadcrumb inicial (raiz) */\n root: BreadcrumbItem;\n /** Níveis hierárquicos de breadcrumbs (cada um pode ter tipo diferente) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n levels: BreadcrumbLevel<any>[];\n}\n\n/**\n * Hook para construir breadcrumbs hierárquicos automaticamente\n *\n * Suporta dois tipos de breadcrumbs:\n * 1. Dinâmico (com dados): Requer dados carregados do backend\n * 2. Estático: Breadcrumb fixo que aparece baseado na URL\n *\n * @param config - Configuração do builder\n * @returns Breadcrumbs e métodos para manipulá-los\n *\n * @example\n * // Breadcrumb dinâmico (com dados do backend)\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'performance',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * {\n * data: subjectData,\n * urlId: subjectId,\n * getId: (data) => data.subjectId,\n * getName: (data) => data.subjectName,\n * getUrl: (data) => `/subjects/${data.subjectId}`,\n * },\n * ],\n * });\n * ```\n *\n * @example\n * // Breadcrumb estático (sem dados)\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'settings',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * {\n * breadcrumb: { id: 'settings', name: 'Configurações', url: '/settings' },\n * urlId: 'settings', // Mostra apenas se 'settings' estiver na URL\n * },\n * {\n * breadcrumb: { id: 'profile', name: 'Perfil', url: '/settings/profile' },\n * urlId: 'profile',\n * },\n * ],\n * });\n * ```\n *\n * @example\n * // Misturar estático e dinâmico\n * ```tsx\n * const { breadcrumbs } = useBreadcrumbBuilder({\n * namespace: 'mixed',\n * root: { id: 'home', name: 'Home', url: '/' },\n * levels: [\n * // Estático\n * {\n * breadcrumb: { id: 'products', name: 'Produtos', url: '/products' },\n * urlId: 'products',\n * },\n * // Dinâmico\n * {\n * data: categoryData,\n * urlId: categoryId,\n * getId: (data) => data.id,\n * getName: (data) => data.name,\n * getUrl: (data) => `/products/${data.id}`,\n * },\n * ],\n * });\n * ```\n */\n/**\n * Type guard para verificar se é um breadcrumb com dados\n */\nconst isBreadcrumbWithData = (\n level: BreadcrumbLevel\n): level is BreadcrumbLevelWithData => {\n return 'data' in level;\n};\n\nexport const useBreadcrumbBuilder = (config: BreadcrumbBuilderConfig) => {\n const { namespace, root, levels } = config;\n const { breadcrumbs, setBreadcrumbs, sliceBreadcrumbs } =\n useBreadcrumb(namespace);\n\n // Extrair apenas os dados dos levels que são as verdadeiras dependências\n const levelDependencies = levels.map((level) =>\n isBreadcrumbWithData(level) ? level.data : null\n );\n const levelUrlIds = levels.map((level) => level.urlId);\n\n useEffect(() => {\n const newBreadcrumbs: BreadcrumbItem[] = [root];\n const previousIds: string[] = [];\n\n // Construir breadcrumbs hierarquicamente\n for (const level of levels) {\n const { urlId } = level;\n\n // Verificar se é breadcrumb com dados ou estático\n if (isBreadcrumbWithData(level)) {\n // Breadcrumb dinâmico (com dados)\n const { data, getId, getName, getUrl } = level;\n\n // Parar se não temos dados\n if (!data) break;\n\n const dataId = getId(data);\n\n // Se urlId está definido, deve corresponder ao dataId\n // Se urlId é undefined, significa que estamos em nível superior, então parar\n if (urlId === undefined || dataId !== urlId) break;\n\n // Adicionar breadcrumb\n newBreadcrumbs.push({\n id: dataId,\n name: getName(data),\n url: getUrl(data, previousIds),\n });\n\n previousIds.push(dataId);\n } else {\n // Breadcrumb estático\n const { breadcrumb } = level;\n\n // Se urlId é undefined, parar (não estamos neste nível)\n if (urlId === undefined) break;\n\n // Adicionar breadcrumb estático\n newBreadcrumbs.push(breadcrumb);\n previousIds.push(breadcrumb.id);\n }\n }\n\n setBreadcrumbs(newBreadcrumbs);\n }, [namespace, ...levelDependencies, ...levelUrlIds, root.id]);\n\n return {\n breadcrumbs,\n sliceBreadcrumbs,\n };\n};\n","import { create } from 'zustand';\n\n/**\n * Interface para um item de breadcrumb\n */\nexport interface BreadcrumbItem {\n id: string;\n name: string;\n url: string;\n}\n\n/**\n * Interface para o estado do store de breadcrumbs\n */\ninterface BreadcrumbStore {\n // Múltiplas instâncias de breadcrumbs identificadas por namespace\n breadcrumbs: Record<string, BreadcrumbItem[]>;\n\n // Define todos os breadcrumbs de uma instância\n setBreadcrumbs: (namespace: string, items: BreadcrumbItem[]) => void;\n\n // Adiciona um breadcrumb ao final da lista\n addBreadcrumb: (namespace: string, item: BreadcrumbItem) => void;\n\n // Atualiza um breadcrumb existente\n updateBreadcrumb: (\n namespace: string,\n itemId: string,\n updates: Partial<BreadcrumbItem>\n ) => void;\n\n // Remove um breadcrumb e todos os seguintes\n removeBreadcrumbFrom: (namespace: string, itemId: string) => void;\n\n // Mantém apenas os breadcrumbs até o índice especificado\n sliceBreadcrumbs: (namespace: string, index: number) => void;\n\n // Limpa todos os breadcrumbs de uma instância\n clearBreadcrumbs: (namespace: string) => void;\n\n // Obtém os breadcrumbs de uma instância\n getBreadcrumbs: (namespace: string) => BreadcrumbItem[];\n}\n\n/**\n * Store Zustand para gerenciar breadcrumbs\n * Suporta múltiplas instâncias através de namespaces\n */\nexport const useBreadcrumbStore = create<BreadcrumbStore>((set, get) => ({\n breadcrumbs: {},\n\n setBreadcrumbs: (namespace: string, items: BreadcrumbItem[]) => {\n set((state) => ({\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: items,\n },\n }));\n },\n\n addBreadcrumb: (namespace: string, item: BreadcrumbItem) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: [...current, item],\n },\n };\n });\n },\n\n updateBreadcrumb: (\n namespace: string,\n itemId: string,\n updates: Partial<BreadcrumbItem>\n ) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.map((item) =>\n item.id === itemId ? { ...item, ...updates } : item\n ),\n },\n };\n });\n },\n\n removeBreadcrumbFrom: (namespace: string, itemId: string) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n const index = current.findIndex((item) => item.id === itemId);\n if (index === -1) return state;\n\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.slice(0, index),\n },\n };\n });\n },\n\n sliceBreadcrumbs: (namespace: string, index: number) => {\n set((state) => {\n const current = state.breadcrumbs[namespace] || [];\n return {\n breadcrumbs: {\n ...state.breadcrumbs,\n [namespace]: current.slice(0, index + 1),\n },\n };\n });\n },\n\n clearBreadcrumbs: (namespace: string) => {\n set((state) => {\n const { [namespace]: _, ...rest } = state.breadcrumbs;\n return {\n breadcrumbs: rest,\n };\n });\n },\n\n getBreadcrumbs: (namespace: string) => {\n return get().breadcrumbs[namespace] || [];\n },\n}));\n\n/**\n * Hook customizado para facilitar o uso de breadcrumbs\n *\n * @param namespace - Identificador único para esta instância de breadcrumbs\n * @returns Objeto com breadcrumbs e métodos para manipulá-los\n *\n * @example\n * ```tsx\n * const { breadcrumbs, setBreadcrumbs, addBreadcrumb } = useBreadcrumb('performance');\n *\n * // Definir breadcrumbs iniciais\n * setBreadcrumbs([\n * { id: 'home', name: 'Home', url: '/' },\n * { id: 'page', name: 'Page', url: '/page' }\n * ]);\n *\n * // Adicionar novo breadcrumb\n * addBreadcrumb({ id: 'detail', name: 'Detail', url: '/page/detail' });\n * ```\n */\nexport const useBreadcrumb = (namespace: string) => {\n const store = useBreadcrumbStore();\n const breadcrumbs = store.breadcrumbs[namespace] || [];\n\n return {\n breadcrumbs,\n\n /**\n * Define todos os breadcrumbs de uma vez\n */\n setBreadcrumbs: (items: BreadcrumbItem[]) => {\n store.setBreadcrumbs(namespace, items);\n },\n\n /**\n * Adiciona um novo breadcrumb ao final\n */\n addBreadcrumb: (item: BreadcrumbItem) => {\n store.addBreadcrumb(namespace, item);\n },\n\n /**\n * Atualiza um breadcrumb existente\n */\n updateBreadcrumb: (itemId: string, updates: Partial<BreadcrumbItem>) => {\n store.updateBreadcrumb(namespace, itemId, updates);\n },\n\n /**\n * Remove um breadcrumb e todos os seguintes\n */\n removeBreadcrumbFrom: (itemId: string) => {\n store.removeBreadcrumbFrom(namespace, itemId);\n },\n\n /**\n * Mantém apenas os breadcrumbs até o índice especificado (inclusivo)\n */\n sliceBreadcrumbs: (index: number) => {\n store.sliceBreadcrumbs(namespace, index);\n },\n\n /**\n * Limpa todos os breadcrumbs\n */\n clearBreadcrumbs: () => {\n store.clearBreadcrumbs(namespace);\n },\n };\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Configuração para extração de parâmetros da URL
3
+ */
4
+ interface UrlParamsConfig {
5
+ /** Mapa de nome do parâmetro para seu índice no path */
6
+ [key: string]: number;
7
+ }
8
+ /**
9
+ * Hook genérico para extrair parâmetros de uma URL baseado em índices
10
+ *
11
+ * @param config - Configuração com os índices dos parâmetros no path
12
+ * @returns Objeto com os parâmetros extraídos
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // URL: /desempenho/lista-temas/123/subtemas/456
17
+ * // Path segments: ['desempenho', 'lista-temas', '123', 'subtemas', '456']
18
+ * const params = useUrlParams({
19
+ * subjectId: 2, // índice 2 = '123'
20
+ * topicId: 4, // índice 4 = '456'
21
+ * });
22
+ *
23
+ * console.log(params); // { subjectId: '123', topicId: '456' }
24
+ * ```
25
+ */
26
+ declare const useUrlParams: <T extends UrlParamsConfig>(config: T) => Record<keyof T, string | undefined>;
27
+
28
+ export { type UrlParamsConfig, useUrlParams };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Configuração para extração de parâmetros da URL
3
+ */
4
+ interface UrlParamsConfig {
5
+ /** Mapa de nome do parâmetro para seu índice no path */
6
+ [key: string]: number;
7
+ }
8
+ /**
9
+ * Hook genérico para extrair parâmetros de uma URL baseado em índices
10
+ *
11
+ * @param config - Configuração com os índices dos parâmetros no path
12
+ * @returns Objeto com os parâmetros extraídos
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // URL: /desempenho/lista-temas/123/subtemas/456
17
+ * // Path segments: ['desempenho', 'lista-temas', '123', 'subtemas', '456']
18
+ * const params = useUrlParams({
19
+ * subjectId: 2, // índice 2 = '123'
20
+ * topicId: 4, // índice 4 = '456'
21
+ * });
22
+ *
23
+ * console.log(params); // { subjectId: '123', topicId: '456' }
24
+ * ```
25
+ */
26
+ declare const useUrlParams: <T extends UrlParamsConfig>(config: T) => Record<keyof T, string | undefined>;
27
+
28
+ export { type UrlParamsConfig, useUrlParams };