@customafk/lunas-ui 0.2.78 → 0.2.80

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 (119) hide show
  1. package/dist/{analysis-panel-CQZ0hmfN.cjs → analysis-panel-Bg0lCfWv.cjs} +2 -2
  2. package/dist/{analysis-panel-CQZ0hmfN.cjs.map → analysis-panel-Bg0lCfWv.cjs.map} +1 -1
  3. package/dist/{analysis-panel-BqZmOU58.mjs → analysis-panel-Cop-l4lx.mjs} +2 -2
  4. package/dist/{analysis-panel-BqZmOU58.mjs.map → analysis-panel-Cop-l4lx.mjs.map} +1 -1
  5. package/dist/{badge-display-RP5VTE10.mjs → badge-display-B0BKsU9T.mjs} +2 -2
  6. package/dist/{badge-display-RP5VTE10.mjs.map → badge-display-B0BKsU9T.mjs.map} +1 -1
  7. package/dist/{badge-display-DmCKpGk9.cjs → badge-display-Dv2UTvzp.cjs} +2 -2
  8. package/dist/{badge-display-DmCKpGk9.cjs.map → badge-display-Dv2UTvzp.cjs.map} +1 -1
  9. package/dist/{boolean-display-B9qxrF5f.mjs → boolean-display-CMX5AupA.mjs} +2 -2
  10. package/dist/{boolean-display-B9qxrF5f.mjs.map → boolean-display-CMX5AupA.mjs.map} +1 -1
  11. package/dist/{boolean-display-BwB-l9k0.cjs → boolean-display-CPX7H39m.cjs} +2 -2
  12. package/dist/{boolean-display-BwB-l9k0.cjs.map → boolean-display-CPX7H39m.cjs.map} +1 -1
  13. package/dist/{currency-display-CEg_HRYv.mjs → currency-display-CanjOswc.mjs} +2 -2
  14. package/dist/{currency-display-CEg_HRYv.mjs.map → currency-display-CanjOswc.mjs.map} +1 -1
  15. package/dist/{currency-display-Buxc6Ph5.cjs → currency-display-xxK62yo4.cjs} +2 -2
  16. package/dist/{currency-display-Buxc6Ph5.cjs.map → currency-display-xxK62yo4.cjs.map} +1 -1
  17. package/dist/data-display/statistic.cjs +1 -1
  18. package/dist/data-display/statistic.cjs.map +1 -1
  19. package/dist/data-display/statistic.mjs +1 -1
  20. package/dist/data-display/statistic.mjs.map +1 -1
  21. package/dist/date-display-DMPhFq8v.cjs +2 -0
  22. package/dist/date-display-DMPhFq8v.cjs.map +1 -0
  23. package/dist/date-display-YE8NIIrl.mjs +2 -0
  24. package/dist/date-display-YE8NIIrl.mjs.map +1 -0
  25. package/dist/{description-display-CW0g3aJa.mjs → description-display-B4KoH6ql.mjs} +2 -2
  26. package/dist/{description-display-CW0g3aJa.mjs.map → description-display-B4KoH6ql.mjs.map} +1 -1
  27. package/dist/{description-display-BR8nXqc_.cjs → description-display-jmAaeMBD.cjs} +2 -2
  28. package/dist/{description-display-BR8nXqc_.cjs.map → description-display-jmAaeMBD.cjs.map} +1 -1
  29. package/dist/detail-dialog-BCM0iEXQ.cjs +2 -0
  30. package/dist/detail-dialog-BCM0iEXQ.cjs.map +1 -0
  31. package/dist/detail-dialog-DwfTi9Fl.mjs +2 -0
  32. package/dist/detail-dialog-DwfTi9Fl.mjs.map +1 -0
  33. package/dist/dialogs/detail-dialog/index.cjs +1 -1
  34. package/dist/dialogs/detail-dialog/index.d.cts +1 -1
  35. package/dist/dialogs/detail-dialog/index.d.mts +1 -1
  36. package/dist/dialogs/detail-dialog/index.mjs +1 -1
  37. package/dist/{email-display-DqKYq0iM.cjs → email-display-CzvqQMhG.cjs} +2 -2
  38. package/dist/{email-display-DqKYq0iM.cjs.map → email-display-CzvqQMhG.cjs.map} +1 -1
  39. package/dist/{email-display-BKcoWmPK.mjs → email-display-D_k7AUmp.mjs} +2 -2
  40. package/dist/{email-display-BKcoWmPK.mjs.map → email-display-D_k7AUmp.mjs.map} +1 -1
  41. package/dist/features/descriptions/index.cjs +1 -1
  42. package/dist/features/descriptions/index.cjs.map +1 -1
  43. package/dist/features/descriptions/index.mjs +1 -1
  44. package/dist/features/descriptions/index.mjs.map +1 -1
  45. package/dist/features/file-icons/index.cjs +2 -0
  46. package/dist/features/file-icons/index.cjs.map +1 -0
  47. package/dist/features/file-icons/index.d.cts +34 -0
  48. package/dist/features/file-icons/index.d.mts +34 -0
  49. package/dist/features/file-icons/index.mjs +2 -0
  50. package/dist/features/file-icons/index.mjs.map +1 -0
  51. package/dist/features/tables/index.cjs +1 -1
  52. package/dist/features/tables/index.mjs +1 -1
  53. package/dist/{filter-DqedvThM.cjs → filter-B5EnnL9I.cjs} +2 -2
  54. package/dist/{filter-DqedvThM.cjs.map → filter-B5EnnL9I.cjs.map} +1 -1
  55. package/dist/{filter-CWuRGTl4.mjs → filter-BCNjqiBx.mjs} +2 -2
  56. package/dist/{filter-CWuRGTl4.mjs.map → filter-BCNjqiBx.mjs.map} +1 -1
  57. package/dist/{index-BOifmu0V.d.cts → index-BXqx1kOJ.d.cts} +4 -2
  58. package/dist/{index-BOifmu0V.d.mts → index-BXqx1kOJ.d.mts} +4 -2
  59. package/dist/index.cjs +1 -1
  60. package/dist/index.d.cts +1 -1
  61. package/dist/index.d.mts +1 -1
  62. package/dist/index.mjs +1 -1
  63. package/dist/list-display-DPxZ_Jbf.cjs +2 -0
  64. package/dist/list-display-DPxZ_Jbf.cjs.map +1 -0
  65. package/dist/list-display-M43N3kle.mjs +2 -0
  66. package/dist/list-display-M43N3kle.mjs.map +1 -0
  67. package/dist/{name-display-B-FtblLL.cjs → name-display-BJ1wPUnS.cjs} +2 -2
  68. package/dist/{name-display-B-FtblLL.cjs.map → name-display-BJ1wPUnS.cjs.map} +1 -1
  69. package/dist/{name-display-CB9XAhXP.mjs → name-display-pWhLLS05.mjs} +2 -2
  70. package/dist/{name-display-CB9XAhXP.mjs.map → name-display-pWhLLS05.mjs.map} +1 -1
  71. package/dist/{permalink-I-INEarM.mjs → permalink-BaMvnKIz.mjs} +2 -2
  72. package/dist/{permalink-I-INEarM.mjs.map → permalink-BaMvnKIz.mjs.map} +1 -1
  73. package/dist/{permalink-CUIKG9VA.cjs → permalink-CMcI__V4.cjs} +2 -2
  74. package/dist/{permalink-CUIKG9VA.cjs.map → permalink-CMcI__V4.cjs.map} +1 -1
  75. package/dist/{phone-number-DJvfJg1b.cjs → phone-number-F9I9sNLK.cjs} +2 -2
  76. package/dist/{phone-number-DJvfJg1b.cjs.map → phone-number-F9I9sNLK.cjs.map} +1 -1
  77. package/dist/{phone-number-Cu7Mnl6J.mjs → phone-number-ao2oCmrO.mjs} +2 -2
  78. package/dist/{phone-number-Cu7Mnl6J.mjs.map → phone-number-ao2oCmrO.mjs.map} +1 -1
  79. package/dist/{progress-display-DbfN7U8m.cjs → progress-display-F8xXJ3T1.cjs} +2 -2
  80. package/dist/{progress-display-DbfN7U8m.cjs.map → progress-display-F8xXJ3T1.cjs.map} +1 -1
  81. package/dist/{progress-display-qgvclwy9.mjs → progress-display-atwRFD6e.mjs} +2 -2
  82. package/dist/{progress-display-qgvclwy9.mjs.map → progress-display-atwRFD6e.mjs.map} +1 -1
  83. package/dist/{statistic-LL4uHlRb.cjs → statistic-B9OqfhOl.cjs} +2 -2
  84. package/dist/{statistic-LL4uHlRb.cjs.map → statistic-B9OqfhOl.cjs.map} +1 -1
  85. package/dist/{statistic-ClkqqDfk.mjs → statistic-CJVc9sNs.mjs} +2 -2
  86. package/dist/{statistic-ClkqqDfk.mjs.map → statistic-CJVc9sNs.mjs.map} +1 -1
  87. package/dist/{status-display-BUphOF18.mjs → status-display-DInGGgiP.mjs} +2 -2
  88. package/dist/{status-display-BUphOF18.mjs.map → status-display-DInGGgiP.mjs.map} +1 -1
  89. package/dist/{status-display-o9inMVvb.cjs → status-display-DpKsYvZJ.cjs} +2 -2
  90. package/dist/{status-display-o9inMVvb.cjs.map → status-display-DpKsYvZJ.cjs.map} +1 -1
  91. package/dist/{summary-bar-Mb1B9Dnf.cjs → summary-bar-DKZh-VSB.cjs} +2 -2
  92. package/dist/{summary-bar-Mb1B9Dnf.cjs.map → summary-bar-DKZh-VSB.cjs.map} +1 -1
  93. package/dist/{summary-bar-CYfgdxrQ.mjs → summary-bar-DX_sOiuL.mjs} +2 -2
  94. package/dist/{summary-bar-CYfgdxrQ.mjs.map → summary-bar-DX_sOiuL.mjs.map} +1 -1
  95. package/dist/{tables-BGzwkdFO.mjs → tables-7_KgoyS-.mjs} +2 -2
  96. package/dist/{tables-BGzwkdFO.mjs.map → tables-7_KgoyS-.mjs.map} +1 -1
  97. package/dist/{tables-078i-X0d.cjs → tables-CS3NhgTc.cjs} +2 -2
  98. package/dist/{tables-078i-X0d.cjs.map → tables-CS3NhgTc.cjs.map} +1 -1
  99. package/dist/{tooltip-BcfELg8e.cjs → tooltip-BcQG6Zw9.cjs} +2 -2
  100. package/dist/{tooltip-BcfELg8e.cjs.map → tooltip-BcQG6Zw9.cjs.map} +1 -1
  101. package/dist/{tooltip-TGmzPdoR.mjs → tooltip-C6flMQgc.mjs} +2 -2
  102. package/dist/{tooltip-TGmzPdoR.mjs.map → tooltip-C6flMQgc.mjs.map} +1 -1
  103. package/dist/ui/file-uploader.cjs +2 -2
  104. package/dist/ui/file-uploader.cjs.map +1 -1
  105. package/dist/ui/file-uploader.mjs +2 -2
  106. package/dist/ui/file-uploader.mjs.map +1 -1
  107. package/package.json +5 -1
  108. package/dist/date-display-BgI7Wjqf.cjs +0 -2
  109. package/dist/date-display-BgI7Wjqf.cjs.map +0 -1
  110. package/dist/date-display-DGfHQhpu.mjs +0 -2
  111. package/dist/date-display-DGfHQhpu.mjs.map +0 -1
  112. package/dist/detail-dialog-Ct0vAjFe.mjs +0 -2
  113. package/dist/detail-dialog-Ct0vAjFe.mjs.map +0 -1
  114. package/dist/detail-dialog-uN5mrCa7.cjs +0 -2
  115. package/dist/detail-dialog-uN5mrCa7.cjs.map +0 -1
  116. package/dist/list-display-BRJVmji0.cjs +0 -2
  117. package/dist/list-display-BRJVmji0.cjs.map +0 -1
  118. package/dist/list-display-Co94sV4H.mjs +0 -2
  119. package/dist/list-display-Co94sV4H.mjs.map +0 -1
