analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 14.5 kB
Source Map (JSON)
{"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":[]}