@customafk/lunas-ui 0.2.81 → 0.2.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{analysis-panel-DYF2CmAH.cjs → analysis-panel-BoKjkPYz.cjs} +2 -2
- package/dist/{analysis-panel-DYF2CmAH.cjs.map → analysis-panel-BoKjkPYz.cjs.map} +1 -1
- package/dist/{analysis-panel-_s1fgcZC.mjs → analysis-panel-CZ8g9AAO.mjs} +2 -2
- package/dist/{analysis-panel-_s1fgcZC.mjs.map → analysis-panel-CZ8g9AAO.mjs.map} +1 -1
- package/dist/{badge-C_KLKwiS.d.cts → badge-BPiU1Ss2.d.cts} +2 -2
- package/dist/{badge-C_KLKwiS.d.mts → badge-BPiU1Ss2.d.mts} +2 -2
- package/dist/{badge-display-D6d7wTEE.mjs → badge-display-B5m09_Hs.mjs} +2 -2
- package/dist/{badge-display-D6d7wTEE.mjs.map → badge-display-B5m09_Hs.mjs.map} +1 -1
- package/dist/{badge-display-DWzSl3rs.cjs → badge-display-DHbCN998.cjs} +2 -2
- package/dist/{badge-display-DWzSl3rs.cjs.map → badge-display-DHbCN998.cjs.map} +1 -1
- package/dist/{boolean-display-Wko_5Jd5.mjs → boolean-display-CzHHDfHW.mjs} +2 -2
- package/dist/{boolean-display-Wko_5Jd5.mjs.map → boolean-display-CzHHDfHW.mjs.map} +1 -1
- package/dist/{boolean-display-C5GIuWnc.cjs → boolean-display-D2wjQhNX.cjs} +2 -2
- package/dist/{boolean-display-C5GIuWnc.cjs.map → boolean-display-D2wjQhNX.cjs.map} +1 -1
- package/dist/{button-CnKmz4qM.d.cts → button-BnoPktln.d.cts} +3 -3
- package/dist/{button-CnKmz4qM.d.mts → button-BnoPktln.d.mts} +3 -3
- package/dist/{calendar-BT6-Fo3T.d.mts → calendar-BkV5hTX2.d.mts} +2 -2
- package/dist/{calendar-D_QmR9VE.d.cts → calendar-iDMPT1kI.d.cts} +2 -2
- package/dist/{carousel-BBI4xPdK.d.mts → carousel-D7VXWJ3S.d.mts} +2 -2
- package/dist/{carousel-B_IXlBdH.d.cts → carousel-bBvM31sh.d.cts} +2 -2
- package/dist/currency-display-7w-ZjVUw.mjs +2 -0
- package/dist/currency-display-7w-ZjVUw.mjs.map +1 -0
- package/dist/currency-display-B06kc2IG.cjs +2 -0
- package/dist/currency-display-B06kc2IG.cjs.map +1 -0
- package/dist/{date-display-DXyb-Ai2.mjs → date-display-BO7OY_AC.mjs} +2 -2
- package/dist/{date-display-DXyb-Ai2.mjs.map → date-display-BO7OY_AC.mjs.map} +1 -1
- package/dist/{date-display-D38qvsh2.cjs → date-display-DHnZr_yf.cjs} +2 -2
- package/dist/{date-display-D38qvsh2.cjs.map → date-display-DHnZr_yf.cjs.map} +1 -1
- package/dist/{description-display-BwBMrRAi.mjs → description-display-CBfoP3Y2.mjs} +2 -2
- package/dist/{description-display-BwBMrRAi.mjs.map → description-display-CBfoP3Y2.mjs.map} +1 -1
- package/dist/{description-display-DIeHy7ll.cjs → description-display-Cckihd1s.cjs} +2 -2
- package/dist/{description-display-DIeHy7ll.cjs.map → description-display-Cckihd1s.cjs.map} +1 -1
- package/dist/dialogs/detail-dialog/components/sidebar.d.cts +1 -1
- package/dist/dialogs/detail-dialog/components/sidebar.d.mts +1 -1
- package/dist/dialogs/side-panel.cjs +2 -0
- package/dist/dialogs/side-panel.cjs.map +1 -0
- package/dist/dialogs/side-panel.d.cts +2 -0
- package/dist/dialogs/side-panel.d.mts +2 -0
- package/dist/dialogs/side-panel.mjs +2 -0
- package/dist/dialogs/side-panel.mjs.map +1 -0
- package/dist/{email-display-Be3b-kDL.mjs → email-display-Bk_furIx.mjs} +2 -2
- package/dist/{email-display-Be3b-kDL.mjs.map → email-display-Bk_furIx.mjs.map} +1 -1
- package/dist/{email-display-_FRE2qcO.cjs → email-display-w-hRYIeL.cjs} +2 -2
- package/dist/{email-display-_FRE2qcO.cjs.map → email-display-w-hRYIeL.cjs.map} +1 -1
- package/dist/features/descriptions/index.d.cts +1 -1
- package/dist/features/descriptions/index.d.mts +1 -1
- package/dist/features/tables/index.cjs +1 -1
- package/dist/features/tables/index.d.cts +1 -1
- package/dist/features/tables/index.d.mts +1 -1
- package/dist/features/tables/index.mjs +1 -1
- package/dist/{filter-C2wE49q7.mjs → filter-BO7ISTIR.mjs} +2 -2
- package/dist/{filter-C2wE49q7.mjs.map → filter-BO7ISTIR.mjs.map} +1 -1
- package/dist/{filter-z7p4lRp8.cjs → filter-CQ9BD0MV.cjs} +2 -2
- package/dist/{filter-z7p4lRp8.cjs.map → filter-CQ9BD0MV.cjs.map} +1 -1
- package/dist/{flex-CIzZIICK.d.cts → flex-CrxTaAXE.d.cts} +2 -2
- package/dist/{flex-CIzZIICK.d.mts → flex-CrxTaAXE.d.mts} +2 -2
- package/dist/{index-BSj8azta.d.cts → index-BMuVmm7f.d.mts} +2 -2
- package/dist/{index-CjiDR-94.d.mts → index-BPo-Lg3p.d.mts} +15 -12
- package/dist/{index-CEmVk1zP.d.mts → index-CLx89ATZ.d.cts} +2 -2
- package/dist/{index-DqAbPipJ.d.cts → index-DaLpXe5l.d.cts} +15 -12
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +13 -11
- package/dist/index.d.mts +13 -11
- package/dist/index.mjs +1 -1
- package/dist/layouts/flex.d.cts +1 -1
- package/dist/layouts/flex.d.mts +1 -1
- package/dist/layouts/ui-grid.cjs +2 -0
- package/dist/layouts/ui-grid.cjs.map +1 -0
- package/dist/layouts/ui-grid.d.cts +2 -0
- package/dist/layouts/ui-grid.d.mts +2 -0
- package/dist/layouts/ui-grid.mjs +2 -0
- package/dist/layouts/ui-grid.mjs.map +1 -0
- package/dist/{list-display-BvKGl7uq.cjs → list-display-DDeJoneW.cjs} +2 -2
- package/dist/{list-display-BvKGl7uq.cjs.map → list-display-DDeJoneW.cjs.map} +1 -1
- package/dist/{list-display-CWQvIMUj.mjs → list-display-DLsm8uAh.mjs} +2 -2
- package/dist/{list-display-CWQvIMUj.mjs.map → list-display-DLsm8uAh.mjs.map} +1 -1
- package/dist/{name-display-DfOtYp7d.cjs → name-display-CKnyugrP.cjs} +2 -2
- package/dist/{name-display-DfOtYp7d.cjs.map → name-display-CKnyugrP.cjs.map} +1 -1
- package/dist/{name-display-CnTRVqX4.mjs → name-display-H5HFH1fU.mjs} +2 -2
- package/dist/{name-display-CnTRVqX4.mjs.map → name-display-H5HFH1fU.mjs.map} +1 -1
- package/dist/{pagination-AxRzmAtZ.d.cts → pagination-BRw-yZBY.d.cts} +2 -2
- package/dist/{pagination-D12pR8_5.d.mts → pagination-BlLiOvY9.d.mts} +2 -2
- package/dist/{paragraph-C5HE9u0Q.d.mts → paragraph-CRo5eC7H.d.mts} +2 -2
- package/dist/{paragraph-DJlHIDmk.d.cts → paragraph-CkCNIsvz.d.cts} +2 -2
- package/dist/{permalink-DhqOATLQ.mjs → permalink-CaCx9fi6.mjs} +2 -2
- package/dist/{permalink-DhqOATLQ.mjs.map → permalink-CaCx9fi6.mjs.map} +1 -1
- package/dist/{permalink-29QzG9Xe.cjs → permalink-azuGQg2b.cjs} +2 -2
- package/dist/{permalink-29QzG9Xe.cjs.map → permalink-azuGQg2b.cjs.map} +1 -1
- package/dist/{phone-number-CQXrATQO.mjs → phone-number-Ba-f4s1Y.mjs} +2 -2
- package/dist/{phone-number-CQXrATQO.mjs.map → phone-number-Ba-f4s1Y.mjs.map} +1 -1
- package/dist/{phone-number-C2k8llhf.cjs → phone-number-BqRhKQdr.cjs} +2 -2
- package/dist/{phone-number-C2k8llhf.cjs.map → phone-number-BqRhKQdr.cjs.map} +1 -1
- package/dist/{progress-display-DZb1qjfY.mjs → progress-display-0UsBzt_r.mjs} +2 -2
- package/dist/{progress-display-DZb1qjfY.mjs.map → progress-display-0UsBzt_r.mjs.map} +1 -1
- package/dist/{progress-display-B4WVzdJw.cjs → progress-display-CiYWPOnq.cjs} +2 -2
- package/dist/{progress-display-B4WVzdJw.cjs.map → progress-display-CiYWPOnq.cjs.map} +1 -1
- package/dist/{resizable-D61lvcIL.d.cts → resizable-C3uADYIg.d.cts} +2 -2
- package/dist/{resizable-D61lvcIL.d.mts → resizable-C3uADYIg.d.mts} +2 -2
- package/dist/side-panel-DPrM5ygG.d.cts +86 -0
- package/dist/side-panel-DPrM5ygG.d.mts +86 -0
- package/dist/statistic-639yMA2d.mjs +2 -0
- package/dist/statistic-639yMA2d.mjs.map +1 -0
- package/dist/statistic-CE_Jg8SN.cjs +2 -0
- package/dist/statistic-CE_Jg8SN.cjs.map +1 -0
- package/dist/{status-display-CcihiYsH.mjs → status-display-BCYpNJmd.mjs} +2 -2
- package/dist/{status-display-CcihiYsH.mjs.map → status-display-BCYpNJmd.mjs.map} +1 -1
- package/dist/{status-display-DJ8fFqyX.cjs → status-display-xcCCGpGS.cjs} +2 -2
- package/dist/{status-display-DJ8fFqyX.cjs.map → status-display-xcCCGpGS.cjs.map} +1 -1
- package/dist/{summary-bar-DK8glsr4.cjs → summary-bar-C08g8bb1.cjs} +2 -2
- package/dist/{summary-bar-DK8glsr4.cjs.map → summary-bar-C08g8bb1.cjs.map} +1 -1
- package/dist/{summary-bar-C4loKj1L.mjs → summary-bar-C3NAnI3V.mjs} +2 -2
- package/dist/{summary-bar-C4loKj1L.mjs.map → summary-bar-C3NAnI3V.mjs.map} +1 -1
- package/dist/tables-BqZ4Zs6e.cjs +2 -0
- package/dist/tables-BqZ4Zs6e.cjs.map +1 -0
- package/dist/tables-Dg3KMBKA.mjs +2 -0
- package/dist/tables-Dg3KMBKA.mjs.map +1 -0
- package/dist/{tooltip-CLjCwnTD.cjs → tooltip-BVzKgxrZ.cjs} +3 -3
- package/dist/{tooltip-CLjCwnTD.cjs.map → tooltip-BVzKgxrZ.cjs.map} +1 -1
- package/dist/{tooltip-BKcU3bMc.mjs → tooltip-D7U_Nl5c.mjs} +3 -3
- package/dist/{tooltip-BKcU3bMc.mjs.map → tooltip-D7U_Nl5c.mjs.map} +1 -1
- package/dist/typography/paragraph.d.cts +1 -1
- package/dist/typography/paragraph.d.mts +1 -1
- package/dist/ui/alert-dialog.cjs +1 -1
- package/dist/ui/alert-dialog.cjs.map +1 -1
- package/dist/ui/alert-dialog.mjs +1 -1
- package/dist/ui/alert-dialog.mjs.map +1 -1
- package/dist/ui/badge.d.cts +1 -1
- package/dist/ui/badge.d.mts +1 -1
- package/dist/ui/button.d.cts +1 -1
- package/dist/ui/button.d.mts +1 -1
- package/dist/ui/calendar.d.cts +1 -1
- package/dist/ui/calendar.d.mts +1 -1
- package/dist/ui/carousel.d.cts +1 -1
- package/dist/ui/carousel.d.mts +1 -1
- package/dist/ui/dialog.cjs +1 -1
- package/dist/ui/dialog.cjs.map +1 -1
- package/dist/ui/dialog.mjs +1 -1
- package/dist/ui/dialog.mjs.map +1 -1
- package/dist/ui/pagination.d.cts +1 -1
- package/dist/ui/pagination.d.mts +1 -1
- package/dist/ui/resizable.d.cts +1 -1
- package/dist/ui/resizable.d.mts +1 -1
- package/dist/ui/sheet.cjs +1 -1
- package/dist/ui/sheet.cjs.map +1 -1
- package/dist/ui/sheet.mjs +1 -1
- package/dist/ui/sheet.mjs.map +1 -1
- package/dist/ui-grid-CzL5J7cm.d.cts +128 -0
- package/dist/ui-grid-CzL5J7cm.d.mts +128 -0
- package/package.json +9 -1
- package/dist/currency-display-BGkpGtN_.mjs +0 -2
- package/dist/currency-display-BGkpGtN_.mjs.map +0 -1
- package/dist/currency-display-Bbh5InhV.cjs +0 -2
- package/dist/currency-display-Bbh5InhV.cjs.map +0 -1
- package/dist/statistic-DoNUSe3e.mjs +0 -2
- package/dist/statistic-DoNUSe3e.mjs.map +0 -1
- package/dist/statistic-wnnjHsKj.cjs +0 -2
- package/dist/statistic-wnnjHsKj.cjs.map +0 -1
- package/dist/tables-BTBtN1di.mjs +0 -2
- package/dist/tables-BTBtN1di.mjs.map +0 -1
- package/dist/tables-BzP8Cnvh.cjs +0 -2
- package/dist/tables-BzP8Cnvh.cjs.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";import{paragraphVariants as e}from"../typography/paragraph.mjs";import{t}from"../close-DYJZ8fkh.mjs";import{cn as n}from"@customafk/react-toolkit/utils";import{jsx as r,jsxs as i}from"react/jsx-runtime";import{Dialog as a}from"radix-ui";const o=({open:o,onOpenChange:s,title:c,description:l,footer:u,showCloseButton:d=!0,children:f,width:p=`sm:w-1/2 sm:max-w-2xl`,modal:m=!0,className:h})=>{let g=!m||d;return r(a.Root,{open:o,onOpenChange:s,modal:m,children:i(a.Portal,{children:[m&&r(a.Overlay,{className:n(`fixed inset-0 z-50 bg-black/50`,`data-[state=open]:fade-in-0 data-[state=open]:animate-in`,`data-[state=closed]:fade-out-0 data-[state=closed]:animate-out`)}),i(a.Content,{className:n(`fixed z-50 flex flex-col bg-background`,`rounded-2xl border border-border-weak shadow-dialog outline-none`,`inset-2 sm:inset-y-2 sm:right-2 sm:left-auto`,p,`data-[state=open]:slide-in-from-right data-[state=open]:animate-in data-[state=open]:duration-500`,`data-[state=closed]:slide-out-to-right data-[state=closed]:animate-out data-[state=closed]:duration-300`,h),onEscapeKeyDown:e=>{m||e.preventDefault()},onInteractOutside:e=>{m||e.preventDefault()},children:[(c||l)&&i(`div`,{className:n(`flex flex-none flex-col gap-1 border-border-weak border-b p-4`,g&&`pr-14`),children:[c&&r(a.Title,{className:`font-bold text-base text-text-positive-strong`,children:c}),l&&r(a.Description,{className:n(e({variant:`muted`}),`not-first:mt-0 md:text-sm`),children:l})]}),r(`div`,{className:`min-h-0 flex-1 overflow-y-auto p-4`,children:f}),u&&r(`div`,{className:`mt-auto flex flex-none flex-col-reverse gap-2 border-t border-border-weak p-4 sm:flex-row sm:justify-end`,children:u}),g&&r(a.Close,{tabIndex:-1,asChild:!0,className:`absolute top-4 right-4`,children:r(t,{"aria-label":`Đóng`})})]})]})})};export{o as SidePanel};
|
|
2
|
+
//# sourceMappingURL=side-panel.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-panel.mjs","names":["SidePanelPrimitive"],"sources":["../../packages/components/dialogs/side-panel.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Dialog as SidePanelPrimitive } from 'radix-ui';\nimport { paragraphVariants } from '../typography/paragraph';\nimport { CloseButton } from '../ui/buttons/close';\n\n/**\n * Props for the {@link SidePanel} component.\n */\nexport type SidePanelProps = {\n /**\n * Controls whether the panel is currently open.\n * This is a **controlled** prop — pair it with `onOpenChange` to manage state.\n */\n open?: boolean;\n\n /**\n * Callback fired when the open state changes (e.g. backdrop click, close button, `Escape`).\n *\n * @param open - `true` when opening, `false` when closing.\n */\n onOpenChange?: (open: boolean) => void;\n\n /** Heading rendered at the top of the panel. */\n title?: React.ReactNode;\n\n /** Supporting text rendered below the title. */\n description?: React.ReactNode;\n\n /** Content rendered pinned to the bottom of the panel, typically action buttons. */\n footer?: React.ReactNode;\n\n /**\n * When `true` (default), renders a `CloseButton` in the top-right corner of the panel.\n *\n * @default true\n */\n showCloseButton?: boolean;\n\n /** Main scrollable body content of the panel. */\n children?: React.ReactNode;\n\n /**\n * Tailwind width classes applied to the panel from the `sm` breakpoint up (below `sm` the\n * panel always fills the available inset area). Override to make the panel narrower, wider,\n * or a fixed size, e.g. `'sm:w-96'` or `'sm:w-full sm:max-w-3xl'`.\n *\n * @default 'sm:w-1/2 sm:max-w-2xl'\n */\n width?: string;\n\n /**\n * When `false`, the panel becomes non-modal: no dimmed overlay is rendered, background content\n * stays fully visible and interactive, and the panel can only be closed via its close button\n * (`Escape` and outside clicks are disabled). `showCloseButton` is forced to `true` in this mode\n * regardless of what's passed, since it becomes the only way to close the panel.\n *\n * @default true\n */\n modal?: boolean;\n\n /** Additional class names applied to the panel itself. */\n className?: string;\n};\n\n/**\n * A controlled dialog panel anchored to the right half of the screen, inset from the viewport\n * edges on both axes. Always lays out as a fixed header, a scrollable body, and a fixed footer.\n *\n * **Import:** `import { SidePanel } from '@customafk/lunas-ui/dialogs/side-panel'`\n *\n * @example\n * ```tsx\n * import { useState } from 'react';\n * import { Button } from '@customafk/lunas-ui/ui/button';\n * import { SidePanel } from '@customafk/lunas-ui/dialogs/side-panel';\n *\n * export function OrderDetailPanel({ order }: { order: Order }) {\n * const [open, setOpen] = useState(false);\n *\n * return (\n * <>\n * <Button onClick={() => setOpen(true)}>Xem chi tiết</Button>\n * <SidePanel\n * open={open}\n * onOpenChange={setOpen}\n * title=\"Chi tiết đơn hàng\"\n * description=\"Xem và cập nhật thông tin đơn hàng.\"\n * footer={<Button onClick={() => setOpen(false)}>Lưu thay đổi</Button>}\n * >\n * <p>Nội dung có thể cuộn ở đây.</p>\n * </SidePanel>\n * </>\n * );\n * }\n * ```\n */\nexport const SidePanel: React.FC<SidePanelProps> = ({\n open,\n onOpenChange,\n title,\n description,\n footer,\n showCloseButton = true,\n children,\n width = 'sm:w-1/2 sm:max-w-2xl',\n modal = true,\n className,\n}) => {\n const resolvedShowCloseButton = modal ? showCloseButton : true;\n\n return (\n <SidePanelPrimitive.Root open={open} onOpenChange={onOpenChange} modal={modal}>\n <SidePanelPrimitive.Portal>\n {modal && (\n <SidePanelPrimitive.Overlay\n className={cn(\n 'fixed inset-0 z-50 bg-black/50',\n 'data-[state=open]:fade-in-0 data-[state=open]:animate-in',\n 'data-[state=closed]:fade-out-0 data-[state=closed]:animate-out'\n )}\n />\n )}\n <SidePanelPrimitive.Content\n className={cn(\n 'fixed z-50 flex flex-col bg-background',\n 'rounded-2xl border border-border-weak shadow-dialog outline-none',\n 'inset-2 sm:inset-y-2 sm:right-2 sm:left-auto',\n width,\n 'data-[state=open]:slide-in-from-right data-[state=open]:animate-in data-[state=open]:duration-500',\n 'data-[state=closed]:slide-out-to-right data-[state=closed]:animate-out data-[state=closed]:duration-300',\n className\n )}\n onEscapeKeyDown={event => {\n if (!modal) event.preventDefault();\n }}\n onInteractOutside={event => {\n if (!modal) event.preventDefault();\n }}\n >\n {(title || description) && (\n <div className={cn('flex flex-none flex-col gap-1 border-border-weak border-b p-4', resolvedShowCloseButton && 'pr-14')}>\n {title && <SidePanelPrimitive.Title className=\"font-bold text-base text-text-positive-strong\">{title}</SidePanelPrimitive.Title>}\n {description && (\n <SidePanelPrimitive.Description className={cn(paragraphVariants({ variant: 'muted' }), 'not-first:mt-0 md:text-sm')}>\n {description}\n </SidePanelPrimitive.Description>\n )}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto p-4\">{children}</div>\n {footer && <div className=\"mt-auto flex flex-none flex-col-reverse gap-2 border-t border-border-weak p-4 sm:flex-row sm:justify-end\">{footer}</div>}\n {resolvedShowCloseButton && (\n <SidePanelPrimitive.Close tabIndex={-1} asChild className=\"absolute top-4 right-4\">\n <CloseButton aria-label=\"Đóng\" />\n </SidePanelPrimitive.Close>\n )}\n </SidePanelPrimitive.Content>\n </SidePanelPrimitive.Portal>\n </SidePanelPrimitive.Root>\n );\n};\n"],"mappings":"0PAmGA,MAAa,GAAuC,CAClD,OACA,eACA,QACA,cACA,SACA,kBAAkB,GAClB,WACA,QAAQ,wBACR,QAAQ,GACR,eACI,CACJ,IAAM,EAA0B,IAAQ,EAExC,OACE,EAACA,EAAmB,KAApB,CAA+B,OAAoB,eAAqB,QACtE,SAAA,EAACA,EAAmB,OAApB,CAAA,SAAA,CACG,GACC,EAACA,EAAmB,QAApB,CACE,UAAW,EACT,iCACA,2DACA,gEACF,CACD,CAAA,EAEH,EAACA,EAAmB,QAApB,CACE,UAAW,EACT,yCACA,mEACA,+CACA,EACA,oGACA,0GACA,CACF,EACA,gBAAiB,GAAS,CACnB,GAAO,EAAM,eAAe,CACnC,EACA,kBAAmB,GAAS,CACrB,GAAO,EAAM,eAAe,CACnC,EAfF,SAAA,EAiBI,GAAS,IACT,EAAC,MAAD,CAAK,UAAW,EAAG,gEAAiE,GAA2B,OAAO,EAAtH,SAAA,CACG,GAAS,EAACA,EAAmB,MAApB,CAA0B,UAAU,gDAAiD,SAAA,CAAgC,CAAA,EAC9H,GACC,EAACA,EAAmB,YAApB,CAAgC,UAAW,EAAG,EAAkB,CAAE,QAAS,OAAQ,CAAC,EAAG,2BAA2B,EAC/G,SAAA,CAC6B,CAAA,CAE/B,IAEP,EAAC,MAAD,CAAK,UAAU,qCAAsC,UAAc,CAAA,EAClE,GAAU,EAAC,MAAD,CAAK,UAAU,2GAA4G,SAAA,CAAY,CAAA,EACjJ,GACC,EAACA,EAAmB,MAApB,CAA0B,SAAU,GAAI,QAAA,GAAQ,UAAU,yBACxD,SAAA,EAAC,EAAD,CAAa,aAAW,MAAQ,CAAA,CACR,CAAA,CAEF,CACH,CAAA,CAAA,CAAA,CAAA,CACJ,CAAA,CAE7B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Tooltip as e,TooltipContent as t,TooltipProvider as n,TooltipTrigger as r}from"./ui/tooltip.mjs";import{Q as i}from"./tables-
|
|
2
|
-
//# sourceMappingURL=email-display-
|
|
1
|
+
import{Tooltip as e,TooltipContent as t,TooltipProvider as n,TooltipTrigger as r}from"./ui/tooltip.mjs";import{Q as i}from"./tables-Dg3KMBKA.mjs";import{CheckIcon as a,CopyIcon as o,MailIcon as s}from"lucide-react";import{useEffect as c,useRef as l,useState as u}from"react";import{jsx as d,jsxs as f}from"react/jsx-runtime";const p=({email:p,linkable:m=!0})=>{let[h,g]=u(!1),_=l(null);return c(()=>()=>{_.current&&clearTimeout(_.current)},[]),p?d(n,{children:f(`div`,{className:`group flex items-center gap-x-1.5`,children:[d(s,{size:13,className:`shrink-0 text-text-positive-weak`}),m?d(`a`,{href:`mailto:${p}`,className:`truncate text-primary text-sm underline-offset-2 hover:underline`,onClick:e=>e.stopPropagation(),children:p}):d(`span`,{className:`truncate text-text-positive text-sm`,children:p}),f(e,{children:[d(r,{asChild:!0,children:d(`button`,{onClick:e=>{e.stopPropagation(),e.preventDefault(),navigator.clipboard.writeText(p).then(()=>{g(!0),_.current=setTimeout(()=>g(!1),1500)})},className:`shrink-0 cursor-pointer text-text-positive-weak opacity-0 transition-opacity group-hover:opacity-100 hover:text-text-positive`,children:h?d(a,{size:13,className:`text-success-strong`}):d(o,{size:13})})}),d(t,{children:h?`Copied!`:`Copy email`})]})]})}):d(i,{})};export{p as UITableEmailDisplay};
|
|
2
|
+
//# sourceMappingURL=email-display-Bk_furIx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-display-
|
|
1
|
+
{"version":3,"file":"email-display-Bk_furIx.mjs","names":[],"sources":["../packages/components/features/tables/components/atoms/email-display.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { CheckIcon, CopyIcon, MailIcon } from 'lucide-react';\n\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableEmailDisplay} component. */\ntype Props = {\n /** The email address to display; `null`/`undefined`/empty renders an empty state. */\n email: string | null | undefined;\n /** When `true`, a `mailto:` anchor wraps the address (default: `true`). */\n linkable?: boolean;\n};\n\n/**\n * Displays an email address in a table cell with a copy-to-clipboard button.\n * Shows a brief checkmark confirmation after copying. Optionally wraps the\n * address in a `mailto:` link. Renders {@link UITableEmpty} when `email` is\n * absent.\n *\n * @example\n * import { UITableEmailDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableEmailDisplay email=\"jane@example.com\" />\n */\nexport const UITableEmailDisplay: React.FC<Props> = ({ email, linkable = true }) => {\n const [copied, setCopied] = useState(false);\n const copiedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (copiedTimeoutRef.current) clearTimeout(copiedTimeoutRef.current);\n };\n }, []);\n\n if (!email) return <UITableEmpty />;\n\n const handleCopy = (e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n navigator.clipboard.writeText(email).then(() => {\n setCopied(true);\n copiedTimeoutRef.current = setTimeout(() => setCopied(false), 1500);\n });\n };\n\n return (\n <TooltipProvider>\n <div className=\"group flex items-center gap-x-1.5\">\n <MailIcon size={13} className=\"shrink-0 text-text-positive-weak\" />\n\n {linkable ? (\n <a href={`mailto:${email}`} className=\"truncate text-primary text-sm underline-offset-2 hover:underline\" onClick={e => e.stopPropagation()}>\n {email}\n </a>\n ) : (\n <span className=\"truncate text-text-positive text-sm\">{email}</span>\n )}\n\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n onClick={handleCopy}\n className=\"shrink-0 cursor-pointer text-text-positive-weak opacity-0 transition-opacity group-hover:opacity-100 hover:text-text-positive\"\n >\n {copied ? <CheckIcon size={13} className=\"text-success-strong\" /> : <CopyIcon size={13} />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{copied ? 'Copied!' : 'Copy email'}</TooltipContent>\n </Tooltip>\n </div>\n </TooltipProvider>\n );\n};\n"],"mappings":"qUA6BA,MAAa,GAAwC,CAAE,QAAO,WAAW,MAAW,CAClF,GAAM,CAAC,EAAQ,GAAa,EAAS,EAAK,EACpC,EAAmB,EAA6C,IAAI,EAmB1E,OAjBA,UACe,CACP,EAAiB,SAAS,aAAa,EAAiB,OAAO,CACrE,EACC,CAAC,CAAC,EAEA,EAYH,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CAAK,UAAU,oCAAf,SAAA,CACE,EAAC,EAAD,CAAU,KAAM,GAAI,UAAU,kCAAoC,CAAA,EAEjE,EACC,EAAC,IAAD,CAAG,KAAM,UAAU,IAAS,UAAU,mEAAmE,QAAS,GAAK,EAAE,gBAAgB,EACtI,SAAA,CACA,CAAA,EAEH,EAAC,OAAD,CAAM,UAAU,sCAAuC,SAAA,CAAY,CAAA,EAGrE,EAAC,EAAD,CAAA,SAAA,CACE,EAAC,EAAD,CAAgB,QAAA,GACd,SAAA,EAAC,SAAD,CACE,QAzBQ,GAAwB,CAC1C,EAAE,gBAAgB,EAClB,EAAE,eAAe,EACjB,UAAU,UAAU,UAAU,CAAK,CAAC,CAAC,SAAW,CAC9C,EAAU,EAAI,EACd,EAAiB,QAAU,eAAiB,EAAU,EAAK,EAAG,IAAI,CACpE,CAAC,CACH,EAmBY,UAAU,gIAET,SAAA,EAAS,EAAC,EAAD,CAAW,KAAM,GAAI,UAAU,qBAAuB,CAAA,EAAI,EAAC,EAAD,CAAU,KAAM,EAAK,CAAA,CACnF,CAAA,CACM,CAAA,EAChB,EAAC,EAAD,CAAA,SAAiB,EAAS,UAAY,YAA6B,CAAA,CAC5D,CAAA,CAAA,CACN,CACU,CAAA,CAAA,CAAA,EApCA,EAAC,EAAD,CAAe,CAAA,CAsCpC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./ui/tooltip.cjs"),t=require("./tables-
|
|
2
|
-
//# sourceMappingURL=email-display-
|
|
1
|
+
const e=require("./ui/tooltip.cjs"),t=require("./tables-BqZ4Zs6e.cjs");let n=require("lucide-react"),r=require("react"),i=require("react/jsx-runtime");const a=({email:a,linkable:o=!0})=>{let[s,c]=(0,r.useState)(!1),l=(0,r.useRef)(null);return(0,r.useEffect)(()=>()=>{l.current&&clearTimeout(l.current)},[]),a?(0,i.jsx)(e.TooltipProvider,{children:(0,i.jsxs)(`div`,{className:`group flex items-center gap-x-1.5`,children:[(0,i.jsx)(n.MailIcon,{size:13,className:`shrink-0 text-text-positive-weak`}),o?(0,i.jsx)(`a`,{href:`mailto:${a}`,className:`truncate text-primary text-sm underline-offset-2 hover:underline`,onClick:e=>e.stopPropagation(),children:a}):(0,i.jsx)(`span`,{className:`truncate text-text-positive text-sm`,children:a}),(0,i.jsxs)(e.Tooltip,{children:[(0,i.jsx)(e.TooltipTrigger,{asChild:!0,children:(0,i.jsx)(`button`,{onClick:e=>{e.stopPropagation(),e.preventDefault(),navigator.clipboard.writeText(a).then(()=>{c(!0),l.current=setTimeout(()=>c(!1),1500)})},className:`shrink-0 cursor-pointer text-text-positive-weak opacity-0 transition-opacity group-hover:opacity-100 hover:text-text-positive`,children:s?(0,i.jsx)(n.CheckIcon,{size:13,className:`text-success-strong`}):(0,i.jsx)(n.CopyIcon,{size:13})})}),(0,i.jsx)(e.TooltipContent,{children:s?`Copied!`:`Copy email`})]})]})}):(0,i.jsx)(t.Q,{})};exports.UITableEmailDisplay=a;
|
|
2
|
+
//# sourceMappingURL=email-display-w-hRYIeL.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-display-
|
|
1
|
+
{"version":3,"file":"email-display-w-hRYIeL.cjs","names":["UITableEmpty","TooltipProvider","MailIcon","Tooltip","TooltipTrigger","CheckIcon","CopyIcon","TooltipContent"],"sources":["../packages/components/features/tables/components/atoms/email-display.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { CheckIcon, CopyIcon, MailIcon } from 'lucide-react';\n\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\n\nimport { UITableEmpty } from './empty';\n\n/** Props for the {@link UITableEmailDisplay} component. */\ntype Props = {\n /** The email address to display; `null`/`undefined`/empty renders an empty state. */\n email: string | null | undefined;\n /** When `true`, a `mailto:` anchor wraps the address (default: `true`). */\n linkable?: boolean;\n};\n\n/**\n * Displays an email address in a table cell with a copy-to-clipboard button.\n * Shows a brief checkmark confirmation after copying. Optionally wraps the\n * address in a `mailto:` link. Renders {@link UITableEmpty} when `email` is\n * absent.\n *\n * @example\n * import { UITableEmailDisplay } from '@customafk/lunas-ui/features/tables';\n *\n * <UITableEmailDisplay email=\"jane@example.com\" />\n */\nexport const UITableEmailDisplay: React.FC<Props> = ({ email, linkable = true }) => {\n const [copied, setCopied] = useState(false);\n const copiedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (copiedTimeoutRef.current) clearTimeout(copiedTimeoutRef.current);\n };\n }, []);\n\n if (!email) return <UITableEmpty />;\n\n const handleCopy = (e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n navigator.clipboard.writeText(email).then(() => {\n setCopied(true);\n copiedTimeoutRef.current = setTimeout(() => setCopied(false), 1500);\n });\n };\n\n return (\n <TooltipProvider>\n <div className=\"group flex items-center gap-x-1.5\">\n <MailIcon size={13} className=\"shrink-0 text-text-positive-weak\" />\n\n {linkable ? (\n <a href={`mailto:${email}`} className=\"truncate text-primary text-sm underline-offset-2 hover:underline\" onClick={e => e.stopPropagation()}>\n {email}\n </a>\n ) : (\n <span className=\"truncate text-text-positive text-sm\">{email}</span>\n )}\n\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n onClick={handleCopy}\n className=\"shrink-0 cursor-pointer text-text-positive-weak opacity-0 transition-opacity group-hover:opacity-100 hover:text-text-positive\"\n >\n {copied ? <CheckIcon size={13} className=\"text-success-strong\" /> : <CopyIcon size={13} />}\n </button>\n </TooltipTrigger>\n <TooltipContent>{copied ? 'Copied!' : 'Copy email'}</TooltipContent>\n </Tooltip>\n </div>\n </TooltipProvider>\n );\n};\n"],"mappings":"uJA6BA,MAAa,GAAwC,CAAE,QAAO,WAAW,MAAW,CAClF,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAAsB,EAAK,EACpC,GAAA,EAAA,EAAA,OAAA,CAAgE,IAAI,EAmB1E,OAjBA,EAAA,EAAA,UAAA,SACe,CACP,EAAiB,SAAS,aAAa,EAAiB,OAAO,CACrE,EACC,CAAC,CAAC,EAEA,GAYH,EAAA,EAAA,IAAA,CAACC,EAAAA,gBAAD,CAAA,UACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,oCAAf,SAAA,EACE,EAAA,EAAA,IAAA,CAACC,EAAAA,SAAD,CAAU,KAAM,GAAI,UAAU,kCAAoC,CAAA,EAEjE,GACC,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,KAAM,UAAU,IAAS,UAAU,mEAAmE,QAAS,GAAK,EAAE,gBAAgB,EACtI,SAAA,CACA,CAAA,GAEH,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,sCAAuC,SAAA,CAAY,CAAA,GAGrE,EAAA,EAAA,KAAA,CAACC,EAAAA,QAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAgB,QAAA,GACd,UAAA,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,QAzBQ,GAAwB,CAC1C,EAAE,gBAAgB,EAClB,EAAE,eAAe,EACjB,UAAU,UAAU,UAAU,CAAK,CAAC,CAAC,SAAW,CAC9C,EAAU,EAAI,EACd,EAAiB,QAAU,eAAiB,EAAU,EAAK,EAAG,IAAI,CACpE,CAAC,CACH,EAmBY,UAAU,gIAET,SAAA,GAAS,EAAA,EAAA,IAAA,CAACC,EAAAA,UAAD,CAAW,KAAM,GAAI,UAAU,qBAAuB,CAAA,GAAI,EAAA,EAAA,IAAA,CAACC,EAAAA,SAAD,CAAU,KAAM,EAAK,CAAA,CACnF,CAAA,CACM,CAAA,GAChB,EAAA,EAAA,IAAA,CAACC,EAAAA,eAAD,CAAA,SAAiB,EAAS,UAAY,YAA6B,CAAA,CAC5D,CAAA,CAAA,CACN,CACU,CAAA,CAAA,CAAA,GApCA,EAAA,EAAA,IAAA,CAACP,EAAAA,EAAD,CAAe,CAAA,CAsCpC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as DescriptionDate, a as DescriptionSection, b as DescriptionBadge, c as DescriptionStatus, d as DescriptionNumberPhone, f as DescriptionName, g as DescriptionEmpty, h as DescriptionImages, i as DescriptionItem, l as DescriptionStatistic, m as DescriptionLink, n as DescriptionGroup, o as DescriptionUser, p as DescriptionLongText, r as DescriptionHeader, s as DescriptionTagList, t as Description, u as DescriptionStatisticProps, v as DescriptionCopy, y as DescriptionBoolean } from "../../index-
|
|
1
|
+
import { _ as DescriptionDate, a as DescriptionSection, b as DescriptionBadge, c as DescriptionStatus, d as DescriptionNumberPhone, f as DescriptionName, g as DescriptionEmpty, h as DescriptionImages, i as DescriptionItem, l as DescriptionStatistic, m as DescriptionLink, n as DescriptionGroup, o as DescriptionUser, p as DescriptionLongText, r as DescriptionHeader, s as DescriptionTagList, t as Description, u as DescriptionStatisticProps, v as DescriptionCopy, y as DescriptionBoolean } from "../../index-CLx89ATZ.cjs";
|
|
2
2
|
export { Description, DescriptionBadge, DescriptionBoolean, DescriptionCopy, DescriptionDate, DescriptionEmpty, DescriptionGroup, DescriptionHeader, DescriptionImages, DescriptionItem, DescriptionLink, DescriptionLongText, DescriptionName, DescriptionNumberPhone, DescriptionSection, DescriptionStatistic, DescriptionStatisticProps, DescriptionStatus, DescriptionTagList, DescriptionUser };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as DescriptionDate, a as DescriptionSection, b as DescriptionBadge, c as DescriptionStatus, d as DescriptionNumberPhone, f as DescriptionName, g as DescriptionEmpty, h as DescriptionImages, i as DescriptionItem, l as DescriptionStatistic, m as DescriptionLink, n as DescriptionGroup, o as DescriptionUser, p as DescriptionLongText, r as DescriptionHeader, s as DescriptionTagList, t as Description, u as DescriptionStatisticProps, v as DescriptionCopy, y as DescriptionBoolean } from "../../index-
|
|
1
|
+
import { _ as DescriptionDate, a as DescriptionSection, b as DescriptionBadge, c as DescriptionStatus, d as DescriptionNumberPhone, f as DescriptionName, g as DescriptionEmpty, h as DescriptionImages, i as DescriptionItem, l as DescriptionStatistic, m as DescriptionLink, n as DescriptionGroup, o as DescriptionUser, p as DescriptionLongText, r as DescriptionHeader, s as DescriptionTagList, t as Description, u as DescriptionStatisticProps, v as DescriptionCopy, y as DescriptionBoolean } from "../../index-BMuVmm7f.mjs";
|
|
2
2
|
export { Description, DescriptionBadge, DescriptionBoolean, DescriptionCopy, DescriptionDate, DescriptionEmpty, DescriptionGroup, DescriptionHeader, DescriptionImages, DescriptionItem, DescriptionLink, DescriptionLongText, DescriptionName, DescriptionNumberPhone, DescriptionSection, DescriptionStatistic, DescriptionStatisticProps, DescriptionStatus, DescriptionTagList, DescriptionUser };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../tables-
|
|
1
|
+
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../tables-BqZ4Zs6e.cjs");exports.UITableAnalysisPanel=e.t,exports.UITableAvatarNameDisplay=e.n,exports.UITableBadgeDisplay=e.r,exports.UITableBody=e.K,exports.UITableBooleanDisplay=e.i,exports.UITableCell=e.G,exports.UITableCellActions=e.W,exports.UITableCellSelect=e.U,exports.UITableContainer=e.D,exports.UITableCurrencyDisplay=e.a,exports.UITableDateDisplay=e.o,exports.UITableDescriptionDisplay=e.s,exports.UITableEditButton=e.c,exports.UITableEmailDisplay=e.l,exports.UITableEmpty=e.Q,exports.UITableEmptyDisplay=e.H,exports.UITableFilter=e.u,exports.UITableFooter=e.V,exports.UITableFooterRow=e.R,exports.UITableHead=e.L,exports.UITableHeadCell=e.F,exports.UITableHeadCellOption=e.I,exports.UITableHeadCellSelect=e.P,exports.UITableHeadRow=e.N,exports.UITableInnerTable=e.M,exports.UITableInnerWrapper=e.j,exports.UITableListDisplay=e.d,exports.UITableLoadMore=e.A,exports.UITableMoreButton=e.f,exports.UITableNameDisplay=e.p,exports.UITablePermalink=e.m,exports.UITablePhoneNumberDisplay=e.h,exports.UITableProgressDisplay=e.g,exports.UITableProvider=e.E,exports.UITableRemoveButton=e._,exports.UITableRow=e.k,exports.UITableStatisticDisplay=e.v,exports.UITableStatusDisplay=e.y,exports.UITableSummaryBar=e.b,exports.UITableToggleButton=e.x,exports.UITableTooltip=e.S,exports.UITableTooltipActions=e.C,exports.UITableTooltipFilter=e.w,exports.UITableUserDataDisplay=e.T,exports.UITableWrapper=e.O;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as FilterType, A as UITableLoadMore, At as TUITableWrapper, B as UITableEmptyDisplay, C as UITableTooltipActions, Ct as TUITableHeadCellOption, D as UITableContainer, Dt as TUITableInnerWrapper, E as UITableProvider, Et as TUITableInnerTable, F as UITableHeadCellOption, G as ActiveFilter, H as UITableCellActions, I as UITableHeadCell, J as ColumnAggregationType, K as BooleanFilterValue, L as UITableHead, M as UITableInnerTable, Mt as TagFilterValue, N as UITableHeadRow, Nt as TextFilterValue, O as UITableWrapper, Ot as TUITableLoadMore, P as UITableHeadCellSelect, Pt as UITableEmpty, Q as FilterOption, R as UITableFooterRow, S as UITableTooltip, St as TUITableHeadCell, T as UITableUserDataDisplay, Tt as TUITableHeadRow, U as UITableCell, V as UITableCellSelect, W as UITableBody, X as DateRangeFilterValue, Y as CsvCell, Z as FilterDefinition, _ as UITableRemoveButton, _t as TUITableCellSelect, a as UITableCurrencyDisplay, at as TTableAnalysisContext, b as UITableSummaryBar, bt as TUITableFooter, c as UITableEditButton, ct as TTableFilterContext, d as UITableListDisplay, dt as TTableInnerWrapperContext, et as FilterValue, f as UITableMoreButton, ft as TTableRowContext, g as UITableProgressDisplay, gt as TUITableCellActions, h as UITablePhoneNumberDisplay, ht as TUITableCell, i as UITableBooleanDisplay, it as SummaryItem, j as UITableInnerWrapper, jt as TableProviderProps, k as UITableRow, kt as TUITableRow, l as UITableEmailDisplay, lt as TTableHeadRowContext, m as UITablePermalink, mt as TUITableBody, n as UITableAvatarNameDisplay, nt as RowData, o as UITableDateDisplay, ot as TTableBodyContext, p as UITableNameDisplay, pt as TTableSummaryContext, q as ColumnAggregation, r as UITableBadgeDisplay, rt as SingleTagFilterValue, s as UITableDescriptionDisplay, st as TTableContext, t as UITableAnalysisPanel, tt as NumberFilterValue, u as UITableFilter, ut as TTableInnerTableContext, v as UITableStatisticDisplay, vt as TUITableColumn, w as UITableTooltipFilter, wt as TUITableHeadCellSelect, x as UITableToggleButton, xt as TUITableHead, y as UITableStatusDisplay, yt as TUITableEmptyDisplay, z as UITableFooter } from "../../index-
|
|
1
|
+
import { $ as FilterType, A as UITableLoadMore, At as TUITableWrapper, B as UITableEmptyDisplay, C as UITableTooltipActions, Ct as TUITableHeadCellOption, D as UITableContainer, Dt as TUITableInnerWrapper, E as UITableProvider, Et as TUITableInnerTable, F as UITableHeadCellOption, G as ActiveFilter, H as UITableCellActions, I as UITableHeadCell, J as ColumnAggregationType, K as BooleanFilterValue, L as UITableHead, M as UITableInnerTable, Mt as TagFilterValue, N as UITableHeadRow, Nt as TextFilterValue, O as UITableWrapper, Ot as TUITableLoadMore, P as UITableHeadCellSelect, Pt as UITableEmpty, Q as FilterOption, R as UITableFooterRow, S as UITableTooltip, St as TUITableHeadCell, T as UITableUserDataDisplay, Tt as TUITableHeadRow, U as UITableCell, V as UITableCellSelect, W as UITableBody, X as DateRangeFilterValue, Y as CsvCell, Z as FilterDefinition, _ as UITableRemoveButton, _t as TUITableCellSelect, a as UITableCurrencyDisplay, at as TTableAnalysisContext, b as UITableSummaryBar, bt as TUITableFooter, c as UITableEditButton, ct as TTableFilterContext, d as UITableListDisplay, dt as TTableInnerWrapperContext, et as FilterValue, f as UITableMoreButton, ft as TTableRowContext, g as UITableProgressDisplay, gt as TUITableCellActions, h as UITablePhoneNumberDisplay, ht as TUITableCell, i as UITableBooleanDisplay, it as SummaryItem, j as UITableInnerWrapper, jt as TableProviderProps, k as UITableRow, kt as TUITableRow, l as UITableEmailDisplay, lt as TTableHeadRowContext, m as UITablePermalink, mt as TUITableBody, n as UITableAvatarNameDisplay, nt as RowData, o as UITableDateDisplay, ot as TTableBodyContext, p as UITableNameDisplay, pt as TTableSummaryContext, q as ColumnAggregation, r as UITableBadgeDisplay, rt as SingleTagFilterValue, s as UITableDescriptionDisplay, st as TTableContext, t as UITableAnalysisPanel, tt as NumberFilterValue, u as UITableFilter, ut as TTableInnerTableContext, v as UITableStatisticDisplay, vt as TUITableColumn, w as UITableTooltipFilter, wt as TUITableHeadCellSelect, x as UITableToggleButton, xt as TUITableHead, y as UITableStatusDisplay, yt as TUITableEmptyDisplay, z as UITableFooter } from "../../index-DaLpXe5l.cjs";
|
|
2
2
|
export { ActiveFilter, BooleanFilterValue, ColumnAggregation, ColumnAggregationType, CsvCell, DateRangeFilterValue, FilterDefinition, FilterOption, FilterType, FilterValue, NumberFilterValue, RowData, SingleTagFilterValue, SummaryItem, TTableAnalysisContext, TTableBodyContext, TTableContext, TTableFilterContext, TTableHeadRowContext, TTableInnerTableContext, TTableInnerWrapperContext, TTableRowContext, TTableSummaryContext, TUITableBody, TUITableCell, TUITableCellActions, TUITableCellSelect, TUITableColumn, TUITableEmptyDisplay, TUITableFooter, TUITableHead, TUITableHeadCell, TUITableHeadCellOption, TUITableHeadCellSelect, TUITableHeadRow, TUITableInnerTable, TUITableInnerWrapper, TUITableLoadMore, TUITableRow, TUITableWrapper, TableProviderProps, TagFilterValue, TextFilterValue, UITableAnalysisPanel, UITableAvatarNameDisplay, UITableBadgeDisplay, UITableBody, UITableBooleanDisplay, UITableCell, UITableCellActions, UITableCellSelect, UITableContainer, UITableCurrencyDisplay, UITableDateDisplay, UITableDescriptionDisplay, UITableEditButton, UITableEmailDisplay, UITableEmpty, UITableEmptyDisplay, UITableFilter, UITableFooter, UITableFooterRow, UITableHead, UITableHeadCell, UITableHeadCellOption, UITableHeadCellSelect, UITableHeadRow, UITableInnerTable, UITableInnerWrapper, UITableListDisplay, UITableLoadMore, UITableMoreButton, UITableNameDisplay, UITablePermalink, UITablePhoneNumberDisplay, UITableProgressDisplay, UITableProvider, UITableRemoveButton, UITableRow, UITableStatisticDisplay, UITableStatusDisplay, UITableSummaryBar, UITableToggleButton, UITableTooltip, UITableTooltipActions, UITableTooltipFilter, UITableUserDataDisplay, UITableWrapper };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as FilterType, A as UITableLoadMore, At as TUITableWrapper, B as UITableEmptyDisplay, C as UITableTooltipActions, Ct as TUITableHeadCellOption, D as UITableContainer, Dt as TUITableInnerWrapper, E as UITableProvider, Et as TUITableInnerTable, F as UITableHeadCellOption, G as ActiveFilter, H as UITableCellActions, I as UITableHeadCell, J as ColumnAggregationType, K as BooleanFilterValue, L as UITableHead, M as UITableInnerTable, Mt as TagFilterValue, N as UITableHeadRow, Nt as TextFilterValue, O as UITableWrapper, Ot as TUITableLoadMore, P as UITableHeadCellSelect, Pt as UITableEmpty, Q as FilterOption, R as UITableFooterRow, S as UITableTooltip, St as TUITableHeadCell, T as UITableUserDataDisplay, Tt as TUITableHeadRow, U as UITableCell, V as UITableCellSelect, W as UITableBody, X as DateRangeFilterValue, Y as CsvCell, Z as FilterDefinition, _ as UITableRemoveButton, _t as TUITableCellSelect, a as UITableCurrencyDisplay, at as TTableAnalysisContext, b as UITableSummaryBar, bt as TUITableFooter, c as UITableEditButton, ct as TTableFilterContext, d as UITableListDisplay, dt as TTableInnerWrapperContext, et as FilterValue, f as UITableMoreButton, ft as TTableRowContext, g as UITableProgressDisplay, gt as TUITableCellActions, h as UITablePhoneNumberDisplay, ht as TUITableCell, i as UITableBooleanDisplay, it as SummaryItem, j as UITableInnerWrapper, jt as TableProviderProps, k as UITableRow, kt as TUITableRow, l as UITableEmailDisplay, lt as TTableHeadRowContext, m as UITablePermalink, mt as TUITableBody, n as UITableAvatarNameDisplay, nt as RowData, o as UITableDateDisplay, ot as TTableBodyContext, p as UITableNameDisplay, pt as TTableSummaryContext, q as ColumnAggregation, r as UITableBadgeDisplay, rt as SingleTagFilterValue, s as UITableDescriptionDisplay, st as TTableContext, t as UITableAnalysisPanel, tt as NumberFilterValue, u as UITableFilter, ut as TTableInnerTableContext, v as UITableStatisticDisplay, vt as TUITableColumn, w as UITableTooltipFilter, wt as TUITableHeadCellSelect, x as UITableToggleButton, xt as TUITableHead, y as UITableStatusDisplay, yt as TUITableEmptyDisplay, z as UITableFooter } from "../../index-
|
|
1
|
+
import { $ as FilterType, A as UITableLoadMore, At as TUITableWrapper, B as UITableEmptyDisplay, C as UITableTooltipActions, Ct as TUITableHeadCellOption, D as UITableContainer, Dt as TUITableInnerWrapper, E as UITableProvider, Et as TUITableInnerTable, F as UITableHeadCellOption, G as ActiveFilter, H as UITableCellActions, I as UITableHeadCell, J as ColumnAggregationType, K as BooleanFilterValue, L as UITableHead, M as UITableInnerTable, Mt as TagFilterValue, N as UITableHeadRow, Nt as TextFilterValue, O as UITableWrapper, Ot as TUITableLoadMore, P as UITableHeadCellSelect, Pt as UITableEmpty, Q as FilterOption, R as UITableFooterRow, S as UITableTooltip, St as TUITableHeadCell, T as UITableUserDataDisplay, Tt as TUITableHeadRow, U as UITableCell, V as UITableCellSelect, W as UITableBody, X as DateRangeFilterValue, Y as CsvCell, Z as FilterDefinition, _ as UITableRemoveButton, _t as TUITableCellSelect, a as UITableCurrencyDisplay, at as TTableAnalysisContext, b as UITableSummaryBar, bt as TUITableFooter, c as UITableEditButton, ct as TTableFilterContext, d as UITableListDisplay, dt as TTableInnerWrapperContext, et as FilterValue, f as UITableMoreButton, ft as TTableRowContext, g as UITableProgressDisplay, gt as TUITableCellActions, h as UITablePhoneNumberDisplay, ht as TUITableCell, i as UITableBooleanDisplay, it as SummaryItem, j as UITableInnerWrapper, jt as TableProviderProps, k as UITableRow, kt as TUITableRow, l as UITableEmailDisplay, lt as TTableHeadRowContext, m as UITablePermalink, mt as TUITableBody, n as UITableAvatarNameDisplay, nt as RowData, o as UITableDateDisplay, ot as TTableBodyContext, p as UITableNameDisplay, pt as TTableSummaryContext, q as ColumnAggregation, r as UITableBadgeDisplay, rt as SingleTagFilterValue, s as UITableDescriptionDisplay, st as TTableContext, t as UITableAnalysisPanel, tt as NumberFilterValue, u as UITableFilter, ut as TTableInnerTableContext, v as UITableStatisticDisplay, vt as TUITableColumn, w as UITableTooltipFilter, wt as TUITableHeadCellSelect, x as UITableToggleButton, xt as TUITableHead, y as UITableStatusDisplay, yt as TUITableEmptyDisplay, z as UITableFooter } from "../../index-BPo-Lg3p.mjs";
|
|
2
2
|
export { ActiveFilter, BooleanFilterValue, ColumnAggregation, ColumnAggregationType, CsvCell, DateRangeFilterValue, FilterDefinition, FilterOption, FilterType, FilterValue, NumberFilterValue, RowData, SingleTagFilterValue, SummaryItem, TTableAnalysisContext, TTableBodyContext, TTableContext, TTableFilterContext, TTableHeadRowContext, TTableInnerTableContext, TTableInnerWrapperContext, TTableRowContext, TTableSummaryContext, TUITableBody, TUITableCell, TUITableCellActions, TUITableCellSelect, TUITableColumn, TUITableEmptyDisplay, TUITableFooter, TUITableHead, TUITableHeadCell, TUITableHeadCellOption, TUITableHeadCellSelect, TUITableHeadRow, TUITableInnerTable, TUITableInnerWrapper, TUITableLoadMore, TUITableRow, TUITableWrapper, TableProviderProps, TagFilterValue, TextFilterValue, UITableAnalysisPanel, UITableAvatarNameDisplay, UITableBadgeDisplay, UITableBody, UITableBooleanDisplay, UITableCell, UITableCellActions, UITableCellSelect, UITableContainer, UITableCurrencyDisplay, UITableDateDisplay, UITableDescriptionDisplay, UITableEditButton, UITableEmailDisplay, UITableEmpty, UITableEmptyDisplay, UITableFilter, UITableFooter, UITableFooterRow, UITableHead, UITableHeadCell, UITableHeadCellOption, UITableHeadCellSelect, UITableHeadRow, UITableInnerTable, UITableInnerWrapper, UITableListDisplay, UITableLoadMore, UITableMoreButton, UITableNameDisplay, UITablePermalink, UITablePhoneNumberDisplay, UITableProgressDisplay, UITableProvider, UITableRemoveButton, UITableRow, UITableStatisticDisplay, UITableStatusDisplay, UITableSummaryBar, UITableToggleButton, UITableTooltip, UITableTooltipActions, UITableTooltipFilter, UITableUserDataDisplay, UITableWrapper };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{A as e,C as t,D as n,E as r,F as i,G as a,H as o,I as s,K as c,L as l,M as u,N as d,O as f,P as p,Q as m,R as h,S as g,T as _,U as v,V as y,W as b,_ as x,a as S,b as C,c as w,d as T,f as E,g as D,h as O,i as k,j as A,k as j,l as M,m as N,n as P,o as F,p as I,r as L,s as R,t as z,u as B,v as V,w as H,x as U,y as W}from"../../tables-
|
|
1
|
+
"use client";import{A as e,C as t,D as n,E as r,F as i,G as a,H as o,I as s,K as c,L as l,M as u,N as d,O as f,P as p,Q as m,R as h,S as g,T as _,U as v,V as y,W as b,_ as x,a as S,b as C,c as w,d as T,f as E,g as D,h as O,i as k,j as A,k as j,l as M,m as N,n as P,o as F,p as I,r as L,s as R,t as z,u as B,v as V,w as H,x as U,y as W}from"../../tables-Dg3KMBKA.mjs";export{z as UITableAnalysisPanel,P as UITableAvatarNameDisplay,L as UITableBadgeDisplay,c as UITableBody,k as UITableBooleanDisplay,a as UITableCell,b as UITableCellActions,v as UITableCellSelect,n as UITableContainer,S as UITableCurrencyDisplay,F as UITableDateDisplay,R as UITableDescriptionDisplay,w as UITableEditButton,M as UITableEmailDisplay,m as UITableEmpty,o as UITableEmptyDisplay,B as UITableFilter,y as UITableFooter,h as UITableFooterRow,l as UITableHead,i as UITableHeadCell,s as UITableHeadCellOption,p as UITableHeadCellSelect,d as UITableHeadRow,u as UITableInnerTable,A as UITableInnerWrapper,T as UITableListDisplay,e as UITableLoadMore,E as UITableMoreButton,I as UITableNameDisplay,N as UITablePermalink,O as UITablePhoneNumberDisplay,D as UITableProgressDisplay,r as UITableProvider,x as UITableRemoveButton,j as UITableRow,V as UITableStatisticDisplay,W as UITableStatusDisplay,C as UITableSummaryBar,U as UITableToggleButton,g as UITableTooltip,t as UITableTooltipActions,H as UITableTooltipFilter,_ as UITableUserDataDisplay,f as UITableWrapper};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Button as e}from"./ui/button.mjs";import{X as t}from"./tables-
|
|
2
|
-
//# sourceMappingURL=filter-
|
|
1
|
+
import{Button as e}from"./ui/button.mjs";import{X as t}from"./tables-Dg3KMBKA.mjs";import{Checkbox as n}from"./ui/checkbox.mjs";import{DropdownMenu as r,DropdownMenuContent as i,DropdownMenuItem as a,DropdownMenuTrigger as o}from"./ui/dropdown-menu.mjs";import{ResizablePanel as s}from"./ui/resizable.mjs";import{Popover as c,PopoverContent as l,PopoverTrigger as u}from"./ui/popover.mjs";import{Input as d}from"./ui/input.mjs";import{Separator as f}from"./ui/separator.mjs";import{Label as p}from"./ui/label.mjs";import{Select as m,SelectContent as h,SelectItem as g,SelectTrigger as _,SelectValue as v}from"./ui/select.mjs";import{CalendarIcon as y,HashIcon as b,ListFilterIcon as x,ListFilterPlus as S,TagIcon as C,ToggleLeftIcon as w,Trash2Icon as T,TypeIcon as E}from"lucide-react";import{Activity as D,useState as O}from"react";import{cn as k}from"@customafk/react-toolkit/utils";import{jsx as A,jsxs as j}from"react/jsx-runtime";const M={tag:A(C,{size:14}),"single-tag":A(C,{size:14}),"date-range":A(y,{size:14}),number:A(b,{size:14}),text:A(E,{size:14}),boolean:A(w,{size:14})},N=[{value:`eq`,label:`Bằng (=)`},{value:`ne`,label:`Không bằng (≠)`},{value:`gt`,label:`Lớn hơn (>)`},{value:`gte`,label:`Ít nhất (≥)`},{value:`lt`,label:`Nhỏ hơn (<)`},{value:`lte`,label:`Nhiều nhất (≤)`},{value:`between`,label:`Trong khoảng`}],P=[{value:`contains`,label:`Chứa`},{value:`equals`,label:`Bằng`},{value:`starts-with`,label:`Bắt đầu bằng`},{value:`ends-with`,label:`Kết thúc bằng`}];function F(e,t){switch(e.type){case`single-tag`:return e.value?t.options?.find(t=>t.value===e.value)?.label??e.value:`Chưa đặt`;case`tag`:return e.values.length?e.values.map(e=>t.options?.find(t=>t.value===e)?.label??e).join(`, `):`Chưa đặt`;case`date-range`:return!e.from&&!e.to?`Ngày không xác định`:e.from&&e.to?`${e.from} → ${e.to}`:e.from?`từ ${e.from}`:`đến ${e.to}`;case`number`:{let t={eq:`=`,ne:`≠`,gt:`>`,gte:`≥`,lt:`<`,lte:`≤`,between:`trong khoảng`}[e.operator];return e.value===void 0?t:e.operator===`between`?`${t} ${e.value} – ${e.valueTo??`?`}`:`${t} ${e.value}`}case`text`:{let t={contains:`chứa`,equals:`là`,"starts-with":`bắt đầu bằng`,"ends-with":`kết thúc bằng`}[e.operator];return e.value?`${t} "${e.value}"`:t}case`boolean`:return e.value===null?`Không xác định`:e.value?`Có`:`Không`}}const I=({value:e,definition:t,onChange:r})=>A(`div`,{className:`flex flex-col gap-1 p-3`,children:(t.options??[]).length===0?A(`p`,{className:`text-xs text-text-positive-muted`,children:`Không có tùy chọn`}):t.options.map(t=>j(p,{className:k(`flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors`,e.values.includes(t.value)&&`bg-primary-muted hover:bg-primary-subtle`),children:[A(n,{checked:e.values.includes(t.value),onCheckedChange:n=>{r({type:`tag`,values:n?[...e.values,t.value]:e.values.filter(e=>e!==t.value)})}}),A(`span`,{className:`text-sm`,children:t.label})]},t.value))}),L=({value:e,definition:t,onChange:r})=>A(`div`,{className:`flex flex-col gap-1 p-3`,children:(t.options??[]).length===0?A(`p`,{className:`text-text-positive-muted text-xs`,children:`Không có tùy chọn`}):t.options?.map(t=>j(p,{className:k(`flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted`,e.value===t.value&&`bg-primary-muted hover:bg-primary-subtle`),children:[A(n,{checked:e.value===t.value,onCheckedChange:e=>{r({type:`single-tag`,value:e?t.value:null})}}),A(`span`,{className:`text-sm`,children:t.label})]},t.value))}),R=({value:e,onChange:t})=>j(`div`,{className:`flex flex-col gap-3 p-3`,children:[j(`div`,{className:`flex flex-col gap-1`,children:[A(`span`,{className:`text-text-positive-muted text-xs`,children:`Từ ngày`}),A(d,{type:`date`,size:`md`,value:e.from??``,onValueChange:n=>t({...e,from:n||void 0})})]}),j(`div`,{className:`flex flex-col gap-1`,children:[A(`span`,{className:`text-text-positive-muted text-xs`,children:`Đến ngày`}),A(d,{type:`date`,size:`md`,value:e.to??``,onValueChange:n=>t({...e,to:n||void 0})})]})]}),z=({value:e,onChange:t})=>j(`div`,{className:`flex flex-col gap-3 p-3`,children:[j(m,{value:e.operator,onValueChange:n=>t({...e,operator:n}),children:[A(_,{size:`sm`,children:A(v,{})}),A(h,{children:N.map(e=>A(g,{value:e.value,children:e.label},e.value))})]}),A(d,{type:`number`,size:`md`,placeholder:`Giá trị`,value:e.value??``,onValueChange:n=>t({...e,value:n?Number(n):void 0})}),e.operator===`between`&&A(d,{type:`number`,size:`md`,placeholder:`Đến giá trị`,value:e.valueTo??``,onValueChange:n=>t({...e,valueTo:n?Number(n):void 0})})]}),B=({value:e,onChange:t})=>j(`div`,{className:`flex flex-col gap-3 p-3`,children:[j(m,{value:e.operator,onValueChange:n=>t({...e,operator:n}),children:[A(_,{size:`sm`,children:A(v,{})}),A(h,{children:P.map(e=>A(g,{value:e.value,children:e.label},e.value))})]}),A(d,{type:`text`,size:`md`,placeholder:`Nhập văn bản...`,value:e.value,onValueChange:n=>t({...e,value:n})})]}),V=[{label:`Có`,value:!0},{label:`Không`,value:!1},{label:`Không xác định`,value:null}],H=({value:t,onChange:n})=>A(`div`,{className:`flex flex-col gap-1 p-3`,children:V.map(({label:r,value:i})=>A(e,{type:`button`,tabIndex:-1,variant:`outline`,className:k(`rounded px-3 py-1.5 text-left text-sm transition-colors`,t.value===i?`bg-primary-muted font-medium`:`hover:bg-muted-bg-subtle`),onClick:()=>n({type:`boolean`,value:i}),children:r},r))});function U({value:e,definition:t,onChange:n}){switch(e.type){case`tag`:return A(I,{value:e,definition:t,onChange:n});case`single-tag`:return A(L,{value:e,definition:t,onChange:n});case`date-range`:return A(R,{value:e,onChange:n});case`number`:return A(z,{value:e,onChange:n});case`text`:return A(B,{value:e,onChange:n});case`boolean`:return A(H,{value:e,onChange:n})}}const W=({filter:t,definition:n,onRemove:r,onUpdate:i})=>j(`div`,{className:`flex items-center gap-1`,children:[j(c,{children:[A(u,{asChild:!0,children:j(e,{type:`button`,variant:`outline`,color:`muted`,className:`max-w-[calc(100%-32px)] flex-1 justify-start bg-white`,innerClassName:`flex truncate gap-1.5`,children:[A(`span`,{className:`shrink-0 font-medium text-text-positive`,children:n.label}),A(`span`,{className:`truncate text-text-positive-weak text-xs`,children:F(t.value,n)})]})}),j(l,{className:`w-64 p-0`,align:`start`,side:`bottom`,children:[A(`div`,{className:`border-border border-b px-3 py-2`,children:j(`div`,{className:`flex items-center gap-1.5`,children:[A(`span`,{className:`text-text-positive-muted`,children:M[n.type]}),A(`p`,{className:`font-medium`,children:n.label})]})}),A(U,{value:t.value,definition:n,onChange:i})]})]}),A(e,{type:`button`,size:`icon`,variant:`soft`,color:`danger`,className:`shrink`,onClick:r,children:A(T,{size:13})})]}),G=()=>{let{filterDefinitions:n,activeFilters:c,addFilter:l,removeFilter:u,updateFilter:d}=t(),[p,m]=O(null),h=n.filter(e=>!c.some(t=>t.definitionId===e.id));return A(s,{defaultSize:25,className:k(`bg-card`,p===null?`max-w-8!`:`min-w-64`),children:j(`div`,{className:`relative z-20 flex size-full bg-muted-bg-subtle`,children:[A(`div`,{className:`min-w-0 flex-1 overflow-hidden`,children:A(D,{mode:p===`filters`?`visible`:`hidden`,children:j(`div`,{className:`flex size-full flex-col gap-2 p-4`,children:[j(`div`,{className:`flex items-center justify-between gap-2`,children:[A(`p`,{className:`font-medium`,children:`Bộ lọc`}),j(r,{children:[A(o,{asChild:!0,children:j(e,{variant:`outline`,color:`muted`,disabled:h.length===0,children:[A(S,{size:13}),`Thêm bộ lọc`]})}),A(i,{align:`end`,children:h.map(e=>j(a,{className:`flex items-center gap-2`,onClick:()=>l(e.id),children:[M[e.type],e.label]},e.id))})]})]}),A(f,{}),c.length===0?A(`p`,{className:`py-6 text-center text-text-positive-muted text-xs`,children:`Không có bộ lọc nào`}):A(`div`,{className:`flex flex-col gap-2 pt-1`,children:c.map(e=>{let t=n.find(t=>t.id===e.definitionId);return t?A(W,{filter:e,definition:t,onRemove:()=>u(e.id),onUpdate:t=>d(e.id,t)},e.id):null})})]})})}),j(`div`,{className:`flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm`,children:[j(`button`,{type:`button`,className:k(`relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4`,p===`filters`&&`bg-card`),onClick:()=>m(p===`filters`?null:`filters`),children:[A(x,{size:18}),c.length>0&&A(`span`,{className:`absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none`,children:c.length}),A(`span`,{className:`text-nowrap [writing-mode:vertical-lr]`,children:`Bộ lọc`})]}),A(f,{})]})]})})};export{G as UITableFilter};
|
|
2
|
+
//# sourceMappingURL=filter-BO7ISTIR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-C2wE49q7.mjs","names":[],"sources":["../packages/components/features/tables/components/table/filter.tsx"],"sourcesContent":["/**\n * @file filter.tsx\n * Collapsible side-panel with column-visibility toggles and a dynamic filter builder.\n *\n * - \"Columns\" tab: toggle individual column visibility.\n * - \"Filters\" tab: \"Add Filter\" dropdown → active filter chips → per-filter Popover editor.\n */\nimport { Activity, useState } from 'react';\n\nimport { CalendarIcon, HashIcon, ListFilterIcon, ListFilterPlus, TagIcon, ToggleLeftIcon, Trash2Icon, TypeIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { ResizablePanel } from '@/components/ui/resizable';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Separator } from '@/components/ui/separator';\n\nimport { useUITableFilterContext } from '../../hooks/use-context';\nimport type {\n ActiveFilter,\n BooleanFilterValue,\n DateRangeFilterValue,\n FilterDefinition,\n FilterType,\n FilterValue,\n NumberFilterValue,\n SingleTagFilterValue,\n TagFilterValue,\n TextFilterValue,\n} from '../../types';\n\n// ── icons per filter type ──────────────────────────────────────────────────────\n\nconst TYPE_ICONS: Record<FilterType, React.ReactNode> = {\n tag: <TagIcon size={14} />,\n 'single-tag': <TagIcon size={14} />,\n 'date-range': <CalendarIcon size={14} />,\n number: <HashIcon size={14} />,\n text: <TypeIcon size={14} />,\n boolean: <ToggleLeftIcon size={14} />,\n};\n\n// ── operator options ───────────────────────────────────────────────────────────\n\nconst NUMBER_OPERATORS: { value: NumberFilterValue['operator']; label: string }[] = [\n { value: 'eq', label: 'Bằng (=)' },\n { value: 'ne', label: 'Không bằng (≠)' },\n { value: 'gt', label: 'Lớn hơn (>)' },\n { value: 'gte', label: 'Ít nhất (≥)' },\n { value: 'lt', label: 'Nhỏ hơn (<)' },\n { value: 'lte', label: 'Nhiều nhất (≤)' },\n { value: 'between', label: 'Trong khoảng' },\n];\n\nconst TEXT_OPERATORS: { value: TextFilterValue['operator']; label: string }[] = [\n { value: 'contains', label: 'Chứa' },\n { value: 'equals', label: 'Bằng' },\n { value: 'starts-with', label: 'Bắt đầu bằng' },\n { value: 'ends-with', label: 'Kết thúc bằng' },\n];\n\n// ── summary label ──────────────────────────────────────────────────────────────\n\nfunction formatFilterValue(value: FilterValue, def: FilterDefinition): string {\n switch (value.type) {\n case 'single-tag': {\n if (!value.value) return 'Chưa đặt';\n return def.options?.find(o => o.value === value.value)?.label ?? value.value;\n }\n case 'tag': {\n if (!value.values.length) return 'Chưa đặt';\n return value.values.map(v => def.options?.find(o => o.value === v)?.label ?? v).join(', ');\n }\n case 'date-range': {\n if (!value.from && !value.to) return 'Ngày không xác định';\n if (value.from && value.to) return `${value.from} → ${value.to}`;\n if (value.from) return `từ ${value.from}`;\n return `đến ${value.to}`;\n }\n case 'number': {\n const op = { eq: '=', ne: '≠', gt: '>', gte: '≥', lt: '<', lte: '≤', between: 'trong khoảng' }[value.operator];\n if (value.value === undefined) return op;\n if (value.operator === 'between') return `${op} ${value.value} – ${value.valueTo ?? '?'}`;\n return `${op} ${value.value}`;\n }\n case 'text': {\n const op = {\n contains: 'chứa',\n equals: 'là',\n 'starts-with': 'bắt đầu bằng',\n 'ends-with': 'kết thúc bằng',\n }[value.operator];\n return value.value ? `${op} \"${value.value}\"` : op;\n }\n case 'boolean':\n if (value.value === null) return 'Không xác định';\n return value.value ? 'Có' : 'Không';\n }\n}\n\n// ── filter editors ─────────────────────────────────────────────────────────────\n\nconst TagFilterEditor: React.FC<{\n value: TagFilterValue;\n definition: FilterDefinition;\n onChange: (v: TagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-xs text-text-positive-muted\">Không có tùy chọn</p>\n ) : (\n definition.options!.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors',\n value.values.includes(option.value) && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.values.includes(option.value)}\n onCheckedChange={checked => {\n const next = checked ? [...value.values, option.value] : value.values.filter(v => v !== option.value);\n onChange({ type: 'tag', values: next });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst SingleTagFilterEditor: React.FC<{\n value: SingleTagFilterValue;\n definition: FilterDefinition;\n onChange: (v: SingleTagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-text-positive-muted text-xs\">Không có tùy chọn</p>\n ) : (\n definition.options?.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted',\n value.value === option.value && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.value === option.value}\n onCheckedChange={checked => {\n onChange({ type: 'single-tag', value: checked ? option.value : null });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst DateRangeFilterEditor: React.FC<{\n value: DateRangeFilterValue;\n onChange: (v: DateRangeFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Từ ngày</span>\n <Input type=\"date\" size=\"md\" value={value.from ?? ''} onValueChange={v => onChange({ ...value, from: v || undefined })} />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Đến ngày</span>\n <Input type=\"date\" size=\"md\" value={value.to ?? ''} onValueChange={v => onChange({ ...value, to: v || undefined })} />\n </div>\n </div>\n);\n\nconst NumberFilterEditor: React.FC<{\n value: NumberFilterValue;\n onChange: (v: NumberFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as NumberFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {NUMBER_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Giá trị\"\n value={value.value ?? ''}\n onValueChange={v => onChange({ ...value, value: v ? Number(v) : undefined })}\n />\n {value.operator === 'between' && (\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Đến giá trị\"\n value={value.valueTo ?? ''}\n onValueChange={v => onChange({ ...value, valueTo: v ? Number(v) : undefined })}\n />\n )}\n </div>\n);\n\nconst TextFilterEditor: React.FC<{\n value: TextFilterValue;\n onChange: (v: TextFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as TextFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TEXT_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input type=\"text\" size=\"md\" placeholder=\"Nhập văn bản...\" value={value.value} onValueChange={v => onChange({ ...value, value: v })} />\n </div>\n);\n\nconst BOOLEAN_OPTIONS = [\n { label: 'Có', value: true as boolean | null },\n { label: 'Không', value: false as boolean | null },\n { label: 'Không xác định', value: null as boolean | null },\n];\n\nconst BooleanFilterEditor: React.FC<{\n value: BooleanFilterValue;\n onChange: (v: BooleanFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {BOOLEAN_OPTIONS.map(({ label, value: v }) => (\n <Button\n key={label}\n type=\"button\"\n tabIndex={-1}\n variant=\"outline\"\n className={cn(\n 'rounded px-3 py-1.5 text-left text-sm transition-colors',\n value.value === v ? 'bg-primary-muted font-medium' : 'hover:bg-muted-bg-subtle'\n )}\n onClick={() => onChange({ type: 'boolean', value: v })}\n >\n {label}\n </Button>\n ))}\n </div>\n);\n\nfunction FilterEditor({ value, definition, onChange }: { value: FilterValue; definition: FilterDefinition; onChange: (v: FilterValue) => void }) {\n switch (value.type) {\n case 'tag':\n return <TagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'single-tag':\n return <SingleTagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'date-range':\n return <DateRangeFilterEditor value={value} onChange={onChange} />;\n case 'number':\n return <NumberFilterEditor value={value} onChange={onChange} />;\n case 'text':\n return <TextFilterEditor value={value} onChange={onChange} />;\n case 'boolean':\n return <BooleanFilterEditor value={value} onChange={onChange} />;\n }\n}\n\n// ── filter item chip ───────────────────────────────────────────────────────────\n\nconst FilterItem: React.FC<{\n filter: ActiveFilter;\n definition: FilterDefinition;\n onRemove: () => void;\n onUpdate: (value: FilterValue) => void;\n}> = ({ filter, definition, onRemove, onUpdate }) => (\n <div className=\"flex items-center gap-1\">\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n color=\"muted\"\n className=\"max-w-[calc(100%-32px)] flex-1 justify-start bg-white\"\n innerClassName=\"flex truncate gap-1.5\"\n >\n <span className=\"shrink-0 font-medium text-text-positive\">{definition.label}</span>\n <span className=\"truncate text-text-positive-weak text-xs\">{formatFilterValue(filter.value, definition)}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\" side=\"bottom\">\n <div className=\"border-border border-b px-3 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-positive-muted\">{TYPE_ICONS[definition.type]}</span>\n <p className=\"font-medium\">{definition.label}</p>\n </div>\n </div>\n <FilterEditor value={filter.value} definition={definition} onChange={onUpdate} />\n </PopoverContent>\n </Popover>\n <Button type=\"button\" size=\"icon\" variant=\"soft\" color=\"danger\" className=\"shrink\" onClick={onRemove}>\n <Trash2Icon size={13} />\n </Button>\n </div>\n);\n\n// ── column visibility row ──────────────────────────────────────────────────────\n\n// const ColumnVisibility: React.FC<{\n// checked: boolean;\n// title: string;\n// onCheckedChange?: (checked: boolean) => void;\n// }> = ({ checked, title, onCheckedChange }) => (\n// <Label>\n// <Checkbox checked={checked} onCheckedChange={onCheckedChange} />\n// <p className=\"text-sm\">{title}</p>\n// </Label>\n// );\n\n// ── main component ─────────────────────────────────────────────────────────────\n\n/**\n * Collapsible side-panel that lets users toggle column visibility and build\n * row filters without leaving the table view.\n *\n * The panel collapses to a narrow icon strip when no tab is active and expands\n * to at least 64 units when the \"Columns\" or \"Filters\" tab is selected.\n *\n * Wire filter capability by passing `filterDefinitions` and `onFilterChange` to\n * the parent `UITableProvider`.\n *\n * @example\n * ```tsx\n * <UITableProvider\n * filterDefinitions={[\n * { id: 'status', label: 'Status', type: 'tag', options: [{ label: 'Active', value: 'active' }] },\n * { id: 'created', label: 'Created At', type: 'date-range' },\n * { id: 'amount', label: 'Amount', type: 'number' },\n * ]}\n * onFilterChange={filters => console.log(filters)}\n * >\n * <ResizablePanelGroup direction=\"horizontal\">\n * <ResizablePanel><UITable /></ResizablePanel>\n * <ResizableHandle />\n * <UITableFilter />\n * </ResizablePanelGroup>\n * </UITableProvider>\n * ```\n */\nexport const UITableFilter = () => {\n // const { table } = useUITableContext();\n const { filterDefinitions, activeFilters, addFilter, removeFilter, updateFilter } = useUITableFilterContext();\n\n const [tab, setTab] = useState<'columns' | 'filters' | null>(null);\n\n const availableDefinitions = filterDefinitions.filter(def => !activeFilters.some(f => f.definitionId === def.id));\n\n return (\n <ResizablePanel defaultSize={25} className={cn('bg-card', tab === null ? 'max-w-8!' : 'min-w-64')}>\n <div className=\"relative z-20 flex size-full bg-muted-bg-subtle\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n {/* Columns tab */}\n {/*<Activity mode={tab === 'columns' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <p className=\"px-2 font-medium\">Columns Visibility</p>\n <Separator />\n <div className=\"flex flex-col gap-4 pt-4\">\n {table.getAllColumns().map(column => {\n if (['select', 'actions'].includes(column.id)) return null;\n return (\n <ColumnVisibility\n key={column.id}\n checked={column.getIsVisible()}\n title={String(column.columnDef.header)}\n onCheckedChange={value => column.toggleVisibility(!!value)}\n />\n );\n })}\n </div>\n </div>\n </Activity>*/}\n\n {/* Filters tab */}\n <Activity mode={tab === 'filters' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"font-medium\">Bộ lọc</p>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" color=\"muted\" disabled={availableDefinitions.length === 0}>\n <ListFilterPlus size={13} />\n Thêm bộ lọc\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {availableDefinitions.map(def => (\n <DropdownMenuItem key={def.id} className=\"flex items-center gap-2\" onClick={() => addFilter(def.id)}>\n {TYPE_ICONS[def.type]}\n {def.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n <Separator />\n {activeFilters.length === 0 ? (\n <p className=\"py-6 text-center text-text-positive-muted text-xs\">Không có bộ lọc nào</p>\n ) : (\n <div className=\"flex flex-col gap-2 pt-1\">\n {activeFilters.map(filter => {\n const def = filterDefinitions.find(d => d.id === filter.definitionId);\n if (!def) return null;\n return (\n <FilterItem\n key={filter.id}\n filter={filter}\n definition={def}\n onRemove={() => removeFilter(filter.id)}\n onUpdate={value => updateFilter(filter.id, value)}\n />\n );\n })}\n </div>\n )}\n </div>\n </Activity>\n </div>\n\n {/* Vertical tab strip */}\n <div className=\"flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm\">\n {/*<button\n type=\"button\"\n className={cn('flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'columns' && 'bg-card')}\n onClick={() => setTab(tab === 'columns' ? null : 'columns')}\n >\n <Columns4Icon size={18} />\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Columns</span>\n </button>\n <Separator />*/}\n <button\n type=\"button\"\n className={cn('relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'filters' && 'bg-card')}\n onClick={() => setTab(tab === 'filters' ? null : 'filters')}\n >\n <ListFilterIcon size={18} />\n {activeFilters.length > 0 && (\n <span className=\"absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none\">\n {activeFilters.length}\n </span>\n )}\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Bộ lọc</span>\n </button>\n <Separator />\n </div>\n </div>\n </ResizablePanel>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filter-BO7ISTIR.mjs","names":[],"sources":["../packages/components/features/tables/components/table/filter.tsx"],"sourcesContent":["/**\n * @file filter.tsx\n * Collapsible side-panel with column-visibility toggles and a dynamic filter builder.\n *\n * - \"Columns\" tab: toggle individual column visibility.\n * - \"Filters\" tab: \"Add Filter\" dropdown → active filter chips → per-filter Popover editor.\n */\nimport { Activity, useState } from 'react';\n\nimport { CalendarIcon, HashIcon, ListFilterIcon, ListFilterPlus, TagIcon, ToggleLeftIcon, Trash2Icon, TypeIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { ResizablePanel } from '@/components/ui/resizable';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Separator } from '@/components/ui/separator';\n\nimport { useUITableFilterContext } from '../../hooks/use-context';\nimport type {\n ActiveFilter,\n BooleanFilterValue,\n DateRangeFilterValue,\n FilterDefinition,\n FilterType,\n FilterValue,\n NumberFilterValue,\n SingleTagFilterValue,\n TagFilterValue,\n TextFilterValue,\n} from '../../types';\n\n// ── icons per filter type ──────────────────────────────────────────────────────\n\nconst TYPE_ICONS: Record<FilterType, React.ReactNode> = {\n tag: <TagIcon size={14} />,\n 'single-tag': <TagIcon size={14} />,\n 'date-range': <CalendarIcon size={14} />,\n number: <HashIcon size={14} />,\n text: <TypeIcon size={14} />,\n boolean: <ToggleLeftIcon size={14} />,\n};\n\n// ── operator options ───────────────────────────────────────────────────────────\n\nconst NUMBER_OPERATORS: { value: NumberFilterValue['operator']; label: string }[] = [\n { value: 'eq', label: 'Bằng (=)' },\n { value: 'ne', label: 'Không bằng (≠)' },\n { value: 'gt', label: 'Lớn hơn (>)' },\n { value: 'gte', label: 'Ít nhất (≥)' },\n { value: 'lt', label: 'Nhỏ hơn (<)' },\n { value: 'lte', label: 'Nhiều nhất (≤)' },\n { value: 'between', label: 'Trong khoảng' },\n];\n\nconst TEXT_OPERATORS: { value: TextFilterValue['operator']; label: string }[] = [\n { value: 'contains', label: 'Chứa' },\n { value: 'equals', label: 'Bằng' },\n { value: 'starts-with', label: 'Bắt đầu bằng' },\n { value: 'ends-with', label: 'Kết thúc bằng' },\n];\n\n// ── summary label ──────────────────────────────────────────────────────────────\n\nfunction formatFilterValue(value: FilterValue, def: FilterDefinition): string {\n switch (value.type) {\n case 'single-tag': {\n if (!value.value) return 'Chưa đặt';\n return def.options?.find(o => o.value === value.value)?.label ?? value.value;\n }\n case 'tag': {\n if (!value.values.length) return 'Chưa đặt';\n return value.values.map(v => def.options?.find(o => o.value === v)?.label ?? v).join(', ');\n }\n case 'date-range': {\n if (!value.from && !value.to) return 'Ngày không xác định';\n if (value.from && value.to) return `${value.from} → ${value.to}`;\n if (value.from) return `từ ${value.from}`;\n return `đến ${value.to}`;\n }\n case 'number': {\n const op = { eq: '=', ne: '≠', gt: '>', gte: '≥', lt: '<', lte: '≤', between: 'trong khoảng' }[value.operator];\n if (value.value === undefined) return op;\n if (value.operator === 'between') return `${op} ${value.value} – ${value.valueTo ?? '?'}`;\n return `${op} ${value.value}`;\n }\n case 'text': {\n const op = {\n contains: 'chứa',\n equals: 'là',\n 'starts-with': 'bắt đầu bằng',\n 'ends-with': 'kết thúc bằng',\n }[value.operator];\n return value.value ? `${op} \"${value.value}\"` : op;\n }\n case 'boolean':\n if (value.value === null) return 'Không xác định';\n return value.value ? 'Có' : 'Không';\n }\n}\n\n// ── filter editors ─────────────────────────────────────────────────────────────\n\nconst TagFilterEditor: React.FC<{\n value: TagFilterValue;\n definition: FilterDefinition;\n onChange: (v: TagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-xs text-text-positive-muted\">Không có tùy chọn</p>\n ) : (\n definition.options!.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors',\n value.values.includes(option.value) && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.values.includes(option.value)}\n onCheckedChange={checked => {\n const next = checked ? [...value.values, option.value] : value.values.filter(v => v !== option.value);\n onChange({ type: 'tag', values: next });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst SingleTagFilterEditor: React.FC<{\n value: SingleTagFilterValue;\n definition: FilterDefinition;\n onChange: (v: SingleTagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-text-positive-muted text-xs\">Không có tùy chọn</p>\n ) : (\n definition.options?.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted',\n value.value === option.value && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.value === option.value}\n onCheckedChange={checked => {\n onChange({ type: 'single-tag', value: checked ? option.value : null });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst DateRangeFilterEditor: React.FC<{\n value: DateRangeFilterValue;\n onChange: (v: DateRangeFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Từ ngày</span>\n <Input type=\"date\" size=\"md\" value={value.from ?? ''} onValueChange={v => onChange({ ...value, from: v || undefined })} />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Đến ngày</span>\n <Input type=\"date\" size=\"md\" value={value.to ?? ''} onValueChange={v => onChange({ ...value, to: v || undefined })} />\n </div>\n </div>\n);\n\nconst NumberFilterEditor: React.FC<{\n value: NumberFilterValue;\n onChange: (v: NumberFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as NumberFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {NUMBER_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Giá trị\"\n value={value.value ?? ''}\n onValueChange={v => onChange({ ...value, value: v ? Number(v) : undefined })}\n />\n {value.operator === 'between' && (\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Đến giá trị\"\n value={value.valueTo ?? ''}\n onValueChange={v => onChange({ ...value, valueTo: v ? Number(v) : undefined })}\n />\n )}\n </div>\n);\n\nconst TextFilterEditor: React.FC<{\n value: TextFilterValue;\n onChange: (v: TextFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as TextFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TEXT_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input type=\"text\" size=\"md\" placeholder=\"Nhập văn bản...\" value={value.value} onValueChange={v => onChange({ ...value, value: v })} />\n </div>\n);\n\nconst BOOLEAN_OPTIONS = [\n { label: 'Có', value: true as boolean | null },\n { label: 'Không', value: false as boolean | null },\n { label: 'Không xác định', value: null as boolean | null },\n];\n\nconst BooleanFilterEditor: React.FC<{\n value: BooleanFilterValue;\n onChange: (v: BooleanFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {BOOLEAN_OPTIONS.map(({ label, value: v }) => (\n <Button\n key={label}\n type=\"button\"\n tabIndex={-1}\n variant=\"outline\"\n className={cn(\n 'rounded px-3 py-1.5 text-left text-sm transition-colors',\n value.value === v ? 'bg-primary-muted font-medium' : 'hover:bg-muted-bg-subtle'\n )}\n onClick={() => onChange({ type: 'boolean', value: v })}\n >\n {label}\n </Button>\n ))}\n </div>\n);\n\nfunction FilterEditor({ value, definition, onChange }: { value: FilterValue; definition: FilterDefinition; onChange: (v: FilterValue) => void }) {\n switch (value.type) {\n case 'tag':\n return <TagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'single-tag':\n return <SingleTagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'date-range':\n return <DateRangeFilterEditor value={value} onChange={onChange} />;\n case 'number':\n return <NumberFilterEditor value={value} onChange={onChange} />;\n case 'text':\n return <TextFilterEditor value={value} onChange={onChange} />;\n case 'boolean':\n return <BooleanFilterEditor value={value} onChange={onChange} />;\n }\n}\n\n// ── filter item chip ───────────────────────────────────────────────────────────\n\nconst FilterItem: React.FC<{\n filter: ActiveFilter;\n definition: FilterDefinition;\n onRemove: () => void;\n onUpdate: (value: FilterValue) => void;\n}> = ({ filter, definition, onRemove, onUpdate }) => (\n <div className=\"flex items-center gap-1\">\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n color=\"muted\"\n className=\"max-w-[calc(100%-32px)] flex-1 justify-start bg-white\"\n innerClassName=\"flex truncate gap-1.5\"\n >\n <span className=\"shrink-0 font-medium text-text-positive\">{definition.label}</span>\n <span className=\"truncate text-text-positive-weak text-xs\">{formatFilterValue(filter.value, definition)}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\" side=\"bottom\">\n <div className=\"border-border border-b px-3 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-positive-muted\">{TYPE_ICONS[definition.type]}</span>\n <p className=\"font-medium\">{definition.label}</p>\n </div>\n </div>\n <FilterEditor value={filter.value} definition={definition} onChange={onUpdate} />\n </PopoverContent>\n </Popover>\n <Button type=\"button\" size=\"icon\" variant=\"soft\" color=\"danger\" className=\"shrink\" onClick={onRemove}>\n <Trash2Icon size={13} />\n </Button>\n </div>\n);\n\n// ── column visibility row ──────────────────────────────────────────────────────\n\n// const ColumnVisibility: React.FC<{\n// checked: boolean;\n// title: string;\n// onCheckedChange?: (checked: boolean) => void;\n// }> = ({ checked, title, onCheckedChange }) => (\n// <Label>\n// <Checkbox checked={checked} onCheckedChange={onCheckedChange} />\n// <p className=\"text-sm\">{title}</p>\n// </Label>\n// );\n\n// ── main component ─────────────────────────────────────────────────────────────\n\n/**\n * Collapsible side-panel that lets users toggle column visibility and build\n * row filters without leaving the table view.\n *\n * The panel collapses to a narrow icon strip when no tab is active and expands\n * to at least 64 units when the \"Columns\" or \"Filters\" tab is selected.\n *\n * Wire filter capability by passing `filterDefinitions` and `onFilterChange` to\n * the parent `UITableProvider`.\n *\n * @example\n * ```tsx\n * <UITableProvider\n * filterDefinitions={[\n * { id: 'status', label: 'Status', type: 'tag', options: [{ label: 'Active', value: 'active' }] },\n * { id: 'created', label: 'Created At', type: 'date-range' },\n * { id: 'amount', label: 'Amount', type: 'number' },\n * ]}\n * onFilterChange={filters => console.log(filters)}\n * >\n * <ResizablePanelGroup direction=\"horizontal\">\n * <ResizablePanel><UITable /></ResizablePanel>\n * <ResizableHandle />\n * <UITableFilter />\n * </ResizablePanelGroup>\n * </UITableProvider>\n * ```\n */\nexport const UITableFilter = () => {\n // const { table } = useUITableContext();\n const { filterDefinitions, activeFilters, addFilter, removeFilter, updateFilter } = useUITableFilterContext();\n\n const [tab, setTab] = useState<'columns' | 'filters' | null>(null);\n\n const availableDefinitions = filterDefinitions.filter(def => !activeFilters.some(f => f.definitionId === def.id));\n\n return (\n <ResizablePanel defaultSize={25} className={cn('bg-card', tab === null ? 'max-w-8!' : 'min-w-64')}>\n <div className=\"relative z-20 flex size-full bg-muted-bg-subtle\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n {/* Columns tab */}\n {/*<Activity mode={tab === 'columns' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <p className=\"px-2 font-medium\">Columns Visibility</p>\n <Separator />\n <div className=\"flex flex-col gap-4 pt-4\">\n {table.getAllColumns().map(column => {\n if (['select', 'actions'].includes(column.id)) return null;\n return (\n <ColumnVisibility\n key={column.id}\n checked={column.getIsVisible()}\n title={String(column.columnDef.header)}\n onCheckedChange={value => column.toggleVisibility(!!value)}\n />\n );\n })}\n </div>\n </div>\n </Activity>*/}\n\n {/* Filters tab */}\n <Activity mode={tab === 'filters' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"font-medium\">Bộ lọc</p>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" color=\"muted\" disabled={availableDefinitions.length === 0}>\n <ListFilterPlus size={13} />\n Thêm bộ lọc\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {availableDefinitions.map(def => (\n <DropdownMenuItem key={def.id} className=\"flex items-center gap-2\" onClick={() => addFilter(def.id)}>\n {TYPE_ICONS[def.type]}\n {def.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n <Separator />\n {activeFilters.length === 0 ? (\n <p className=\"py-6 text-center text-text-positive-muted text-xs\">Không có bộ lọc nào</p>\n ) : (\n <div className=\"flex flex-col gap-2 pt-1\">\n {activeFilters.map(filter => {\n const def = filterDefinitions.find(d => d.id === filter.definitionId);\n if (!def) return null;\n return (\n <FilterItem\n key={filter.id}\n filter={filter}\n definition={def}\n onRemove={() => removeFilter(filter.id)}\n onUpdate={value => updateFilter(filter.id, value)}\n />\n );\n })}\n </div>\n )}\n </div>\n </Activity>\n </div>\n\n {/* Vertical tab strip */}\n <div className=\"flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm\">\n {/*<button\n type=\"button\"\n className={cn('flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'columns' && 'bg-card')}\n onClick={() => setTab(tab === 'columns' ? null : 'columns')}\n >\n <Columns4Icon size={18} />\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Columns</span>\n </button>\n <Separator />*/}\n <button\n type=\"button\"\n className={cn('relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'filters' && 'bg-card')}\n onClick={() => setTab(tab === 'filters' ? null : 'filters')}\n >\n <ListFilterIcon size={18} />\n {activeFilters.length > 0 && (\n <span className=\"absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none\">\n {activeFilters.length}\n </span>\n )}\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Bộ lọc</span>\n </button>\n <Separator />\n </div>\n </div>\n </ResizablePanel>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./ui/button.cjs"),t=require("./tables-
|
|
2
|
-
//# sourceMappingURL=filter-
|
|
1
|
+
const e=require("./ui/button.cjs"),t=require("./tables-BqZ4Zs6e.cjs"),n=require("./ui/checkbox.cjs"),r=require("./ui/dropdown-menu.cjs"),i=require("./ui/resizable.cjs"),a=require("./ui/popover.cjs"),o=require("./ui/input.cjs"),s=require("./ui/separator.cjs"),c=require("./ui/label.cjs"),l=require("./ui/select.cjs");let u=require("lucide-react"),d=require("react"),f=require("@customafk/react-toolkit/utils"),p=require("react/jsx-runtime");const m={tag:(0,p.jsx)(u.TagIcon,{size:14}),"single-tag":(0,p.jsx)(u.TagIcon,{size:14}),"date-range":(0,p.jsx)(u.CalendarIcon,{size:14}),number:(0,p.jsx)(u.HashIcon,{size:14}),text:(0,p.jsx)(u.TypeIcon,{size:14}),boolean:(0,p.jsx)(u.ToggleLeftIcon,{size:14})},h=[{value:`eq`,label:`Bằng (=)`},{value:`ne`,label:`Không bằng (≠)`},{value:`gt`,label:`Lớn hơn (>)`},{value:`gte`,label:`Ít nhất (≥)`},{value:`lt`,label:`Nhỏ hơn (<)`},{value:`lte`,label:`Nhiều nhất (≤)`},{value:`between`,label:`Trong khoảng`}],g=[{value:`contains`,label:`Chứa`},{value:`equals`,label:`Bằng`},{value:`starts-with`,label:`Bắt đầu bằng`},{value:`ends-with`,label:`Kết thúc bằng`}];function _(e,t){switch(e.type){case`single-tag`:return e.value?t.options?.find(t=>t.value===e.value)?.label??e.value:`Chưa đặt`;case`tag`:return e.values.length?e.values.map(e=>t.options?.find(t=>t.value===e)?.label??e).join(`, `):`Chưa đặt`;case`date-range`:return!e.from&&!e.to?`Ngày không xác định`:e.from&&e.to?`${e.from} → ${e.to}`:e.from?`từ ${e.from}`:`đến ${e.to}`;case`number`:{let t={eq:`=`,ne:`≠`,gt:`>`,gte:`≥`,lt:`<`,lte:`≤`,between:`trong khoảng`}[e.operator];return e.value===void 0?t:e.operator===`between`?`${t} ${e.value} – ${e.valueTo??`?`}`:`${t} ${e.value}`}case`text`:{let t={contains:`chứa`,equals:`là`,"starts-with":`bắt đầu bằng`,"ends-with":`kết thúc bằng`}[e.operator];return e.value?`${t} "${e.value}"`:t}case`boolean`:return e.value===null?`Không xác định`:e.value?`Có`:`Không`}}const v=({value:e,definition:t,onChange:r})=>(0,p.jsx)(`div`,{className:`flex flex-col gap-1 p-3`,children:(t.options??[]).length===0?(0,p.jsx)(`p`,{className:`text-xs text-text-positive-muted`,children:`Không có tùy chọn`}):t.options.map(t=>(0,p.jsxs)(c.Label,{className:(0,f.cn)(`flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors`,e.values.includes(t.value)&&`bg-primary-muted hover:bg-primary-subtle`),children:[(0,p.jsx)(n.Checkbox,{checked:e.values.includes(t.value),onCheckedChange:n=>{r({type:`tag`,values:n?[...e.values,t.value]:e.values.filter(e=>e!==t.value)})}}),(0,p.jsx)(`span`,{className:`text-sm`,children:t.label})]},t.value))}),y=({value:e,definition:t,onChange:r})=>(0,p.jsx)(`div`,{className:`flex flex-col gap-1 p-3`,children:(t.options??[]).length===0?(0,p.jsx)(`p`,{className:`text-text-positive-muted text-xs`,children:`Không có tùy chọn`}):t.options?.map(t=>(0,p.jsxs)(c.Label,{className:(0,f.cn)(`flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted`,e.value===t.value&&`bg-primary-muted hover:bg-primary-subtle`),children:[(0,p.jsx)(n.Checkbox,{checked:e.value===t.value,onCheckedChange:e=>{r({type:`single-tag`,value:e?t.value:null})}}),(0,p.jsx)(`span`,{className:`text-sm`,children:t.label})]},t.value))}),b=({value:e,onChange:t})=>(0,p.jsxs)(`div`,{className:`flex flex-col gap-3 p-3`,children:[(0,p.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,p.jsx)(`span`,{className:`text-text-positive-muted text-xs`,children:`Từ ngày`}),(0,p.jsx)(o.Input,{type:`date`,size:`md`,value:e.from??``,onValueChange:n=>t({...e,from:n||void 0})})]}),(0,p.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,p.jsx)(`span`,{className:`text-text-positive-muted text-xs`,children:`Đến ngày`}),(0,p.jsx)(o.Input,{type:`date`,size:`md`,value:e.to??``,onValueChange:n=>t({...e,to:n||void 0})})]})]}),x=({value:e,onChange:t})=>(0,p.jsxs)(`div`,{className:`flex flex-col gap-3 p-3`,children:[(0,p.jsxs)(l.Select,{value:e.operator,onValueChange:n=>t({...e,operator:n}),children:[(0,p.jsx)(l.SelectTrigger,{size:`sm`,children:(0,p.jsx)(l.SelectValue,{})}),(0,p.jsx)(l.SelectContent,{children:h.map(e=>(0,p.jsx)(l.SelectItem,{value:e.value,children:e.label},e.value))})]}),(0,p.jsx)(o.Input,{type:`number`,size:`md`,placeholder:`Giá trị`,value:e.value??``,onValueChange:n=>t({...e,value:n?Number(n):void 0})}),e.operator===`between`&&(0,p.jsx)(o.Input,{type:`number`,size:`md`,placeholder:`Đến giá trị`,value:e.valueTo??``,onValueChange:n=>t({...e,valueTo:n?Number(n):void 0})})]}),S=({value:e,onChange:t})=>(0,p.jsxs)(`div`,{className:`flex flex-col gap-3 p-3`,children:[(0,p.jsxs)(l.Select,{value:e.operator,onValueChange:n=>t({...e,operator:n}),children:[(0,p.jsx)(l.SelectTrigger,{size:`sm`,children:(0,p.jsx)(l.SelectValue,{})}),(0,p.jsx)(l.SelectContent,{children:g.map(e=>(0,p.jsx)(l.SelectItem,{value:e.value,children:e.label},e.value))})]}),(0,p.jsx)(o.Input,{type:`text`,size:`md`,placeholder:`Nhập văn bản...`,value:e.value,onValueChange:n=>t({...e,value:n})})]}),C=[{label:`Có`,value:!0},{label:`Không`,value:!1},{label:`Không xác định`,value:null}],w=({value:t,onChange:n})=>(0,p.jsx)(`div`,{className:`flex flex-col gap-1 p-3`,children:C.map(({label:r,value:i})=>(0,p.jsx)(e.Button,{type:`button`,tabIndex:-1,variant:`outline`,className:(0,f.cn)(`rounded px-3 py-1.5 text-left text-sm transition-colors`,t.value===i?`bg-primary-muted font-medium`:`hover:bg-muted-bg-subtle`),onClick:()=>n({type:`boolean`,value:i}),children:r},r))});function T({value:e,definition:t,onChange:n}){switch(e.type){case`tag`:return(0,p.jsx)(v,{value:e,definition:t,onChange:n});case`single-tag`:return(0,p.jsx)(y,{value:e,definition:t,onChange:n});case`date-range`:return(0,p.jsx)(b,{value:e,onChange:n});case`number`:return(0,p.jsx)(x,{value:e,onChange:n});case`text`:return(0,p.jsx)(S,{value:e,onChange:n});case`boolean`:return(0,p.jsx)(w,{value:e,onChange:n})}}const E=({filter:t,definition:n,onRemove:r,onUpdate:i})=>(0,p.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,p.jsxs)(a.Popover,{children:[(0,p.jsx)(a.PopoverTrigger,{asChild:!0,children:(0,p.jsxs)(e.Button,{type:`button`,variant:`outline`,color:`muted`,className:`max-w-[calc(100%-32px)] flex-1 justify-start bg-white`,innerClassName:`flex truncate gap-1.5`,children:[(0,p.jsx)(`span`,{className:`shrink-0 font-medium text-text-positive`,children:n.label}),(0,p.jsx)(`span`,{className:`truncate text-text-positive-weak text-xs`,children:_(t.value,n)})]})}),(0,p.jsxs)(a.PopoverContent,{className:`w-64 p-0`,align:`start`,side:`bottom`,children:[(0,p.jsx)(`div`,{className:`border-border border-b px-3 py-2`,children:(0,p.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`text-text-positive-muted`,children:m[n.type]}),(0,p.jsx)(`p`,{className:`font-medium`,children:n.label})]})}),(0,p.jsx)(T,{value:t.value,definition:n,onChange:i})]})]}),(0,p.jsx)(e.Button,{type:`button`,size:`icon`,variant:`soft`,color:`danger`,className:`shrink`,onClick:r,children:(0,p.jsx)(u.Trash2Icon,{size:13})})]}),D=()=>{let{filterDefinitions:n,activeFilters:a,addFilter:o,removeFilter:c,updateFilter:l}=t.X(),[h,g]=(0,d.useState)(null),_=n.filter(e=>!a.some(t=>t.definitionId===e.id));return(0,p.jsx)(i.ResizablePanel,{defaultSize:25,className:(0,f.cn)(`bg-card`,h===null?`max-w-8!`:`min-w-64`),children:(0,p.jsxs)(`div`,{className:`relative z-20 flex size-full bg-muted-bg-subtle`,children:[(0,p.jsx)(`div`,{className:`min-w-0 flex-1 overflow-hidden`,children:(0,p.jsx)(d.Activity,{mode:h===`filters`?`visible`:`hidden`,children:(0,p.jsxs)(`div`,{className:`flex size-full flex-col gap-2 p-4`,children:[(0,p.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,p.jsx)(`p`,{className:`font-medium`,children:`Bộ lọc`}),(0,p.jsxs)(r.DropdownMenu,{children:[(0,p.jsx)(r.DropdownMenuTrigger,{asChild:!0,children:(0,p.jsxs)(e.Button,{variant:`outline`,color:`muted`,disabled:_.length===0,children:[(0,p.jsx)(u.ListFilterPlus,{size:13}),`Thêm bộ lọc`]})}),(0,p.jsx)(r.DropdownMenuContent,{align:`end`,children:_.map(e=>(0,p.jsxs)(r.DropdownMenuItem,{className:`flex items-center gap-2`,onClick:()=>o(e.id),children:[m[e.type],e.label]},e.id))})]})]}),(0,p.jsx)(s.Separator,{}),a.length===0?(0,p.jsx)(`p`,{className:`py-6 text-center text-text-positive-muted text-xs`,children:`Không có bộ lọc nào`}):(0,p.jsx)(`div`,{className:`flex flex-col gap-2 pt-1`,children:a.map(e=>{let t=n.find(t=>t.id===e.definitionId);return t?(0,p.jsx)(E,{filter:e,definition:t,onRemove:()=>c(e.id),onUpdate:t=>l(e.id,t)},e.id):null})})]})})}),(0,p.jsxs)(`div`,{className:`flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm`,children:[(0,p.jsxs)(`button`,{type:`button`,className:(0,f.cn)(`relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4`,h===`filters`&&`bg-card`),onClick:()=>g(h===`filters`?null:`filters`),children:[(0,p.jsx)(u.ListFilterIcon,{size:18}),a.length>0&&(0,p.jsx)(`span`,{className:`absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none`,children:a.length}),(0,p.jsx)(`span`,{className:`text-nowrap [writing-mode:vertical-lr]`,children:`Bộ lọc`})]}),(0,p.jsx)(s.Separator,{})]})]})})};exports.UITableFilter=D;
|
|
2
|
+
//# sourceMappingURL=filter-CQ9BD0MV.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-z7p4lRp8.cjs","names":["TagIcon","CalendarIcon","HashIcon","TypeIcon","ToggleLeftIcon","Label","Checkbox","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Button","Popover","PopoverTrigger","PopoverContent","Trash2Icon","useUITableFilterContext","ResizablePanel","Activity","DropdownMenu","DropdownMenuTrigger","ListFilterPlus","DropdownMenuContent","DropdownMenuItem","Separator","ListFilterIcon"],"sources":["../packages/components/features/tables/components/table/filter.tsx"],"sourcesContent":["/**\n * @file filter.tsx\n * Collapsible side-panel with column-visibility toggles and a dynamic filter builder.\n *\n * - \"Columns\" tab: toggle individual column visibility.\n * - \"Filters\" tab: \"Add Filter\" dropdown → active filter chips → per-filter Popover editor.\n */\nimport { Activity, useState } from 'react';\n\nimport { CalendarIcon, HashIcon, ListFilterIcon, ListFilterPlus, TagIcon, ToggleLeftIcon, Trash2Icon, TypeIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { ResizablePanel } from '@/components/ui/resizable';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Separator } from '@/components/ui/separator';\n\nimport { useUITableFilterContext } from '../../hooks/use-context';\nimport type {\n ActiveFilter,\n BooleanFilterValue,\n DateRangeFilterValue,\n FilterDefinition,\n FilterType,\n FilterValue,\n NumberFilterValue,\n SingleTagFilterValue,\n TagFilterValue,\n TextFilterValue,\n} from '../../types';\n\n// ── icons per filter type ──────────────────────────────────────────────────────\n\nconst TYPE_ICONS: Record<FilterType, React.ReactNode> = {\n tag: <TagIcon size={14} />,\n 'single-tag': <TagIcon size={14} />,\n 'date-range': <CalendarIcon size={14} />,\n number: <HashIcon size={14} />,\n text: <TypeIcon size={14} />,\n boolean: <ToggleLeftIcon size={14} />,\n};\n\n// ── operator options ───────────────────────────────────────────────────────────\n\nconst NUMBER_OPERATORS: { value: NumberFilterValue['operator']; label: string }[] = [\n { value: 'eq', label: 'Bằng (=)' },\n { value: 'ne', label: 'Không bằng (≠)' },\n { value: 'gt', label: 'Lớn hơn (>)' },\n { value: 'gte', label: 'Ít nhất (≥)' },\n { value: 'lt', label: 'Nhỏ hơn (<)' },\n { value: 'lte', label: 'Nhiều nhất (≤)' },\n { value: 'between', label: 'Trong khoảng' },\n];\n\nconst TEXT_OPERATORS: { value: TextFilterValue['operator']; label: string }[] = [\n { value: 'contains', label: 'Chứa' },\n { value: 'equals', label: 'Bằng' },\n { value: 'starts-with', label: 'Bắt đầu bằng' },\n { value: 'ends-with', label: 'Kết thúc bằng' },\n];\n\n// ── summary label ──────────────────────────────────────────────────────────────\n\nfunction formatFilterValue(value: FilterValue, def: FilterDefinition): string {\n switch (value.type) {\n case 'single-tag': {\n if (!value.value) return 'Chưa đặt';\n return def.options?.find(o => o.value === value.value)?.label ?? value.value;\n }\n case 'tag': {\n if (!value.values.length) return 'Chưa đặt';\n return value.values.map(v => def.options?.find(o => o.value === v)?.label ?? v).join(', ');\n }\n case 'date-range': {\n if (!value.from && !value.to) return 'Ngày không xác định';\n if (value.from && value.to) return `${value.from} → ${value.to}`;\n if (value.from) return `từ ${value.from}`;\n return `đến ${value.to}`;\n }\n case 'number': {\n const op = { eq: '=', ne: '≠', gt: '>', gte: '≥', lt: '<', lte: '≤', between: 'trong khoảng' }[value.operator];\n if (value.value === undefined) return op;\n if (value.operator === 'between') return `${op} ${value.value} – ${value.valueTo ?? '?'}`;\n return `${op} ${value.value}`;\n }\n case 'text': {\n const op = {\n contains: 'chứa',\n equals: 'là',\n 'starts-with': 'bắt đầu bằng',\n 'ends-with': 'kết thúc bằng',\n }[value.operator];\n return value.value ? `${op} \"${value.value}\"` : op;\n }\n case 'boolean':\n if (value.value === null) return 'Không xác định';\n return value.value ? 'Có' : 'Không';\n }\n}\n\n// ── filter editors ─────────────────────────────────────────────────────────────\n\nconst TagFilterEditor: React.FC<{\n value: TagFilterValue;\n definition: FilterDefinition;\n onChange: (v: TagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-xs text-text-positive-muted\">Không có tùy chọn</p>\n ) : (\n definition.options!.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors',\n value.values.includes(option.value) && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.values.includes(option.value)}\n onCheckedChange={checked => {\n const next = checked ? [...value.values, option.value] : value.values.filter(v => v !== option.value);\n onChange({ type: 'tag', values: next });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst SingleTagFilterEditor: React.FC<{\n value: SingleTagFilterValue;\n definition: FilterDefinition;\n onChange: (v: SingleTagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-text-positive-muted text-xs\">Không có tùy chọn</p>\n ) : (\n definition.options?.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted',\n value.value === option.value && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.value === option.value}\n onCheckedChange={checked => {\n onChange({ type: 'single-tag', value: checked ? option.value : null });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst DateRangeFilterEditor: React.FC<{\n value: DateRangeFilterValue;\n onChange: (v: DateRangeFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Từ ngày</span>\n <Input type=\"date\" size=\"md\" value={value.from ?? ''} onValueChange={v => onChange({ ...value, from: v || undefined })} />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Đến ngày</span>\n <Input type=\"date\" size=\"md\" value={value.to ?? ''} onValueChange={v => onChange({ ...value, to: v || undefined })} />\n </div>\n </div>\n);\n\nconst NumberFilterEditor: React.FC<{\n value: NumberFilterValue;\n onChange: (v: NumberFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as NumberFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {NUMBER_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Giá trị\"\n value={value.value ?? ''}\n onValueChange={v => onChange({ ...value, value: v ? Number(v) : undefined })}\n />\n {value.operator === 'between' && (\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Đến giá trị\"\n value={value.valueTo ?? ''}\n onValueChange={v => onChange({ ...value, valueTo: v ? Number(v) : undefined })}\n />\n )}\n </div>\n);\n\nconst TextFilterEditor: React.FC<{\n value: TextFilterValue;\n onChange: (v: TextFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as TextFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TEXT_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input type=\"text\" size=\"md\" placeholder=\"Nhập văn bản...\" value={value.value} onValueChange={v => onChange({ ...value, value: v })} />\n </div>\n);\n\nconst BOOLEAN_OPTIONS = [\n { label: 'Có', value: true as boolean | null },\n { label: 'Không', value: false as boolean | null },\n { label: 'Không xác định', value: null as boolean | null },\n];\n\nconst BooleanFilterEditor: React.FC<{\n value: BooleanFilterValue;\n onChange: (v: BooleanFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {BOOLEAN_OPTIONS.map(({ label, value: v }) => (\n <Button\n key={label}\n type=\"button\"\n tabIndex={-1}\n variant=\"outline\"\n className={cn(\n 'rounded px-3 py-1.5 text-left text-sm transition-colors',\n value.value === v ? 'bg-primary-muted font-medium' : 'hover:bg-muted-bg-subtle'\n )}\n onClick={() => onChange({ type: 'boolean', value: v })}\n >\n {label}\n </Button>\n ))}\n </div>\n);\n\nfunction FilterEditor({ value, definition, onChange }: { value: FilterValue; definition: FilterDefinition; onChange: (v: FilterValue) => void }) {\n switch (value.type) {\n case 'tag':\n return <TagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'single-tag':\n return <SingleTagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'date-range':\n return <DateRangeFilterEditor value={value} onChange={onChange} />;\n case 'number':\n return <NumberFilterEditor value={value} onChange={onChange} />;\n case 'text':\n return <TextFilterEditor value={value} onChange={onChange} />;\n case 'boolean':\n return <BooleanFilterEditor value={value} onChange={onChange} />;\n }\n}\n\n// ── filter item chip ───────────────────────────────────────────────────────────\n\nconst FilterItem: React.FC<{\n filter: ActiveFilter;\n definition: FilterDefinition;\n onRemove: () => void;\n onUpdate: (value: FilterValue) => void;\n}> = ({ filter, definition, onRemove, onUpdate }) => (\n <div className=\"flex items-center gap-1\">\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n color=\"muted\"\n className=\"max-w-[calc(100%-32px)] flex-1 justify-start bg-white\"\n innerClassName=\"flex truncate gap-1.5\"\n >\n <span className=\"shrink-0 font-medium text-text-positive\">{definition.label}</span>\n <span className=\"truncate text-text-positive-weak text-xs\">{formatFilterValue(filter.value, definition)}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\" side=\"bottom\">\n <div className=\"border-border border-b px-3 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-positive-muted\">{TYPE_ICONS[definition.type]}</span>\n <p className=\"font-medium\">{definition.label}</p>\n </div>\n </div>\n <FilterEditor value={filter.value} definition={definition} onChange={onUpdate} />\n </PopoverContent>\n </Popover>\n <Button type=\"button\" size=\"icon\" variant=\"soft\" color=\"danger\" className=\"shrink\" onClick={onRemove}>\n <Trash2Icon size={13} />\n </Button>\n </div>\n);\n\n// ── column visibility row ──────────────────────────────────────────────────────\n\n// const ColumnVisibility: React.FC<{\n// checked: boolean;\n// title: string;\n// onCheckedChange?: (checked: boolean) => void;\n// }> = ({ checked, title, onCheckedChange }) => (\n// <Label>\n// <Checkbox checked={checked} onCheckedChange={onCheckedChange} />\n// <p className=\"text-sm\">{title}</p>\n// </Label>\n// );\n\n// ── main component ─────────────────────────────────────────────────────────────\n\n/**\n * Collapsible side-panel that lets users toggle column visibility and build\n * row filters without leaving the table view.\n *\n * The panel collapses to a narrow icon strip when no tab is active and expands\n * to at least 64 units when the \"Columns\" or \"Filters\" tab is selected.\n *\n * Wire filter capability by passing `filterDefinitions` and `onFilterChange` to\n * the parent `UITableProvider`.\n *\n * @example\n * ```tsx\n * <UITableProvider\n * filterDefinitions={[\n * { id: 'status', label: 'Status', type: 'tag', options: [{ label: 'Active', value: 'active' }] },\n * { id: 'created', label: 'Created At', type: 'date-range' },\n * { id: 'amount', label: 'Amount', type: 'number' },\n * ]}\n * onFilterChange={filters => console.log(filters)}\n * >\n * <ResizablePanelGroup direction=\"horizontal\">\n * <ResizablePanel><UITable /></ResizablePanel>\n * <ResizableHandle />\n * <UITableFilter />\n * </ResizablePanelGroup>\n * </UITableProvider>\n * ```\n */\nexport const UITableFilter = () => {\n // const { table } = useUITableContext();\n const { filterDefinitions, activeFilters, addFilter, removeFilter, updateFilter } = useUITableFilterContext();\n\n const [tab, setTab] = useState<'columns' | 'filters' | null>(null);\n\n const availableDefinitions = filterDefinitions.filter(def => !activeFilters.some(f => f.definitionId === def.id));\n\n return (\n <ResizablePanel defaultSize={25} className={cn('bg-card', tab === null ? 'max-w-8!' : 'min-w-64')}>\n <div className=\"relative z-20 flex size-full bg-muted-bg-subtle\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n {/* Columns tab */}\n {/*<Activity mode={tab === 'columns' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <p className=\"px-2 font-medium\">Columns Visibility</p>\n <Separator />\n <div className=\"flex flex-col gap-4 pt-4\">\n {table.getAllColumns().map(column => {\n if (['select', 'actions'].includes(column.id)) return null;\n return (\n <ColumnVisibility\n key={column.id}\n checked={column.getIsVisible()}\n title={String(column.columnDef.header)}\n onCheckedChange={value => column.toggleVisibility(!!value)}\n />\n );\n })}\n </div>\n </div>\n </Activity>*/}\n\n {/* Filters tab */}\n <Activity mode={tab === 'filters' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"font-medium\">Bộ lọc</p>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" color=\"muted\" disabled={availableDefinitions.length === 0}>\n <ListFilterPlus size={13} />\n Thêm bộ lọc\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {availableDefinitions.map(def => (\n <DropdownMenuItem key={def.id} className=\"flex items-center gap-2\" onClick={() => addFilter(def.id)}>\n {TYPE_ICONS[def.type]}\n {def.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n <Separator />\n {activeFilters.length === 0 ? (\n <p className=\"py-6 text-center text-text-positive-muted text-xs\">Không có bộ lọc nào</p>\n ) : (\n <div className=\"flex flex-col gap-2 pt-1\">\n {activeFilters.map(filter => {\n const def = filterDefinitions.find(d => d.id === filter.definitionId);\n if (!def) return null;\n return (\n <FilterItem\n key={filter.id}\n filter={filter}\n definition={def}\n onRemove={() => removeFilter(filter.id)}\n onUpdate={value => updateFilter(filter.id, value)}\n />\n );\n })}\n </div>\n )}\n </div>\n </Activity>\n </div>\n\n {/* Vertical tab strip */}\n <div className=\"flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm\">\n {/*<button\n type=\"button\"\n className={cn('flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'columns' && 'bg-card')}\n onClick={() => setTab(tab === 'columns' ? null : 'columns')}\n >\n <Columns4Icon size={18} />\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Columns</span>\n </button>\n <Separator />*/}\n <button\n type=\"button\"\n className={cn('relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'filters' && 'bg-card')}\n onClick={() => setTab(tab === 'filters' ? null : 'filters')}\n >\n <ListFilterIcon size={18} />\n {activeFilters.length > 0 && (\n <span className=\"absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none\">\n {activeFilters.length}\n </span>\n )}\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Bộ lọc</span>\n </button>\n <Separator />\n </div>\n </div>\n </ResizablePanel>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filter-CQ9BD0MV.cjs","names":["TagIcon","CalendarIcon","HashIcon","TypeIcon","ToggleLeftIcon","Label","Checkbox","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Button","Popover","PopoverTrigger","PopoverContent","Trash2Icon","useUITableFilterContext","ResizablePanel","Activity","DropdownMenu","DropdownMenuTrigger","ListFilterPlus","DropdownMenuContent","DropdownMenuItem","Separator","ListFilterIcon"],"sources":["../packages/components/features/tables/components/table/filter.tsx"],"sourcesContent":["/**\n * @file filter.tsx\n * Collapsible side-panel with column-visibility toggles and a dynamic filter builder.\n *\n * - \"Columns\" tab: toggle individual column visibility.\n * - \"Filters\" tab: \"Add Filter\" dropdown → active filter chips → per-filter Popover editor.\n */\nimport { Activity, useState } from 'react';\n\nimport { CalendarIcon, HashIcon, ListFilterIcon, ListFilterPlus, TagIcon, ToggleLeftIcon, Trash2Icon, TypeIcon } from 'lucide-react';\n\nimport { cn } from '@customafk/react-toolkit/utils';\n\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { ResizablePanel } from '@/components/ui/resizable';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Separator } from '@/components/ui/separator';\n\nimport { useUITableFilterContext } from '../../hooks/use-context';\nimport type {\n ActiveFilter,\n BooleanFilterValue,\n DateRangeFilterValue,\n FilterDefinition,\n FilterType,\n FilterValue,\n NumberFilterValue,\n SingleTagFilterValue,\n TagFilterValue,\n TextFilterValue,\n} from '../../types';\n\n// ── icons per filter type ──────────────────────────────────────────────────────\n\nconst TYPE_ICONS: Record<FilterType, React.ReactNode> = {\n tag: <TagIcon size={14} />,\n 'single-tag': <TagIcon size={14} />,\n 'date-range': <CalendarIcon size={14} />,\n number: <HashIcon size={14} />,\n text: <TypeIcon size={14} />,\n boolean: <ToggleLeftIcon size={14} />,\n};\n\n// ── operator options ───────────────────────────────────────────────────────────\n\nconst NUMBER_OPERATORS: { value: NumberFilterValue['operator']; label: string }[] = [\n { value: 'eq', label: 'Bằng (=)' },\n { value: 'ne', label: 'Không bằng (≠)' },\n { value: 'gt', label: 'Lớn hơn (>)' },\n { value: 'gte', label: 'Ít nhất (≥)' },\n { value: 'lt', label: 'Nhỏ hơn (<)' },\n { value: 'lte', label: 'Nhiều nhất (≤)' },\n { value: 'between', label: 'Trong khoảng' },\n];\n\nconst TEXT_OPERATORS: { value: TextFilterValue['operator']; label: string }[] = [\n { value: 'contains', label: 'Chứa' },\n { value: 'equals', label: 'Bằng' },\n { value: 'starts-with', label: 'Bắt đầu bằng' },\n { value: 'ends-with', label: 'Kết thúc bằng' },\n];\n\n// ── summary label ──────────────────────────────────────────────────────────────\n\nfunction formatFilterValue(value: FilterValue, def: FilterDefinition): string {\n switch (value.type) {\n case 'single-tag': {\n if (!value.value) return 'Chưa đặt';\n return def.options?.find(o => o.value === value.value)?.label ?? value.value;\n }\n case 'tag': {\n if (!value.values.length) return 'Chưa đặt';\n return value.values.map(v => def.options?.find(o => o.value === v)?.label ?? v).join(', ');\n }\n case 'date-range': {\n if (!value.from && !value.to) return 'Ngày không xác định';\n if (value.from && value.to) return `${value.from} → ${value.to}`;\n if (value.from) return `từ ${value.from}`;\n return `đến ${value.to}`;\n }\n case 'number': {\n const op = { eq: '=', ne: '≠', gt: '>', gte: '≥', lt: '<', lte: '≤', between: 'trong khoảng' }[value.operator];\n if (value.value === undefined) return op;\n if (value.operator === 'between') return `${op} ${value.value} – ${value.valueTo ?? '?'}`;\n return `${op} ${value.value}`;\n }\n case 'text': {\n const op = {\n contains: 'chứa',\n equals: 'là',\n 'starts-with': 'bắt đầu bằng',\n 'ends-with': 'kết thúc bằng',\n }[value.operator];\n return value.value ? `${op} \"${value.value}\"` : op;\n }\n case 'boolean':\n if (value.value === null) return 'Không xác định';\n return value.value ? 'Có' : 'Không';\n }\n}\n\n// ── filter editors ─────────────────────────────────────────────────────────────\n\nconst TagFilterEditor: React.FC<{\n value: TagFilterValue;\n definition: FilterDefinition;\n onChange: (v: TagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-xs text-text-positive-muted\">Không có tùy chọn</p>\n ) : (\n definition.options!.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 bg-secondary-bg-subtle hover:bg-secondary-muted px-4 py-2 rounded transition-colors',\n value.values.includes(option.value) && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.values.includes(option.value)}\n onCheckedChange={checked => {\n const next = checked ? [...value.values, option.value] : value.values.filter(v => v !== option.value);\n onChange({ type: 'tag', values: next });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst SingleTagFilterEditor: React.FC<{\n value: SingleTagFilterValue;\n definition: FilterDefinition;\n onChange: (v: SingleTagFilterValue) => void;\n}> = ({ value, definition, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {(definition.options ?? []).length === 0 ? (\n <p className=\"text-text-positive-muted text-xs\">Không có tùy chọn</p>\n ) : (\n definition.options?.map(option => (\n <Label\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded bg-secondary-bg-subtle px-4 py-2 transition-colors hover:bg-secondary-muted',\n value.value === option.value && 'bg-primary-muted hover:bg-primary-subtle'\n )}\n >\n <Checkbox\n checked={value.value === option.value}\n onCheckedChange={checked => {\n onChange({ type: 'single-tag', value: checked ? option.value : null });\n }}\n />\n <span className=\"text-sm\">{option.label}</span>\n </Label>\n ))\n )}\n </div>\n);\n\nconst DateRangeFilterEditor: React.FC<{\n value: DateRangeFilterValue;\n onChange: (v: DateRangeFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Từ ngày</span>\n <Input type=\"date\" size=\"md\" value={value.from ?? ''} onValueChange={v => onChange({ ...value, from: v || undefined })} />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-text-positive-muted text-xs\">Đến ngày</span>\n <Input type=\"date\" size=\"md\" value={value.to ?? ''} onValueChange={v => onChange({ ...value, to: v || undefined })} />\n </div>\n </div>\n);\n\nconst NumberFilterEditor: React.FC<{\n value: NumberFilterValue;\n onChange: (v: NumberFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as NumberFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {NUMBER_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Giá trị\"\n value={value.value ?? ''}\n onValueChange={v => onChange({ ...value, value: v ? Number(v) : undefined })}\n />\n {value.operator === 'between' && (\n <Input\n type=\"number\"\n size=\"md\"\n placeholder=\"Đến giá trị\"\n value={value.valueTo ?? ''}\n onValueChange={v => onChange({ ...value, valueTo: v ? Number(v) : undefined })}\n />\n )}\n </div>\n);\n\nconst TextFilterEditor: React.FC<{\n value: TextFilterValue;\n onChange: (v: TextFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-3 p-3\">\n <Select value={value.operator} onValueChange={op => onChange({ ...value, operator: op as TextFilterValue['operator'] })}>\n <SelectTrigger size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TEXT_OPERATORS.map(op => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input type=\"text\" size=\"md\" placeholder=\"Nhập văn bản...\" value={value.value} onValueChange={v => onChange({ ...value, value: v })} />\n </div>\n);\n\nconst BOOLEAN_OPTIONS = [\n { label: 'Có', value: true as boolean | null },\n { label: 'Không', value: false as boolean | null },\n { label: 'Không xác định', value: null as boolean | null },\n];\n\nconst BooleanFilterEditor: React.FC<{\n value: BooleanFilterValue;\n onChange: (v: BooleanFilterValue) => void;\n}> = ({ value, onChange }) => (\n <div className=\"flex flex-col gap-1 p-3\">\n {BOOLEAN_OPTIONS.map(({ label, value: v }) => (\n <Button\n key={label}\n type=\"button\"\n tabIndex={-1}\n variant=\"outline\"\n className={cn(\n 'rounded px-3 py-1.5 text-left text-sm transition-colors',\n value.value === v ? 'bg-primary-muted font-medium' : 'hover:bg-muted-bg-subtle'\n )}\n onClick={() => onChange({ type: 'boolean', value: v })}\n >\n {label}\n </Button>\n ))}\n </div>\n);\n\nfunction FilterEditor({ value, definition, onChange }: { value: FilterValue; definition: FilterDefinition; onChange: (v: FilterValue) => void }) {\n switch (value.type) {\n case 'tag':\n return <TagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'single-tag':\n return <SingleTagFilterEditor value={value} definition={definition} onChange={onChange} />;\n case 'date-range':\n return <DateRangeFilterEditor value={value} onChange={onChange} />;\n case 'number':\n return <NumberFilterEditor value={value} onChange={onChange} />;\n case 'text':\n return <TextFilterEditor value={value} onChange={onChange} />;\n case 'boolean':\n return <BooleanFilterEditor value={value} onChange={onChange} />;\n }\n}\n\n// ── filter item chip ───────────────────────────────────────────────────────────\n\nconst FilterItem: React.FC<{\n filter: ActiveFilter;\n definition: FilterDefinition;\n onRemove: () => void;\n onUpdate: (value: FilterValue) => void;\n}> = ({ filter, definition, onRemove, onUpdate }) => (\n <div className=\"flex items-center gap-1\">\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n color=\"muted\"\n className=\"max-w-[calc(100%-32px)] flex-1 justify-start bg-white\"\n innerClassName=\"flex truncate gap-1.5\"\n >\n <span className=\"shrink-0 font-medium text-text-positive\">{definition.label}</span>\n <span className=\"truncate text-text-positive-weak text-xs\">{formatFilterValue(filter.value, definition)}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\" side=\"bottom\">\n <div className=\"border-border border-b px-3 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-positive-muted\">{TYPE_ICONS[definition.type]}</span>\n <p className=\"font-medium\">{definition.label}</p>\n </div>\n </div>\n <FilterEditor value={filter.value} definition={definition} onChange={onUpdate} />\n </PopoverContent>\n </Popover>\n <Button type=\"button\" size=\"icon\" variant=\"soft\" color=\"danger\" className=\"shrink\" onClick={onRemove}>\n <Trash2Icon size={13} />\n </Button>\n </div>\n);\n\n// ── column visibility row ──────────────────────────────────────────────────────\n\n// const ColumnVisibility: React.FC<{\n// checked: boolean;\n// title: string;\n// onCheckedChange?: (checked: boolean) => void;\n// }> = ({ checked, title, onCheckedChange }) => (\n// <Label>\n// <Checkbox checked={checked} onCheckedChange={onCheckedChange} />\n// <p className=\"text-sm\">{title}</p>\n// </Label>\n// );\n\n// ── main component ─────────────────────────────────────────────────────────────\n\n/**\n * Collapsible side-panel that lets users toggle column visibility and build\n * row filters without leaving the table view.\n *\n * The panel collapses to a narrow icon strip when no tab is active and expands\n * to at least 64 units when the \"Columns\" or \"Filters\" tab is selected.\n *\n * Wire filter capability by passing `filterDefinitions` and `onFilterChange` to\n * the parent `UITableProvider`.\n *\n * @example\n * ```tsx\n * <UITableProvider\n * filterDefinitions={[\n * { id: 'status', label: 'Status', type: 'tag', options: [{ label: 'Active', value: 'active' }] },\n * { id: 'created', label: 'Created At', type: 'date-range' },\n * { id: 'amount', label: 'Amount', type: 'number' },\n * ]}\n * onFilterChange={filters => console.log(filters)}\n * >\n * <ResizablePanelGroup direction=\"horizontal\">\n * <ResizablePanel><UITable /></ResizablePanel>\n * <ResizableHandle />\n * <UITableFilter />\n * </ResizablePanelGroup>\n * </UITableProvider>\n * ```\n */\nexport const UITableFilter = () => {\n // const { table } = useUITableContext();\n const { filterDefinitions, activeFilters, addFilter, removeFilter, updateFilter } = useUITableFilterContext();\n\n const [tab, setTab] = useState<'columns' | 'filters' | null>(null);\n\n const availableDefinitions = filterDefinitions.filter(def => !activeFilters.some(f => f.definitionId === def.id));\n\n return (\n <ResizablePanel defaultSize={25} className={cn('bg-card', tab === null ? 'max-w-8!' : 'min-w-64')}>\n <div className=\"relative z-20 flex size-full bg-muted-bg-subtle\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n {/* Columns tab */}\n {/*<Activity mode={tab === 'columns' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <p className=\"px-2 font-medium\">Columns Visibility</p>\n <Separator />\n <div className=\"flex flex-col gap-4 pt-4\">\n {table.getAllColumns().map(column => {\n if (['select', 'actions'].includes(column.id)) return null;\n return (\n <ColumnVisibility\n key={column.id}\n checked={column.getIsVisible()}\n title={String(column.columnDef.header)}\n onCheckedChange={value => column.toggleVisibility(!!value)}\n />\n );\n })}\n </div>\n </div>\n </Activity>*/}\n\n {/* Filters tab */}\n <Activity mode={tab === 'filters' ? 'visible' : 'hidden'}>\n <div className=\"flex size-full flex-col gap-2 p-4\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"font-medium\">Bộ lọc</p>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" color=\"muted\" disabled={availableDefinitions.length === 0}>\n <ListFilterPlus size={13} />\n Thêm bộ lọc\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {availableDefinitions.map(def => (\n <DropdownMenuItem key={def.id} className=\"flex items-center gap-2\" onClick={() => addFilter(def.id)}>\n {TYPE_ICONS[def.type]}\n {def.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n <Separator />\n {activeFilters.length === 0 ? (\n <p className=\"py-6 text-center text-text-positive-muted text-xs\">Không có bộ lọc nào</p>\n ) : (\n <div className=\"flex flex-col gap-2 pt-1\">\n {activeFilters.map(filter => {\n const def = filterDefinitions.find(d => d.id === filter.definitionId);\n if (!def) return null;\n return (\n <FilterItem\n key={filter.id}\n filter={filter}\n definition={def}\n onRemove={() => removeFilter(filter.id)}\n onUpdate={value => updateFilter(filter.id, value)}\n />\n );\n })}\n </div>\n )}\n </div>\n </Activity>\n </div>\n\n {/* Vertical tab strip */}\n <div className=\"flex h-full flex-col border-border border-l bg-muted-bg-subtle text-sm\">\n {/*<button\n type=\"button\"\n className={cn('flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'columns' && 'bg-card')}\n onClick={() => setTab(tab === 'columns' ? null : 'columns')}\n >\n <Columns4Icon size={18} />\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Columns</span>\n </button>\n <Separator />*/}\n <button\n type=\"button\"\n className={cn('relative flex h-32 cursor-pointer flex-col items-center gap-y-2 p-2 py-4', tab === 'filters' && 'bg-card')}\n onClick={() => setTab(tab === 'filters' ? null : 'filters')}\n >\n <ListFilterIcon size={18} />\n {activeFilters.length > 0 && (\n <span className=\"absolute top-2 right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground leading-none\">\n {activeFilters.length}\n </span>\n )}\n <span className=\"text-nowrap [writing-mode:vertical-lr]\">Bộ lọc</span>\n </button>\n <Separator />\n </div>\n </div>\n </ResizablePanel>\n );\n};\n"],"mappings":"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"}
|