@@ -1,2 +1,2 @@
1
- const e=require("./data-display/statistic.cjs"),t=require("./tables-078i-X0d.cjs");let n=require("lucide-react"),r=require("react"),i=require("@customafk/react-toolkit/utils"),a=require("react/jsx-runtime");const o={sum:`Tổng`,avg:`Trung bình`,count:`Đếm`,min:`Nhỏ nhất`,max:`Lớn nhất`},s=(0,r.memo)(()=>{let{table:s,totalRows:l}=t.Y(),{rowSelectionState:u}=t.J(),{isOpen:d,toggle:f}=t.q(),p=(0,r.useMemo)(()=>s.getRowModel().rows,[s]),m=(0,r.useMemo)(()=>s.getSelectedRowModel().flatRows,[s,u]),h=(0,r.useMemo)(()=>s.getHeaderGroups()[0]?.headers??[],[s]),g=(0,r.useMemo)(()=>h.filter(e=>![`select`,`actions`].includes(e.id)).flatMap(e=>{let n=e.column.columnDef.meta?.aggregation;if(!n)return[];let r=n.label??(typeof e.column.columnDef.header==`string`?e.column.columnDef.header:e.id),i=t.B(p,e.id),a=m.length>0?t.B(m,e.id):null;return[{colId:e.id,header:r,aggregation:n,allValue:t.z(p.length,i,n.type),selectedValue:a===null?null:t.z(m.length,a,n.type)}]}),[h,p,m]);return(0,a.jsxs)(`div`,{"data-slot":`table-analysis-panel`,className:`w-full border-t border-border`,children:[(0,a.jsxs)(`button`,{type:`button`,className:(0,i.cn)(`flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive`,`hover:bg-muted-bg-subtle transition-colors outline-none`,`focus-visible:ring-2 focus-visible:ring-primary-weak`),onClick:f,"aria-expanded":d,children:[(0,a.jsx)(`span`,{children:`Tổng quan dữ liệu`}),d?(0,a.jsx)(n.ChevronUpIcon,{size:14}):(0,a.jsx)(n.ChevronDownIcon,{size:14})]}),d&&(0,a.jsxs)(`div`,{className:`px-4 pb-4 pt-2 space-y-4`,children:[(0,a.jsxs)(`div`,{className:`flex flex-wrap gap-4`,children:[(0,a.jsx)(c,{label:`Tổng bản ghi`,value:l??p.length}),(0,a.jsx)(c,{label:`Hàng hiển thị`,value:p.length}),(0,a.jsx)(c,{label:`Hàng đã chọn`,value:m.length,highlight:m.length>0})]}),g.length>0&&(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak`,children:`Tóm tắt cột`}),(0,a.jsx)(`div`,{className:`overflow-x-auto rounded-md border border-border`,children:(0,a.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,a.jsx)(`thead`,{children:(0,a.jsxs)(`tr`,{className:`border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak`,children:[(0,a.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Cột`}),(0,a.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Kiểu`}),(0,a.jsx)(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Tất cả hàng`}),m.length>0&&(0,a.jsx)(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Hàng đã chọn`})]})}),(0,a.jsx)(`tbody`,{children:g.map((t,n)=>(0,a.jsxs)(`tr`,{className:(0,i.cn)(`border-b border-border last:border-b-0`,n%2==1&&`bg-muted-bg-subtle/50`),children:[(0,a.jsx)(`td`,{className:`px-3 py-2 text-text-positive font-medium`,children:t.header}),(0,a.jsx)(`td`,{className:`px-3 py-2 text-text-positive-weak`,children:o[t.aggregation.type]}),(0,a.jsx)(`td`,{className:`px-3 py-2 text-right`,children:(0,a.jsx)(e.Statistic,{value:t.allValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})}),m.length>0&&(0,a.jsx)(`td`,{className:`px-3 py-2 text-right`,children:t.selectedValue===null?(0,a.jsx)(`span`,{className:`text-text-positive-weak`,children:`—`}):(0,a.jsx)(e.Statistic,{value:t.selectedValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})})]},t.colId))})]})})]})]})]})});s.displayName=`UITableAnalysisPanel`;const c=(0,r.memo)(({label:e,value:t,highlight:n})=>(0,a.jsxs)(`div`,{className:(0,i.cn)(`flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white`,n&&t>0?`border-primary bg-primary-bg-subtle`:`border-border bg-white`),children:[(0,a.jsx)(`span`,{className:`text-[11px] text-text-positive-weak`,children:e}),(0,a.jsx)(`span`,{className:`text-base font-semibold tabular-nums text-text-positive-strong`,children:t.toLocaleString()})]}));c.displayName=`StatChip`,exports.UITableAnalysisPanel=s;
2
- //# sourceMappingURL=analysis-panel-CQZ0hmfN.cjs.map
1
+ const e=require("./data-display/statistic.cjs"),t=require("./tables-CS3NhgTc.cjs");let n=require("lucide-react"),r=require("react"),i=require("@customafk/react-toolkit/utils"),a=require("react/jsx-runtime");const o={sum:`Tổng`,avg:`Trung bình`,count:`Đếm`,min:`Nhỏ nhất`,max:`Lớn nhất`},s=(0,r.memo)(()=>{let{table:s,totalRows:l}=t.Y(),{rowSelectionState:u}=t.J(),{isOpen:d,toggle:f}=t.q(),p=(0,r.useMemo)(()=>s.getRowModel().rows,[s]),m=(0,r.useMemo)(()=>s.getSelectedRowModel().flatRows,[s,u]),h=(0,r.useMemo)(()=>s.getHeaderGroups()[0]?.headers??[],[s]),g=(0,r.useMemo)(()=>h.filter(e=>![`select`,`actions`].includes(e.id)).flatMap(e=>{let n=e.column.columnDef.meta?.aggregation;if(!n)return[];let r=n.label??(typeof e.column.columnDef.header==`string`?e.column.columnDef.header:e.id),i=t.B(p,e.id),a=m.length>0?t.B(m,e.id):null;return[{colId:e.id,header:r,aggregation:n,allValue:t.z(p.length,i,n.type),selectedValue:a===null?null:t.z(m.length,a,n.type)}]}),[h,p,m]);return(0,a.jsxs)(`div`,{"data-slot":`table-analysis-panel`,className:`w-full border-t border-border`,children:[(0,a.jsxs)(`button`,{type:`button`,className:(0,i.cn)(`flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive`,`hover:bg-muted-bg-subtle transition-colors outline-none`,`focus-visible:ring-2 focus-visible:ring-primary-weak`),onClick:f,"aria-expanded":d,children:[(0,a.jsx)(`span`,{children:`Tổng quan dữ liệu`}),d?(0,a.jsx)(n.ChevronUpIcon,{size:14}):(0,a.jsx)(n.ChevronDownIcon,{size:14})]}),d&&(0,a.jsxs)(`div`,{className:`px-4 pb-4 pt-2 space-y-4`,children:[(0,a.jsxs)(`div`,{className:`flex flex-wrap gap-4`,children:[(0,a.jsx)(c,{label:`Tổng bản ghi`,value:l??p.length}),(0,a.jsx)(c,{label:`Hàng hiển thị`,value:p.length}),(0,a.jsx)(c,{label:`Hàng đã chọn`,value:m.length,highlight:m.length>0})]}),g.length>0&&(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak`,children:`Tóm tắt cột`}),(0,a.jsx)(`div`,{className:`overflow-x-auto rounded-md border border-border`,children:(0,a.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,a.jsx)(`thead`,{children:(0,a.jsxs)(`tr`,{className:`border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak`,children:[(0,a.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Cột`}),(0,a.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Kiểu`}),(0,a.jsx)(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Tất cả hàng`}),m.length>0&&(0,a.jsx)(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Hàng đã chọn`})]})}),(0,a.jsx)(`tbody`,{children:g.map((t,n)=>(0,a.jsxs)(`tr`,{className:(0,i.cn)(`border-b border-border last:border-b-0`,n%2==1&&`bg-muted-bg-subtle/50`),children:[(0,a.jsx)(`td`,{className:`px-3 py-2 text-text-positive font-medium`,children:t.header}),(0,a.jsx)(`td`,{className:`px-3 py-2 text-text-positive-weak`,children:o[t.aggregation.type]}),(0,a.jsx)(`td`,{className:`px-3 py-2 text-right`,children:(0,a.jsx)(e.Statistic,{value:t.allValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})}),m.length>0&&(0,a.jsx)(`td`,{className:`px-3 py-2 text-right`,children:t.selectedValue===null?(0,a.jsx)(`span`,{className:`text-text-positive-weak`,children:`—`}):(0,a.jsx)(e.Statistic,{value:t.selectedValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})})]},t.colId))})]})})]})]})]})});s.displayName=`UITableAnalysisPanel`;const c=(0,r.memo)(({label:e,value:t,highlight:n})=>(0,a.jsxs)(`div`,{className:(0,i.cn)(`flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white`,n&&t>0?`border-primary bg-primary-bg-subtle`:`border-border bg-white`),children:[(0,a.jsx)(`span`,{className:`text-[11px] text-text-positive-weak`,children:e}),(0,a.jsx)(`span`,{className:`text-base font-semibold tabular-nums text-text-positive-strong`,children:t.toLocaleString()})]}));c.displayName=`StatChip`,exports.UITableAnalysisPanel=s;
2
+ //# sourceMappingURL=analysis-panel-Bg0lCfWv.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-panel-CQZ0hmfN.cjs","names":["useUITableContext","useUITableBodyContext","useUITableAnalysisContext","extractNumericValues","computeAggregation","ChevronUpIcon","ChevronDownIcon","Statistic"],"sources":["../packages/components/features/tables/components/table/analysis-panel.tsx"],"sourcesContent":["'use client';\nimport { memo, useMemo } from 'react';\n\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Statistic } from '@/components/data-display/statistic';\nimport type { AnyEntity } from '@/types';\nimport { useUITableAnalysisContext, useUITableBodyContext, useUITableContext } from '../../hooks/use-context';\nimport type { ColumnAggregation, ColumnAggregationType } from '../../types';\nimport { computeAggregation, extractNumericValues } from '../../utils/aggregation';\n\ntype AggregationLabel = {\n colId: string;\n header: string;\n aggregation: ColumnAggregation;\n allValue: number;\n selectedValue: number | null;\n};\n\nconst typeLabels: Record<ColumnAggregationType, string> = {\n sum: 'Tổng',\n avg: 'Trung bình',\n count: 'Đếm',\n min: 'Nhỏ nhất',\n max: 'Lớn nhất',\n};\n\nexport const UITableAnalysisPanel = memo(() => {\n const { table, totalRows } = useUITableContext();\n const { rowSelectionState } = useUITableBodyContext();\n const { isOpen, toggle } = useUITableAnalysisContext();\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: row model\n const allRows = useMemo(() => table.getRowModel().rows, [table]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: selected rows\n const selectedRows = useMemo(() => table.getSelectedRowModel().flatRows, [table, rowSelectionState]);\n\n const headers = useMemo(() => table.getHeaderGroups()[0]?.headers ?? [], [table]);\n\n const aggregationRows = useMemo<AggregationLabel[]>(() => {\n return headers\n .filter(h => !['select', 'actions'].includes(h.id))\n .flatMap(header => {\n const agg = (header.column.columnDef.meta as AnyEntity)?.aggregation as ColumnAggregation | undefined;\n if (!agg) return [];\n\n const headerText = agg.label ?? (typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.id);\n\n const allValues = extractNumericValues(allRows, header.id);\n const selectedValues = selectedRows.length > 0 ? extractNumericValues(selectedRows, header.id) : null;\n\n return [\n {\n colId: header.id,\n header: headerText,\n aggregation: agg,\n allValue: computeAggregation(allRows.length, allValues, agg.type),\n selectedValue: selectedValues !== null ? computeAggregation(selectedRows.length, selectedValues, agg.type) : null,\n },\n ];\n });\n }, [headers, allRows, selectedRows]);\n\n return (\n <div data-slot=\"table-analysis-panel\" className=\"w-full border-t border-border\">\n <button\n type=\"button\"\n className={cn(\n 'flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive',\n 'hover:bg-muted-bg-subtle transition-colors outline-none',\n 'focus-visible:ring-2 focus-visible:ring-primary-weak'\n )}\n onClick={toggle}\n aria-expanded={isOpen}\n >\n <span>Tổng quan dữ liệu</span>\n {isOpen ? <ChevronUpIcon size={14} /> : <ChevronDownIcon size={14} />}\n </button>\n\n {isOpen && (\n <div className=\"px-4 pb-4 pt-2 space-y-4\">\n {/* Row summary */}\n <div className=\"flex flex-wrap gap-4\">\n <StatChip label=\"Tổng bản ghi\" value={totalRows ?? allRows.length} />\n <StatChip label=\"Hàng hiển thị\" value={allRows.length} />\n <StatChip label=\"Hàng đã chọn\" value={selectedRows.length} highlight={selectedRows.length > 0} />\n </div>\n\n {/* Column aggregations */}\n {aggregationRows.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak\">Tóm tắt cột</p>\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak\">\n <th className=\"px-3 py-2 text-left font-medium\">Cột</th>\n <th className=\"px-3 py-2 text-left font-medium\">Kiểu</th>\n <th className=\"px-3 py-2 text-right font-medium\">Tất cả hàng</th>\n {selectedRows.length > 0 && <th className=\"px-3 py-2 text-right font-medium\">Hàng đã chọn</th>}\n </tr>\n </thead>\n <tbody>\n {aggregationRows.map((row, idx) => (\n <tr key={row.colId} className={cn('border-b border-border last:border-b-0', idx % 2 === 1 && 'bg-muted-bg-subtle/50')}>\n <td className=\"px-3 py-2 text-text-positive font-medium\">{row.header}</td>\n <td className=\"px-3 py-2 text-text-positive-weak\">{typeLabels[row.aggregation.type]}</td>\n <td className=\"px-3 py-2 text-right\">\n <Statistic\n value={row.allValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n </td>\n {selectedRows.length > 0 && (\n <td className=\"px-3 py-2 text-right\">\n {row.selectedValue !== null ? (\n <Statistic\n value={row.selectedValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n ) : (\n <span className=\"text-text-positive-weak\">—</span>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n});\nUITableAnalysisPanel.displayName = 'UITableAnalysisPanel';\n\nconst StatChip = memo<{ label: string; value: number; highlight?: boolean }>(({ label, value, highlight }) => (\n <div\n className={cn(\n 'flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white',\n highlight && value > 0 ? 'border-primary bg-primary-bg-subtle' : 'border-border bg-white'\n )}\n >\n <span className=\"text-[11px] text-text-positive-weak\">{label}</span>\n <span className=\"text-base font-semibold tabular-nums text-text-positive-strong\">{value.toLocaleString()}</span>\n </div>\n));\nStatChip.displayName = 'StatChip';\n"],"mappings":"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"}
1
+ {"version":3,"file":"analysis-panel-Bg0lCfWv.cjs","names":["useUITableContext","useUITableBodyContext","useUITableAnalysisContext","extractNumericValues","computeAggregation","ChevronUpIcon","ChevronDownIcon","Statistic"],"sources":["../packages/components/features/tables/components/table/analysis-panel.tsx"],"sourcesContent":["'use client';\nimport { memo, useMemo } from 'react';\n\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Statistic } from '@/components/data-display/statistic';\nimport type { AnyEntity } from '@/types';\nimport { useUITableAnalysisContext, useUITableBodyContext, useUITableContext } from '../../hooks/use-context';\nimport type { ColumnAggregation, ColumnAggregationType } from '../../types';\nimport { computeAggregation, extractNumericValues } from '../../utils/aggregation';\n\ntype AggregationLabel = {\n colId: string;\n header: string;\n aggregation: ColumnAggregation;\n allValue: number;\n selectedValue: number | null;\n};\n\nconst typeLabels: Record<ColumnAggregationType, string> = {\n sum: 'Tổng',\n avg: 'Trung bình',\n count: 'Đếm',\n min: 'Nhỏ nhất',\n max: 'Lớn nhất',\n};\n\nexport const UITableAnalysisPanel = memo(() => {\n const { table, totalRows } = useUITableContext();\n const { rowSelectionState } = useUITableBodyContext();\n const { isOpen, toggle } = useUITableAnalysisContext();\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: row model\n const allRows = useMemo(() => table.getRowModel().rows, [table]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: selected rows\n const selectedRows = useMemo(() => table.getSelectedRowModel().flatRows, [table, rowSelectionState]);\n\n const headers = useMemo(() => table.getHeaderGroups()[0]?.headers ?? [], [table]);\n\n const aggregationRows = useMemo<AggregationLabel[]>(() => {\n return headers\n .filter(h => !['select', 'actions'].includes(h.id))\n .flatMap(header => {\n const agg = (header.column.columnDef.meta as AnyEntity)?.aggregation as ColumnAggregation | undefined;\n if (!agg) return [];\n\n const headerText = agg.label ?? (typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.id);\n\n const allValues = extractNumericValues(allRows, header.id);\n const selectedValues = selectedRows.length > 0 ? extractNumericValues(selectedRows, header.id) : null;\n\n return [\n {\n colId: header.id,\n header: headerText,\n aggregation: agg,\n allValue: computeAggregation(allRows.length, allValues, agg.type),\n selectedValue: selectedValues !== null ? computeAggregation(selectedRows.length, selectedValues, agg.type) : null,\n },\n ];\n });\n }, [headers, allRows, selectedRows]);\n\n return (\n <div data-slot=\"table-analysis-panel\" className=\"w-full border-t border-border\">\n <button\n type=\"button\"\n className={cn(\n 'flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive',\n 'hover:bg-muted-bg-subtle transition-colors outline-none',\n 'focus-visible:ring-2 focus-visible:ring-primary-weak'\n )}\n onClick={toggle}\n aria-expanded={isOpen}\n >\n <span>Tổng quan dữ liệu</span>\n {isOpen ? <ChevronUpIcon size={14} /> : <ChevronDownIcon size={14} />}\n </button>\n\n {isOpen && (\n <div className=\"px-4 pb-4 pt-2 space-y-4\">\n {/* Row summary */}\n <div className=\"flex flex-wrap gap-4\">\n <StatChip label=\"Tổng bản ghi\" value={totalRows ?? allRows.length} />\n <StatChip label=\"Hàng hiển thị\" value={allRows.length} />\n <StatChip label=\"Hàng đã chọn\" value={selectedRows.length} highlight={selectedRows.length > 0} />\n </div>\n\n {/* Column aggregations */}\n {aggregationRows.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak\">Tóm tắt cột</p>\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak\">\n <th className=\"px-3 py-2 text-left font-medium\">Cột</th>\n <th className=\"px-3 py-2 text-left font-medium\">Kiểu</th>\n <th className=\"px-3 py-2 text-right font-medium\">Tất cả hàng</th>\n {selectedRows.length > 0 && <th className=\"px-3 py-2 text-right font-medium\">Hàng đã chọn</th>}\n </tr>\n </thead>\n <tbody>\n {aggregationRows.map((row, idx) => (\n <tr key={row.colId} className={cn('border-b border-border last:border-b-0', idx % 2 === 1 && 'bg-muted-bg-subtle/50')}>\n <td className=\"px-3 py-2 text-text-positive font-medium\">{row.header}</td>\n <td className=\"px-3 py-2 text-text-positive-weak\">{typeLabels[row.aggregation.type]}</td>\n <td className=\"px-3 py-2 text-right\">\n <Statistic\n value={row.allValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n </td>\n {selectedRows.length > 0 && (\n <td className=\"px-3 py-2 text-right\">\n {row.selectedValue !== null ? (\n <Statistic\n value={row.selectedValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n ) : (\n <span className=\"text-text-positive-weak\">—</span>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n});\nUITableAnalysisPanel.displayName = 'UITableAnalysisPanel';\n\nconst StatChip = memo<{ label: string; value: number; highlight?: boolean }>(({ label, value, highlight }) => (\n <div\n className={cn(\n 'flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white',\n highlight && value > 0 ? 'border-primary bg-primary-bg-subtle' : 'border-border bg-white'\n )}\n >\n <span className=\"text-[11px] text-text-positive-weak\">{label}</span>\n <span className=\"text-base font-semibold tabular-nums text-text-positive-strong\">{value.toLocaleString()}</span>\n </div>\n));\nStatChip.displayName = 'StatChip';\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{Statistic as e}from"./data-display/statistic.mjs";import{B as t,J as n,Y as r,q as i,z as a}from"./tables-BGzwkdFO.mjs";import{ChevronDownIcon as o,ChevronUpIcon as s}from"lucide-react";import{memo as c,useMemo as l}from"react";import{cn as u}from"@customafk/react-toolkit/utils";import{jsx as d,jsxs as f}from"react/jsx-runtime";const p={sum:`Tổng`,avg:`Trung bình`,count:`Đếm`,min:`Nhỏ nhất`,max:`Lớn nhất`},m=c(()=>{let{table:c,totalRows:m}=r(),{rowSelectionState:g}=n(),{isOpen:_,toggle:v}=i(),y=l(()=>c.getRowModel().rows,[c]),b=l(()=>c.getSelectedRowModel().flatRows,[c,g]),x=l(()=>c.getHeaderGroups()[0]?.headers??[],[c]),S=l(()=>x.filter(e=>![`select`,`actions`].includes(e.id)).flatMap(e=>{let n=e.column.columnDef.meta?.aggregation;if(!n)return[];let r=n.label??(typeof e.column.columnDef.header==`string`?e.column.columnDef.header:e.id),i=t(y,e.id),o=b.length>0?t(b,e.id):null;return[{colId:e.id,header:r,aggregation:n,allValue:a(y.length,i,n.type),selectedValue:o===null?null:a(b.length,o,n.type)}]}),[x,y,b]);return f(`div`,{"data-slot":`table-analysis-panel`,className:`w-full border-t border-border`,children:[f(`button`,{type:`button`,className:u(`flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive`,`hover:bg-muted-bg-subtle transition-colors outline-none`,`focus-visible:ring-2 focus-visible:ring-primary-weak`),onClick:v,"aria-expanded":_,children:[d(`span`,{children:`Tổng quan dữ liệu`}),d(_?s:o,{size:14})]}),_&&f(`div`,{className:`px-4 pb-4 pt-2 space-y-4`,children:[f(`div`,{className:`flex flex-wrap gap-4`,children:[d(h,{label:`Tổng bản ghi`,value:m??y.length}),d(h,{label:`Hàng hiển thị`,value:y.length}),d(h,{label:`Hàng đã chọn`,value:b.length,highlight:b.length>0})]}),S.length>0&&f(`div`,{children:[d(`p`,{className:`mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak`,children:`Tóm tắt cột`}),d(`div`,{className:`overflow-x-auto rounded-md border border-border`,children:f(`table`,{className:`w-full text-sm`,children:[d(`thead`,{children:f(`tr`,{className:`border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak`,children:[d(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Cột`}),d(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Kiểu`}),d(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Tất cả hàng`}),b.length>0&&d(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Hàng đã chọn`})]})}),d(`tbody`,{children:S.map((t,n)=>f(`tr`,{className:u(`border-b border-border last:border-b-0`,n%2==1&&`bg-muted-bg-subtle/50`),children:[d(`td`,{className:`px-3 py-2 text-text-positive font-medium`,children:t.header}),d(`td`,{className:`px-3 py-2 text-text-positive-weak`,children:p[t.aggregation.type]}),d(`td`,{className:`px-3 py-2 text-right`,children:d(e,{value:t.allValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})}),b.length>0&&d(`td`,{className:`px-3 py-2 text-right`,children:t.selectedValue===null?d(`span`,{className:`text-text-positive-weak`,children:`—`}):d(e,{value:t.selectedValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})})]},t.colId))})]})})]})]})]})});m.displayName=`UITableAnalysisPanel`;const h=c(({label:e,value:t,highlight:n})=>f(`div`,{className:u(`flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white`,n&&t>0?`border-primary bg-primary-bg-subtle`:`border-border bg-white`),children:[d(`span`,{className:`text-[11px] text-text-positive-weak`,children:e}),d(`span`,{className:`text-base font-semibold tabular-nums text-text-positive-strong`,children:t.toLocaleString()})]}));h.displayName=`StatChip`;export{m as UITableAnalysisPanel};
2
- //# sourceMappingURL=analysis-panel-BqZmOU58.mjs.map
1
+ import{Statistic as e}from"./data-display/statistic.mjs";import{B as t,J as n,Y as r,q as i,z as a}from"./tables-7_KgoyS-.mjs";import{ChevronDownIcon as o,ChevronUpIcon as s}from"lucide-react";import{memo as c,useMemo as l}from"react";import{cn as u}from"@customafk/react-toolkit/utils";import{jsx as d,jsxs as f}from"react/jsx-runtime";const p={sum:`Tổng`,avg:`Trung bình`,count:`Đếm`,min:`Nhỏ nhất`,max:`Lớn nhất`},m=c(()=>{let{table:c,totalRows:m}=r(),{rowSelectionState:g}=n(),{isOpen:_,toggle:v}=i(),y=l(()=>c.getRowModel().rows,[c]),b=l(()=>c.getSelectedRowModel().flatRows,[c,g]),x=l(()=>c.getHeaderGroups()[0]?.headers??[],[c]),S=l(()=>x.filter(e=>![`select`,`actions`].includes(e.id)).flatMap(e=>{let n=e.column.columnDef.meta?.aggregation;if(!n)return[];let r=n.label??(typeof e.column.columnDef.header==`string`?e.column.columnDef.header:e.id),i=t(y,e.id),o=b.length>0?t(b,e.id):null;return[{colId:e.id,header:r,aggregation:n,allValue:a(y.length,i,n.type),selectedValue:o===null?null:a(b.length,o,n.type)}]}),[x,y,b]);return f(`div`,{"data-slot":`table-analysis-panel`,className:`w-full border-t border-border`,children:[f(`button`,{type:`button`,className:u(`flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive`,`hover:bg-muted-bg-subtle transition-colors outline-none`,`focus-visible:ring-2 focus-visible:ring-primary-weak`),onClick:v,"aria-expanded":_,children:[d(`span`,{children:`Tổng quan dữ liệu`}),d(_?s:o,{size:14})]}),_&&f(`div`,{className:`px-4 pb-4 pt-2 space-y-4`,children:[f(`div`,{className:`flex flex-wrap gap-4`,children:[d(h,{label:`Tổng bản ghi`,value:m??y.length}),d(h,{label:`Hàng hiển thị`,value:y.length}),d(h,{label:`Hàng đã chọn`,value:b.length,highlight:b.length>0})]}),S.length>0&&f(`div`,{children:[d(`p`,{className:`mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak`,children:`Tóm tắt cột`}),d(`div`,{className:`overflow-x-auto rounded-md border border-border`,children:f(`table`,{className:`w-full text-sm`,children:[d(`thead`,{children:f(`tr`,{className:`border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak`,children:[d(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Cột`}),d(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Kiểu`}),d(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Tất cả hàng`}),b.length>0&&d(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Hàng đã chọn`})]})}),d(`tbody`,{children:S.map((t,n)=>f(`tr`,{className:u(`border-b border-border last:border-b-0`,n%2==1&&`bg-muted-bg-subtle/50`),children:[d(`td`,{className:`px-3 py-2 text-text-positive font-medium`,children:t.header}),d(`td`,{className:`px-3 py-2 text-text-positive-weak`,children:p[t.aggregation.type]}),d(`td`,{className:`px-3 py-2 text-right`,children:d(e,{value:t.allValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})}),b.length>0&&d(`td`,{className:`px-3 py-2 text-right`,children:t.selectedValue===null?d(`span`,{className:`text-text-positive-weak`,children:`—`}):d(e,{value:t.selectedValue,prefix:t.aggregation.prefix,suffix:t.aggregation.suffix,precision:t.aggregation.precision,size:`sm`})})]},t.colId))})]})})]})]})]})});m.displayName=`UITableAnalysisPanel`;const h=c(({label:e,value:t,highlight:n})=>f(`div`,{className:u(`flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white`,n&&t>0?`border-primary bg-primary-bg-subtle`:`border-border bg-white`),children:[d(`span`,{className:`text-[11px] text-text-positive-weak`,children:e}),d(`span`,{className:`text-base font-semibold tabular-nums text-text-positive-strong`,children:t.toLocaleString()})]}));h.displayName=`StatChip`;export{m as UITableAnalysisPanel};
2
+ //# sourceMappingURL=analysis-panel-Cop-l4lx.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-panel-BqZmOU58.mjs","names":[],"sources":["../packages/components/features/tables/components/table/analysis-panel.tsx"],"sourcesContent":["'use client';\nimport { memo, useMemo } from 'react';\n\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Statistic } from '@/components/data-display/statistic';\nimport type { AnyEntity } from '@/types';\nimport { useUITableAnalysisContext, useUITableBodyContext, useUITableContext } from '../../hooks/use-context';\nimport type { ColumnAggregation, ColumnAggregationType } from '../../types';\nimport { computeAggregation, extractNumericValues } from '../../utils/aggregation';\n\ntype AggregationLabel = {\n colId: string;\n header: string;\n aggregation: ColumnAggregation;\n allValue: number;\n selectedValue: number | null;\n};\n\nconst typeLabels: Record<ColumnAggregationType, string> = {\n sum: 'Tổng',\n avg: 'Trung bình',\n count: 'Đếm',\n min: 'Nhỏ nhất',\n max: 'Lớn nhất',\n};\n\nexport const UITableAnalysisPanel = memo(() => {\n const { table, totalRows } = useUITableContext();\n const { rowSelectionState } = useUITableBodyContext();\n const { isOpen, toggle } = useUITableAnalysisContext();\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: row model\n const allRows = useMemo(() => table.getRowModel().rows, [table]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: selected rows\n const selectedRows = useMemo(() => table.getSelectedRowModel().flatRows, [table, rowSelectionState]);\n\n const headers = useMemo(() => table.getHeaderGroups()[0]?.headers ?? [], [table]);\n\n const aggregationRows = useMemo<AggregationLabel[]>(() => {\n return headers\n .filter(h => !['select', 'actions'].includes(h.id))\n .flatMap(header => {\n const agg = (header.column.columnDef.meta as AnyEntity)?.aggregation as ColumnAggregation | undefined;\n if (!agg) return [];\n\n const headerText = agg.label ?? (typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.id);\n\n const allValues = extractNumericValues(allRows, header.id);\n const selectedValues = selectedRows.length > 0 ? extractNumericValues(selectedRows, header.id) : null;\n\n return [\n {\n colId: header.id,\n header: headerText,\n aggregation: agg,\n allValue: computeAggregation(allRows.length, allValues, agg.type),\n selectedValue: selectedValues !== null ? computeAggregation(selectedRows.length, selectedValues, agg.type) : null,\n },\n ];\n });\n }, [headers, allRows, selectedRows]);\n\n return (\n <div data-slot=\"table-analysis-panel\" className=\"w-full border-t border-border\">\n <button\n type=\"button\"\n className={cn(\n 'flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive',\n 'hover:bg-muted-bg-subtle transition-colors outline-none',\n 'focus-visible:ring-2 focus-visible:ring-primary-weak'\n )}\n onClick={toggle}\n aria-expanded={isOpen}\n >\n <span>Tổng quan dữ liệu</span>\n {isOpen ? <ChevronUpIcon size={14} /> : <ChevronDownIcon size={14} />}\n </button>\n\n {isOpen && (\n <div className=\"px-4 pb-4 pt-2 space-y-4\">\n {/* Row summary */}\n <div className=\"flex flex-wrap gap-4\">\n <StatChip label=\"Tổng bản ghi\" value={totalRows ?? allRows.length} />\n <StatChip label=\"Hàng hiển thị\" value={allRows.length} />\n <StatChip label=\"Hàng đã chọn\" value={selectedRows.length} highlight={selectedRows.length > 0} />\n </div>\n\n {/* Column aggregations */}\n {aggregationRows.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak\">Tóm tắt cột</p>\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak\">\n <th className=\"px-3 py-2 text-left font-medium\">Cột</th>\n <th className=\"px-3 py-2 text-left font-medium\">Kiểu</th>\n <th className=\"px-3 py-2 text-right font-medium\">Tất cả hàng</th>\n {selectedRows.length > 0 && <th className=\"px-3 py-2 text-right font-medium\">Hàng đã chọn</th>}\n </tr>\n </thead>\n <tbody>\n {aggregationRows.map((row, idx) => (\n <tr key={row.colId} className={cn('border-b border-border last:border-b-0', idx % 2 === 1 && 'bg-muted-bg-subtle/50')}>\n <td className=\"px-3 py-2 text-text-positive font-medium\">{row.header}</td>\n <td className=\"px-3 py-2 text-text-positive-weak\">{typeLabels[row.aggregation.type]}</td>\n <td className=\"px-3 py-2 text-right\">\n <Statistic\n value={row.allValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n </td>\n {selectedRows.length > 0 && (\n <td className=\"px-3 py-2 text-right\">\n {row.selectedValue !== null ? (\n <Statistic\n value={row.selectedValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n ) : (\n <span className=\"text-text-positive-weak\">—</span>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n});\nUITableAnalysisPanel.displayName = 'UITableAnalysisPanel';\n\nconst StatChip = memo<{ label: string; value: number; highlight?: boolean }>(({ label, value, highlight }) => (\n <div\n className={cn(\n 'flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white',\n highlight && value > 0 ? 'border-primary bg-primary-bg-subtle' : 'border-border bg-white'\n )}\n >\n <span className=\"text-[11px] text-text-positive-weak\">{label}</span>\n <span className=\"text-base font-semibold tabular-nums text-text-positive-strong\">{value.toLocaleString()}</span>\n </div>\n));\nStatChip.displayName = 'StatChip';\n"],"mappings":"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"}
1
+ {"version":3,"file":"analysis-panel-Cop-l4lx.mjs","names":[],"sources":["../packages/components/features/tables/components/table/analysis-panel.tsx"],"sourcesContent":["'use client';\nimport { memo, useMemo } from 'react';\n\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Statistic } from '@/components/data-display/statistic';\nimport type { AnyEntity } from '@/types';\nimport { useUITableAnalysisContext, useUITableBodyContext, useUITableContext } from '../../hooks/use-context';\nimport type { ColumnAggregation, ColumnAggregationType } from '../../types';\nimport { computeAggregation, extractNumericValues } from '../../utils/aggregation';\n\ntype AggregationLabel = {\n colId: string;\n header: string;\n aggregation: ColumnAggregation;\n allValue: number;\n selectedValue: number | null;\n};\n\nconst typeLabels: Record<ColumnAggregationType, string> = {\n sum: 'Tổng',\n avg: 'Trung bình',\n count: 'Đếm',\n min: 'Nhỏ nhất',\n max: 'Lớn nhất',\n};\n\nexport const UITableAnalysisPanel = memo(() => {\n const { table, totalRows } = useUITableContext();\n const { rowSelectionState } = useUITableBodyContext();\n const { isOpen, toggle } = useUITableAnalysisContext();\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: row model\n const allRows = useMemo(() => table.getRowModel().rows, [table]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: selected rows\n const selectedRows = useMemo(() => table.getSelectedRowModel().flatRows, [table, rowSelectionState]);\n\n const headers = useMemo(() => table.getHeaderGroups()[0]?.headers ?? [], [table]);\n\n const aggregationRows = useMemo<AggregationLabel[]>(() => {\n return headers\n .filter(h => !['select', 'actions'].includes(h.id))\n .flatMap(header => {\n const agg = (header.column.columnDef.meta as AnyEntity)?.aggregation as ColumnAggregation | undefined;\n if (!agg) return [];\n\n const headerText = agg.label ?? (typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.id);\n\n const allValues = extractNumericValues(allRows, header.id);\n const selectedValues = selectedRows.length > 0 ? extractNumericValues(selectedRows, header.id) : null;\n\n return [\n {\n colId: header.id,\n header: headerText,\n aggregation: agg,\n allValue: computeAggregation(allRows.length, allValues, agg.type),\n selectedValue: selectedValues !== null ? computeAggregation(selectedRows.length, selectedValues, agg.type) : null,\n },\n ];\n });\n }, [headers, allRows, selectedRows]);\n\n return (\n <div data-slot=\"table-analysis-panel\" className=\"w-full border-t border-border\">\n <button\n type=\"button\"\n className={cn(\n 'flex w-full items-center justify-between px-4 py-2 text-sm font-medium text-text-positive',\n 'hover:bg-muted-bg-subtle transition-colors outline-none',\n 'focus-visible:ring-2 focus-visible:ring-primary-weak'\n )}\n onClick={toggle}\n aria-expanded={isOpen}\n >\n <span>Tổng quan dữ liệu</span>\n {isOpen ? <ChevronUpIcon size={14} /> : <ChevronDownIcon size={14} />}\n </button>\n\n {isOpen && (\n <div className=\"px-4 pb-4 pt-2 space-y-4\">\n {/* Row summary */}\n <div className=\"flex flex-wrap gap-4\">\n <StatChip label=\"Tổng bản ghi\" value={totalRows ?? allRows.length} />\n <StatChip label=\"Hàng hiển thị\" value={allRows.length} />\n <StatChip label=\"Hàng đã chọn\" value={selectedRows.length} highlight={selectedRows.length > 0} />\n </div>\n\n {/* Column aggregations */}\n {aggregationRows.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-positive-weak\">Tóm tắt cột</p>\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted-bg-subtle text-xs text-text-positive-weak\">\n <th className=\"px-3 py-2 text-left font-medium\">Cột</th>\n <th className=\"px-3 py-2 text-left font-medium\">Kiểu</th>\n <th className=\"px-3 py-2 text-right font-medium\">Tất cả hàng</th>\n {selectedRows.length > 0 && <th className=\"px-3 py-2 text-right font-medium\">Hàng đã chọn</th>}\n </tr>\n </thead>\n <tbody>\n {aggregationRows.map((row, idx) => (\n <tr key={row.colId} className={cn('border-b border-border last:border-b-0', idx % 2 === 1 && 'bg-muted-bg-subtle/50')}>\n <td className=\"px-3 py-2 text-text-positive font-medium\">{row.header}</td>\n <td className=\"px-3 py-2 text-text-positive-weak\">{typeLabels[row.aggregation.type]}</td>\n <td className=\"px-3 py-2 text-right\">\n <Statistic\n value={row.allValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n </td>\n {selectedRows.length > 0 && (\n <td className=\"px-3 py-2 text-right\">\n {row.selectedValue !== null ? (\n <Statistic\n value={row.selectedValue}\n prefix={row.aggregation.prefix}\n suffix={row.aggregation.suffix}\n precision={row.aggregation.precision}\n size=\"sm\"\n />\n ) : (\n <span className=\"text-text-positive-weak\">—</span>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n});\nUITableAnalysisPanel.displayName = 'UITableAnalysisPanel';\n\nconst StatChip = memo<{ label: string; value: number; highlight?: boolean }>(({ label, value, highlight }) => (\n <div\n className={cn(\n 'flex flex-col gap-0.5 rounded border px-3 py-2 min-w-25 bg-white',\n highlight && value > 0 ? 'border-primary bg-primary-bg-subtle' : 'border-border bg-white'\n )}\n >\n <span className=\"text-[11px] text-text-positive-weak\">{label}</span>\n <span className=\"text-base font-semibold tabular-nums text-text-positive-strong\">{value.toLocaleString()}</span>\n </div>\n));\nStatChip.displayName = 'StatChip';\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{Q as e}from"./tables-BGzwkdFO.mjs";import{XIcon as t}from"lucide-react";import{jsx as n,jsxs as r}from"react/jsx-runtime";const i=({label:i,onClick:a,onRemove:o})=>i?o?r(`div`,{className:`flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:[i,n(`button`,{className:`cursor-pointer text-text-positive-weak hover:text-text-positive-strong`,onClick:e=>{o?.(),e.stopPropagation(),e.preventDefault()},children:n(t,{size:12})})]}):n(`button`,{className:`w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:i}):n(e,{});export{i as UITableBadgeDisplay};
2
- //# sourceMappingURL=badge-display-RP5VTE10.mjs.map
1
+ import{Q as e}from"./tables-7_KgoyS-.mjs";import{XIcon as t}from"lucide-react";import{jsx as n,jsxs as r}from"react/jsx-runtime";const i=({label:i,onClick:a,onRemove:o})=>i?o?r(`div`,{className:`flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:[i,n(`button`,{className:`cursor-pointer text-text-positive-weak hover:text-text-positive-strong`,onClick:e=>{o?.(),e.stopPropagation(),e.preventDefault()},children:n(t,{size:12})})]}):n(`button`,{className:`w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:i}):n(e,{});export{i as UITableBadgeDisplay};
2
+ //# sourceMappingURL=badge-display-B0BKsU9T.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge-display-RP5VTE10.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/badge-display.tsx"],"sourcesContent":["import { XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\n/**\n * Renders a pill-shaped badge for a table cell that optionally supports a click\n * action and an inline remove button; falls back to {@link UITableEmpty} when\n * `label` is falsy.\n *\n * @example\n * import { UITableBadgeDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableBadgeDisplay\n * label=\"Active\"\n * onClick={() => console.log('badge clicked')}\n * onRemove={() => console.log('remove clicked')}\n * />\n */\nexport const UITableBadgeDisplay: React.FC<{\n /** The text or number to display inside the badge. */\n label: string | number | null | undefined;\n /** Optional callback fired when the badge itself is clicked. */\n onClick?: () => void;\n /** When provided, renders a remove (×) button and fires this callback on click. */\n onRemove?: () => void;\n}> = ({ label, onClick, onRemove }) => {\n if (!label) return <UITableEmpty />;\n if (onRemove) {\n return (\n <div\n className=\"flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n <button\n className=\"cursor-pointer text-text-positive-weak hover:text-text-positive-strong\"\n onClick={e => {\n onRemove?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n <XIcon size={12} />\n </button>\n </div>\n );\n }\n return (\n <button\n className=\"w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n </button>\n );\n};\n"],"mappings":"iIAkBA,MAAa,GAOP,CAAE,QAAO,UAAS,cACjB,EACD,EAEA,EAAC,MAAD,CACE,UAAU,6GACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EANF,SAAA,CAQG,EACD,EAAC,SAAD,CACE,UAAU,yEACV,QAAS,GAAK,CACZ,IAAW,EACX,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEA,SAAA,EAAC,EAAD,CAAO,KAAM,EAAK,CAAA,CACZ,CAAA,CACL,IAIP,EAAC,SAAD,CACE,UAAU,yFACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEC,SAAA,CACK,CAAA,EAnCS,EAAC,EAAD,CAAe,CAAA"}
1
+ {"version":3,"file":"badge-display-B0BKsU9T.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/badge-display.tsx"],"sourcesContent":["import { XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\n/**\n * Renders a pill-shaped badge for a table cell that optionally supports a click\n * action and an inline remove button; falls back to {@link UITableEmpty} when\n * `label` is falsy.\n *\n * @example\n * import { UITableBadgeDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableBadgeDisplay\n * label=\"Active\"\n * onClick={() => console.log('badge clicked')}\n * onRemove={() => console.log('remove clicked')}\n * />\n */\nexport const UITableBadgeDisplay: React.FC<{\n /** The text or number to display inside the badge. */\n label: string | number | null | undefined;\n /** Optional callback fired when the badge itself is clicked. */\n onClick?: () => void;\n /** When provided, renders a remove (×) button and fires this callback on click. */\n onRemove?: () => void;\n}> = ({ label, onClick, onRemove }) => {\n if (!label) return <UITableEmpty />;\n if (onRemove) {\n return (\n <div\n className=\"flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n <button\n className=\"cursor-pointer text-text-positive-weak hover:text-text-positive-strong\"\n onClick={e => {\n onRemove?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n <XIcon size={12} />\n </button>\n </div>\n );\n }\n return (\n <button\n className=\"w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n </button>\n );\n};\n"],"mappings":"iIAkBA,MAAa,GAOP,CAAE,QAAO,UAAS,cACjB,EACD,EAEA,EAAC,MAAD,CACE,UAAU,6GACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EANF,SAAA,CAQG,EACD,EAAC,SAAD,CACE,UAAU,yEACV,QAAS,GAAK,CACZ,IAAW,EACX,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEA,SAAA,EAAC,EAAD,CAAO,KAAM,EAAK,CAAA,CACZ,CAAA,CACL,IAIP,EAAC,SAAD,CACE,UAAU,yFACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEC,SAAA,CACK,CAAA,EAnCS,EAAC,EAAD,CAAe,CAAA"}
@@ -1,2 +1,2 @@
1
- const e=require("./tables-078i-X0d.cjs");let t=require("lucide-react"),n=require("react/jsx-runtime");const r=({label:r,onClick:i,onRemove:a})=>r?a?(0,n.jsxs)(`div`,{className:`flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs`,onClick:e=>{i?.(),e.stopPropagation(),e.preventDefault()},children:[r,(0,n.jsx)(`button`,{className:`cursor-pointer text-text-positive-weak hover:text-text-positive-strong`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:(0,n.jsx)(t.XIcon,{size:12})})]}):(0,n.jsx)(`button`,{className:`w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs`,onClick:e=>{i?.(),e.stopPropagation(),e.preventDefault()},children:r}):(0,n.jsx)(e.Q,{});exports.UITableBadgeDisplay=r;
2
- //# sourceMappingURL=badge-display-DmCKpGk9.cjs.map
1
+ const e=require("./tables-CS3NhgTc.cjs");let t=require("lucide-react"),n=require("react/jsx-runtime");const r=({label:r,onClick:i,onRemove:a})=>r?a?(0,n.jsxs)(`div`,{className:`flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs`,onClick:e=>{i?.(),e.stopPropagation(),e.preventDefault()},children:[r,(0,n.jsx)(`button`,{className:`cursor-pointer text-text-positive-weak hover:text-text-positive-strong`,onClick:e=>{a?.(),e.stopPropagation(),e.preventDefault()},children:(0,n.jsx)(t.XIcon,{size:12})})]}):(0,n.jsx)(`button`,{className:`w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs`,onClick:e=>{i?.(),e.stopPropagation(),e.preventDefault()},children:r}):(0,n.jsx)(e.Q,{});exports.UITableBadgeDisplay=r;
2
+ //# sourceMappingURL=badge-display-Dv2UTvzp.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge-display-DmCKpGk9.cjs","names":["UITableEmpty","XIcon"],"sources":["../packages/components/features/tables/components/atoms/badge-display.tsx"],"sourcesContent":["import { XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\n/**\n * Renders a pill-shaped badge for a table cell that optionally supports a click\n * action and an inline remove button; falls back to {@link UITableEmpty} when\n * `label` is falsy.\n *\n * @example\n * import { UITableBadgeDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableBadgeDisplay\n * label=\"Active\"\n * onClick={() => console.log('badge clicked')}\n * onRemove={() => console.log('remove clicked')}\n * />\n */\nexport const UITableBadgeDisplay: React.FC<{\n /** The text or number to display inside the badge. */\n label: string | number | null | undefined;\n /** Optional callback fired when the badge itself is clicked. */\n onClick?: () => void;\n /** When provided, renders a remove (×) button and fires this callback on click. */\n onRemove?: () => void;\n}> = ({ label, onClick, onRemove }) => {\n if (!label) return <UITableEmpty />;\n if (onRemove) {\n return (\n <div\n className=\"flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n <button\n className=\"cursor-pointer text-text-positive-weak hover:text-text-positive-strong\"\n onClick={e => {\n onRemove?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n <XIcon size={12} />\n </button>\n </div>\n );\n }\n return (\n <button\n className=\"w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n </button>\n );\n};\n"],"mappings":"sGAkBA,MAAa,GAOP,CAAE,QAAO,UAAS,cACjB,EACD,GAEA,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAU,6GACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EANF,SAAA,CAQG,GACD,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,UAAU,yEACV,QAAS,GAAK,CACZ,IAAW,EACX,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEA,UAAA,EAAA,EAAA,IAAA,CAACC,EAAAA,MAAD,CAAO,KAAM,EAAK,CAAA,CACZ,CAAA,CACL,KAIP,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,UAAU,yFACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEC,SAAA,CACK,CAAA,GAnCS,EAAA,EAAA,IAAA,CAACD,EAAAA,EAAD,CAAe,CAAA"}
1
+ {"version":3,"file":"badge-display-Dv2UTvzp.cjs","names":["UITableEmpty","XIcon"],"sources":["../packages/components/features/tables/components/atoms/badge-display.tsx"],"sourcesContent":["import { XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\n/**\n * Renders a pill-shaped badge for a table cell that optionally supports a click\n * action and an inline remove button; falls back to {@link UITableEmpty} when\n * `label` is falsy.\n *\n * @example\n * import { UITableBadgeDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableBadgeDisplay\n * label=\"Active\"\n * onClick={() => console.log('badge clicked')}\n * onRemove={() => console.log('remove clicked')}\n * />\n */\nexport const UITableBadgeDisplay: React.FC<{\n /** The text or number to display inside the badge. */\n label: string | number | null | undefined;\n /** Optional callback fired when the badge itself is clicked. */\n onClick?: () => void;\n /** When provided, renders a remove (×) button and fires this callback on click. */\n onRemove?: () => void;\n}> = ({ label, onClick, onRemove }) => {\n if (!label) return <UITableEmpty />;\n if (onRemove) {\n return (\n <div\n className=\"flex w-fit gap-x-0.5 rounded-full border border-border py-1 pr-2 pl-3 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n <button\n className=\"cursor-pointer text-text-positive-weak hover:text-text-positive-strong\"\n onClick={e => {\n onRemove?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n <XIcon size={12} />\n </button>\n </div>\n );\n }\n return (\n <button\n className=\"w-fit rounded-full border border-border px-3 py-1 text-text-positive text-xs shadow-xs\"\n onClick={e => {\n onClick?.();\n e.stopPropagation();\n e.preventDefault();\n }}\n >\n {label}\n </button>\n );\n};\n"],"mappings":"sGAkBA,MAAa,GAOP,CAAE,QAAO,UAAS,cACjB,EACD,GAEA,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAU,6GACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EANF,SAAA,CAQG,GACD,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,UAAU,yEACV,QAAS,GAAK,CACZ,IAAW,EACX,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEA,UAAA,EAAA,EAAA,IAAA,CAACC,EAAAA,MAAD,CAAO,KAAM,EAAK,CAAA,CACZ,CAAA,CACL,KAIP,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,UAAU,yFACV,QAAS,GAAK,CACZ,IAAU,EACV,EAAE,gBAAgB,EAClB,EAAE,eAAe,CACnB,EAEC,SAAA,CACK,CAAA,GAnCS,EAAA,EAAA,IAAA,CAACD,EAAAA,EAAD,CAAe,CAAA"}
@@ -1,2 +1,2 @@
1
- import{Q as e}from"./tables-BGzwkdFO.mjs";import{CheckIcon as t,XIcon as n}from"lucide-react";import{jsx as r}from"react/jsx-runtime";const i=({value:i})=>i==null?r(e,{}):i===!1?r(n,{size:14,strokeWidth:2,className:`text-danger-strong`}):r(t,{size:14,strokeWidth:2,className:`text-success-strong`});export{i as UITableBooleanDisplay};
2
- //# sourceMappingURL=boolean-display-B9qxrF5f.mjs.map
1
+ import{Q as e}from"./tables-7_KgoyS-.mjs";import{CheckIcon as t,XIcon as n}from"lucide-react";import{jsx as r}from"react/jsx-runtime";const i=({value:i})=>i==null?r(e,{}):i===!1?r(n,{size:14,strokeWidth:2,className:`text-danger-strong`}):r(t,{size:14,strokeWidth:2,className:`text-success-strong`});export{i as UITableBooleanDisplay};
2
+ //# sourceMappingURL=boolean-display-CMX5AupA.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"boolean-display-B9qxrF5f.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/boolean-display.tsx"],"sourcesContent":["import { CheckIcon, XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\nexport const UITableBooleanDisplay: React.FC<{\n value: boolean | null | undefined;\n}> = ({ value }) => {\n if (value === null || value === undefined) return <UITableEmpty />;\n if (value === false) {\n return <XIcon size={14} strokeWidth={2} className=\"text-danger-strong\" />;\n }\n return <CheckIcon size={14} strokeWidth={2} className=\"text-success-strong\" />;\n};\n"],"mappings":"sIAIA,MAAa,GAEP,CAAE,WACF,GAAU,KAAoC,EAAC,EAAD,CAAe,CAAA,EAC7D,IAAU,GACL,EAAC,EAAD,CAAO,KAAM,GAAI,YAAa,EAAG,UAAU,oBAAsB,CAAA,EAEnE,EAAC,EAAD,CAAW,KAAM,GAAI,YAAa,EAAG,UAAU,qBAAuB,CAAA"}
1
+ {"version":3,"file":"boolean-display-CMX5AupA.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/boolean-display.tsx"],"sourcesContent":["import { CheckIcon, XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\nexport const UITableBooleanDisplay: React.FC<{\n value: boolean | null | undefined;\n}> = ({ value }) => {\n if (value === null || value === undefined) return <UITableEmpty />;\n if (value === false) {\n return <XIcon size={14} strokeWidth={2} className=\"text-danger-strong\" />;\n }\n return <CheckIcon size={14} strokeWidth={2} className=\"text-success-strong\" />;\n};\n"],"mappings":"sIAIA,MAAa,GAEP,CAAE,WACF,GAAU,KAAoC,EAAC,EAAD,CAAe,CAAA,EAC7D,IAAU,GACL,EAAC,EAAD,CAAO,KAAM,GAAI,YAAa,EAAG,UAAU,oBAAsB,CAAA,EAEnE,EAAC,EAAD,CAAW,KAAM,GAAI,YAAa,EAAG,UAAU,qBAAuB,CAAA"}
@@ -1,2 +1,2 @@
1
- const e=require("./tables-078i-X0d.cjs");let t=require("lucide-react"),n=require("react/jsx-runtime");const r=({value:r})=>r==null?(0,n.jsx)(e.Q,{}):r===!1?(0,n.jsx)(t.XIcon,{size:14,strokeWidth:2,className:`text-danger-strong`}):(0,n.jsx)(t.CheckIcon,{size:14,strokeWidth:2,className:`text-success-strong`});exports.UITableBooleanDisplay=r;
2
- //# sourceMappingURL=boolean-display-BwB-l9k0.cjs.map
1
+ const e=require("./tables-CS3NhgTc.cjs");let t=require("lucide-react"),n=require("react/jsx-runtime");const r=({value:r})=>r==null?(0,n.jsx)(e.Q,{}):r===!1?(0,n.jsx)(t.XIcon,{size:14,strokeWidth:2,className:`text-danger-strong`}):(0,n.jsx)(t.CheckIcon,{size:14,strokeWidth:2,className:`text-success-strong`});exports.UITableBooleanDisplay=r;
2
+ //# sourceMappingURL=boolean-display-CPX7H39m.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"boolean-display-BwB-l9k0.cjs","names":["UITableEmpty","XIcon","CheckIcon"],"sources":["../packages/components/features/tables/components/atoms/boolean-display.tsx"],"sourcesContent":["import { CheckIcon, XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\nexport const UITableBooleanDisplay: React.FC<{\n value: boolean | null | undefined;\n}> = ({ value }) => {\n if (value === null || value === undefined) return <UITableEmpty />;\n if (value === false) {\n return <XIcon size={14} strokeWidth={2} className=\"text-danger-strong\" />;\n }\n return <CheckIcon size={14} strokeWidth={2} className=\"text-success-strong\" />;\n};\n"],"mappings":"sGAIA,MAAa,GAEP,CAAE,WACF,GAAU,MAAoC,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,EAC7D,IAAU,IACL,EAAA,EAAA,IAAA,CAACC,EAAAA,MAAD,CAAO,KAAM,GAAI,YAAa,EAAG,UAAU,oBAAsB,CAAA,GAEnE,EAAA,EAAA,IAAA,CAACC,EAAAA,UAAD,CAAW,KAAM,GAAI,YAAa,EAAG,UAAU,qBAAuB,CAAA"}
1
+ {"version":3,"file":"boolean-display-CPX7H39m.cjs","names":["UITableEmpty","XIcon","CheckIcon"],"sources":["../packages/components/features/tables/components/atoms/boolean-display.tsx"],"sourcesContent":["import { CheckIcon, XIcon } from 'lucide-react';\n\nimport { UITableEmpty } from './empty';\n\nexport const UITableBooleanDisplay: React.FC<{\n value: boolean | null | undefined;\n}> = ({ value }) => {\n if (value === null || value === undefined) return <UITableEmpty />;\n if (value === false) {\n return <XIcon size={14} strokeWidth={2} className=\"text-danger-strong\" />;\n }\n return <CheckIcon size={14} strokeWidth={2} className=\"text-success-strong\" />;\n};\n"],"mappings":"sGAIA,MAAa,GAEP,CAAE,WACF,GAAU,MAAoC,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,EAC7D,IAAU,IACL,EAAA,EAAA,IAAA,CAACC,EAAAA,MAAD,CAAO,KAAM,GAAI,YAAa,EAAG,UAAU,oBAAsB,CAAA,GAEnE,EAAA,EAAA,IAAA,CAACC,EAAAA,UAAD,CAAW,KAAM,GAAI,YAAa,EAAG,UAAU,qBAAuB,CAAA"}
@@ -1,2 +1,2 @@
1
- import{Q as e}from"./tables-BGzwkdFO.mjs";import{memo as t,useMemo as n}from"react";import{cn as r}from"@customafk/react-toolkit/utils";import{jsx as i}from"react/jsx-runtime";const a=t(({value:t,currency:a=`USD`,locale:o=`en-US`,display:s=`symbol`,size:c=`md`,colorize:l=!1})=>{let u=n(()=>{let e=typeof t==`string`?Number(t.trim()):t;return e==null||Number.isNaN(e)||!Number.isFinite(e)?null:new Intl.NumberFormat(o,{style:`currency`,currency:a,currencyDisplay:s,minimumFractionDigits:2,maximumFractionDigits:2}).format(e)},[t,a,o,s]),d=n(()=>{let e=typeof t==`string`?Number(t.trim()):t;return typeof e==`number`&&e<0},[t]);return u?i(`p`,{className:r(`font-number tabular-nums`,c===`xs`&&`text-xs`,c===`sm`&&`text-sm`,c===`md`&&`text-base`,c===`lg`&&`text-lg`,c===`xl`&&`text-xl`,!l&&`text-text-positive`,l&&d&&`text-danger-strong`,l&&!d&&`text-success-strong`),children:u}):i(e,{})});a.displayName=`UITableCurrencyDisplay`;export{a as UITableCurrencyDisplay};
2
- //# sourceMappingURL=currency-display-CEg_HRYv.mjs.map
1
+ import{Q as e}from"./tables-7_KgoyS-.mjs";import{memo as t,useMemo as n}from"react";import{cn as r}from"@customafk/react-toolkit/utils";import{jsx as i}from"react/jsx-runtime";const a=t(({value:t,currency:a=`USD`,locale:o=`en-US`,display:s=`symbol`,size:c=`md`,colorize:l=!1})=>{let u=n(()=>{let e=typeof t==`string`?Number(t.trim()):t;return e==null||Number.isNaN(e)||!Number.isFinite(e)?null:new Intl.NumberFormat(o,{style:`currency`,currency:a,currencyDisplay:s,minimumFractionDigits:0,maximumFractionDigits:0}).format(e)},[t,a,o,s]),d=n(()=>{let e=typeof t==`string`?Number(t.trim()):t;return typeof e==`number`&&e<0},[t]);return u?i(`p`,{className:r(`font-number tabular-nums`,c===`xs`&&`text-xs`,c===`sm`&&`text-sm`,c===`md`&&`text-base`,c===`lg`&&`text-lg`,c===`xl`&&`text-xl`,!l&&`text-text-positive`,l&&d&&`text-danger-strong`,l&&!d&&`text-success-strong`),children:u}):i(e,{})});a.displayName=`UITableCurrencyDisplay`;export{a as UITableCurrencyDisplay};
2
+ //# sourceMappingURL=currency-display-CanjOswc.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"currency-display-CEg_HRYv.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/currency-display.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useMemo } from 'react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableCurrencyDisplay} component. */\ntype Props = {\n /** The numeric value to format as currency; falsy / `NaN` renders an empty state. */\n value: number | string | null | undefined;\n /** ISO 4217 currency code (default: `'USD'`). */\n currency?: string;\n /**\n * BCP 47 locale used for number formatting (default: `'en-US'`).\n * Controls digit grouping and decimal separators.\n */\n locale?: string;\n /** How to display the currency symbol — `'symbol'` (default), `'code'`, or `'name'`. */\n display?: 'symbol' | 'code' | 'name';\n /** Font-size variant (default: `'md'`). */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** When `true`, applies a green tint for positive and red tint for negative values. */\n colorize?: boolean;\n};\n\n/**\n * Formats a numeric value as a locale-aware currency string in a table cell.\n * Always shows exactly two decimal places and uses the browser's `Intl` API for\n * symbol placement. Renders {@link UITableEmpty} when the value is absent or\n * invalid.\n *\n * @example\n * import { UITableCurrencyDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableCurrencyDisplay value={1234.5} currency=\"USD\" colorize />\n */\nexport const UITableCurrencyDisplay = memo(({ value, currency = 'USD', locale = 'en-US', display = 'symbol', size = 'md', colorize = false }: Props) => {\n const formatted = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n if (num === null || num === undefined || Number.isNaN(num) || !Number.isFinite(num)) return null;\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n currencyDisplay: display,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(num);\n }, [value, currency, locale, display]);\n\n const isNegative = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n return typeof num === 'number' && num < 0;\n }, [value]);\n\n if (!formatted) return <UITableEmpty />;\n\n return (\n <p\n className={cn(\n 'font-number tabular-nums',\n size === 'xs' && 'text-xs',\n size === 'sm' && 'text-sm',\n size === 'md' && 'text-base',\n size === 'lg' && 'text-lg',\n size === 'xl' && 'text-xl',\n !colorize && 'text-text-positive',\n colorize && isNegative && 'text-danger-strong',\n colorize && !isNegative && 'text-success-strong'\n )}\n >\n {formatted}\n </p>\n );\n});\nUITableCurrencyDisplay.displayName = 'UITableCurrencyDisplay';\n"],"mappings":"gLAsCA,MAAa,EAAyB,GAAM,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,UAAU,SAAU,OAAO,KAAM,WAAW,MAAmB,CACtJ,IAAM,EAAY,MAAc,CAC9B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAG/D,OAFI,GAAQ,MAA6B,OAAO,MAAM,CAAG,GAAK,CAAC,OAAO,SAAS,CAAG,EAAU,KAErF,IAAI,KAAK,aAAa,EAAQ,CACnC,MAAO,WACP,WACA,gBAAiB,EACjB,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,CAAC,CAAC,OAAO,CAAG,CACf,EAAG,CAAC,EAAO,EAAU,EAAQ,CAAO,CAAC,EAE/B,EAAa,MAAc,CAC/B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAC/D,OAAO,OAAO,GAAQ,UAAY,EAAM,CAC1C,EAAG,CAAC,CAAK,CAAC,EAIV,OAFK,EAGH,EAAC,IAAD,CACE,UAAW,EACT,2BACA,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,YACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,CAAC,GAAY,qBACb,GAAY,GAAc,qBAC1B,GAAY,CAAC,GAAc,qBAC7B,EAEC,SAAA,CACA,CAAA,EAjBkB,EAAC,EAAD,CAAe,CAAA,CAmBxC,CAAC,EACD,EAAuB,YAAc"}
1
+ {"version":3,"file":"currency-display-CanjOswc.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/currency-display.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useMemo } from 'react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableCurrencyDisplay} component. */\ntype Props = {\n /** The numeric value to format as currency; falsy / `NaN` renders an empty state. */\n value: number | string | null | undefined;\n /** ISO 4217 currency code (default: `'USD'`). */\n currency?: string;\n /**\n * BCP 47 locale used for number formatting (default: `'en-US'`).\n * Controls digit grouping and decimal separators.\n */\n locale?: string;\n /** How to display the currency symbol — `'symbol'` (default), `'code'`, or `'name'`. */\n display?: 'symbol' | 'code' | 'name';\n /** Font-size variant (default: `'md'`). */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** When `true`, applies a green tint for positive and red tint for negative values. */\n colorize?: boolean;\n};\n\n/**\n * Formats a numeric value as a locale-aware currency string in a table cell.\n * Always shows exactly two decimal places and uses the browser's `Intl` API for\n * symbol placement. Renders {@link UITableEmpty} when the value is absent or\n * invalid.\n *\n * @example\n * import { UITableCurrencyDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableCurrencyDisplay value={1234.5} currency=\"USD\" colorize />\n */\nexport const UITableCurrencyDisplay = memo(({ value, currency = 'USD', locale = 'en-US', display = 'symbol', size = 'md', colorize = false }: Props) => {\n const formatted = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n if (num === null || num === undefined || Number.isNaN(num) || !Number.isFinite(num)) return null;\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n currencyDisplay: display,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }).format(num);\n }, [value, currency, locale, display]);\n\n const isNegative = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n return typeof num === 'number' && num < 0;\n }, [value]);\n\n if (!formatted) return <UITableEmpty />;\n\n return (\n <p\n className={cn(\n 'font-number tabular-nums',\n size === 'xs' && 'text-xs',\n size === 'sm' && 'text-sm',\n size === 'md' && 'text-base',\n size === 'lg' && 'text-lg',\n size === 'xl' && 'text-xl',\n !colorize && 'text-text-positive',\n colorize && isNegative && 'text-danger-strong',\n colorize && !isNegative && 'text-success-strong'\n )}\n >\n {formatted}\n </p>\n );\n});\nUITableCurrencyDisplay.displayName = 'UITableCurrencyDisplay';\n"],"mappings":"gLAsCA,MAAa,EAAyB,GAAM,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,UAAU,SAAU,OAAO,KAAM,WAAW,MAAmB,CACtJ,IAAM,EAAY,MAAc,CAC9B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAG/D,OAFI,GAAQ,MAA6B,OAAO,MAAM,CAAG,GAAK,CAAC,OAAO,SAAS,CAAG,EAAU,KAErF,IAAI,KAAK,aAAa,EAAQ,CACnC,MAAO,WACP,WACA,gBAAiB,EACjB,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,CAAC,CAAC,OAAO,CAAG,CACf,EAAG,CAAC,EAAO,EAAU,EAAQ,CAAO,CAAC,EAE/B,EAAa,MAAc,CAC/B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAC/D,OAAO,OAAO,GAAQ,UAAY,EAAM,CAC1C,EAAG,CAAC,CAAK,CAAC,EAIV,OAFK,EAGH,EAAC,IAAD,CACE,UAAW,EACT,2BACA,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,YACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,CAAC,GAAY,qBACb,GAAY,GAAc,qBAC1B,GAAY,CAAC,GAAc,qBAC7B,EAEC,SAAA,CACA,CAAA,EAjBkB,EAAC,EAAD,CAAe,CAAA,CAmBxC,CAAC,EACD,EAAuB,YAAc"}
@@ -1,2 +1,2 @@
1
- const e=require("./tables-078i-X0d.cjs");let t=require("react"),n=require("@customafk/react-toolkit/utils"),r=require("react/jsx-runtime");const i=(0,t.memo)(({value:i,currency:a=`USD`,locale:o=`en-US`,display:s=`symbol`,size:c=`md`,colorize:l=!1})=>{let u=(0,t.useMemo)(()=>{let e=typeof i==`string`?Number(i.trim()):i;return e==null||Number.isNaN(e)||!Number.isFinite(e)?null:new Intl.NumberFormat(o,{style:`currency`,currency:a,currencyDisplay:s,minimumFractionDigits:2,maximumFractionDigits:2}).format(e)},[i,a,o,s]),d=(0,t.useMemo)(()=>{let e=typeof i==`string`?Number(i.trim()):i;return typeof e==`number`&&e<0},[i]);return u?(0,r.jsx)(`p`,{className:(0,n.cn)(`font-number tabular-nums`,c===`xs`&&`text-xs`,c===`sm`&&`text-sm`,c===`md`&&`text-base`,c===`lg`&&`text-lg`,c===`xl`&&`text-xl`,!l&&`text-text-positive`,l&&d&&`text-danger-strong`,l&&!d&&`text-success-strong`),children:u}):(0,r.jsx)(e.Q,{})});i.displayName=`UITableCurrencyDisplay`,exports.UITableCurrencyDisplay=i;
2
- //# sourceMappingURL=currency-display-Buxc6Ph5.cjs.map
1
+ const e=require("./tables-CS3NhgTc.cjs");let t=require("react"),n=require("@customafk/react-toolkit/utils"),r=require("react/jsx-runtime");const i=(0,t.memo)(({value:i,currency:a=`USD`,locale:o=`en-US`,display:s=`symbol`,size:c=`md`,colorize:l=!1})=>{let u=(0,t.useMemo)(()=>{let e=typeof i==`string`?Number(i.trim()):i;return e==null||Number.isNaN(e)||!Number.isFinite(e)?null:new Intl.NumberFormat(o,{style:`currency`,currency:a,currencyDisplay:s,minimumFractionDigits:0,maximumFractionDigits:0}).format(e)},[i,a,o,s]),d=(0,t.useMemo)(()=>{let e=typeof i==`string`?Number(i.trim()):i;return typeof e==`number`&&e<0},[i]);return u?(0,r.jsx)(`p`,{className:(0,n.cn)(`font-number tabular-nums`,c===`xs`&&`text-xs`,c===`sm`&&`text-sm`,c===`md`&&`text-base`,c===`lg`&&`text-lg`,c===`xl`&&`text-xl`,!l&&`text-text-positive`,l&&d&&`text-danger-strong`,l&&!d&&`text-success-strong`),children:u}):(0,r.jsx)(e.Q,{})});i.displayName=`UITableCurrencyDisplay`,exports.UITableCurrencyDisplay=i;
2
+ //# sourceMappingURL=currency-display-xxK62yo4.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"currency-display-Buxc6Ph5.cjs","names":["UITableEmpty"],"sources":["../packages/components/features/tables/components/atoms/currency-display.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useMemo } from 'react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableCurrencyDisplay} component. */\ntype Props = {\n /** The numeric value to format as currency; falsy / `NaN` renders an empty state. */\n value: number | string | null | undefined;\n /** ISO 4217 currency code (default: `'USD'`). */\n currency?: string;\n /**\n * BCP 47 locale used for number formatting (default: `'en-US'`).\n * Controls digit grouping and decimal separators.\n */\n locale?: string;\n /** How to display the currency symbol — `'symbol'` (default), `'code'`, or `'name'`. */\n display?: 'symbol' | 'code' | 'name';\n /** Font-size variant (default: `'md'`). */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** When `true`, applies a green tint for positive and red tint for negative values. */\n colorize?: boolean;\n};\n\n/**\n * Formats a numeric value as a locale-aware currency string in a table cell.\n * Always shows exactly two decimal places and uses the browser's `Intl` API for\n * symbol placement. Renders {@link UITableEmpty} when the value is absent or\n * invalid.\n *\n * @example\n * import { UITableCurrencyDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableCurrencyDisplay value={1234.5} currency=\"USD\" colorize />\n */\nexport const UITableCurrencyDisplay = memo(({ value, currency = 'USD', locale = 'en-US', display = 'symbol', size = 'md', colorize = false }: Props) => {\n const formatted = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n if (num === null || num === undefined || Number.isNaN(num) || !Number.isFinite(num)) return null;\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n currencyDisplay: display,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(num);\n }, [value, currency, locale, display]);\n\n const isNegative = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n return typeof num === 'number' && num < 0;\n }, [value]);\n\n if (!formatted) return <UITableEmpty />;\n\n return (\n <p\n className={cn(\n 'font-number tabular-nums',\n size === 'xs' && 'text-xs',\n size === 'sm' && 'text-sm',\n size === 'md' && 'text-base',\n size === 'lg' && 'text-lg',\n size === 'xl' && 'text-xl',\n !colorize && 'text-text-positive',\n colorize && isNegative && 'text-danger-strong',\n colorize && !isNegative && 'text-success-strong'\n )}\n >\n {formatted}\n </p>\n );\n});\nUITableCurrencyDisplay.displayName = 'UITableCurrencyDisplay';\n"],"mappings":"2IAsCA,MAAa,GAAA,EAAA,EAAA,KAAA,EAA+B,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,UAAU,SAAU,OAAO,KAAM,WAAW,MAAmB,CACtJ,IAAM,GAAA,EAAA,EAAA,QAAA,KAA0B,CAC9B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAG/D,OAFI,GAAQ,MAA6B,OAAO,MAAM,CAAG,GAAK,CAAC,OAAO,SAAS,CAAG,EAAU,KAErF,IAAI,KAAK,aAAa,EAAQ,CACnC,MAAO,WACP,WACA,gBAAiB,EACjB,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,CAAC,CAAC,OAAO,CAAG,CACf,EAAG,CAAC,EAAO,EAAU,EAAQ,CAAO,CAAC,EAE/B,GAAA,EAAA,EAAA,QAAA,KAA2B,CAC/B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAC/D,OAAO,OAAO,GAAQ,UAAY,EAAM,CAC1C,EAAG,CAAC,CAAK,CAAC,EAIV,OAFK,GAGH,EAAA,EAAA,IAAA,CAAC,IAAD,CACE,WAAA,EAAA,EAAA,GAAA,CACE,2BACA,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,YACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,CAAC,GAAY,qBACb,GAAY,GAAc,qBAC1B,GAAY,CAAC,GAAc,qBAC7B,EAEC,SAAA,CACA,CAAA,GAjBkB,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,CAmBxC,CAAC,EACD,EAAuB,YAAc"}
1
+ {"version":3,"file":"currency-display-xxK62yo4.cjs","names":["UITableEmpty"],"sources":["../packages/components/features/tables/components/atoms/currency-display.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useMemo } from 'react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableCurrencyDisplay} component. */\ntype Props = {\n /** The numeric value to format as currency; falsy / `NaN` renders an empty state. */\n value: number | string | null | undefined;\n /** ISO 4217 currency code (default: `'USD'`). */\n currency?: string;\n /**\n * BCP 47 locale used for number formatting (default: `'en-US'`).\n * Controls digit grouping and decimal separators.\n */\n locale?: string;\n /** How to display the currency symbol — `'symbol'` (default), `'code'`, or `'name'`. */\n display?: 'symbol' | 'code' | 'name';\n /** Font-size variant (default: `'md'`). */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** When `true`, applies a green tint for positive and red tint for negative values. */\n colorize?: boolean;\n};\n\n/**\n * Formats a numeric value as a locale-aware currency string in a table cell.\n * Always shows exactly two decimal places and uses the browser's `Intl` API for\n * symbol placement. Renders {@link UITableEmpty} when the value is absent or\n * invalid.\n *\n * @example\n * import { UITableCurrencyDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableCurrencyDisplay value={1234.5} currency=\"USD\" colorize />\n */\nexport const UITableCurrencyDisplay = memo(({ value, currency = 'USD', locale = 'en-US', display = 'symbol', size = 'md', colorize = false }: Props) => {\n const formatted = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n if (num === null || num === undefined || Number.isNaN(num) || !Number.isFinite(num)) return null;\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n currencyDisplay: display,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }).format(num);\n }, [value, currency, locale, display]);\n\n const isNegative = useMemo(() => {\n const num = typeof value === 'string' ? Number(value.trim()) : value;\n return typeof num === 'number' && num < 0;\n }, [value]);\n\n if (!formatted) return <UITableEmpty />;\n\n return (\n <p\n className={cn(\n 'font-number tabular-nums',\n size === 'xs' && 'text-xs',\n size === 'sm' && 'text-sm',\n size === 'md' && 'text-base',\n size === 'lg' && 'text-lg',\n size === 'xl' && 'text-xl',\n !colorize && 'text-text-positive',\n colorize && isNegative && 'text-danger-strong',\n colorize && !isNegative && 'text-success-strong'\n )}\n >\n {formatted}\n </p>\n );\n});\nUITableCurrencyDisplay.displayName = 'UITableCurrencyDisplay';\n"],"mappings":"2IAsCA,MAAa,GAAA,EAAA,EAAA,KAAA,EAA+B,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,UAAU,SAAU,OAAO,KAAM,WAAW,MAAmB,CACtJ,IAAM,GAAA,EAAA,EAAA,QAAA,KAA0B,CAC9B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAG/D,OAFI,GAAQ,MAA6B,OAAO,MAAM,CAAG,GAAK,CAAC,OAAO,SAAS,CAAG,EAAU,KAErF,IAAI,KAAK,aAAa,EAAQ,CACnC,MAAO,WACP,WACA,gBAAiB,EACjB,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,CAAC,CAAC,OAAO,CAAG,CACf,EAAG,CAAC,EAAO,EAAU,EAAQ,CAAO,CAAC,EAE/B,GAAA,EAAA,EAAA,QAAA,KAA2B,CAC/B,IAAM,EAAM,OAAO,GAAU,SAAW,OAAO,EAAM,KAAK,CAAC,EAAI,EAC/D,OAAO,OAAO,GAAQ,UAAY,EAAM,CAC1C,EAAG,CAAC,CAAK,CAAC,EAIV,OAFK,GAGH,EAAA,EAAA,IAAA,CAAC,IAAD,CACE,WAAA,EAAA,EAAA,GAAA,CACE,2BACA,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,YACjB,IAAS,MAAQ,UACjB,IAAS,MAAQ,UACjB,CAAC,GAAY,qBACb,GAAY,GAAc,qBAC1B,GAAY,CAAC,GAAc,qBAC7B,EAEC,SAAA,CACA,CAAA,GAjBkB,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,CAmBxC,CAAC,EACD,EAAuB,YAAc"}
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("@customafk/react-toolkit/utils"),n=require("class-variance-authority"),r=require("react/jsx-runtime");const i=(0,n.cva)(`inline-flex items-center gap-1 font-number tabular-nums transition-colors`,{variants:{size:{xs:`text-xs`,sm:`text-sm`,md:`text-base`,lg:`text-lg`,xl:`text-xl`},trend:{neutral:`text-text-positive-strong`,up:`text-success`,down:`text-danger`}},defaultVariants:{size:`lg`,trend:`neutral`}}),a=(0,e.memo)(({decimalSeparator:n=`.`,groupSeparator:a=`,`,prefix:o,suffix:s,precision:c,roundingMode:l=`round`,showTrailingZeros:u=!1,size:d=`lg`,trend:f=`neutral`,value:p,className:m})=>{let h=(0,e.useCallback)((e,t)=>{let n=10**t;switch(l){case`floor`:return Math.floor(e*n)/n;case`ceil`:return Math.ceil(e*n)/n;default:return Math.round(e*n)/n}},[l]),g=(0,e.useMemo)(()=>{let e={};return typeof c==`number`&&c>=0&&(u&&(e.minimumFractionDigits=c),e.maximumFractionDigits=c),e},[c,u]),_=(0,e.useCallback)(e=>{let t=e;return typeof c==`number`&&c>=0&&(t=h(e,c)),t.toLocaleString(`en-US`,g)},[h,g,c]),v=(0,e.useMemo)(()=>{if(typeof p==`number`)return Number.isNaN(p)||!Number.isFinite(p)?`N/A`:_(p);if(typeof p==`string`){let e=p.trim();if(!e)return`N/A`;let t=Number(e);return Number.isNaN(t)||!Number.isFinite(t)?`N/A`:_(t)}return`N/A`},[p,_]),y=(0,e.useMemo)(()=>n===`.`&&a===`,`?v:v.replace(/,/g,a).replace(/\./g,n),[v,n,a]);return(0,r.jsxs)(`div`,{"data-slot":`statistic`,className:(0,t.cn)(i({size:d,trend:f}),m),children:[o&&(0,r.jsx)(`span`,{"data-slot":`statistic-prefix`,children:o}),(0,r.jsx)(`p`,{"data-slot":`statistic-value`,children:y}),s&&(0,r.jsx)(`span`,{"data-slot":`statistic-suffix`,children:s})]})});a.displayName=`Statistic`,exports.Statistic=a;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("@customafk/react-toolkit/utils"),n=require("class-variance-authority"),r=require("react/jsx-runtime");const i=(0,n.cva)(`inline-flex items-center gap-1 font-number tabular-nums transition-colors`,{variants:{size:{xs:`text-xs`,sm:`text-sm`,md:`text-base`,lg:`text-lg`,xl:`text-xl`},trend:{neutral:`text-text-positive-strong`,up:`text-success`,down:`text-danger`}},defaultVariants:{size:`lg`,trend:`neutral`}}),a=(0,e.memo)(({decimalSeparator:n=`.`,groupSeparator:a=`,`,prefix:o,suffix:s,precision:c,roundingMode:l=`round`,showTrailingZeros:u=!1,size:d=`lg`,trend:f=`neutral`,value:p,className:m})=>{let h=(0,e.useCallback)((e,t)=>{let n=10**t;switch(l){case`floor`:return Math.floor(e*n)/n;case`ceil`:return Math.ceil(e*n)/n;default:return Math.round(e*n)/n}},[l]),g=(0,e.useMemo)(()=>{let e={};return typeof c==`number`&&c>=0&&(u&&(e.minimumFractionDigits=c),e.maximumFractionDigits=c),e},[c,u]),_=(0,e.useCallback)(e=>{let t=e;return typeof c==`number`&&c>=0&&(t=h(e,c)),t.toLocaleString(`vi-VN`,g)},[h,g,c]),v=(0,e.useMemo)(()=>{if(typeof p==`number`)return Number.isNaN(p)||!Number.isFinite(p)?`N/A`:_(p);if(typeof p==`string`){let e=p.trim();if(!e)return`N/A`;let t=Number(e);return Number.isNaN(t)||!Number.isFinite(t)?`N/A`:_(t)}return`N/A`},[p,_]),y=(0,e.useMemo)(()=>n===`.`&&a===`,`?v:v.replace(/,/g,a).replace(/\./g,n),[v,n,a]);return(0,r.jsxs)(`div`,{"data-slot":`statistic`,className:(0,t.cn)(i({size:d,trend:f}),m),children:[o&&(0,r.jsx)(`span`,{"data-slot":`statistic-prefix`,children:o}),(0,r.jsx)(`p`,{"data-slot":`statistic-value`,children:y}),s&&(0,r.jsx)(`span`,{"data-slot":`statistic-suffix`,children:s})]})});a.displayName=`Statistic`,exports.Statistic=a;
2
2
  //# sourceMappingURL=statistic.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"statistic.cjs","names":[],"sources":["../../packages/components/data-display/statistic.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useCallback, useMemo } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@customafk/react-toolkit/utils';\n\nconst statisticVariants = cva('inline-flex items-center gap-1 font-number tabular-nums transition-colors', {\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n },\n trend: {\n neutral: 'text-text-positive-strong',\n up: 'text-success',\n down: 'text-danger',\n },\n },\n defaultVariants: {\n size: 'lg',\n trend: 'neutral',\n },\n});\n\nexport type StatisticProps = VariantProps<typeof statisticVariants> & {\n /** Character used to separate the decimal part. Defaults to `'.'`. */\n decimalSeparator?: string;\n /** Character used to separate thousands groups. Defaults to `','`. */\n groupSeparator?: string;\n /** Optional node rendered before the numeric value (e.g. a currency symbol). */\n prefix?: React.ReactNode;\n /** Optional node rendered after the numeric value (e.g. a unit label). */\n suffix?: React.ReactNode;\n /** Number of decimal digits to display; omit to show all significant digits. */\n precision?: number;\n /** Rounding strategy applied before formatting. Defaults to `'round'`. */\n roundingMode?: 'round' | 'floor' | 'ceil';\n /** When `true`, pads the decimal part with trailing zeros up to `precision`. Defaults to `false`. */\n showTrailingZeros?: boolean;\n /** The numeric (or numeric-string) value to format and display. */\n value: number | string;\n /** Additional CSS classes applied to the wrapper element. */\n className?: string;\n /** Colour trend indicator: `'neutral'` (default), `'up'` (green), or `'down'` (red). */\n trend?: 'neutral' | 'up' | 'down';\n};\n\n/**\n * A memoised numeric display component with locale-aware formatting, optional prefix/suffix, trend colouring, and configurable rounding.\n *\n * @example\n * ```tsx\n * import { Statistic } from '@customafk/lunas-ui/data-display/statistic';\n *\n * <Statistic value={1234567.89} precision={2} prefix=\"$\" trend=\"up\" size=\"lg\" />\n * ```\n */\nexport const Statistic = memo(\n ({\n decimalSeparator = '.',\n groupSeparator = ',',\n prefix: Prefix,\n suffix: Suffix,\n precision,\n roundingMode = 'round',\n showTrailingZeros = false,\n size = 'lg',\n trend = 'neutral',\n value,\n className,\n }: StatisticProps) => {\n const applyRounding = useCallback(\n (num: number, precisionValue: number): number => {\n const multiplier = 10 ** precisionValue;\n switch (roundingMode) {\n case 'floor':\n return Math.floor(num * multiplier) / multiplier;\n case 'ceil':\n return Math.ceil(num * multiplier) / multiplier;\n default:\n return Math.round(num * multiplier) / multiplier;\n }\n },\n [roundingMode]\n );\n\n const formatOptions = useMemo((): Intl.NumberFormatOptions => {\n const options: Intl.NumberFormatOptions = {};\n if (typeof precision === 'number' && precision >= 0) {\n if (showTrailingZeros) {\n options.minimumFractionDigits = precision;\n options.maximumFractionDigits = precision;\n } else {\n options.maximumFractionDigits = precision;\n }\n }\n return options;\n }, [precision, showTrailingZeros]);\n\n const formatNumber = useCallback(\n (num: number): string => {\n let processedNum = num;\n if (typeof precision === 'number' && precision >= 0) {\n processedNum = applyRounding(num, precision);\n }\n return processedNum.toLocaleString('en-US', formatOptions);\n },\n [applyRounding, formatOptions, precision]\n );\n\n const processedValue = useMemo((): string => {\n if (typeof value === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) return 'N/A';\n return formatNumber(value);\n }\n if (typeof value === 'string') {\n const trimmedValue = value.trim();\n if (!trimmedValue) return 'N/A';\n const numValue = Number(trimmedValue);\n if (Number.isNaN(numValue) || !Number.isFinite(numValue)) return 'N/A';\n return formatNumber(numValue);\n }\n return 'N/A';\n }, [value, formatNumber]);\n\n const finalFormattedValue = useMemo((): string => {\n if (decimalSeparator === '.' && groupSeparator === ',') return processedValue;\n return processedValue.replace(/,/g, groupSeparator).replace(/\\./g, decimalSeparator);\n }, [processedValue, decimalSeparator, groupSeparator]);\n\n return (\n <div data-slot=\"statistic\" className={cn(statisticVariants({ size, trend }), className)}>\n {Prefix && <span data-slot=\"statistic-prefix\">{Prefix}</span>}\n <p data-slot=\"statistic-value\">{finalFormattedValue}</p>\n {Suffix && <span data-slot=\"statistic-suffix\">{Suffix}</span>}\n </div>\n );\n }\n);\nStatistic.displayName = 'Statistic';\n"],"mappings":"wNAMA,MAAM,GAAA,EAAA,EAAA,IAAA,CAAwB,4EAA6E,CACzG,SAAU,CACR,KAAM,CACJ,GAAI,UACJ,GAAI,UACJ,GAAI,YACJ,GAAI,UACJ,GAAI,SACN,EACA,MAAO,CACL,QAAS,4BACT,GAAI,eACJ,KAAM,aACR,CACF,EACA,gBAAiB,CACf,KAAM,KACN,MAAO,SACT,CACF,CAAC,EAmCY,GAAA,EAAA,EAAA,KAAA,EACV,CACC,mBAAmB,IACnB,iBAAiB,IACjB,OAAQ,EACR,OAAQ,EACR,YACA,eAAe,QACf,oBAAoB,GACpB,OAAO,KACP,QAAQ,UACR,QACA,eACoB,CACpB,IAAM,GAAA,EAAA,EAAA,YAAA,EACH,EAAa,IAAmC,CAC/C,IAAM,EAAa,IAAM,EACzB,OAAQ,EAAR,CACE,IAAK,QACH,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,EACxC,IAAK,OACH,OAAO,KAAK,KAAK,EAAM,CAAU,EAAI,EACvC,QACE,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,CAC1C,CACF,EACA,CAAC,CAAY,CACf,EAEM,GAAA,EAAA,EAAA,QAAA,KAAwD,CAC5D,IAAM,EAAoC,CAAC,EAS3C,OARI,OAAO,GAAc,UAAY,GAAa,IAC5C,IACF,EAAQ,sBAAwB,GAGhC,EAAQ,sBAAwB,GAG7B,CACT,EAAG,CAAC,EAAW,CAAiB,CAAC,EAE3B,GAAA,EAAA,EAAA,YAAA,CACH,GAAwB,CACvB,IAAI,EAAe,EAInB,OAHI,OAAO,GAAc,UAAY,GAAa,IAChD,EAAe,EAAc,EAAK,CAAS,GAEtC,EAAa,eAAe,QAAS,CAAa,CAC3D,EACA,CAAC,EAAe,EAAe,CAAS,CAC1C,EAEM,GAAA,EAAA,EAAA,QAAA,KAAuC,CAC3C,GAAI,OAAO,GAAU,SAEnB,OADI,OAAO,MAAM,CAAK,GAAK,CAAC,OAAO,SAAS,CAAK,EAAU,MACpD,EAAa,CAAK,EAE3B,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAe,EAAM,KAAK,EAChC,GAAI,CAAC,EAAc,MAAO,MAC1B,IAAM,EAAW,OAAO,CAAY,EAEpC,OADI,OAAO,MAAM,CAAQ,GAAK,CAAC,OAAO,SAAS,CAAQ,EAAU,MAC1D,EAAa,CAAQ,CAC9B,CACA,MAAO,KACT,EAAG,CAAC,EAAO,CAAY,CAAC,EAElB,GAAA,EAAA,EAAA,QAAA,KACA,IAAqB,KAAO,IAAmB,IAAY,EACxD,EAAe,QAAQ,KAAM,CAAc,CAAC,CAAC,QAAQ,MAAO,CAAgB,EAClF,CAAC,EAAgB,EAAkB,CAAc,CAAC,EAErD,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,YAAU,YAAY,WAAA,EAAA,EAAA,GAAA,CAAc,EAAkB,CAAE,OAAM,OAAM,CAAC,EAAG,CAAS,EAAtF,SAAA,CACG,IAAU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,GAC5D,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,YAAU,kBAAmB,SAAA,CAAuB,CAAA,EACtD,IAAU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,CACzD,GAET,CACF,EACA,EAAU,YAAc"}
