@apipass/design-system 5.9.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/charts.index.cjs +1 -1
- package/dist/lib/charts.index.js +11 -8
- package/dist/lib/charts.index.js.map +1 -1
- package/dist/lib/embedded-styles.js +2 -2
- package/dist/lib/lib.index.cjs +1 -1
- package/dist/lib/lib.index.js +657 -657
- package/dist/lib/lib.index.js.map +1 -1
- package/dist/lib/style.css +1 -1
- package/dist/lib/ui/components/DataTable/DataTable.cjs +1 -1
- package/dist/lib/ui/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/lib/ui/components/DataTable/DataTable.js +217 -3
- package/dist/lib/ui/components/DataTable/DataTable.js.map +1 -1
- package/dist/lib/ui/components/charts/BarChart/bar-chart-option.cjs +1 -1
- package/dist/lib/ui/components/charts/BarChart/bar-chart-option.cjs.map +1 -1
- package/dist/lib/ui/components/charts/BarChart/bar-chart-option.js +75 -104
- package/dist/lib/ui/components/charts/BarChart/bar-chart-option.js.map +1 -1
- package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.cjs +1 -1
- package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.cjs.map +1 -1
- package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.js +27 -26
- package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.js.map +1 -1
- package/dist/lib/ui/components/charts/PieChart/PieChart.cjs +2 -0
- package/dist/lib/ui/components/charts/PieChart/PieChart.cjs.map +1 -0
- package/dist/lib/ui/components/charts/PieChart/PieChart.js +177 -0
- package/dist/lib/ui/components/charts/PieChart/PieChart.js.map +1 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.cjs +2 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.cjs.map +1 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.js +124 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.js.map +1 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-slices.cjs +2 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-slices.cjs.map +1 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-slices.js +65 -0
- package/dist/lib/ui/components/charts/PieChart/pie-chart-slices.js.map +1 -0
- package/dist/lib/ui/components/charts/chart-color-tone.cjs +2 -0
- package/dist/lib/ui/components/charts/chart-color-tone.cjs.map +1 -0
- package/dist/lib/ui/components/charts/chart-color-tone.js +14 -0
- package/dist/lib/ui/components/charts/chart-color-tone.js.map +1 -0
- package/dist/lib/ui/components/charts/chart-label-color.cjs +2 -0
- package/dist/lib/ui/components/charts/chart-label-color.cjs.map +1 -0
- package/dist/lib/ui/components/charts/chart-label-color.js +35 -0
- package/dist/lib/ui/components/charts/chart-label-color.js.map +1 -0
- package/dist/lib/ui/components/charts/chart-palette.cjs +1 -1
- package/dist/lib/ui/components/charts/chart-palette.cjs.map +1 -1
- package/dist/lib/ui/components/charts/chart-palette.js +2 -1
- package/dist/lib/ui/components/charts/chart-palette.js.map +1 -1
- package/dist/lib/ui/components/charts/chart-theme.cjs +1 -1
- package/dist/lib/ui/components/charts/chart-theme.cjs.map +1 -1
- package/dist/lib/ui/components/charts/chart-theme.js +4 -3
- package/dist/lib/ui/components/charts/chart-theme.js.map +1 -1
- package/dist/lib/ui/components/charts/echarts-modules.cjs +1 -1
- package/dist/lib/ui/components/charts/echarts-modules.cjs.map +1 -1
- package/dist/lib/ui/components/charts/echarts-modules.js +11 -9
- package/dist/lib/ui/components/charts/echarts-modules.js.map +1 -1
- package/dist/lib/ui/primitives/Table/Table.cjs +1 -1
- package/dist/lib/ui/primitives/Table/Table.cjs.map +1 -1
- package/dist/lib/ui/primitives/Table/Table.js +123 -12
- package/dist/lib/ui/primitives/Table/Table.js.map +1 -1
- package/dist/types/charts.index.d.ts +1 -0
- package/dist/types/ui/components/DataTable/DataTable.d.ts +79 -11
- package/dist/types/ui/components/charts/ChartLegend/ChartLegend.d.ts +1 -0
- package/dist/types/ui/components/charts/PieChart/PieChart.d.ts +32 -0
- package/dist/types/ui/components/charts/PieChart/pie-chart-option.d.ts +13 -0
- package/dist/types/ui/components/charts/PieChart/pie-chart-slices.d.ts +30 -0
- package/dist/types/ui/components/charts/chart-color-tone.d.ts +1 -0
- package/dist/types/ui/components/charts/chart-label-color.d.ts +2 -0
- package/dist/types/ui/components/charts/chart-palette.d.ts +1 -0
- package/dist/types/ui/components/charts/chart-theme.d.ts +1 -0
- package/dist/types/ui/primitives/Table/Table.d.ts +32 -22
- package/package.json +1 -1
- package/dist/lib/ui/primitives/Table/DataDrivenTable.cjs +0 -2
- package/dist/lib/ui/primitives/Table/DataDrivenTable.cjs.map +0 -1
- package/dist/lib/ui/primitives/Table/DataDrivenTable.js +0 -196
- package/dist/lib/ui/primitives/Table/DataDrivenTable.js.map +0 -1
- package/dist/lib/ui/primitives/Table/TableBase.cjs +0 -2
- package/dist/lib/ui/primitives/Table/TableBase.cjs.map +0 -1
- package/dist/lib/ui/primitives/Table/TableBase.js +0 -127
- package/dist/lib/ui/primitives/Table/TableBase.js.map +0 -1
- package/dist/types/ui/primitives/Table/DataDrivenTable.d.ts +0 -68
- package/dist/types/ui/primitives/Table/TableBase.d.ts +0 -35
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});;/* empty css */const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),h=require("react");;/* empty css */const de=require("../../primitives/Search/Search.cjs"),o=require("../../primitives/Table/Table.cjs"),ue=require("../../icons/IconChevronDown.cjs"),he=require("../../icons/IconChevronRight.cjs"),be=require("../../primitives/Pagination/Pagination.cjs"),ge=require("../../primitives/PermissionGate/PermissionGate.cjs"),xe=require("../../layout/Flex/Flex.cjs"),fe=new Intl.Collator(void 0,{numeric:!0,sensitivity:"base"});function pe(n,s){return n==null||s==null?n==null?s==null?0:1:-1:n instanceof Date&&s instanceof Date?n.getTime()-s.getTime():typeof n=="number"&&typeof s=="number"?n-s:fe.compare(String(n),String(s))}function we(n,s,d){const i=s.sortValue??(b=>b[s.key]),m=d==="descending"?-1:1;return[...n].sort((b,g)=>pe(i(b),i(g))*m)}function je({action:n,item:s}){const d=n.isAllowed!==!1,i=a.jsx("button",{type:"button",className:"data-table-row-action-btn","aria-label":n.label,disabled:!d,onClick:d?()=>n.onPress(s):void 0,children:n.icon});return d?i:a.jsx(ge.PermissionGate,{isAllowed:!1,noAccessLabel:n.noAccessLabel??"",children:i})}function G({columns:n,data:s,actions:d,rowActions:i,rowActionsLabel:m="",selectable:b=!1,selectionType:g="checkbox",grid:H=!1,selectedKeys:O,onSelectionChange:V,defaultSortDescriptor:$,sortDescriptor:Q,onSortChange:S,searchPlaceholder:z="Search...",searchKeys:C=[],isLoading:J=!1,loadingMessage:q="Loading...",emptyMessage:U="No records found",previousLabel:W="Previous",nextLabel:X="Next",pageSize:x=10,nestedColumns:k,getNestedData:D,nestedLoadingMessage:Y="Loading...",nestedEmptyMessage:Z="No records found",nestedSearchKeys:_,nestedSearchPlaceholder:A,nestedActions:N,nestedPageSize:K}){const[y,ee]=h.useState(""),[ae,T]=h.useState(1),[te,ne]=h.useState($),u=Q??te,[L,se]=h.useState(new Set),[I,f]=h.useState(new Map),v=!!D&&!!k,M=!!i;function E(e,t){se(r=>{const c=new Set(r);return t?c.add(e):c.delete(e),c})}function le(e){const t=e.id,r=!L.has(t);if(E(t,r),!r||I.has(t))return;const c=D(e);c instanceof Promise?(f(l=>new Map(l).set(t,{status:"loading",data:[]})),c.then(l=>{f(j=>new Map(j).set(t,{status:"loaded",data:l}))},()=>{f(l=>{const j=new Map(l);return j.delete(t),j}),E(t,!1)})):f(l=>new Map(l).set(t,{status:"loaded",data:c}))}const p=C.length>0,re=p||!!d,w=h.useMemo(()=>{if(!y.trim()||!p)return s;const e=y.toLowerCase();return s.filter(t=>C.some(r=>String(t[r]??"").toLowerCase().includes(e)))},[s,y,C,p]),P=n.find(e=>e.sortable&&String(e.key)===String(u==null?void 0:u.column)),F=h.useMemo(()=>P&&u?we(w,P,u.direction):w,[w,P,u]);function oe(e){ne(e),T(1),S==null||S(e)}const B=Math.max(1,Math.ceil(F.length/x)),R=Math.min(ae,B),ie=F.slice((R-1)*x,R*x);function ce(e,t){return t.render?t.render(e):String(e[t.key]??"")}return a.jsxs(xe.Flex,{direction:"column",gap:"300",className:"data-table",children:[re&&a.jsxs("div",{className:"data-table-toolbar",children:[p&&a.jsx(de.Search,{placeholder:z,onSearch:e=>{ee(e),T(1)},className:"data-table-search"}),d&&a.jsx("div",{className:"data-table-actions",children:d})]}),J?a.jsx("div",{role:"status","aria-live":"polite","aria-label":q,className:"data-table-status",children:q}):w.length===0?a.jsx("div",{role:"status",className:"data-table-status data-table-empty",children:U}):a.jsxs(o.Table,{selectionMode:b?g==="radio"?"single":"multiple":"none",selectionType:g,grid:H,selectedKeys:O,onSelectionChange:V,sortDescriptor:u,onSortChange:oe,children:[a.jsxs(o.TableHead,{children:[v&&a.jsx(o.TableColumn,{className:"data-table-expand-col"}),n.map((e,t)=>a.jsx(o.TableColumn,{id:String(e.key),align:e.align,allowsSorting:e.sortable,isRowHeader:t===0,children:e.label},String(e.key))),M&&a.jsx(o.TableColumn,{align:"right",className:"data-table-row-actions-col",children:m})]}),a.jsx(o.TableBody,{children:ie.flatMap(e=>{const t=L.has(e.id),r=I.get(e.id),c=[a.jsxs(o.TableRow,{id:e.id,children:[v&&a.jsx(o.TableCell,{className:"data-table-expand-cell",children:a.jsx("button",{type:"button",className:"data-table-expand-btn","aria-label":t?"Collapse row":"Expand row","aria-expanded":t,onClick:()=>le(e),children:t?a.jsx(ue.IconChevronDown,{size:"16"}):a.jsx(he.IconChevronRight,{size:"16"})})}),n.map(l=>a.jsx(o.TableCell,{align:l.align,children:ce(e,l)},String(l.key))),M&&a.jsx(o.TableCell,{align:"right",className:"data-table-row-actions-cell",children:a.jsx("div",{className:"data-table-row-actions",children:(typeof i=="function"?i(e):i).map(l=>a.jsx(je,{action:l,item:e},l.key))})})]},e.id)];return t&&c.push(a.jsx(o.TableRow,{id:`${e.id}-nested`,className:"data-table-nested-row",children:a.jsx(o.TableCell,{colSpan:n.length+(v?1:0)+(b?1:0)+(M?1:0),className:"data-table-nested-cell",children:a.jsx(G,{columns:k,data:(r==null?void 0:r.data)??[],isLoading:!r||r.status==="loading",loadingMessage:Y,emptyMessage:Z,searchKeys:_,searchPlaceholder:A,actions:N==null?void 0:N(e),pageSize:K??x})})},`${e.id}-nested`)),c})})]}),a.jsx(be.Pagination,{page:R,totalPages:B,onPageChange:T,previousLabel:W,nextLabel:X})]})}exports.DataTable=G;
|
|
2
2
|
//# sourceMappingURL=DataTable.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTable.cjs","sources":["../../../../../src/ui/components/DataTable/DataTable.tsx"],"sourcesContent":["import { Table, type DataDrivenTableProps } from \"primitives\";\n// Estilos do modo data-driven do Table. Ficam importados aqui, e não no primitivo, para\n// manter a posição do bloco no style.css — mover o import muda a ordem da cascata. Ao\n// remover o DataTable, mover este import para o fim de primitives/index.ts.\nimport \"./datatable.css\";\n\n/**\n * @deprecated Use `Table` com `columns` e `data` — as props são idênticas. Mantido só\n * para a migração gradual dos consumidores; será removido quando nenhum repositório\n * importar mais o `DataTable`.\n */\nexport const DataTable = Table as <T extends { id: string }>(\n props: DataDrivenTableProps<T>,\n) => ReturnType<typeof Table>;\n\n/** @deprecated Use `DataDrivenTableProps`. */\nexport type DataTableProps<T extends { id: string }> = DataDrivenTableProps<T>;\n"],"names":["DataTable","Table"],"mappings":"mKAWaA,EAAYC,EAAAA"}
|
|
1
|
+
{"version":3,"file":"DataTable.cjs","sources":["../../../../../src/ui/components/DataTable/DataTable.tsx"],"sourcesContent":["import {\n Pagination,\n PermissionGate,\n Search,\n Table,\n TableBody,\n TableCell,\n TableColumn,\n TableHead,\n TableRow,\n} from \"primitives\";\nimport { Flex } from \"layout\";\nimport { IconChevronDown, IconChevronRight } from \"icons\";\nimport type { ReactNode } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport type { Selection, SortDescriptor } from \"react-aria-components\";\nimport \"./datatable.css\";\n\nexport interface Column<T> {\n key: keyof T | string;\n label: string;\n align?: \"start\" | \"center\" | \"right\";\n render?: (item: T) => ReactNode;\n /** When true, the header becomes clickable and the rows can be sorted by this column. */\n sortable?: boolean;\n /** Value used to sort this column. Defaults to `item[key]`. */\n sortValue?: (item: T) => SortableValue;\n}\n\ntype SortableValue = string | number | Date | null | undefined;\n\nconst sortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: \"base\" });\n\nfunction compareSortableValues(a: SortableValue, b: SortableValue): number {\n if (a == null || b == null) return a == null ? (b == null ? 0 : 1) : -1;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n return sortCollator.compare(String(a), String(b));\n}\n\nfunction sortRows<T>(rows: T[], column: Column<T>, direction: SortDescriptor[\"direction\"]): T[] {\n const valueOf = column.sortValue ?? ((item: T) => (item as Record<string, unknown>)[column.key as string] as SortableValue);\n const directionFactor = direction === \"descending\" ? -1 : 1;\n return [...rows].sort((a, b) => compareSortableValues(valueOf(a), valueOf(b)) * directionFactor);\n}\n\nexport interface RowActionDef<T> {\n /** Unique key for this action. */\n key: string;\n /** aria-label for the button. */\n label: string;\n /** Icon element rendered inside the button. */\n icon: ReactNode;\n /** When false, button is disabled and a tooltip with `noAccessLabel` is shown. Default: true. */\n isAllowed?: boolean;\n /** Tooltip text shown when `isAllowed` is false. */\n noAccessLabel?: string;\n /** Called with the row item when the button is pressed. */\n onPress: (item: T) => void;\n}\n\nfunction RowActionButton<T>({\n action,\n item,\n}: {\n action: RowActionDef<T>;\n item: T;\n}) {\n const allowed = action.isAllowed !== false;\n const btn = (\n <button\n type=\"button\"\n className=\"data-table-row-action-btn\"\n aria-label={action.label}\n disabled={!allowed}\n onClick={allowed ? () => action.onPress(item) : undefined}\n >\n {action.icon}\n </button>\n );\n if (allowed) return btn;\n return (\n <PermissionGate isAllowed={false} noAccessLabel={action.noAccessLabel ?? \"\"}>\n {btn}\n </PermissionGate>\n );\n}\n\n// O tipo da linha aninhada é independente de T (não há relação genérica entre linha pai e linhas\n// filhas), então \"any\" é usado deliberadamente como fronteira de erasure de tipo.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype NestedStatus = { status: \"loading\"; data: never[] } | { status: \"loaded\"; data: any[] };\n\nexport interface DataTableProps<T extends { id: string }> {\n columns: Column<T>[];\n data: T[];\n actions?: ReactNode;\n /** Per-row action buttons rendered in a dedicated last column. */\n rowActions?: RowActionDef<T>[] | ((item: T) => RowActionDef<T>[]);\n /** Label for the row actions column header. Defaults to empty string. */\n rowActionsLabel?: string;\n /**\n * When true, renders a selection column before the first data column — a per-row control on\n * every row (see `selectionType`), plus a \"select all\" checkbox in the header when\n * `selectionType` is \"checkbox\". Off by default.\n */\n selectable?: boolean;\n /**\n * Visual style of the built-in selection control. \"checkbox\" (default) allows selecting\n * multiple rows and shows a \"select all\" in the header. \"radio\" restricts selection to a\n * single row (no \"select all\" — there is nothing to select all *to* with one choice) and\n * renders a round control instead of a checkbox.\n */\n selectionType?: \"checkbox\" | \"radio\";\n /** When true, draws vertical lines between columns. Off by default. */\n grid?: boolean;\n /** Controlled selection state. Omit to let the table manage its own selection internally. */\n selectedKeys?: Selection;\n onSelectionChange?: (keys: Selection) => void;\n /** Initial sort when the table manages its own sorting. Only columns with `sortable` can be sorted. */\n defaultSortDescriptor?: SortDescriptor;\n /** Controlled sort state. Omit to let the table manage its own sorting internally. */\n sortDescriptor?: SortDescriptor;\n onSortChange?: (descriptor: SortDescriptor) => void;\n searchPlaceholder?: string;\n searchKeys?: (keyof T)[];\n isLoading?: boolean;\n loadingMessage?: string;\n emptyMessage?: string;\n previousLabel?: string;\n nextLabel?: string;\n pageSize?: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n nestedColumns?: Column<any>[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n getNestedData?: (item: T) => any[] | Promise<any[]>;\n nestedLoadingMessage?: string;\n nestedEmptyMessage?: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n nestedSearchKeys?: (keyof any)[];\n nestedSearchPlaceholder?: string;\n nestedActions?: (item: T) => ReactNode;\n nestedPageSize?: number;\n}\n\nexport function DataTable<T extends { id: string }>({\n columns,\n data,\n actions,\n rowActions,\n rowActionsLabel = \"\",\n selectable = false,\n selectionType = \"checkbox\",\n grid = false,\n selectedKeys,\n onSelectionChange,\n defaultSortDescriptor,\n sortDescriptor: controlledSortDescriptor,\n onSortChange,\n searchPlaceholder = \"Search...\",\n searchKeys = [],\n isLoading = false,\n loadingMessage = \"Loading...\",\n emptyMessage = \"No records found\",\n previousLabel = \"Previous\",\n nextLabel = \"Next\",\n pageSize = 10,\n nestedColumns,\n getNestedData,\n nestedLoadingMessage = \"Loading...\",\n nestedEmptyMessage = \"No records found\",\n nestedSearchKeys,\n nestedSearchPlaceholder,\n nestedActions,\n nestedPageSize,\n}: DataTableProps<T>) {\n const [query, setQuery] = useState(\"\");\n const [page, setPage] = useState(1);\n const [internalSortDescriptor, setInternalSortDescriptor] = useState(defaultSortDescriptor);\n const sortDescriptor = controlledSortDescriptor ?? internalSortDescriptor;\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [nestedCache, setNestedCache] = useState<Map<string, NestedStatus>>(new Map());\n\n const hasNested = !!getNestedData && !!nestedColumns;\n const hasRowActions = !!rowActions;\n\n function setRowExpanded(id: string, isExpanded: boolean) {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (isExpanded) next.add(id);\n else next.delete(id);\n return next;\n });\n }\n\n // A carga fica fora do updater do setExpanded: o React pode chamar updaters mais de uma\n // vez (StrictMode), o que dispararia getNestedData em dobro.\n function toggleRow(item: T) {\n const id = item.id;\n const willExpand = !expanded.has(id);\n setRowExpanded(id, willExpand);\n if (!willExpand || nestedCache.has(id)) return;\n\n const result = getNestedData!(item);\n if (result instanceof Promise) {\n setNestedCache((c) => new Map(c).set(id, { status: \"loading\", data: [] }));\n result.then(\n (rows) => {\n setNestedCache((c) => new Map(c).set(id, { status: \"loaded\", data: rows }));\n },\n () => {\n // Na falha, descarta a entrada e recolhe a linha: expandir de novo refaz a carga,\n // em vez de a linha ficar presa em \"loading\".\n setNestedCache((c) => {\n const next = new Map(c);\n next.delete(id);\n return next;\n });\n setRowExpanded(id, false);\n },\n );\n } else {\n setNestedCache((c) => new Map(c).set(id, { status: \"loaded\", data: result }));\n }\n }\n\n const hasSearch = searchKeys.length > 0;\n const hasToolbar = hasSearch || !!actions;\n\n const filtered = useMemo(() => {\n if (!query.trim() || !hasSearch) return data;\n const lower = query.toLowerCase();\n return data.filter((item) =>\n searchKeys.some((k) =>\n String(item[k] ?? \"\")\n .toLowerCase()\n .includes(lower),\n ),\n );\n }, [data, query, searchKeys, hasSearch]);\n\n const sortColumn = columns.find((col) => col.sortable && String(col.key) === String(sortDescriptor?.column));\n\n const sorted = useMemo(\n () => (sortColumn && sortDescriptor ? sortRows(filtered, sortColumn, sortDescriptor.direction) : filtered),\n [filtered, sortColumn, sortDescriptor],\n );\n\n function handleSortChange(descriptor: SortDescriptor) {\n setInternalSortDescriptor(descriptor);\n setPage(1);\n onSortChange?.(descriptor);\n }\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n const currentPage = Math.min(page, totalPages);\n const pageData = sorted.slice(\n (currentPage - 1) * pageSize,\n currentPage * pageSize,\n );\n\n function getCell(item: T, col: Column<T>): ReactNode {\n if (col.render) return col.render(item);\n return String((item as Record<string, unknown>)[col.key as string] ?? \"\");\n }\n\n return (\n <Flex direction=\"column\" gap=\"300\" className=\"data-table\">\n {hasToolbar && (\n <div className=\"data-table-toolbar\">\n {hasSearch && (\n <Search\n placeholder={searchPlaceholder}\n onSearch={(v) => {\n setQuery(v);\n setPage(1);\n }}\n className=\"data-table-search\"\n />\n )}\n {actions && <div className=\"data-table-actions\">{actions}</div>}\n </div>\n )}\n\n {isLoading ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label={loadingMessage}\n className=\"data-table-status\"\n >\n {loadingMessage}\n </div>\n ) : filtered.length === 0 ? (\n <div role=\"status\" className=\"data-table-status data-table-empty\">\n {emptyMessage}\n </div>\n ) : (\n <Table\n selectionMode={selectable ? (selectionType === \"radio\" ? \"single\" : \"multiple\") : \"none\"}\n selectionType={selectionType}\n grid={grid}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n sortDescriptor={sortDescriptor}\n onSortChange={handleSortChange}\n >\n <TableHead>\n {hasNested && <TableColumn className=\"data-table-expand-col\" />}\n {columns.map((col, idx) => (\n <TableColumn\n key={String(col.key)}\n id={String(col.key)}\n align={col.align}\n allowsSorting={col.sortable}\n isRowHeader={idx === 0}\n >\n {col.label}\n </TableColumn>\n ))}\n {hasRowActions && (\n <TableColumn align=\"right\" className=\"data-table-row-actions-col\">\n {rowActionsLabel}\n </TableColumn>\n )}\n </TableHead>\n <TableBody>\n {pageData.flatMap((item) => {\n const isExpanded = expanded.has(item.id);\n const cached = nestedCache.get(item.id);\n const rows: ReactNode[] = [\n <TableRow key={item.id} id={item.id}>\n {hasNested && (\n <TableCell className=\"data-table-expand-cell\">\n <button\n type=\"button\"\n className=\"data-table-expand-btn\"\n aria-label={isExpanded ? \"Collapse row\" : \"Expand row\"}\n aria-expanded={isExpanded}\n onClick={() => toggleRow(item)}\n >\n {isExpanded ? (\n <IconChevronDown size=\"16\" />\n ) : (\n <IconChevronRight size=\"16\" />\n )}\n </button>\n </TableCell>\n )}\n {columns.map((col) => (\n <TableCell key={String(col.key)} align={col.align}>\n {getCell(item, col)}\n </TableCell>\n ))}\n {hasRowActions && (\n <TableCell align=\"right\" className=\"data-table-row-actions-cell\">\n <div className=\"data-table-row-actions\">\n {(typeof rowActions === \"function\"\n ? rowActions(item)\n : rowActions!\n ).map((action) => (\n <RowActionButton key={action.key} action={action} item={item} />\n ))}\n </div>\n </TableCell>\n )}\n </TableRow>,\n ];\n if (isExpanded) {\n rows.push(\n <TableRow key={`${item.id}-nested`} id={`${item.id}-nested`} className=\"data-table-nested-row\">\n <TableCell\n colSpan={\n columns.length +\n (hasNested ? 1 : 0) +\n (selectable ? 1 : 0) +\n (hasRowActions ? 1 : 0)\n }\n className=\"data-table-nested-cell\"\n >\n <DataTable\n columns={nestedColumns!}\n data={cached?.data ?? []}\n isLoading={!cached || cached.status === \"loading\"}\n loadingMessage={nestedLoadingMessage}\n emptyMessage={nestedEmptyMessage}\n searchKeys={nestedSearchKeys}\n searchPlaceholder={nestedSearchPlaceholder}\n actions={nestedActions?.(item)}\n pageSize={nestedPageSize ?? pageSize}\n />\n </TableCell>\n </TableRow>,\n );\n }\n return rows;\n })}\n </TableBody>\n </Table>\n )}\n\n <Pagination\n page={currentPage}\n totalPages={totalPages}\n onPageChange={setPage}\n previousLabel={previousLabel}\n nextLabel={nextLabel}\n />\n </Flex>\n );\n}\n"],"names":["sortCollator","compareSortableValues","a","b","sortRows","rows","column","direction","valueOf","item","directionFactor","RowActionButton","action","allowed","btn","jsx","PermissionGate","DataTable","columns","data","actions","rowActions","rowActionsLabel","selectable","selectionType","grid","selectedKeys","onSelectionChange","defaultSortDescriptor","controlledSortDescriptor","onSortChange","searchPlaceholder","searchKeys","isLoading","loadingMessage","emptyMessage","previousLabel","nextLabel","pageSize","nestedColumns","getNestedData","nestedLoadingMessage","nestedEmptyMessage","nestedSearchKeys","nestedSearchPlaceholder","nestedActions","nestedPageSize","query","setQuery","useState","page","setPage","internalSortDescriptor","setInternalSortDescriptor","sortDescriptor","expanded","setExpanded","nestedCache","setNestedCache","hasNested","hasRowActions","setRowExpanded","id","isExpanded","prev","next","toggleRow","willExpand","result","c","hasSearch","hasToolbar","filtered","useMemo","lower","k","sortColumn","col","sorted","handleSortChange","descriptor","totalPages","currentPage","pageData","getCell","Flex","jsxs","Search","v","Table","TableHead","TableColumn","idx","TableBody","cached","TableRow","TableCell","IconChevronDown","IconChevronRight","Pagination"],"mappings":"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"}
|
|
@@ -1,7 +1,221 @@
|
|
|
1
|
+
import { jsxs as h, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { useState as f, useMemo as q } from "react";
|
|
1
3
|
/* empty css */
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
+
import { Search as fe } from "../../primitives/Search/Search.js";
|
|
5
|
+
import { Table as pe, TableHead as ge, TableColumn as D, TableBody as me, TableRow as G, TableCell as N } from "../../primitives/Table/Table.js";
|
|
6
|
+
import { IconChevronDown as be } from "../../icons/IconChevronDown.js";
|
|
7
|
+
import { IconChevronRight as we } from "../../icons/IconChevronRight.js";
|
|
8
|
+
import { Pagination as xe } from "../../primitives/Pagination/Pagination.js";
|
|
9
|
+
import { PermissionGate as Ne } from "../../primitives/PermissionGate/PermissionGate.js";
|
|
10
|
+
import { Flex as Se } from "../../layout/Flex/Flex.js";
|
|
11
|
+
const ye = new Intl.Collator(void 0, { numeric: !0, sensitivity: "base" });
|
|
12
|
+
function ve(n, l) {
|
|
13
|
+
return n == null || l == null ? n == null ? l == null ? 0 : 1 : -1 : n instanceof Date && l instanceof Date ? n.getTime() - l.getTime() : typeof n == "number" && typeof l == "number" ? n - l : ye.compare(String(n), String(l));
|
|
14
|
+
}
|
|
15
|
+
function Ce(n, l, d) {
|
|
16
|
+
const o = l.sortValue ?? ((u) => u[l.key]), S = d === "descending" ? -1 : 1;
|
|
17
|
+
return [...n].sort((u, p) => ve(o(u), o(p)) * S);
|
|
18
|
+
}
|
|
19
|
+
function Me({
|
|
20
|
+
action: n,
|
|
21
|
+
item: l
|
|
22
|
+
}) {
|
|
23
|
+
const d = n.isAllowed !== !1, o = /* @__PURE__ */ t(
|
|
24
|
+
"button",
|
|
25
|
+
{
|
|
26
|
+
type: "button",
|
|
27
|
+
className: "data-table-row-action-btn",
|
|
28
|
+
"aria-label": n.label,
|
|
29
|
+
disabled: !d,
|
|
30
|
+
onClick: d ? () => n.onPress(l) : void 0,
|
|
31
|
+
children: n.icon
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
return d ? o : /* @__PURE__ */ t(Ne, { isAllowed: !1, noAccessLabel: n.noAccessLabel ?? "", children: o });
|
|
35
|
+
}
|
|
36
|
+
function ke({
|
|
37
|
+
columns: n,
|
|
38
|
+
data: l,
|
|
39
|
+
actions: d,
|
|
40
|
+
rowActions: o,
|
|
41
|
+
rowActionsLabel: S = "",
|
|
42
|
+
selectable: u = !1,
|
|
43
|
+
selectionType: p = "checkbox",
|
|
44
|
+
grid: O = !1,
|
|
45
|
+
selectedKeys: Q,
|
|
46
|
+
onSelectionChange: z,
|
|
47
|
+
defaultSortDescriptor: J,
|
|
48
|
+
sortDescriptor: U,
|
|
49
|
+
onSortChange: y,
|
|
50
|
+
searchPlaceholder: W = "Search...",
|
|
51
|
+
searchKeys: v = [],
|
|
52
|
+
isLoading: X = !1,
|
|
53
|
+
loadingMessage: E = "Loading...",
|
|
54
|
+
emptyMessage: Y = "No records found",
|
|
55
|
+
previousLabel: Z = "Previous",
|
|
56
|
+
nextLabel: _ = "Next",
|
|
57
|
+
pageSize: g = 10,
|
|
58
|
+
nestedColumns: I,
|
|
59
|
+
getNestedData: j,
|
|
60
|
+
nestedLoadingMessage: A = "Loading...",
|
|
61
|
+
nestedEmptyMessage: K = "No records found",
|
|
62
|
+
nestedSearchKeys: ee,
|
|
63
|
+
nestedSearchPlaceholder: ae,
|
|
64
|
+
nestedActions: C,
|
|
65
|
+
nestedPageSize: te
|
|
66
|
+
}) {
|
|
67
|
+
const [M, ne] = f(""), [le, k] = f(1), [re, se] = f(J), c = U ?? re, [B, oe] = f(/* @__PURE__ */ new Set()), [F, m] = f(/* @__PURE__ */ new Map()), P = !!j && !!I, T = !!o;
|
|
68
|
+
function H(e, a) {
|
|
69
|
+
oe((s) => {
|
|
70
|
+
const i = new Set(s);
|
|
71
|
+
return a ? i.add(e) : i.delete(e), i;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function ie(e) {
|
|
75
|
+
const a = e.id, s = !B.has(a);
|
|
76
|
+
if (H(a, s), !s || F.has(a)) return;
|
|
77
|
+
const i = j(e);
|
|
78
|
+
i instanceof Promise ? (m((r) => new Map(r).set(a, { status: "loading", data: [] })), i.then(
|
|
79
|
+
(r) => {
|
|
80
|
+
m((x) => new Map(x).set(a, { status: "loaded", data: r }));
|
|
81
|
+
},
|
|
82
|
+
() => {
|
|
83
|
+
m((r) => {
|
|
84
|
+
const x = new Map(r);
|
|
85
|
+
return x.delete(a), x;
|
|
86
|
+
}), H(a, !1);
|
|
87
|
+
}
|
|
88
|
+
)) : m((r) => new Map(r).set(a, { status: "loaded", data: i }));
|
|
89
|
+
}
|
|
90
|
+
const b = v.length > 0, de = b || !!d, w = q(() => {
|
|
91
|
+
if (!M.trim() || !b) return l;
|
|
92
|
+
const e = M.toLowerCase();
|
|
93
|
+
return l.filter(
|
|
94
|
+
(a) => v.some(
|
|
95
|
+
(s) => String(a[s] ?? "").toLowerCase().includes(e)
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
}, [l, M, v, b]), R = n.find((e) => e.sortable && String(e.key) === String(c == null ? void 0 : c.column)), V = q(
|
|
99
|
+
() => R && c ? Ce(w, R, c.direction) : w,
|
|
100
|
+
[w, R, c]
|
|
101
|
+
);
|
|
102
|
+
function ce(e) {
|
|
103
|
+
se(e), k(1), y == null || y(e);
|
|
104
|
+
}
|
|
105
|
+
const $ = Math.max(1, Math.ceil(V.length / g)), L = Math.min(le, $), ue = V.slice(
|
|
106
|
+
(L - 1) * g,
|
|
107
|
+
L * g
|
|
108
|
+
);
|
|
109
|
+
function he(e, a) {
|
|
110
|
+
return a.render ? a.render(e) : String(e[a.key] ?? "");
|
|
111
|
+
}
|
|
112
|
+
return /* @__PURE__ */ h(Se, { direction: "column", gap: "300", className: "data-table", children: [
|
|
113
|
+
de && /* @__PURE__ */ h("div", { className: "data-table-toolbar", children: [
|
|
114
|
+
b && /* @__PURE__ */ t(
|
|
115
|
+
fe,
|
|
116
|
+
{
|
|
117
|
+
placeholder: W,
|
|
118
|
+
onSearch: (e) => {
|
|
119
|
+
ne(e), k(1);
|
|
120
|
+
},
|
|
121
|
+
className: "data-table-search"
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
d && /* @__PURE__ */ t("div", { className: "data-table-actions", children: d })
|
|
125
|
+
] }),
|
|
126
|
+
X ? /* @__PURE__ */ t(
|
|
127
|
+
"div",
|
|
128
|
+
{
|
|
129
|
+
role: "status",
|
|
130
|
+
"aria-live": "polite",
|
|
131
|
+
"aria-label": E,
|
|
132
|
+
className: "data-table-status",
|
|
133
|
+
children: E
|
|
134
|
+
}
|
|
135
|
+
) : w.length === 0 ? /* @__PURE__ */ t("div", { role: "status", className: "data-table-status data-table-empty", children: Y }) : /* @__PURE__ */ h(
|
|
136
|
+
pe,
|
|
137
|
+
{
|
|
138
|
+
selectionMode: u ? p === "radio" ? "single" : "multiple" : "none",
|
|
139
|
+
selectionType: p,
|
|
140
|
+
grid: O,
|
|
141
|
+
selectedKeys: Q,
|
|
142
|
+
onSelectionChange: z,
|
|
143
|
+
sortDescriptor: c,
|
|
144
|
+
onSortChange: ce,
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ h(ge, { children: [
|
|
147
|
+
P && /* @__PURE__ */ t(D, { className: "data-table-expand-col" }),
|
|
148
|
+
n.map((e, a) => /* @__PURE__ */ t(
|
|
149
|
+
D,
|
|
150
|
+
{
|
|
151
|
+
id: String(e.key),
|
|
152
|
+
align: e.align,
|
|
153
|
+
allowsSorting: e.sortable,
|
|
154
|
+
isRowHeader: a === 0,
|
|
155
|
+
children: e.label
|
|
156
|
+
},
|
|
157
|
+
String(e.key)
|
|
158
|
+
)),
|
|
159
|
+
T && /* @__PURE__ */ t(D, { align: "right", className: "data-table-row-actions-col", children: S })
|
|
160
|
+
] }),
|
|
161
|
+
/* @__PURE__ */ t(me, { children: ue.flatMap((e) => {
|
|
162
|
+
const a = B.has(e.id), s = F.get(e.id), i = [
|
|
163
|
+
/* @__PURE__ */ h(G, { id: e.id, children: [
|
|
164
|
+
P && /* @__PURE__ */ t(N, { className: "data-table-expand-cell", children: /* @__PURE__ */ t(
|
|
165
|
+
"button",
|
|
166
|
+
{
|
|
167
|
+
type: "button",
|
|
168
|
+
className: "data-table-expand-btn",
|
|
169
|
+
"aria-label": a ? "Collapse row" : "Expand row",
|
|
170
|
+
"aria-expanded": a,
|
|
171
|
+
onClick: () => ie(e),
|
|
172
|
+
children: a ? /* @__PURE__ */ t(be, { size: "16" }) : /* @__PURE__ */ t(we, { size: "16" })
|
|
173
|
+
}
|
|
174
|
+
) }),
|
|
175
|
+
n.map((r) => /* @__PURE__ */ t(N, { align: r.align, children: he(e, r) }, String(r.key))),
|
|
176
|
+
T && /* @__PURE__ */ t(N, { align: "right", className: "data-table-row-actions-cell", children: /* @__PURE__ */ t("div", { className: "data-table-row-actions", children: (typeof o == "function" ? o(e) : o).map((r) => /* @__PURE__ */ t(Me, { action: r, item: e }, r.key)) }) })
|
|
177
|
+
] }, e.id)
|
|
178
|
+
];
|
|
179
|
+
return a && i.push(
|
|
180
|
+
/* @__PURE__ */ t(G, { id: `${e.id}-nested`, className: "data-table-nested-row", children: /* @__PURE__ */ t(
|
|
181
|
+
N,
|
|
182
|
+
{
|
|
183
|
+
colSpan: n.length + (P ? 1 : 0) + (u ? 1 : 0) + (T ? 1 : 0),
|
|
184
|
+
className: "data-table-nested-cell",
|
|
185
|
+
children: /* @__PURE__ */ t(
|
|
186
|
+
ke,
|
|
187
|
+
{
|
|
188
|
+
columns: I,
|
|
189
|
+
data: (s == null ? void 0 : s.data) ?? [],
|
|
190
|
+
isLoading: !s || s.status === "loading",
|
|
191
|
+
loadingMessage: A,
|
|
192
|
+
emptyMessage: K,
|
|
193
|
+
searchKeys: ee,
|
|
194
|
+
searchPlaceholder: ae,
|
|
195
|
+
actions: C == null ? void 0 : C(e),
|
|
196
|
+
pageSize: te ?? g
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
) }, `${e.id}-nested`)
|
|
201
|
+
), i;
|
|
202
|
+
}) })
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
/* @__PURE__ */ t(
|
|
207
|
+
xe,
|
|
208
|
+
{
|
|
209
|
+
page: L,
|
|
210
|
+
totalPages: $,
|
|
211
|
+
onPageChange: k,
|
|
212
|
+
previousLabel: Z,
|
|
213
|
+
nextLabel: _
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] });
|
|
217
|
+
}
|
|
4
218
|
export {
|
|
5
|
-
|
|
219
|
+
ke as DataTable
|
|
6
220
|
};
|
|
7
221
|
//# sourceMappingURL=DataTable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTable.js","sources":["../../../../../src/ui/components/DataTable/DataTable.tsx"],"sourcesContent":["import { Table, type DataDrivenTableProps } from \"primitives\";\n// Estilos do modo data-driven do Table. Ficam importados aqui, e não no primitivo, para\n// manter a posição do bloco no style.css — mover o import muda a ordem da cascata. Ao\n// remover o DataTable, mover este import para o fim de primitives/index.ts.\nimport \"./datatable.css\";\n\n/**\n * @deprecated Use `Table` com `columns` e `data` — as props são idênticas. Mantido só\n * para a migração gradual dos consumidores; será removido quando nenhum repositório\n * importar mais o `DataTable`.\n */\nexport const DataTable = Table as <T extends { id: string }>(\n props: DataDrivenTableProps<T>,\n) => ReturnType<typeof Table>;\n\n/** @deprecated Use `DataDrivenTableProps`. */\nexport type DataTableProps<T extends { id: string }> = DataDrivenTableProps<T>;\n"],"names":["DataTable","Table"],"mappings":";;AAWO,MAAMA,IAAYC;"}
|
|
1
|
+
{"version":3,"file":"DataTable.js","sources":["../../../../../src/ui/components/DataTable/DataTable.tsx"],"sourcesContent":["import {\n Pagination,\n PermissionGate,\n Search,\n Table,\n TableBody,\n TableCell,\n TableColumn,\n TableHead,\n TableRow,\n} from \"primitives\";\nimport { Flex } from \"layout\";\nimport { IconChevronDown, IconChevronRight } from \"icons\";\nimport type { ReactNode } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport type { Selection, SortDescriptor } from \"react-aria-components\";\nimport \"./datatable.css\";\n\nexport interface Column<T> {\n key: keyof T | string;\n label: string;\n align?: \"start\" | \"center\" | \"right\";\n render?: (item: T) => ReactNode;\n /** When true, the header becomes clickable and the rows can be sorted by this column. */\n sortable?: boolean;\n /** Value used to sort this column. Defaults to `item[key]`. */\n sortValue?: (item: T) => SortableValue;\n}\n\ntype SortableValue = string | number | Date | null | undefined;\n\nconst sortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: \"base\" });\n\nfunction compareSortableValues(a: SortableValue, b: SortableValue): number {\n if (a == null || b == null) return a == null ? (b == null ? 0 : 1) : -1;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n return sortCollator.compare(String(a), String(b));\n}\n\nfunction sortRows<T>(rows: T[], column: Column<T>, direction: SortDescriptor[\"direction\"]): T[] {\n const valueOf = column.sortValue ?? ((item: T) => (item as Record<string, unknown>)[column.key as string] as SortableValue);\n const directionFactor = direction === \"descending\" ? -1 : 1;\n return [...rows].sort((a, b) => compareSortableValues(valueOf(a), valueOf(b)) * directionFactor);\n}\n\nexport interface RowActionDef<T> {\n /** Unique key for this action. */\n key: string;\n /** aria-label for the button. */\n label: string;\n /** Icon element rendered inside the button. */\n icon: ReactNode;\n /** When false, button is disabled and a tooltip with `noAccessLabel` is shown. Default: true. */\n isAllowed?: boolean;\n /** Tooltip text shown when `isAllowed` is false. */\n noAccessLabel?: string;\n /** Called with the row item when the button is pressed. */\n onPress: (item: T) => void;\n}\n\nfunction RowActionButton<T>({\n action,\n item,\n}: {\n action: RowActionDef<T>;\n item: T;\n}) {\n const allowed = action.isAllowed !== false;\n const btn = (\n <button\n type=\"button\"\n className=\"data-table-row-action-btn\"\n aria-label={action.label}\n disabled={!allowed}\n onClick={allowed ? () => action.onPress(item) : undefined}\n >\n {action.icon}\n </button>\n );\n if (allowed) return btn;\n return (\n <PermissionGate isAllowed={false} noAccessLabel={action.noAccessLabel ?? \"\"}>\n {btn}\n </PermissionGate>\n );\n}\n\n// O tipo da linha aninhada é independente de T (não há relação genérica entre linha pai e linhas\n// filhas), então \"any\" é usado deliberadamente como fronteira de erasure de tipo.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype NestedStatus = { status: \"loading\"; data: never[] } | { status: \"loaded\"; data: any[] };\n\nexport interface DataTableProps<T extends { id: string }> {\n columns: Column<T>[];\n data: T[];\n actions?: ReactNode;\n /** Per-row action buttons rendered in a dedicated last column. */\n rowActions?: RowActionDef<T>[] | ((item: T) => RowActionDef<T>[]);\n /** Label for the row actions column header. Defaults to empty string. */\n rowActionsLabel?: string;\n /**\n * When true, renders a selection column before the first data column — a per-row control on\n * every row (see `selectionType`), plus a \"select all\" checkbox in the header when\n * `selectionType` is \"checkbox\". Off by default.\n */\n selectable?: boolean;\n /**\n * Visual style of the built-in selection control. \"checkbox\" (default) allows selecting\n * multiple rows and shows a \"select all\" in the header. \"radio\" restricts selection to a\n * single row (no \"select all\" — there is nothing to select all *to* with one choice) and\n * renders a round control instead of a checkbox.\n */\n selectionType?: \"checkbox\" | \"radio\";\n /** When true, draws vertical lines between columns. Off by default. */\n grid?: boolean;\n /** Controlled selection state. Omit to let the table manage its own selection internally. */\n selectedKeys?: Selection;\n onSelectionChange?: (keys: Selection) => void;\n /** Initial sort when the table manages its own sorting. Only columns with `sortable` can be sorted. */\n defaultSortDescriptor?: SortDescriptor;\n /** Controlled sort state. Omit to let the table manage its own sorting internally. */\n sortDescriptor?: SortDescriptor;\n onSortChange?: (descriptor: SortDescriptor) => void;\n searchPlaceholder?: string;\n searchKeys?: (keyof T)[];\n isLoading?: boolean;\n loadingMessage?: string;\n emptyMessage?: string;\n previousLabel?: string;\n nextLabel?: string;\n pageSize?: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n nestedColumns?: Column<any>[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n getNestedData?: (item: T) => any[] | Promise<any[]>;\n nestedLoadingMessage?: string;\n nestedEmptyMessage?: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- linha aninhada é de tipo independente de T\n nestedSearchKeys?: (keyof any)[];\n nestedSearchPlaceholder?: string;\n nestedActions?: (item: T) => ReactNode;\n nestedPageSize?: number;\n}\n\nexport function DataTable<T extends { id: string }>({\n columns,\n data,\n actions,\n rowActions,\n rowActionsLabel = \"\",\n selectable = false,\n selectionType = \"checkbox\",\n grid = false,\n selectedKeys,\n onSelectionChange,\n defaultSortDescriptor,\n sortDescriptor: controlledSortDescriptor,\n onSortChange,\n searchPlaceholder = \"Search...\",\n searchKeys = [],\n isLoading = false,\n loadingMessage = \"Loading...\",\n emptyMessage = \"No records found\",\n previousLabel = \"Previous\",\n nextLabel = \"Next\",\n pageSize = 10,\n nestedColumns,\n getNestedData,\n nestedLoadingMessage = \"Loading...\",\n nestedEmptyMessage = \"No records found\",\n nestedSearchKeys,\n nestedSearchPlaceholder,\n nestedActions,\n nestedPageSize,\n}: DataTableProps<T>) {\n const [query, setQuery] = useState(\"\");\n const [page, setPage] = useState(1);\n const [internalSortDescriptor, setInternalSortDescriptor] = useState(defaultSortDescriptor);\n const sortDescriptor = controlledSortDescriptor ?? internalSortDescriptor;\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [nestedCache, setNestedCache] = useState<Map<string, NestedStatus>>(new Map());\n\n const hasNested = !!getNestedData && !!nestedColumns;\n const hasRowActions = !!rowActions;\n\n function setRowExpanded(id: string, isExpanded: boolean) {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (isExpanded) next.add(id);\n else next.delete(id);\n return next;\n });\n }\n\n // A carga fica fora do updater do setExpanded: o React pode chamar updaters mais de uma\n // vez (StrictMode), o que dispararia getNestedData em dobro.\n function toggleRow(item: T) {\n const id = item.id;\n const willExpand = !expanded.has(id);\n setRowExpanded(id, willExpand);\n if (!willExpand || nestedCache.has(id)) return;\n\n const result = getNestedData!(item);\n if (result instanceof Promise) {\n setNestedCache((c) => new Map(c).set(id, { status: \"loading\", data: [] }));\n result.then(\n (rows) => {\n setNestedCache((c) => new Map(c).set(id, { status: \"loaded\", data: rows }));\n },\n () => {\n // Na falha, descarta a entrada e recolhe a linha: expandir de novo refaz a carga,\n // em vez de a linha ficar presa em \"loading\".\n setNestedCache((c) => {\n const next = new Map(c);\n next.delete(id);\n return next;\n });\n setRowExpanded(id, false);\n },\n );\n } else {\n setNestedCache((c) => new Map(c).set(id, { status: \"loaded\", data: result }));\n }\n }\n\n const hasSearch = searchKeys.length > 0;\n const hasToolbar = hasSearch || !!actions;\n\n const filtered = useMemo(() => {\n if (!query.trim() || !hasSearch) return data;\n const lower = query.toLowerCase();\n return data.filter((item) =>\n searchKeys.some((k) =>\n String(item[k] ?? \"\")\n .toLowerCase()\n .includes(lower),\n ),\n );\n }, [data, query, searchKeys, hasSearch]);\n\n const sortColumn = columns.find((col) => col.sortable && String(col.key) === String(sortDescriptor?.column));\n\n const sorted = useMemo(\n () => (sortColumn && sortDescriptor ? sortRows(filtered, sortColumn, sortDescriptor.direction) : filtered),\n [filtered, sortColumn, sortDescriptor],\n );\n\n function handleSortChange(descriptor: SortDescriptor) {\n setInternalSortDescriptor(descriptor);\n setPage(1);\n onSortChange?.(descriptor);\n }\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n const currentPage = Math.min(page, totalPages);\n const pageData = sorted.slice(\n (currentPage - 1) * pageSize,\n currentPage * pageSize,\n );\n\n function getCell(item: T, col: Column<T>): ReactNode {\n if (col.render) return col.render(item);\n return String((item as Record<string, unknown>)[col.key as string] ?? \"\");\n }\n\n return (\n <Flex direction=\"column\" gap=\"300\" className=\"data-table\">\n {hasToolbar && (\n <div className=\"data-table-toolbar\">\n {hasSearch && (\n <Search\n placeholder={searchPlaceholder}\n onSearch={(v) => {\n setQuery(v);\n setPage(1);\n }}\n className=\"data-table-search\"\n />\n )}\n {actions && <div className=\"data-table-actions\">{actions}</div>}\n </div>\n )}\n\n {isLoading ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label={loadingMessage}\n className=\"data-table-status\"\n >\n {loadingMessage}\n </div>\n ) : filtered.length === 0 ? (\n <div role=\"status\" className=\"data-table-status data-table-empty\">\n {emptyMessage}\n </div>\n ) : (\n <Table\n selectionMode={selectable ? (selectionType === \"radio\" ? \"single\" : \"multiple\") : \"none\"}\n selectionType={selectionType}\n grid={grid}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n sortDescriptor={sortDescriptor}\n onSortChange={handleSortChange}\n >\n <TableHead>\n {hasNested && <TableColumn className=\"data-table-expand-col\" />}\n {columns.map((col, idx) => (\n <TableColumn\n key={String(col.key)}\n id={String(col.key)}\n align={col.align}\n allowsSorting={col.sortable}\n isRowHeader={idx === 0}\n >\n {col.label}\n </TableColumn>\n ))}\n {hasRowActions && (\n <TableColumn align=\"right\" className=\"data-table-row-actions-col\">\n {rowActionsLabel}\n </TableColumn>\n )}\n </TableHead>\n <TableBody>\n {pageData.flatMap((item) => {\n const isExpanded = expanded.has(item.id);\n const cached = nestedCache.get(item.id);\n const rows: ReactNode[] = [\n <TableRow key={item.id} id={item.id}>\n {hasNested && (\n <TableCell className=\"data-table-expand-cell\">\n <button\n type=\"button\"\n className=\"data-table-expand-btn\"\n aria-label={isExpanded ? \"Collapse row\" : \"Expand row\"}\n aria-expanded={isExpanded}\n onClick={() => toggleRow(item)}\n >\n {isExpanded ? (\n <IconChevronDown size=\"16\" />\n ) : (\n <IconChevronRight size=\"16\" />\n )}\n </button>\n </TableCell>\n )}\n {columns.map((col) => (\n <TableCell key={String(col.key)} align={col.align}>\n {getCell(item, col)}\n </TableCell>\n ))}\n {hasRowActions && (\n <TableCell align=\"right\" className=\"data-table-row-actions-cell\">\n <div className=\"data-table-row-actions\">\n {(typeof rowActions === \"function\"\n ? rowActions(item)\n : rowActions!\n ).map((action) => (\n <RowActionButton key={action.key} action={action} item={item} />\n ))}\n </div>\n </TableCell>\n )}\n </TableRow>,\n ];\n if (isExpanded) {\n rows.push(\n <TableRow key={`${item.id}-nested`} id={`${item.id}-nested`} className=\"data-table-nested-row\">\n <TableCell\n colSpan={\n columns.length +\n (hasNested ? 1 : 0) +\n (selectable ? 1 : 0) +\n (hasRowActions ? 1 : 0)\n }\n className=\"data-table-nested-cell\"\n >\n <DataTable\n columns={nestedColumns!}\n data={cached?.data ?? []}\n isLoading={!cached || cached.status === \"loading\"}\n loadingMessage={nestedLoadingMessage}\n emptyMessage={nestedEmptyMessage}\n searchKeys={nestedSearchKeys}\n searchPlaceholder={nestedSearchPlaceholder}\n actions={nestedActions?.(item)}\n pageSize={nestedPageSize ?? pageSize}\n />\n </TableCell>\n </TableRow>,\n );\n }\n return rows;\n })}\n </TableBody>\n </Table>\n )}\n\n <Pagination\n page={currentPage}\n totalPages={totalPages}\n onPageChange={setPage}\n previousLabel={previousLabel}\n nextLabel={nextLabel}\n />\n </Flex>\n );\n}\n"],"names":["sortCollator","compareSortableValues","a","b","sortRows","rows","column","direction","valueOf","item","directionFactor","RowActionButton","action","allowed","btn","jsx","PermissionGate","DataTable","columns","data","actions","rowActions","rowActionsLabel","selectable","selectionType","grid","selectedKeys","onSelectionChange","defaultSortDescriptor","controlledSortDescriptor","onSortChange","searchPlaceholder","searchKeys","isLoading","loadingMessage","emptyMessage","previousLabel","nextLabel","pageSize","nestedColumns","getNestedData","nestedLoadingMessage","nestedEmptyMessage","nestedSearchKeys","nestedSearchPlaceholder","nestedActions","nestedPageSize","query","setQuery","useState","page","setPage","internalSortDescriptor","setInternalSortDescriptor","sortDescriptor","expanded","setExpanded","nestedCache","setNestedCache","hasNested","hasRowActions","setRowExpanded","id","isExpanded","prev","next","toggleRow","willExpand","result","c","hasSearch","hasToolbar","filtered","useMemo","lower","k","sortColumn","col","sorted","handleSortChange","descriptor","totalPages","currentPage","pageData","getCell","Flex","jsxs","Search","v","Table","TableHead","TableColumn","idx","TableBody","cached","TableRow","TableCell","IconChevronDown","IconChevronRight","Pagination"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("../chart-label-color.cjs"),x={top:16,right:16,bottom:16,left:16},L={vertical:140,horizontal:200},p=48,A="total",s=100,T=new Intl.NumberFormat(void 0,{style:"percent",maximumFractionDigits:1});function _(e){return T.format(e/s)}function w(e){return e.stacking==="percent"?_:e.valueFormatter}function c(e){const o=w(e);if(o)return t=>t===null?"":o(t)}function O(e,o){const t=new Map(e.points.map(r=>[r.category,r.value]));return o.map(r=>t.get(r)??null)}function S(e,o){const t=Array.from({length:o},(r,n)=>e.reduce((l,a)=>l+(a[n]??0),0));return e.map(r=>r.map((n,l)=>{const a=t[l];return n===null||a===0?null:n/a*s}))}function h(e){return e.stacking!=="off"?"inside":e.orientation==="horizontal"?"right":"top"}function P(e){return e.labelRect.width<=e.rect.width&&e.labelRect.height<=e.rect.height}function F(e){const o=e.valueLabel==="auto";return!o||h(e)!=="inside"?{hideOverlap:o}:t=>({hideOverlap:o,fontSize:P(t)?void 0:0})}function V(e,o){const t=h(e),r=c(e);return{show:e.valueLabel!=="never",position:t,color:t==="inside"?v.labelColorOnFill(o):e.theme.labelColor,formatter:r?n=>r(n.value):void 0}}function k(e){const{categories:o,theme:t,orientation:r}=e;return{type:"category",data:o,inverse:r==="horizontal",axisLine:{lineStyle:{color:t.axisLineColor}},axisTick:{show:!1},axisLabel:{color:t.labelColor,hideOverlap:!0,width:L[r],overflow:"truncate"},splitLine:{show:!1}}}function B(e){const{valueAxis:o,stacking:t,theme:r}=e,n=t==="percent",l=c(e);return{type:o.scale==="log"?"log":"value",scale:!n&&o.includeZero===!1,min:n?0:o.min,max:n?s:o.max,axisLine:{show:!1},axisLabel:{color:r.labelColor,formatter:l},splitLine:{lineStyle:{color:r.splitLineColor}}}}function E(e){const{categories:o,series:t,orientation:r,stacking:n,theme:l}=e,a=r==="horizontal",b=c(e),u=t.map(i=>O(i,o)),C=n==="percent"?S(u,o.length):u,y=F(e),f=k(e),m=B(e);return{animation:!1,color:l.seriesColors,textStyle:{fontFamily:l.fontFamily,color:l.labelColor},grid:{...x,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"shadow"},backgroundColor:l.tooltipBackgroundColor,borderColor:l.tooltipBorderColor,textStyle:{color:l.labelColor},valueFormatter:b},xAxis:a?m:f,yAxis:a?f:m,series:t.map((i,g)=>{const d=e.seriesColorOverrides[i.id]??l.seriesColors[g%l.seriesColors.length];return{id:i.id,name:i.name,type:"bar",stack:n==="off"?void 0:A,barMaxWidth:p,data:C[g],itemStyle:{color:d},label:V(e,d),labelLayout:y}})}}exports.buildBarChartOption=E;
|
|
2
2
|
//# sourceMappingURL=bar-chart-option.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar-chart-option.cjs","sources":["../../../../../../src/ui/components/charts/BarChart/bar-chart-option.ts"],"sourcesContent":["import type { ChartTheme } from \"../chart-theme\";\n\nexport interface BarChartPoint {\n category: string;\n value: number | null;\n}\n\nexport interface BarChartSeriesData {\n id: string;\n name: string;\n points: BarChartPoint[];\n // Nome de token, nunca hex: é o que mantém a cor válida nos dois temas. Sem ele a série\n // recebe a próxima cor da paleta.\n colorToken?: string;\n}\n\nexport type BarChartOrientation = \"vertical\" | \"horizontal\";\n\nexport type BarChartStacking = \"off\" | \"stacked\" | \"percent\";\n\nexport type BarChartValueLabel = \"auto\" | \"always\" | \"never\";\n\nexport type BarChartLegendMode = \"inline\" | \"none\";\n\nexport type BarChartAxisScale = \"linear\" | \"log\";\n\nexport interface BarChartValueAxisOptions {\n scale?: BarChartAxisScale;\n min?: number;\n max?: number;\n includeZero?: boolean;\n}\n\nexport interface BarChartOptionInput {\n categories: string[];\n series: BarChartSeriesData[];\n orientation: BarChartOrientation;\n stacking: BarChartStacking;\n valueLabel: BarChartValueLabel;\n valueAxis: BarChartValueAxisOptions;\n theme: ChartTheme;\n seriesColorOverrides: Record<string, string>;\n valueFormatter?: (value: number) => string;\n}\n\n// A legenda saiu do canvas e virou HTML (`ChartLegend`), entao a grade nao reserva mais faixa\n// para ela: quem divide a altura agora e o flex do componente.\nconst GRID_PADDING = { top: 16, right: 16, bottom: 16, left: 16 } as const;\n\n// Na horizontal o rótulo da categoria disputa largura com a própria barra; na vertical ele fica\n// sob a barra e uma faixa mais estreita já dá conta.\nconst CATEGORY_LABEL_MAX_WIDTH_PX: Record<BarChartOrientation, number> = {\n vertical: 140,\n horizontal: 200,\n};\n\nconst BAR_MAX_WIDTH_PX: number = 48;\n\nconst STACK_ID: string = \"total\";\n\nconst PERCENT_SCALE: number = 100;\n\n// O rótulo dentro da barra é lido contra a cor da série, não contra o fundo da página: a paleta\n// de séries é a mesma nos dois temas, então quem decide entre texto claro e escuro é o\n// preenchimento. O branco que o ECharts usa por padrão reprova no contraste em toda a paleta —\n// 2,24:1 sobre a `yellow-500`.\nconst LABEL_ON_DARK_FILL: string = \"#ffffff\";\n\nconst LABEL_ON_LIGHT_FILL: string = \"#1e1e1e\";\n\nconst LABEL_ON_LIGHT_FILL_LUMINANCE: number = 0.0144;\n\nconst WHITE_LUMINANCE: number = 1;\n\nfunction channelLuminance(channel: number): number {\n const normalized: number = channel / 255;\n return normalized <= 0.03928\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\nfunction parseColorChannels(color: string): [number, number, number] | undefined {\n const hexMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hexMatch) {\n const digits: string = hexMatch[1];\n const expanded: string =\n digits.length === 3\n ? digits\n .split(\"\")\n .map((digit: string) => digit + digit)\n .join(\"\")\n : digits;\n return [0, 2, 4].map((start: number) => parseInt(expanded.slice(start, start + 2), 16)) as [\n number,\n number,\n number,\n ];\n }\n\n const rgbMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)/i);\n if (rgbMatch) {\n return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];\n }\n\n return undefined;\n}\n\nfunction relativeLuminance(color: string): number | undefined {\n const channels: [number, number, number] | undefined = parseColorChannels(color);\n if (!channels) return undefined;\n const [red, green, blue] = channels.map(channelLuminance);\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n}\n\nfunction contrastRatio(lighter: number, darker: number): number {\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction labelColorOnFill(fillColor: string): string {\n const luminance: number | undefined = relativeLuminance(fillColor);\n if (luminance === undefined) return LABEL_ON_DARK_FILL;\n const againstLightText: number = contrastRatio(WHITE_LUMINANCE, luminance);\n const againstDarkText: number = contrastRatio(luminance, LABEL_ON_LIGHT_FILL_LUMINANCE);\n return againstDarkText >= againstLightText ? LABEL_ON_LIGHT_FILL : LABEL_ON_DARK_FILL;\n}\n\nconst PERCENT_LABEL: Intl.NumberFormat = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\nfunction formatPercent(value: number): string {\n return PERCENT_LABEL.format(value / PERCENT_SCALE);\n}\n\n// Em `percent` o valor desenhado é a participação na categoria, e não mais o dado do consumidor:\n// aplicar ali o formatador dele escreveria \"31 ms\" numa barra que vale 31%.\nfunction resolveValueFormatter(input: BarChartOptionInput): ((value: number) => string) | undefined {\n return input.stacking === \"percent\" ? formatPercent : input.valueFormatter;\n}\n\n// Categoria sem valor chega ao formatter como `null` — o ECharts formata o vazio junto com o\n// resto. O tipo público promete `number` ao consumidor, e é esta guarda que mantém a promessa.\nfunction nullSafeValueFormatter(\n input: BarChartOptionInput,\n): ((value: number | null) => string) | undefined {\n const formatValue: ((value: number) => string) | undefined = resolveValueFormatter(input);\n if (!formatValue) return undefined;\n return (value: number | null) => (value === null ? \"\" : formatValue(value));\n}\n\nfunction alignValuesToCategories(\n data: BarChartSeriesData,\n categories: string[],\n): Array<number | null> {\n const valueByCategory: Map<string, number | null> = new Map(\n data.points.map((point: BarChartPoint) => [point.category, point.value]),\n );\n return categories.map((category: string) => valueByCategory.get(category) ?? null);\n}\n\nfunction toShareOfCategoryTotal(\n valuesBySeries: Array<Array<number | null>>,\n categoryCount: number,\n): Array<Array<number | null>> {\n const categoryTotals: number[] = Array.from(\n { length: categoryCount },\n (_unused, categoryIndex: number) =>\n valuesBySeries.reduce(\n (total: number, values: Array<number | null>) => total + (values[categoryIndex] ?? 0),\n 0,\n ),\n );\n return valuesBySeries.map((values: Array<number | null>) =>\n values.map((value: number | null, categoryIndex: number) => {\n const categoryTotal: number = categoryTotals[categoryIndex];\n if (value === null || categoryTotal === 0) return null;\n return (value / categoryTotal) * PERCENT_SCALE;\n }),\n );\n}\n\nfunction labelPosition(input: BarChartOptionInput): string {\n if (input.stacking !== \"off\") return \"inside\";\n return input.orientation === \"horizontal\" ? \"right\" : \"top\";\n}\n\ninterface LabelLayoutParams {\n rect: { width: number; height: number };\n labelRect: { width: number; height: number };\n}\n\ninterface LabelLayout {\n hideOverlap: boolean;\n fontSize?: number;\n}\n\ntype SeriesLabelLayout = LabelLayout | ((params: LabelLayoutParams) => LabelLayout);\n\nfunction fitsInsideBar(params: LabelLayoutParams): boolean {\n return (\n params.labelRect.width <= params.rect.width && params.labelRect.height <= params.rect.height\n );\n}\n\n// `hideOverlap` resolve rótulo que encosta em rótulo, mas não rótulo maior que a própria fatia:\n// numa barra empilhada o ECharts desenha o número por cima das fatias vizinhas. `fontSize: 0` é\n// o que o `labelLayout` oferece para sumir com um rótulo caso a caso.\nfunction seriesLabelLayout(input: BarChartOptionInput): SeriesLabelLayout {\n const hideOverlap: boolean = input.valueLabel === \"auto\";\n if (!hideOverlap || labelPosition(input) !== \"inside\") return { hideOverlap };\n return (params: LabelLayoutParams) => ({\n hideOverlap,\n fontSize: fitsInsideBar(params) ? undefined : 0,\n });\n}\n\nfunction seriesLabel(input: BarChartOptionInput, fillColor: string): Record<string, unknown> {\n const position: string = labelPosition(input);\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n show: input.valueLabel !== \"never\",\n position,\n color: position === \"inside\" ? labelColorOnFill(fillColor) : input.theme.labelColor,\n formatter: formatValue\n ? (params: { value: number | null }) => formatValue(params.value)\n : undefined,\n };\n}\n\nfunction categoryAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, theme, orientation } = input;\n return {\n type: \"category\",\n data: categories,\n // Na horizontal o ECharts empilha a categoria de baixo para cima, invertendo a ordem que o\n // app escolheu ao ordenar as barras.\n inverse: orientation === \"horizontal\",\n axisLine: { lineStyle: { color: theme.axisLineColor } },\n axisTick: { show: false },\n axisLabel: {\n color: theme.labelColor,\n hideOverlap: true,\n width: CATEGORY_LABEL_MAX_WIDTH_PX[orientation],\n overflow: \"truncate\",\n },\n splitLine: { show: false },\n };\n}\n\nfunction valueAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { valueAxis: options, stacking, theme } = input;\n const isPercent: boolean = stacking === \"percent\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n type: options.scale === \"log\" ? \"log\" : \"value\",\n // Barra mede por comprimento: eixo cortado mente sobre a proporção entre as barras, então\n // aqui o zero entra por padrão — ao contrário da série temporal, que só mostra variação.\n scale: !isPercent && options.includeZero === false,\n min: isPercent ? 0 : options.min,\n max: isPercent ? PERCENT_SCALE : options.max,\n axisLine: { show: false },\n axisLabel: { color: theme.labelColor, formatter: formatValue },\n splitLine: { lineStyle: { color: theme.splitLineColor } },\n };\n}\n\n// O retorno é `Record<string, unknown>` de propósito, e não `EChartsOption`: é o que impede\n// um tipo da biblioteca de vazar para o resto do design system.\nexport function buildBarChartOption(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, series, orientation, stacking, theme } = input;\n const isHorizontal: boolean = orientation === \"horizontal\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n\n const alignedValues: Array<Array<number | null>> = series.map((data: BarChartSeriesData) =>\n alignValuesToCategories(data, categories),\n );\n // O ECharts não tem empilhamento 100%: a participação precisa chegar calculada no dado.\n const plottedValues: Array<Array<number | null>> =\n stacking === \"percent\"\n ? toShareOfCategoryTotal(alignedValues, categories.length)\n : alignedValues;\n\n const labelLayout: SeriesLabelLayout = seriesLabelLayout(input);\n const categoryAxisOption: Record<string, unknown> = categoryAxis(input);\n const valueAxisOption: Record<string, unknown> = valueAxis(input);\n\n return {\n animation: false,\n color: theme.seriesColors,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n grid: {\n ...GRID_PADDING,\n containLabel: true,\n },\n tooltip: {\n trigger: \"axis\",\n axisPointer: { type: \"shadow\" },\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n valueFormatter: formatValue,\n },\n xAxis: isHorizontal ? valueAxisOption : categoryAxisOption,\n yAxis: isHorizontal ? categoryAxisOption : valueAxisOption,\n series: series.map((data: BarChartSeriesData, index: number) => {\n const fillColor: string =\n input.seriesColorOverrides[data.id] ??\n theme.seriesColors[index % theme.seriesColors.length];\n return {\n id: data.id,\n name: data.name,\n type: \"bar\",\n stack: stacking === \"off\" ? undefined : STACK_ID,\n barMaxWidth: BAR_MAX_WIDTH_PX,\n data: plottedValues[index],\n itemStyle: { color: fillColor },\n label: seriesLabel(input, fillColor),\n labelLayout,\n };\n }),\n };\n}\n"],"names":["GRID_PADDING","CATEGORY_LABEL_MAX_WIDTH_PX","BAR_MAX_WIDTH_PX","STACK_ID","PERCENT_SCALE","LABEL_ON_DARK_FILL","LABEL_ON_LIGHT_FILL","LABEL_ON_LIGHT_FILL_LUMINANCE","WHITE_LUMINANCE","channelLuminance","channel","normalized","parseColorChannels","color","hexMatch","digits","expanded","digit","start","rgbMatch","relativeLuminance","channels","red","green","blue","contrastRatio","lighter","darker","labelColorOnFill","fillColor","luminance","againstLightText","PERCENT_LABEL","formatPercent","value","resolveValueFormatter","input","nullSafeValueFormatter","formatValue","alignValuesToCategories","data","categories","valueByCategory","point","category","toShareOfCategoryTotal","valuesBySeries","categoryCount","categoryTotals","_unused","categoryIndex","total","values","categoryTotal","labelPosition","fitsInsideBar","params","seriesLabelLayout","hideOverlap","seriesLabel","position","categoryAxis","theme","orientation","valueAxis","options","stacking","isPercent","buildBarChartOption","series","isHorizontal","alignedValues","plottedValues","labelLayout","categoryAxisOption","valueAxisOption","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bar-chart-option.cjs","sources":["../../../../../../src/ui/components/charts/BarChart/bar-chart-option.ts"],"sourcesContent":["import { labelColorOnFill } from \"../chart-label-color\";\nimport type { ChartTheme } from \"../chart-theme\";\n\nexport interface BarChartPoint {\n category: string;\n value: number | null;\n}\n\nexport interface BarChartSeriesData {\n id: string;\n name: string;\n points: BarChartPoint[];\n // Nome de token, nunca hex: é o que mantém a cor válida nos dois temas. Sem ele a série\n // recebe a próxima cor da paleta.\n colorToken?: string;\n}\n\nexport type BarChartOrientation = \"vertical\" | \"horizontal\";\n\nexport type BarChartStacking = \"off\" | \"stacked\" | \"percent\";\n\nexport type BarChartValueLabel = \"auto\" | \"always\" | \"never\";\n\nexport type BarChartLegendMode = \"inline\" | \"none\";\n\nexport type BarChartAxisScale = \"linear\" | \"log\";\n\nexport interface BarChartValueAxisOptions {\n scale?: BarChartAxisScale;\n min?: number;\n max?: number;\n includeZero?: boolean;\n}\n\nexport interface BarChartOptionInput {\n categories: string[];\n series: BarChartSeriesData[];\n orientation: BarChartOrientation;\n stacking: BarChartStacking;\n valueLabel: BarChartValueLabel;\n valueAxis: BarChartValueAxisOptions;\n theme: ChartTheme;\n seriesColorOverrides: Record<string, string>;\n valueFormatter?: (value: number) => string;\n}\n\n// A legenda saiu do canvas e virou HTML (`ChartLegend`), entao a grade nao reserva mais faixa\n// para ela: quem divide a altura agora e o flex do componente.\nconst GRID_PADDING = { top: 16, right: 16, bottom: 16, left: 16 } as const;\n\n// Na horizontal o rótulo da categoria disputa largura com a própria barra; na vertical ele fica\n// sob a barra e uma faixa mais estreita já dá conta.\nconst CATEGORY_LABEL_MAX_WIDTH_PX: Record<BarChartOrientation, number> = {\n vertical: 140,\n horizontal: 200,\n};\n\nconst BAR_MAX_WIDTH_PX: number = 48;\n\nconst STACK_ID: string = \"total\";\n\nconst PERCENT_SCALE: number = 100;\n\nconst PERCENT_LABEL: Intl.NumberFormat = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\nfunction formatPercent(value: number): string {\n return PERCENT_LABEL.format(value / PERCENT_SCALE);\n}\n\n// Em `percent` o valor desenhado é a participação na categoria, e não mais o dado do consumidor:\n// aplicar ali o formatador dele escreveria \"31 ms\" numa barra que vale 31%.\nfunction resolveValueFormatter(input: BarChartOptionInput): ((value: number) => string) | undefined {\n return input.stacking === \"percent\" ? formatPercent : input.valueFormatter;\n}\n\n// Categoria sem valor chega ao formatter como `null` — o ECharts formata o vazio junto com o\n// resto. O tipo público promete `number` ao consumidor, e é esta guarda que mantém a promessa.\nfunction nullSafeValueFormatter(\n input: BarChartOptionInput,\n): ((value: number | null) => string) | undefined {\n const formatValue: ((value: number) => string) | undefined = resolveValueFormatter(input);\n if (!formatValue) return undefined;\n return (value: number | null) => (value === null ? \"\" : formatValue(value));\n}\n\nfunction alignValuesToCategories(\n data: BarChartSeriesData,\n categories: string[],\n): Array<number | null> {\n const valueByCategory: Map<string, number | null> = new Map(\n data.points.map((point: BarChartPoint) => [point.category, point.value]),\n );\n return categories.map((category: string) => valueByCategory.get(category) ?? null);\n}\n\nfunction toShareOfCategoryTotal(\n valuesBySeries: Array<Array<number | null>>,\n categoryCount: number,\n): Array<Array<number | null>> {\n const categoryTotals: number[] = Array.from(\n { length: categoryCount },\n (_unused, categoryIndex: number) =>\n valuesBySeries.reduce(\n (total: number, values: Array<number | null>) => total + (values[categoryIndex] ?? 0),\n 0,\n ),\n );\n return valuesBySeries.map((values: Array<number | null>) =>\n values.map((value: number | null, categoryIndex: number) => {\n const categoryTotal: number = categoryTotals[categoryIndex];\n if (value === null || categoryTotal === 0) return null;\n return (value / categoryTotal) * PERCENT_SCALE;\n }),\n );\n}\n\nfunction labelPosition(input: BarChartOptionInput): string {\n if (input.stacking !== \"off\") return \"inside\";\n return input.orientation === \"horizontal\" ? \"right\" : \"top\";\n}\n\ninterface LabelLayoutParams {\n rect: { width: number; height: number };\n labelRect: { width: number; height: number };\n}\n\ninterface LabelLayout {\n hideOverlap: boolean;\n fontSize?: number;\n}\n\ntype SeriesLabelLayout = LabelLayout | ((params: LabelLayoutParams) => LabelLayout);\n\nfunction fitsInsideBar(params: LabelLayoutParams): boolean {\n return (\n params.labelRect.width <= params.rect.width && params.labelRect.height <= params.rect.height\n );\n}\n\n// `hideOverlap` resolve rótulo que encosta em rótulo, mas não rótulo maior que a própria fatia:\n// numa barra empilhada o ECharts desenha o número por cima das fatias vizinhas. `fontSize: 0` é\n// o que o `labelLayout` oferece para sumir com um rótulo caso a caso.\nfunction seriesLabelLayout(input: BarChartOptionInput): SeriesLabelLayout {\n const hideOverlap: boolean = input.valueLabel === \"auto\";\n if (!hideOverlap || labelPosition(input) !== \"inside\") return { hideOverlap };\n return (params: LabelLayoutParams) => ({\n hideOverlap,\n fontSize: fitsInsideBar(params) ? undefined : 0,\n });\n}\n\nfunction seriesLabel(input: BarChartOptionInput, fillColor: string): Record<string, unknown> {\n const position: string = labelPosition(input);\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n show: input.valueLabel !== \"never\",\n position,\n color: position === \"inside\" ? labelColorOnFill(fillColor) : input.theme.labelColor,\n formatter: formatValue\n ? (params: { value: number | null }) => formatValue(params.value)\n : undefined,\n };\n}\n\nfunction categoryAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, theme, orientation } = input;\n return {\n type: \"category\",\n data: categories,\n // Na horizontal o ECharts empilha a categoria de baixo para cima, invertendo a ordem que o\n // app escolheu ao ordenar as barras.\n inverse: orientation === \"horizontal\",\n axisLine: { lineStyle: { color: theme.axisLineColor } },\n axisTick: { show: false },\n axisLabel: {\n color: theme.labelColor,\n hideOverlap: true,\n width: CATEGORY_LABEL_MAX_WIDTH_PX[orientation],\n overflow: \"truncate\",\n },\n splitLine: { show: false },\n };\n}\n\nfunction valueAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { valueAxis: options, stacking, theme } = input;\n const isPercent: boolean = stacking === \"percent\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n type: options.scale === \"log\" ? \"log\" : \"value\",\n // Barra mede por comprimento: eixo cortado mente sobre a proporção entre as barras, então\n // aqui o zero entra por padrão — ao contrário da série temporal, que só mostra variação.\n scale: !isPercent && options.includeZero === false,\n min: isPercent ? 0 : options.min,\n max: isPercent ? PERCENT_SCALE : options.max,\n axisLine: { show: false },\n axisLabel: { color: theme.labelColor, formatter: formatValue },\n splitLine: { lineStyle: { color: theme.splitLineColor } },\n };\n}\n\n// O retorno é `Record<string, unknown>` de propósito, e não `EChartsOption`: é o que impede\n// um tipo da biblioteca de vazar para o resto do design system.\nexport function buildBarChartOption(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, series, orientation, stacking, theme } = input;\n const isHorizontal: boolean = orientation === \"horizontal\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n\n const alignedValues: Array<Array<number | null>> = series.map((data: BarChartSeriesData) =>\n alignValuesToCategories(data, categories),\n );\n // O ECharts não tem empilhamento 100%: a participação precisa chegar calculada no dado.\n const plottedValues: Array<Array<number | null>> =\n stacking === \"percent\"\n ? toShareOfCategoryTotal(alignedValues, categories.length)\n : alignedValues;\n\n const labelLayout: SeriesLabelLayout = seriesLabelLayout(input);\n const categoryAxisOption: Record<string, unknown> = categoryAxis(input);\n const valueAxisOption: Record<string, unknown> = valueAxis(input);\n\n return {\n animation: false,\n color: theme.seriesColors,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n grid: {\n ...GRID_PADDING,\n containLabel: true,\n },\n tooltip: {\n trigger: \"axis\",\n axisPointer: { type: \"shadow\" },\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n valueFormatter: formatValue,\n },\n xAxis: isHorizontal ? valueAxisOption : categoryAxisOption,\n yAxis: isHorizontal ? categoryAxisOption : valueAxisOption,\n series: series.map((data: BarChartSeriesData, index: number) => {\n const fillColor: string =\n input.seriesColorOverrides[data.id] ??\n theme.seriesColors[index % theme.seriesColors.length];\n return {\n id: data.id,\n name: data.name,\n type: \"bar\",\n stack: stacking === \"off\" ? undefined : STACK_ID,\n barMaxWidth: BAR_MAX_WIDTH_PX,\n data: plottedValues[index],\n itemStyle: { color: fillColor },\n label: seriesLabel(input, fillColor),\n labelLayout,\n };\n }),\n };\n}\n"],"names":["GRID_PADDING","CATEGORY_LABEL_MAX_WIDTH_PX","BAR_MAX_WIDTH_PX","STACK_ID","PERCENT_SCALE","PERCENT_LABEL","formatPercent","value","resolveValueFormatter","input","nullSafeValueFormatter","formatValue","alignValuesToCategories","data","categories","valueByCategory","point","category","toShareOfCategoryTotal","valuesBySeries","categoryCount","categoryTotals","_unused","categoryIndex","total","values","categoryTotal","labelPosition","fitsInsideBar","params","seriesLabelLayout","hideOverlap","seriesLabel","fillColor","position","labelColorOnFill","categoryAxis","theme","orientation","valueAxis","options","stacking","isPercent","buildBarChartOption","series","isHorizontal","alignedValues","plottedValues","labelLayout","categoryAxisOption","valueAxisOption","index"],"mappings":"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"}
|