1
+ {"version":3,"file":"statistic.cjs","names":[],"sources":["../../packages/components/data-display/statistic.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useCallback, useMemo } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@customafk/react-toolkit/utils';\n\nconst statisticVariants = cva('inline-flex items-center gap-1 font-number tabular-nums transition-colors', {\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n },\n trend: {\n neutral: 'text-text-positive-strong',\n up: 'text-success',\n down: 'text-danger',\n },\n },\n defaultVariants: {\n size: 'lg',\n trend: 'neutral',\n },\n});\n\nexport type StatisticProps = VariantProps<typeof statisticVariants> & {\n /** Character used to separate the decimal part. Defaults to `'.'`. */\n decimalSeparator?: string;\n /** Character used to separate thousands groups. Defaults to `','`. */\n groupSeparator?: string;\n /** Optional node rendered before the numeric value (e.g. a currency symbol). */\n prefix?: React.ReactNode;\n /** Optional node rendered after the numeric value (e.g. a unit label). */\n suffix?: React.ReactNode;\n /** Number of decimal digits to display; omit to show all significant digits. */\n precision?: number;\n /** Rounding strategy applied before formatting. Defaults to `'round'`. */\n roundingMode?: 'round' | 'floor' | 'ceil';\n /** When `true`, pads the decimal part with trailing zeros up to `precision`. Defaults to `false`. */\n showTrailingZeros?: boolean;\n /** The numeric (or numeric-string) value to format and display. */\n value: number | string;\n /** Additional CSS classes applied to the wrapper element. */\n className?: string;\n /** Colour trend indicator: `'neutral'` (default), `'up'` (green), or `'down'` (red). */\n trend?: 'neutral' | 'up' | 'down';\n};\n\n/**\n * A memoised numeric display component with locale-aware formatting, optional prefix/suffix, trend colouring, and configurable rounding.\n *\n * @example\n * ```tsx\n * import { Statistic } from '@customafk/lunas-ui/data-display/statistic';\n *\n * <Statistic value={1234567.89} precision={2} prefix=\"$\" trend=\"up\" size=\"lg\" />\n * ```\n */\nexport const Statistic = memo(\n ({\n decimalSeparator = '.',\n groupSeparator = ',',\n prefix: Prefix,\n suffix: Suffix,\n precision,\n roundingMode = 'round',\n showTrailingZeros = false,\n size = 'lg',\n trend = 'neutral',\n value,\n className,\n }: StatisticProps) => {\n const applyRounding = useCallback(\n (num: number, precisionValue: number): number => {\n const multiplier = 10 ** precisionValue;\n switch (roundingMode) {\n case 'floor':\n return Math.floor(num * multiplier) / multiplier;\n case 'ceil':\n return Math.ceil(num * multiplier) / multiplier;\n default:\n return Math.round(num * multiplier) / multiplier;\n }\n },\n [roundingMode]\n );\n\n const formatOptions = useMemo((): Intl.NumberFormatOptions => {\n const options: Intl.NumberFormatOptions = {};\n if (typeof precision === 'number' && precision >= 0) {\n if (showTrailingZeros) {\n options.minimumFractionDigits = precision;\n options.maximumFractionDigits = precision;\n } else {\n options.maximumFractionDigits = precision;\n }\n }\n return options;\n }, [precision, showTrailingZeros]);\n\n const formatNumber = useCallback(\n (num: number): string => {\n let processedNum = num;\n if (typeof precision === 'number' && precision >= 0) {\n processedNum = applyRounding(num, precision);\n }\n return processedNum.toLocaleString('vi-VN', formatOptions);\n },\n [applyRounding, formatOptions, precision]\n );\n\n const processedValue = useMemo((): string => {\n if (typeof value === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) return 'N/A';\n return formatNumber(value);\n }\n if (typeof value === 'string') {\n const trimmedValue = value.trim();\n if (!trimmedValue) return 'N/A';\n const numValue = Number(trimmedValue);\n if (Number.isNaN(numValue) || !Number.isFinite(numValue)) return 'N/A';\n return formatNumber(numValue);\n }\n return 'N/A';\n }, [value, formatNumber]);\n\n const finalFormattedValue = useMemo((): string => {\n if (decimalSeparator === '.' && groupSeparator === ',') return processedValue;\n return processedValue.replace(/,/g, groupSeparator).replace(/\\./g, decimalSeparator);\n }, [processedValue, decimalSeparator, groupSeparator]);\n\n return (\n <div data-slot=\"statistic\" className={cn(statisticVariants({ size, trend }), className)}>\n {Prefix && <span data-slot=\"statistic-prefix\">{Prefix}</span>}\n <p data-slot=\"statistic-value\">{finalFormattedValue}</p>\n {Suffix && <span data-slot=\"statistic-suffix\">{Suffix}</span>}\n </div>\n );\n }\n);\nStatistic.displayName = 'Statistic';\n"],"mappings":"wNAMA,MAAM,GAAA,EAAA,EAAA,IAAA,CAAwB,4EAA6E,CACzG,SAAU,CACR,KAAM,CACJ,GAAI,UACJ,GAAI,UACJ,GAAI,YACJ,GAAI,UACJ,GAAI,SACN,EACA,MAAO,CACL,QAAS,4BACT,GAAI,eACJ,KAAM,aACR,CACF,EACA,gBAAiB,CACf,KAAM,KACN,MAAO,SACT,CACF,CAAC,EAmCY,GAAA,EAAA,EAAA,KAAA,EACV,CACC,mBAAmB,IACnB,iBAAiB,IACjB,OAAQ,EACR,OAAQ,EACR,YACA,eAAe,QACf,oBAAoB,GACpB,OAAO,KACP,QAAQ,UACR,QACA,eACoB,CACpB,IAAM,GAAA,EAAA,EAAA,YAAA,EACH,EAAa,IAAmC,CAC/C,IAAM,EAAa,IAAM,EACzB,OAAQ,EAAR,CACE,IAAK,QACH,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,EACxC,IAAK,OACH,OAAO,KAAK,KAAK,EAAM,CAAU,EAAI,EACvC,QACE,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,CAC1C,CACF,EACA,CAAC,CAAY,CACf,EAEM,GAAA,EAAA,EAAA,QAAA,KAAwD,CAC5D,IAAM,EAAoC,CAAC,EAS3C,OARI,OAAO,GAAc,UAAY,GAAa,IAC5C,IACF,EAAQ,sBAAwB,GAGhC,EAAQ,sBAAwB,GAG7B,CACT,EAAG,CAAC,EAAW,CAAiB,CAAC,EAE3B,GAAA,EAAA,EAAA,YAAA,CACH,GAAwB,CACvB,IAAI,EAAe,EAInB,OAHI,OAAO,GAAc,UAAY,GAAa,IAChD,EAAe,EAAc,EAAK,CAAS,GAEtC,EAAa,eAAe,QAAS,CAAa,CAC3D,EACA,CAAC,EAAe,EAAe,CAAS,CAC1C,EAEM,GAAA,EAAA,EAAA,QAAA,KAAuC,CAC3C,GAAI,OAAO,GAAU,SAEnB,OADI,OAAO,MAAM,CAAK,GAAK,CAAC,OAAO,SAAS,CAAK,EAAU,MACpD,EAAa,CAAK,EAE3B,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAe,EAAM,KAAK,EAChC,GAAI,CAAC,EAAc,MAAO,MAC1B,IAAM,EAAW,OAAO,CAAY,EAEpC,OADI,OAAO,MAAM,CAAQ,GAAK,CAAC,OAAO,SAAS,CAAQ,EAAU,MAC1D,EAAa,CAAQ,CAC9B,CACA,MAAO,KACT,EAAG,CAAC,EAAO,CAAY,CAAC,EAElB,GAAA,EAAA,EAAA,QAAA,KACA,IAAqB,KAAO,IAAmB,IAAY,EACxD,EAAe,QAAQ,KAAM,CAAc,CAAC,CAAC,QAAQ,MAAO,CAAgB,EAClF,CAAC,EAAgB,EAAkB,CAAc,CAAC,EAErD,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,YAAU,YAAY,WAAA,EAAA,EAAA,GAAA,CAAc,EAAkB,CAAE,OAAM,OAAM,CAAC,EAAG,CAAS,EAAtF,SAAA,CACG,IAAU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,GAC5D,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,YAAU,kBAAmB,SAAA,CAAuB,CAAA,EACtD,IAAU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,CACzD,GAET,CACF,EACA,EAAU,YAAc"}
@@ -1,2 +1,2 @@
1
- "use client";import{memo as e,useCallback as t,useMemo as n}from"react";import{cn as r}from"@customafk/react-toolkit/utils";import{cva as i}from"class-variance-authority";import{jsx as a,jsxs as o}from"react/jsx-runtime";const s=i(`inline-flex items-center gap-1 font-number tabular-nums transition-colors`,{variants:{size:{xs:`text-xs`,sm:`text-sm`,md:`text-base`,lg:`text-lg`,xl:`text-xl`},trend:{neutral:`text-text-positive-strong`,up:`text-success`,down:`text-danger`}},defaultVariants:{size:`lg`,trend:`neutral`}}),c=e(({decimalSeparator:e=`.`,groupSeparator:i=`,`,prefix:c,suffix:l,precision:u,roundingMode:d=`round`,showTrailingZeros:f=!1,size:p=`lg`,trend:m=`neutral`,value:h,className:g})=>{let _=t((e,t)=>{let n=10**t;switch(d){case`floor`:return Math.floor(e*n)/n;case`ceil`:return Math.ceil(e*n)/n;default:return Math.round(e*n)/n}},[d]),v=n(()=>{let e={};return typeof u==`number`&&u>=0&&(f&&(e.minimumFractionDigits=u),e.maximumFractionDigits=u),e},[u,f]),y=t(e=>{let t=e;return typeof u==`number`&&u>=0&&(t=_(e,u)),t.toLocaleString(`en-US`,v)},[_,v,u]),b=n(()=>{if(typeof h==`number`)return Number.isNaN(h)||!Number.isFinite(h)?`N/A`:y(h);if(typeof h==`string`){let e=h.trim();if(!e)return`N/A`;let t=Number(e);return Number.isNaN(t)||!Number.isFinite(t)?`N/A`:y(t)}return`N/A`},[h,y]),x=n(()=>e===`.`&&i===`,`?b:b.replace(/,/g,i).replace(/\./g,e),[b,e,i]);return o(`div`,{"data-slot":`statistic`,className:r(s({size:p,trend:m}),g),children:[c&&a(`span`,{"data-slot":`statistic-prefix`,children:c}),a(`p`,{"data-slot":`statistic-value`,children:x}),l&&a(`span`,{"data-slot":`statistic-suffix`,children:l})]})});c.displayName=`Statistic`;export{c as Statistic};
1
+ "use client";import{memo as e,useCallback as t,useMemo as n}from"react";import{cn as r}from"@customafk/react-toolkit/utils";import{cva as i}from"class-variance-authority";import{jsx as a,jsxs as o}from"react/jsx-runtime";const s=i(`inline-flex items-center gap-1 font-number tabular-nums transition-colors`,{variants:{size:{xs:`text-xs`,sm:`text-sm`,md:`text-base`,lg:`text-lg`,xl:`text-xl`},trend:{neutral:`text-text-positive-strong`,up:`text-success`,down:`text-danger`}},defaultVariants:{size:`lg`,trend:`neutral`}}),c=e(({decimalSeparator:e=`.`,groupSeparator:i=`,`,prefix:c,suffix:l,precision:u,roundingMode:d=`round`,showTrailingZeros:f=!1,size:p=`lg`,trend:m=`neutral`,value:h,className:g})=>{let _=t((e,t)=>{let n=10**t;switch(d){case`floor`:return Math.floor(e*n)/n;case`ceil`:return Math.ceil(e*n)/n;default:return Math.round(e*n)/n}},[d]),v=n(()=>{let e={};return typeof u==`number`&&u>=0&&(f&&(e.minimumFractionDigits=u),e.maximumFractionDigits=u),e},[u,f]),y=t(e=>{let t=e;return typeof u==`number`&&u>=0&&(t=_(e,u)),t.toLocaleString(`vi-VN`,v)},[_,v,u]),b=n(()=>{if(typeof h==`number`)return Number.isNaN(h)||!Number.isFinite(h)?`N/A`:y(h);if(typeof h==`string`){let e=h.trim();if(!e)return`N/A`;let t=Number(e);return Number.isNaN(t)||!Number.isFinite(t)?`N/A`:y(t)}return`N/A`},[h,y]),x=n(()=>e===`.`&&i===`,`?b:b.replace(/,/g,i).replace(/\./g,e),[b,e,i]);return o(`div`,{"data-slot":`statistic`,className:r(s({size:p,trend:m}),g),children:[c&&a(`span`,{"data-slot":`statistic-prefix`,children:c}),a(`p`,{"data-slot":`statistic-value`,children:x}),l&&a(`span`,{"data-slot":`statistic-suffix`,children:l})]})});c.displayName=`Statistic`;export{c as Statistic};
2
2
  //# sourceMappingURL=statistic.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"statistic.mjs","names":[],"sources":["../../packages/components/data-display/statistic.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useCallback, useMemo } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@customafk/react-toolkit/utils';\n\nconst statisticVariants = cva('inline-flex items-center gap-1 font-number tabular-nums transition-colors', {\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n },\n trend: {\n neutral: 'text-text-positive-strong',\n up: 'text-success',\n down: 'text-danger',\n },\n },\n defaultVariants: {\n size: 'lg',\n trend: 'neutral',\n },\n});\n\nexport type StatisticProps = VariantProps<typeof statisticVariants> & {\n /** Character used to separate the decimal part. Defaults to `'.'`. */\n decimalSeparator?: string;\n /** Character used to separate thousands groups. Defaults to `','`. */\n groupSeparator?: string;\n /** Optional node rendered before the numeric value (e.g. a currency symbol). */\n prefix?: React.ReactNode;\n /** Optional node rendered after the numeric value (e.g. a unit label). */\n suffix?: React.ReactNode;\n /** Number of decimal digits to display; omit to show all significant digits. */\n precision?: number;\n /** Rounding strategy applied before formatting. Defaults to `'round'`. */\n roundingMode?: 'round' | 'floor' | 'ceil';\n /** When `true`, pads the decimal part with trailing zeros up to `precision`. Defaults to `false`. */\n showTrailingZeros?: boolean;\n /** The numeric (or numeric-string) value to format and display. */\n value: number | string;\n /** Additional CSS classes applied to the wrapper element. */\n className?: string;\n /** Colour trend indicator: `'neutral'` (default), `'up'` (green), or `'down'` (red). */\n trend?: 'neutral' | 'up' | 'down';\n};\n\n/**\n * A memoised numeric display component with locale-aware formatting, optional prefix/suffix, trend colouring, and configurable rounding.\n *\n * @example\n * ```tsx\n * import { Statistic } from '@customafk/lunas-ui/data-display/statistic';\n *\n * <Statistic value={1234567.89} precision={2} prefix=\"$\" trend=\"up\" size=\"lg\" />\n * ```\n */\nexport const Statistic = memo(\n ({\n decimalSeparator = '.',\n groupSeparator = ',',\n prefix: Prefix,\n suffix: Suffix,\n precision,\n roundingMode = 'round',\n showTrailingZeros = false,\n size = 'lg',\n trend = 'neutral',\n value,\n className,\n }: StatisticProps) => {\n const applyRounding = useCallback(\n (num: number, precisionValue: number): number => {\n const multiplier = 10 ** precisionValue;\n switch (roundingMode) {\n case 'floor':\n return Math.floor(num * multiplier) / multiplier;\n case 'ceil':\n return Math.ceil(num * multiplier) / multiplier;\n default:\n return Math.round(num * multiplier) / multiplier;\n }\n },\n [roundingMode]\n );\n\n const formatOptions = useMemo((): Intl.NumberFormatOptions => {\n const options: Intl.NumberFormatOptions = {};\n if (typeof precision === 'number' && precision >= 0) {\n if (showTrailingZeros) {\n options.minimumFractionDigits = precision;\n options.maximumFractionDigits = precision;\n } else {\n options.maximumFractionDigits = precision;\n }\n }\n return options;\n }, [precision, showTrailingZeros]);\n\n const formatNumber = useCallback(\n (num: number): string => {\n let processedNum = num;\n if (typeof precision === 'number' && precision >= 0) {\n processedNum = applyRounding(num, precision);\n }\n return processedNum.toLocaleString('en-US', formatOptions);\n },\n [applyRounding, formatOptions, precision]\n );\n\n const processedValue = useMemo((): string => {\n if (typeof value === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) return 'N/A';\n return formatNumber(value);\n }\n if (typeof value === 'string') {\n const trimmedValue = value.trim();\n if (!trimmedValue) return 'N/A';\n const numValue = Number(trimmedValue);\n if (Number.isNaN(numValue) || !Number.isFinite(numValue)) return 'N/A';\n return formatNumber(numValue);\n }\n return 'N/A';\n }, [value, formatNumber]);\n\n const finalFormattedValue = useMemo((): string => {\n if (decimalSeparator === '.' && groupSeparator === ',') return processedValue;\n return processedValue.replace(/,/g, groupSeparator).replace(/\\./g, decimalSeparator);\n }, [processedValue, decimalSeparator, groupSeparator]);\n\n return (\n <div data-slot=\"statistic\" className={cn(statisticVariants({ size, trend }), className)}>\n {Prefix && <span data-slot=\"statistic-prefix\">{Prefix}</span>}\n <p data-slot=\"statistic-value\">{finalFormattedValue}</p>\n {Suffix && <span data-slot=\"statistic-suffix\">{Suffix}</span>}\n </div>\n );\n }\n);\nStatistic.displayName = 'Statistic';\n"],"mappings":"6NAMA,MAAM,EAAoB,EAAI,4EAA6E,CACzG,SAAU,CACR,KAAM,CACJ,GAAI,UACJ,GAAI,UACJ,GAAI,YACJ,GAAI,UACJ,GAAI,SACN,EACA,MAAO,CACL,QAAS,4BACT,GAAI,eACJ,KAAM,aACR,CACF,EACA,gBAAiB,CACf,KAAM,KACN,MAAO,SACT,CACF,CAAC,EAmCY,EAAY,GACtB,CACC,mBAAmB,IACnB,iBAAiB,IACjB,OAAQ,EACR,OAAQ,EACR,YACA,eAAe,QACf,oBAAoB,GACpB,OAAO,KACP,QAAQ,UACR,QACA,eACoB,CACpB,IAAM,EAAgB,GACnB,EAAa,IAAmC,CAC/C,IAAM,EAAa,IAAM,EACzB,OAAQ,EAAR,CACE,IAAK,QACH,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,EACxC,IAAK,OACH,OAAO,KAAK,KAAK,EAAM,CAAU,EAAI,EACvC,QACE,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,CAC1C,CACF,EACA,CAAC,CAAY,CACf,EAEM,EAAgB,MAAwC,CAC5D,IAAM,EAAoC,CAAC,EAS3C,OARI,OAAO,GAAc,UAAY,GAAa,IAC5C,IACF,EAAQ,sBAAwB,GAGhC,EAAQ,sBAAwB,GAG7B,CACT,EAAG,CAAC,EAAW,CAAiB,CAAC,EAE3B,EAAe,EAClB,GAAwB,CACvB,IAAI,EAAe,EAInB,OAHI,OAAO,GAAc,UAAY,GAAa,IAChD,EAAe,EAAc,EAAK,CAAS,GAEtC,EAAa,eAAe,QAAS,CAAa,CAC3D,EACA,CAAC,EAAe,EAAe,CAAS,CAC1C,EAEM,EAAiB,MAAsB,CAC3C,GAAI,OAAO,GAAU,SAEnB,OADI,OAAO,MAAM,CAAK,GAAK,CAAC,OAAO,SAAS,CAAK,EAAU,MACpD,EAAa,CAAK,EAE3B,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAe,EAAM,KAAK,EAChC,GAAI,CAAC,EAAc,MAAO,MAC1B,IAAM,EAAW,OAAO,CAAY,EAEpC,OADI,OAAO,MAAM,CAAQ,GAAK,CAAC,OAAO,SAAS,CAAQ,EAAU,MAC1D,EAAa,CAAQ,CAC9B,CACA,MAAO,KACT,EAAG,CAAC,EAAO,CAAY,CAAC,EAElB,EAAsB,MACtB,IAAqB,KAAO,IAAmB,IAAY,EACxD,EAAe,QAAQ,KAAM,CAAc,CAAC,CAAC,QAAQ,MAAO,CAAgB,EAClF,CAAC,EAAgB,EAAkB,CAAc,CAAC,EAErD,OACE,EAAC,MAAD,CAAK,YAAU,YAAY,UAAW,EAAG,EAAkB,CAAE,OAAM,OAAM,CAAC,EAAG,CAAS,EAAtF,SAAA,CACG,GAAU,EAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,EAC5D,EAAC,IAAD,CAAG,YAAU,kBAAmB,SAAA,CAAuB,CAAA,EACtD,GAAU,EAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,CACzD,GAET,CACF,EACA,EAAU,YAAc"}
1
+ {"version":3,"file":"statistic.mjs","names":[],"sources":["../../packages/components/data-display/statistic.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useCallback, useMemo } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@customafk/react-toolkit/utils';\n\nconst statisticVariants = cva('inline-flex items-center gap-1 font-number tabular-nums transition-colors', {\n variants: {\n size: {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n },\n trend: {\n neutral: 'text-text-positive-strong',\n up: 'text-success',\n down: 'text-danger',\n },\n },\n defaultVariants: {\n size: 'lg',\n trend: 'neutral',\n },\n});\n\nexport type StatisticProps = VariantProps<typeof statisticVariants> & {\n /** Character used to separate the decimal part. Defaults to `'.'`. */\n decimalSeparator?: string;\n /** Character used to separate thousands groups. Defaults to `','`. */\n groupSeparator?: string;\n /** Optional node rendered before the numeric value (e.g. a currency symbol). */\n prefix?: React.ReactNode;\n /** Optional node rendered after the numeric value (e.g. a unit label). */\n suffix?: React.ReactNode;\n /** Number of decimal digits to display; omit to show all significant digits. */\n precision?: number;\n /** Rounding strategy applied before formatting. Defaults to `'round'`. */\n roundingMode?: 'round' | 'floor' | 'ceil';\n /** When `true`, pads the decimal part with trailing zeros up to `precision`. Defaults to `false`. */\n showTrailingZeros?: boolean;\n /** The numeric (or numeric-string) value to format and display. */\n value: number | string;\n /** Additional CSS classes applied to the wrapper element. */\n className?: string;\n /** Colour trend indicator: `'neutral'` (default), `'up'` (green), or `'down'` (red). */\n trend?: 'neutral' | 'up' | 'down';\n};\n\n/**\n * A memoised numeric display component with locale-aware formatting, optional prefix/suffix, trend colouring, and configurable rounding.\n *\n * @example\n * ```tsx\n * import { Statistic } from '@customafk/lunas-ui/data-display/statistic';\n *\n * <Statistic value={1234567.89} precision={2} prefix=\"$\" trend=\"up\" size=\"lg\" />\n * ```\n */\nexport const Statistic = memo(\n ({\n decimalSeparator = '.',\n groupSeparator = ',',\n prefix: Prefix,\n suffix: Suffix,\n precision,\n roundingMode = 'round',\n showTrailingZeros = false,\n size = 'lg',\n trend = 'neutral',\n value,\n className,\n }: StatisticProps) => {\n const applyRounding = useCallback(\n (num: number, precisionValue: number): number => {\n const multiplier = 10 ** precisionValue;\n switch (roundingMode) {\n case 'floor':\n return Math.floor(num * multiplier) / multiplier;\n case 'ceil':\n return Math.ceil(num * multiplier) / multiplier;\n default:\n return Math.round(num * multiplier) / multiplier;\n }\n },\n [roundingMode]\n );\n\n const formatOptions = useMemo((): Intl.NumberFormatOptions => {\n const options: Intl.NumberFormatOptions = {};\n if (typeof precision === 'number' && precision >= 0) {\n if (showTrailingZeros) {\n options.minimumFractionDigits = precision;\n options.maximumFractionDigits = precision;\n } else {\n options.maximumFractionDigits = precision;\n }\n }\n return options;\n }, [precision, showTrailingZeros]);\n\n const formatNumber = useCallback(\n (num: number): string => {\n let processedNum = num;\n if (typeof precision === 'number' && precision >= 0) {\n processedNum = applyRounding(num, precision);\n }\n return processedNum.toLocaleString('vi-VN', formatOptions);\n },\n [applyRounding, formatOptions, precision]\n );\n\n const processedValue = useMemo((): string => {\n if (typeof value === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) return 'N/A';\n return formatNumber(value);\n }\n if (typeof value === 'string') {\n const trimmedValue = value.trim();\n if (!trimmedValue) return 'N/A';\n const numValue = Number(trimmedValue);\n if (Number.isNaN(numValue) || !Number.isFinite(numValue)) return 'N/A';\n return formatNumber(numValue);\n }\n return 'N/A';\n }, [value, formatNumber]);\n\n const finalFormattedValue = useMemo((): string => {\n if (decimalSeparator === '.' && groupSeparator === ',') return processedValue;\n return processedValue.replace(/,/g, groupSeparator).replace(/\\./g, decimalSeparator);\n }, [processedValue, decimalSeparator, groupSeparator]);\n\n return (\n <div data-slot=\"statistic\" className={cn(statisticVariants({ size, trend }), className)}>\n {Prefix && <span data-slot=\"statistic-prefix\">{Prefix}</span>}\n <p data-slot=\"statistic-value\">{finalFormattedValue}</p>\n {Suffix && <span data-slot=\"statistic-suffix\">{Suffix}</span>}\n </div>\n );\n }\n);\nStatistic.displayName = 'Statistic';\n"],"mappings":"6NAMA,MAAM,EAAoB,EAAI,4EAA6E,CACzG,SAAU,CACR,KAAM,CACJ,GAAI,UACJ,GAAI,UACJ,GAAI,YACJ,GAAI,UACJ,GAAI,SACN,EACA,MAAO,CACL,QAAS,4BACT,GAAI,eACJ,KAAM,aACR,CACF,EACA,gBAAiB,CACf,KAAM,KACN,MAAO,SACT,CACF,CAAC,EAmCY,EAAY,GACtB,CACC,mBAAmB,IACnB,iBAAiB,IACjB,OAAQ,EACR,OAAQ,EACR,YACA,eAAe,QACf,oBAAoB,GACpB,OAAO,KACP,QAAQ,UACR,QACA,eACoB,CACpB,IAAM,EAAgB,GACnB,EAAa,IAAmC,CAC/C,IAAM,EAAa,IAAM,EACzB,OAAQ,EAAR,CACE,IAAK,QACH,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,EACxC,IAAK,OACH,OAAO,KAAK,KAAK,EAAM,CAAU,EAAI,EACvC,QACE,OAAO,KAAK,MAAM,EAAM,CAAU,EAAI,CAC1C,CACF,EACA,CAAC,CAAY,CACf,EAEM,EAAgB,MAAwC,CAC5D,IAAM,EAAoC,CAAC,EAS3C,OARI,OAAO,GAAc,UAAY,GAAa,IAC5C,IACF,EAAQ,sBAAwB,GAGhC,EAAQ,sBAAwB,GAG7B,CACT,EAAG,CAAC,EAAW,CAAiB,CAAC,EAE3B,EAAe,EAClB,GAAwB,CACvB,IAAI,EAAe,EAInB,OAHI,OAAO,GAAc,UAAY,GAAa,IAChD,EAAe,EAAc,EAAK,CAAS,GAEtC,EAAa,eAAe,QAAS,CAAa,CAC3D,EACA,CAAC,EAAe,EAAe,CAAS,CAC1C,EAEM,EAAiB,MAAsB,CAC3C,GAAI,OAAO,GAAU,SAEnB,OADI,OAAO,MAAM,CAAK,GAAK,CAAC,OAAO,SAAS,CAAK,EAAU,MACpD,EAAa,CAAK,EAE3B,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAe,EAAM,KAAK,EAChC,GAAI,CAAC,EAAc,MAAO,MAC1B,IAAM,EAAW,OAAO,CAAY,EAEpC,OADI,OAAO,MAAM,CAAQ,GAAK,CAAC,OAAO,SAAS,CAAQ,EAAU,MAC1D,EAAa,CAAQ,CAC9B,CACA,MAAO,KACT,EAAG,CAAC,EAAO,CAAY,CAAC,EAElB,EAAsB,MACtB,IAAqB,KAAO,IAAmB,IAAY,EACxD,EAAe,QAAQ,KAAM,CAAc,CAAC,CAAC,QAAQ,MAAO,CAAgB,EAClF,CAAC,EAAgB,EAAkB,CAAc,CAAC,EAErD,OACE,EAAC,MAAD,CAAK,YAAU,YAAY,UAAW,EAAG,EAAkB,CAAE,OAAM,OAAM,CAAC,EAAG,CAAS,EAAtF,SAAA,CACG,GAAU,EAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,EAC5D,EAAC,IAAD,CAAG,YAAU,kBAAmB,SAAA,CAAuB,CAAA,EACtD,GAAU,EAAC,OAAD,CAAM,YAAU,mBAAoB,SAAA,CAAa,CAAA,CACzD,GAET,CACF,EACA,EAAU,YAAc"}
@@ -0,0 +1,2 @@
1
+ const e=require("./date-B3cozmfV.cjs"),t=require("./ui/tooltip.cjs"),n=require("./tables-CS3NhgTc.cjs");let r=require("react/jsx-runtime");const i=({date:i})=>i==null?(0,r.jsx)(n.Q,{}):(0,r.jsx)(t.TooltipProvider,{children:(0,r.jsxs)(t.Tooltip,{children:[(0,r.jsx)(t.TooltipTrigger,{asChild:!0,children:(0,r.jsx)(e.t,{date:i,format:`medium`})}),(0,r.jsx)(t.TooltipContent,{className:`rounded px-2`,children:(0,r.jsx)(e.t,{date:i,format:`full`,showTime:!0,className:`font-medium text-text-negative text-xs`})})]})});exports.UITableDateDisplay=i;
2
+ //# sourceMappingURL=date-display-DMPhFq8v.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-display-DMPhFq8v.cjs","names":["UITableEmpty","TooltipProvider","Tooltip","TooltipTrigger","DateDisplay","TooltipContent"],"sources":["../packages/components/features/tables/components/atoms/date-display.tsx"],"sourcesContent":["// import { Badge } from '@/components/ui/badge';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { DateDisplay } from '@/components/data-display/date';\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableDateDisplay} component. */\ntype Props = {\n /** The date value to format and display; `null`/`undefined` renders an empty state. */\n date: Date | string | number | null | undefined;\n};\n\n/**\n * Displays a date as a compact badge in a table cell with a tooltip that shows\n * the full date and time on hover; renders {@link UITableEmpty} when `date` is\n * `null` or `undefined`.\n *\n * @example\n * import { UITableDateDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDateDisplay date={new Date('2024-06-15T10:30:00Z')} />\n */\nexport const UITableDateDisplay: React.FC<Props> = ({ date }) => {\n if (typeof date === 'undefined' || date === null) return <UITableEmpty />;\n return (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n {/*<Badge className=\"h-fit\">*/}\n <DateDisplay date={date} format=\"medium\" />\n {/*</Badge>*/}\n </TooltipTrigger>\n <TooltipContent className=\"rounded px-2\">\n <DateDisplay date={date} format=\"full\" showTime className=\"font-medium text-text-negative text-xs\" />\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n};\n"],"mappings":"2IAsBA,MAAa,GAAuC,CAAE,UACzC,GAAiC,MAAa,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,GAEtE,EAAA,EAAA,IAAA,CAACC,EAAAA,gBAAD,CAAA,UACE,EAAA,EAAA,KAAA,CAACC,EAAAA,QAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAgB,QAAA,GAEd,UAAA,EAAA,EAAA,IAAA,CAACC,EAAAA,EAAD,CAAmB,OAAM,OAAO,QAAU,CAAA,CAE5B,CAAA,GAChB,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAgB,UAAU,eACxB,UAAA,EAAA,EAAA,IAAA,CAACD,EAAAA,EAAD,CAAmB,OAAM,OAAO,OAAO,SAAA,GAAS,UAAU,wCAA0C,CAAA,CACtF,CAAA,CACT,CAAA,CAAA,CACM,CAAA"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./date-Nsz0Pewe.mjs";import{Tooltip as t,TooltipContent as n,TooltipProvider as r,TooltipTrigger as i}from"./ui/tooltip.mjs";import{Q as a}from"./tables-7_KgoyS-.mjs";import{jsx as o,jsxs as s}from"react/jsx-runtime";const c=({date:c})=>c==null?o(a,{}):o(r,{children:s(t,{children:[o(i,{asChild:!0,children:o(e,{date:c,format:`medium`})}),o(n,{className:`rounded px-2`,children:o(e,{date:c,format:`full`,showTime:!0,className:`font-medium text-text-negative text-xs`})})]})});export{c as UITableDateDisplay};
2
+ //# sourceMappingURL=date-display-YE8NIIrl.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-display-YE8NIIrl.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/date-display.tsx"],"sourcesContent":["// import { Badge } from '@/components/ui/badge';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { DateDisplay } from '@/components/data-display/date';\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableDateDisplay} component. */\ntype Props = {\n /** The date value to format and display; `null`/`undefined` renders an empty state. */\n date: Date | string | number | null | undefined;\n};\n\n/**\n * Displays a date as a compact badge in a table cell with a tooltip that shows\n * the full date and time on hover; renders {@link UITableEmpty} when `date` is\n * `null` or `undefined`.\n *\n * @example\n * import { UITableDateDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDateDisplay date={new Date('2024-06-15T10:30:00Z')} />\n */\nexport const UITableDateDisplay: React.FC<Props> = ({ date }) => {\n if (typeof date === 'undefined' || date === null) return <UITableEmpty />;\n return (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n {/*<Badge className=\"h-fit\">*/}\n <DateDisplay date={date} format=\"medium\" />\n {/*</Badge>*/}\n </TooltipTrigger>\n <TooltipContent className=\"rounded px-2\">\n <DateDisplay date={date} format=\"full\" showTime className=\"font-medium text-text-negative text-xs\" />\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n};\n"],"mappings":"4OAsBA,MAAa,GAAuC,CAAE,UACzC,GAAiC,KAAa,EAAC,EAAD,CAAe,CAAA,EAEtE,EAAC,EAAD,CAAA,SACE,EAAC,EAAD,CAAA,SAAA,CACE,EAAC,EAAD,CAAgB,QAAA,GAEd,SAAA,EAAC,EAAD,CAAmB,OAAM,OAAO,QAAU,CAAA,CAE5B,CAAA,EAChB,EAAC,EAAD,CAAgB,UAAU,eACxB,SAAA,EAAC,EAAD,CAAmB,OAAM,OAAO,OAAO,SAAA,GAAS,UAAU,wCAA0C,CAAA,CACtF,CAAA,CACT,CAAA,CAAA,CACM,CAAA"}
@@ -1,2 +1,2 @@
1
- import{Paragraph as e}from"./typography/paragraph.mjs";import{Tooltip as t,TooltipContent as n,TooltipTrigger as r}from"./ui/tooltip.mjs";import{Q as i}from"./tables-BGzwkdFO.mjs";import{jsx as a,jsxs as o}from"react/jsx-runtime";const s=({content:s})=>s==null?a(i,{}):o(t,{children:[a(r,{children:a(e,{variant:`sm`,className:`line-clamp-2 whitespace-pre-line break-all`,children:s})}),a(n,{align:`start`,className:`h-fit min-w-48 max-w-80 pt-4`,children:o(`div`,{className:`flex flex-col gap-y-2`,children:[a(e,{variant:`xs`,className:`whitespace-pre-line text-wrap break-keep text-text-negative-weak`,children:s}),o(`p`,{className:`w-full text-end`,children:[s.toString().length,` chars`]})]})})]});export{s as UITableDescriptionDisplay};
2
- //# sourceMappingURL=description-display-CW0g3aJa.mjs.map
1
+ import{Paragraph as e}from"./typography/paragraph.mjs";import{Tooltip as t,TooltipContent as n,TooltipTrigger as r}from"./ui/tooltip.mjs";import{Q as i}from"./tables-7_KgoyS-.mjs";import{jsx as a,jsxs as o}from"react/jsx-runtime";const s=({content:s})=>s==null?a(i,{}):o(t,{children:[a(r,{children:a(e,{variant:`sm`,className:`line-clamp-2 whitespace-pre-line break-all`,children:s})}),a(n,{align:`start`,className:`h-fit min-w-48 max-w-80 pt-4`,children:o(`div`,{className:`flex flex-col gap-y-2`,children:[a(e,{variant:`xs`,className:`whitespace-pre-line text-wrap break-keep text-text-negative-weak`,children:s}),o(`p`,{className:`w-full text-end`,children:[s.toString().length,` chars`]})]})})]});export{s as UITableDescriptionDisplay};
2
+ //# sourceMappingURL=description-display-B4KoH6ql.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"description-display-CW0g3aJa.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/description-display.tsx"],"sourcesContent":["import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\nimport { Paragraph } from '@/components/typography/paragraph';\n\n/**\n * Renders a two-line-clamped description in a table cell with a tooltip that\n * reveals the full text and its character count; falls back to\n * {@link UITableEmpty} when `content` is `null` or `undefined`.\n *\n * @example\n * import { UITableDescriptionDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDescriptionDisplay content=\"A detailed description of this record.\" />\n */\nexport const UITableDescriptionDisplay: React.FC<{\n /** The text or numeric value to display; `null`/`undefined` renders an empty state. */\n content: string | null | undefined | number;\n}> = ({ content }) => {\n if (content === undefined || content === null) {\n return <UITableEmpty />;\n }\n return (\n <Tooltip>\n <TooltipTrigger>\n <Paragraph variant=\"sm\" className=\"line-clamp-2 whitespace-pre-line break-all\">\n {content}\n </Paragraph>\n </TooltipTrigger>\n <TooltipContent align=\"start\" className=\"h-fit min-w-48 max-w-80 pt-4\">\n <div className=\"flex flex-col gap-y-2\">\n <Paragraph variant=\"xs\" className=\"whitespace-pre-line text-wrap break-keep text-text-negative-weak\">\n {content}\n </Paragraph>\n <p className=\"w-full text-end\">{content.toString().length} chars</p>\n </div>\n </TooltipContent>\n </Tooltip>\n );\n};\n"],"mappings":"sOAeA,MAAa,GAGP,CAAE,aACF,GAAqC,KAChC,EAAC,EAAD,CAAe,CAAA,EAGtB,EAAC,EAAD,CAAA,SAAA,CACE,EAAC,EAAD,CAAA,SACE,EAAC,EAAD,CAAW,QAAQ,KAAK,UAAU,6CAC/B,SAAA,CACQ,CAAA,CACG,CAAA,EAChB,EAAC,EAAD,CAAgB,MAAM,QAAQ,UAAU,+BACtC,SAAA,EAAC,MAAD,CAAK,UAAU,wBAAf,SAAA,CACE,EAAC,EAAD,CAAW,QAAQ,KAAK,UAAU,mEAC/B,SAAA,CACQ,CAAA,EACX,EAAC,IAAD,CAAG,UAAU,kBAAb,SAAA,CAAgC,EAAQ,SAAS,CAAC,CAAC,OAAO,QAAS,CAChE,CAAA,CAAA,GACS,CAAA,CACT,CAAA,CAAA"}
1
+ {"version":3,"file":"description-display-B4KoH6ql.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/description-display.tsx"],"sourcesContent":["import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\nimport { Paragraph } from '@/components/typography/paragraph';\n\n/**\n * Renders a two-line-clamped description in a table cell with a tooltip that\n * reveals the full text and its character count; falls back to\n * {@link UITableEmpty} when `content` is `null` or `undefined`.\n *\n * @example\n * import { UITableDescriptionDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDescriptionDisplay content=\"A detailed description of this record.\" />\n */\nexport const UITableDescriptionDisplay: React.FC<{\n /** The text or numeric value to display; `null`/`undefined` renders an empty state. */\n content: string | null | undefined | number;\n}> = ({ content }) => {\n if (content === undefined || content === null) {\n return <UITableEmpty />;\n }\n return (\n <Tooltip>\n <TooltipTrigger>\n <Paragraph variant=\"sm\" className=\"line-clamp-2 whitespace-pre-line break-all\">\n {content}\n </Paragraph>\n </TooltipTrigger>\n <TooltipContent align=\"start\" className=\"h-fit min-w-48 max-w-80 pt-4\">\n <div className=\"flex flex-col gap-y-2\">\n <Paragraph variant=\"xs\" className=\"whitespace-pre-line text-wrap break-keep text-text-negative-weak\">\n {content}\n </Paragraph>\n <p className=\"w-full text-end\">{content.toString().length} chars</p>\n </div>\n </TooltipContent>\n </Tooltip>\n );\n};\n"],"mappings":"sOAeA,MAAa,GAGP,CAAE,aACF,GAAqC,KAChC,EAAC,EAAD,CAAe,CAAA,EAGtB,EAAC,EAAD,CAAA,SAAA,CACE,EAAC,EAAD,CAAA,SACE,EAAC,EAAD,CAAW,QAAQ,KAAK,UAAU,6CAC/B,SAAA,CACQ,CAAA,CACG,CAAA,EAChB,EAAC,EAAD,CAAgB,MAAM,QAAQ,UAAU,+BACtC,SAAA,EAAC,MAAD,CAAK,UAAU,wBAAf,SAAA,CACE,EAAC,EAAD,CAAW,QAAQ,KAAK,UAAU,mEAC/B,SAAA,CACQ,CAAA,EACX,EAAC,IAAD,CAAG,UAAU,kBAAb,SAAA,CAAgC,EAAQ,SAAS,CAAC,CAAC,OAAO,QAAS,CAChE,CAAA,CAAA,GACS,CAAA,CACT,CAAA,CAAA"}
@@ -1,2 +1,2 @@
1
- const e=require("./typography/paragraph.cjs"),t=require("./ui/tooltip.cjs"),n=require("./tables-078i-X0d.cjs");let r=require("react/jsx-runtime");const i=({content:i})=>i==null?(0,r.jsx)(n.Q,{}):(0,r.jsxs)(t.Tooltip,{children:[(0,r.jsx)(t.TooltipTrigger,{children:(0,r.jsx)(e.Paragraph,{variant:`sm`,className:`line-clamp-2 whitespace-pre-line break-all`,children:i})}),(0,r.jsx)(t.TooltipContent,{align:`start`,className:`h-fit min-w-48 max-w-80 pt-4`,children:(0,r.jsxs)(`div`,{className:`flex flex-col gap-y-2`,children:[(0,r.jsx)(e.Paragraph,{variant:`xs`,className:`whitespace-pre-line text-wrap break-keep text-text-negative-weak`,children:i}),(0,r.jsxs)(`p`,{className:`w-full text-end`,children:[i.toString().length,` chars`]})]})})]});exports.UITableDescriptionDisplay=i;
2
- //# sourceMappingURL=description-display-BR8nXqc_.cjs.map
1
+ const e=require("./typography/paragraph.cjs"),t=require("./ui/tooltip.cjs"),n=require("./tables-CS3NhgTc.cjs");let r=require("react/jsx-runtime");const i=({content:i})=>i==null?(0,r.jsx)(n.Q,{}):(0,r.jsxs)(t.Tooltip,{children:[(0,r.jsx)(t.TooltipTrigger,{children:(0,r.jsx)(e.Paragraph,{variant:`sm`,className:`line-clamp-2 whitespace-pre-line break-all`,children:i})}),(0,r.jsx)(t.TooltipContent,{align:`start`,className:`h-fit min-w-48 max-w-80 pt-4`,children:(0,r.jsxs)(`div`,{className:`flex flex-col gap-y-2`,children:[(0,r.jsx)(e.Paragraph,{variant:`xs`,className:`whitespace-pre-line text-wrap break-keep text-text-negative-weak`,children:i}),(0,r.jsxs)(`p`,{className:`w-full text-end`,children:[i.toString().length,` chars`]})]})})]});exports.UITableDescriptionDisplay=i;
2
+ //# sourceMappingURL=description-display-jmAaeMBD.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"description-display-BR8nXqc_.cjs","names":["UITableEmpty","Tooltip","TooltipTrigger","Paragraph","TooltipContent"],"sources":["../packages/components/features/tables/components/atoms/description-display.tsx"],"sourcesContent":["import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\nimport { Paragraph } from '@/components/typography/paragraph';\n\n/**\n * Renders a two-line-clamped description in a table cell with a tooltip that\n * reveals the full text and its character count; falls back to\n * {@link UITableEmpty} when `content` is `null` or `undefined`.\n *\n * @example\n * import { UITableDescriptionDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDescriptionDisplay content=\"A detailed description of this record.\" />\n */\nexport const UITableDescriptionDisplay: React.FC<{\n /** The text or numeric value to display; `null`/`undefined` renders an empty state. */\n content: string | null | undefined | number;\n}> = ({ content }) => {\n if (content === undefined || content === null) {\n return <UITableEmpty />;\n }\n return (\n <Tooltip>\n <TooltipTrigger>\n <Paragraph variant=\"sm\" className=\"line-clamp-2 whitespace-pre-line break-all\">\n {content}\n </Paragraph>\n </TooltipTrigger>\n <TooltipContent align=\"start\" className=\"h-fit min-w-48 max-w-80 pt-4\">\n <div className=\"flex flex-col gap-y-2\">\n <Paragraph variant=\"xs\" className=\"whitespace-pre-line text-wrap break-keep text-text-negative-weak\">\n {content}\n </Paragraph>\n <p className=\"w-full text-end\">{content.toString().length} chars</p>\n </div>\n </TooltipContent>\n </Tooltip>\n );\n};\n"],"mappings":"kJAeA,MAAa,GAGP,CAAE,aACF,GAAqC,MAChC,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,GAGtB,EAAA,EAAA,KAAA,CAACC,EAAAA,QAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAACC,EAAAA,UAAD,CAAW,QAAQ,KAAK,UAAU,6CAC/B,SAAA,CACQ,CAAA,CACG,CAAA,GAChB,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAgB,MAAM,QAAQ,UAAU,+BACtC,UAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,wBAAf,SAAA,EACE,EAAA,EAAA,IAAA,CAACD,EAAAA,UAAD,CAAW,QAAQ,KAAK,UAAU,mEAC/B,SAAA,CACQ,CAAA,GACX,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAU,kBAAb,SAAA,CAAgC,EAAQ,SAAS,CAAC,CAAC,OAAO,QAAS,CAChE,CAAA,CAAA,GACS,CAAA,CACT,CAAA,CAAA"}
1
+ {"version":3,"file":"description-display-jmAaeMBD.cjs","names":["UITableEmpty","Tooltip","TooltipTrigger","Paragraph","TooltipContent"],"sources":["../packages/components/features/tables/components/atoms/description-display.tsx"],"sourcesContent":["import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\nimport { Paragraph } from '@/components/typography/paragraph';\n\n/**\n * Renders a two-line-clamped description in a table cell with a tooltip that\n * reveals the full text and its character count; falls back to\n * {@link UITableEmpty} when `content` is `null` or `undefined`.\n *\n * @example\n * import { UITableDescriptionDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableDescriptionDisplay content=\"A detailed description of this record.\" />\n */\nexport const UITableDescriptionDisplay: React.FC<{\n /** The text or numeric value to display; `null`/`undefined` renders an empty state. */\n content: string | null | undefined | number;\n}> = ({ content }) => {\n if (content === undefined || content === null) {\n return <UITableEmpty />;\n }\n return (\n <Tooltip>\n <TooltipTrigger>\n <Paragraph variant=\"sm\" className=\"line-clamp-2 whitespace-pre-line break-all\">\n {content}\n </Paragraph>\n </TooltipTrigger>\n <TooltipContent align=\"start\" className=\"h-fit min-w-48 max-w-80 pt-4\">\n <div className=\"flex flex-col gap-y-2\">\n <Paragraph variant=\"xs\" className=\"whitespace-pre-line text-wrap break-keep text-text-negative-weak\">\n {content}\n </Paragraph>\n <p className=\"w-full text-end\">{content.toString().length} chars</p>\n </div>\n </TooltipContent>\n </Tooltip>\n );\n};\n"],"mappings":"kJAeA,MAAa,GAGP,CAAE,aACF,GAAqC,MAChC,EAAA,EAAA,IAAA,CAACA,EAAAA,EAAD,CAAe,CAAA,GAGtB,EAAA,EAAA,KAAA,CAACC,EAAAA,QAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAACC,EAAAA,UAAD,CAAW,QAAQ,KAAK,UAAU,6CAC/B,SAAA,CACQ,CAAA,CACG,CAAA,GAChB,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAgB,MAAM,QAAQ,UAAU,+BACtC,UAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,wBAAf,SAAA,EACE,EAAA,EAAA,IAAA,CAACD,EAAAA,UAAD,CAAW,QAAQ,KAAK,UAAU,mEAC/B,SAAA,CACQ,CAAA,GACX,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAU,kBAAb,SAAA,CAAgC,EAAQ,SAAS,CAAC,CAAC,OAAO,QAAS,CAChE,CAAA,CAAA,GACS,CAAA,CACT,CAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ const e=require("./ui/skeleton.cjs"),t=require("./layouts/flex.cjs"),n=require("./date-B3cozmfV.cjs"),r=require("./ui/tooltip.cjs"),i=require("./typography/title.cjs"),a=require("./sidebar-core-DUdB9WCv.cjs"),o=require("./features/logo/index.cjs");let s=require("lucide-react"),c=require("react"),l=require("@customafk/react-toolkit/utils"),u=require("react/jsx-runtime"),d=require("radix-ui");function f(){return(0,u.jsx)(t.Flex,{justify:`center`,className:`inset-shadow-sm min-h-0 bg-muted-muted`,children:(0,u.jsx)(`div`,{className:`loader`})})}function p({isLoading:e,children:t}){return(0,u.jsx)(`main`,{"data-slot":`detail-dialog-main`,className:`@container col-start-2 row-start-2 grid min-h-0 min-w-0 grid-rows-1`,children:e?(0,u.jsx)(f,{}):(0,u.jsx)(c.Suspense,{fallback:(0,u.jsx)(f,{}),children:(0,u.jsx)(`section`,{"data-slot":`detail-dialog-body`,className:`relative inset-shadow-sm grid min-h-0 snap-y grid-cols-1 overflow-y-auto bg-white`,children:t})})})}function m(){return(0,u.jsxs)(`div`,{"data-slot":`detail-dialog-header-skeleton`,className:`grid justify-items-start gap-1.5`,children:[(0,u.jsx)(e.Skeleton,{className:`h-5 w-40`}),(0,u.jsx)(e.Skeleton,{className:`h-3 w-24`})]})}function h({title:e,createdAt:t,headerComponent:r}){return(0,u.jsxs)(`header`,{"data-slot":`detail-dialog-header`,className:`col-start-2 row-start-1 grid grid-cols-[auto_1fr] items-start gap-x-2.5 border-border-weak border-b bg-card py-2.5 pr-12 pl-2`,children:[(0,u.jsx)(a.s,{}),(0,u.jsx)(`div`,{"data-slot":`detail-dialog-header-content`,className:`min-w-0 overflow-x-auto`,children:(0,u.jsx)(c.Suspense,{fallback:(0,u.jsx)(m,{}),children:r??(0,u.jsxs)(`div`,{className:`grid justify-items-start gap-0`,children:[(0,u.jsx)(i.Title,{level:5,className:`line-clamp-1 truncate text-wrap`,children:e||`Detail Dialog`}),!!t&&(0,u.jsxs)(`div`,{className:`relative grid grid-flow-col items-center gap-1 text-text-positive-weak`,children:[(0,u.jsx)(s.CalendarIcon,{size:12,className:`text-primary-strong`}),(0,u.jsx)(`p`,{className:`text-primary-strong text-xs`,children:`Ngày Tạo`}),(0,u.jsx)(n.t,{showHoliday:!0,date:t,format:`medium`})]})]})})})]})}function g({defaultOpen:e=!0,open:t,onOpenChange:n,sidebarWidth:i,className:o,style:s,children:c,...d}){let f=a._({defaultOpen:e,open:t,onOpenChange:n});return(0,u.jsx)(a.m.Provider,{value:f,children:(0,u.jsx)(r.TooltipProvider,{delayDuration:0,children:(0,u.jsx)(`div`,{"data-slot":`detail-dialog-wrapper`,style:{"--sidebar-width":i??`18rem`,"--sidebar-width-icon":a.f,...s},className:(0,l.cn)(`group/sidebar-wrapper size-full min-h-[85dvh]`,`grid grid-cols-[auto_1fr] grid-rows-[auto_1fr]`,o),...d,children:c})})})}function _({title:e,sidebarTitle:t,content:n,footer:r}){return(0,u.jsx)(`div`,{className:`col-start-1 row-span-2 row-start-1`,children:(0,u.jsxs)(a.p,{children:[(0,u.jsx)(a.r,{children:(0,u.jsx)(a.i,{children:(0,u.jsx)(a.o,{children:(0,u.jsxs)(a.a,{size:`lg`,tabIndex:-1,children:[(0,u.jsx)(o.LunasLogo,{variant:`icon`,iconStyle:`solid`,size:`md`,className:`size-8 min-h-8 min-w-8`}),(0,u.jsxs)(`div`,{className:`grid flex-1 text-left text-sm leading-tight`,children:[(0,u.jsx)(`span`,{className:`truncate font-medium`,children:t||`Detail Dialog`}),(0,u.jsx)(`span`,{className:`truncate text-xs`,children:`Lunas Enterprise`})]})]})})})}),(0,u.jsx)(a.t,{children:n}),(0,u.jsx)(a.n,{children:r})]})})}function v({open:e,onOpenChange:t,children:n}){let r=(0,c.useCallback)(e=>{e.preventDefault(),e.stopPropagation()},[]);return(0,u.jsx)(d.Dialog.Root,{"data-slot":`detail-dialog`,open:e,onOpenChange:t,children:(0,u.jsx)(d.Dialog.Portal,{"data-slot":`detail-dialog-portal`,children:(0,u.jsx)(d.Dialog.Overlay,{"data-slot":`detail-dialog-overlay`,className:`data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 flex overflow-auto bg-black/50 p-4 data-[state=closed]:animate-out data-[state=open]:animate-in supports-backdrop-filter:backdrop-blur-xs`,children:(0,u.jsxs)(d.Dialog.Content,{"data-slot":`dialog-content`,className:(0,l.cn)(`relative z-50 m-auto grid`,`gap-4 overflow-hidden rounded-sm border-none bg-background p-0 shadow-dialog outline-none duration-200`,`size-full max-h-dvh min-h-160 min-w-264 max-w-svw`,`data-[state=closed]:animate-out data-[state=open]:animate-in`,`data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0`,`data-[state=closed]:zoom-out-80 data-[state=open]:zoom-in-80`),onInteractOutside:r,children:[n,(0,u.jsx)(d.Dialog.Close,{"data-slot":`dialog-close`,tabIndex:-1,asChild:!0,className:`absolute top-3 right-3`,children:(0,u.jsx)(`button`,{className:`flex cursor-pointer items-center justify-center rounded-full p-2 text-text-positive-weak transition-colors hover:bg-muted-muted hover:text-text-positive active:bg-muted-weak active:text-text-positive-strong disabled:pointer-events-none disabled:opacity-60`,children:(0,u.jsx)(s.XIcon,{size:24})})})]})})})})}const y=({open:e,isLoading:t,title:n,createdAt:r,onOpenChange:i,sidebar:a,headerComponent:o,children:s})=>(0,u.jsx)(v,{open:e,onOpenChange:i,children:(0,u.jsxs)(g,{sidebarWidth:a?.width,children:[(0,u.jsx)(_,{title:a?.title,content:a?.content,footer:a?.footer}),(0,u.jsx)(h,{title:n,createdAt:r,headerComponent:o}),(0,u.jsx)(p,{isLoading:t,children:s})]})});Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return y}});
2
+ //# sourceMappingURL=detail-dialog-BCM0iEXQ.cjs.map