@mendylanda/ui 0.3.0-alpha.6 → 0.3.0-alpha.8

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/README.md CHANGED
@@ -82,7 +82,7 @@ Opening the menu shows the category list without choosing a filter. Focusing a c
82
82
 
83
83
  ### Defaults and clearing
84
84
 
85
- `FilterBar` and composed `FilterList` include Clear all after the chips. It clears filters and search. Set `showClear={false}` to opt out. Choice search is enabled by default; use `searchable: false` for short lists. Menu selections keep the menu open, and selecting the current single choice again clears it. Chip editor popups open instantly; `editorAnimation` opts into their animation.
85
+ `FilterBar` and composed `FilterList` show Clear all after the chips when a removable filter is active. It clears filters and search. Search-only bars use the input’s clear control and hide the filter menu when no menu fields are available. Set `showClear={false}` to opt out. Choice search is enabled by default; use `searchable: false` for short lists. Menu selections keep the menu open, and selecting the current single choice again clears it. Chip editor popups open instantly; `editorAnimation` opts into their animation.
86
86
 
87
87
  See [defaults and app configuration](https://ui.mendylanda.com/docs/defaults) for the full behavior and [system reference](https://ui.mendylanda.com/docs/system) for query adapters, selected-label loading, grouped fields, and custom editors.
88
88
 
@@ -106,4 +106,21 @@ export function Projects({ rows }: { rows: Project[] }) {
106
106
 
107
107
  Use `useDataTable` and `TableView` when the application already controls sorting, pagination, preferences, or selection. Data fetching and mutations stay in the application. `useResultSelection` represents explicit IDs or all matching results with exclusions. `TableSavedViews` accepts application-owned views; it does not create a backend.
108
108
 
109
+ Pass a filter controller once to place the shared filter bar and connect table recovery behavior:
110
+
111
+ ```tsx
112
+ <DataTable
113
+ table={table}
114
+ filters={filters}
115
+ toolbar={<ProjectActions />}
116
+ filterBar={{ showSearch: false }}
117
+ />
118
+ ```
119
+
120
+ Create the controller with `useFilters`, `useUrlFilters`, or `useControlledFilters`. Its values remain application query state. The table does not derive a predicate or fetch rows from filter definitions. Set `filterBar={false}` when controls live elsewhere, or use `TableFilters` and `TableView` with the same controller in a composed layout.
121
+
122
+ Tables fit their rows, headers, and empty content by default, capped at 65dvh. Short tables do not reserve a vertical scrollbar. Full-page layouts can set an explicit `height`. Rows remain 44px unless `rowHeight="auto"` opts into measurement for wrapped or editable content. Selected rows receive the standard highlight; `isRowHighlighted` adds application state. `onRowClick`, `rowClassName`, and `renderRowDetail` cover row actions and expandable content.
123
+
124
+ Changes to table query state or the shared controller reset scroll and cell selection. Appending rows keeps the current position and selection. Empty states distinguish an empty dataset, an empty filtered result with one controller clear, and an empty later page that can return to the first page. Locked filters never get a clear action.
125
+
109
126
  See the [table documentation](https://ui.mendylanda.com/docs/components/table) for composition, remote data, and persistence.
@@ -1 +1 @@
1
- export const originalClassNames = {"mui-cb20bd519346":"pointer-events-auto","mui-33228ff7d583":"pointer-events-none","mui-b75af7ef6c4d":"invisible","mui-d42ef1497900":"visible","mui-32fb090591d9":"sr-only","mui-747355bdc2a2":"absolute","mui-d2d9e1f13413":"relative","mui-964a9431ff49":"sticky","mui-ce13093ad8c9":"inset-0","mui-3ba24c062d55":"inset-x-0","mui-eb9e48c5dda9":"inset-y-0","mui-cced28c6dc3f":"start","mui-207bd0b3f259":"start-2","mui-cea70f23972e":"start-3","mui-361e48d0308f":"end","mui-13422ddc8d83":"end-1","mui-585f4729f611":"end-9","mui-98599e4ee250":"top-0","mui-4e45f4841abb":"top-1/2","mui-a74c4477017c":"right-0","mui-30150dd033ab":"bottom-0","mui-a5c36273c0f0":"bottom-2","mui-635702706586":"left-0","mui-014aadadffad":"isolate","mui-d7efd1b0b0f9":"z-1","mui-418e44ad4f9e":"z-10","mui-4e8f0a87a0dc":"z-20","mui-fbb62f5cb6fe":"z-30","mui-3eef1ce97dba":"z-50","mui-a42d519714d6":"container","mui-a2526bc2efa3":"m-0","mui-abba77319850":"-mx-1","mui-1752f11474a6":"mx-auto","mui-d8747231f142":"my-1","mui-958e2cfcf5b6":"-ms-2","mui-291952c2525a":"-ms-px","mui-8cc46fa87f41":"-me-1.5","mui-f28fea81a5cd":"mt-2","mui-cc51bda60e7e":"ml-auto","mui-496aca80e4d8":"block","mui-d1b2a59fbea7":"contents","mui-222f930b8752":"flex","mui-0f2a693e93e2":"grid","mui-e564b4081d7a":"hidden","mui-995cf20a9c45":"inline","mui-123306850fe1":"inline-flex","mui-0d4fc4a78d37":"table","mui-3da89b3ed14b":"field-sizing-content","mui-129d6f9b1e07":"aspect-square","mui-f7d12b41bceb":"size-(--cell-size)","mui-dc797fcc7165":"size-1.5","mui-5e34f5313859":"size-3","mui-61c000c8a98a":"size-3.5","mui-100c22d5776b":"size-4","mui-2bd43fb57913":"size-5","mui-0712570dcc9f":"size-6","mui-79ede756e761":"size-7","mui-ebd37e04d422":"size-8","mui-3ee10ef4c057":"size-9","mui-d0a383a9c24f":"size-10","mui-4dad94bd15e3":"size-auto","mui-a5960ac1d283":"h-(--cell-size)","mui-c7d5500b77ab":"h-0","mui-2edce89ef182":"h-3","mui-099be97e1fa4":"h-4","mui-ce1945804664":"h-6","mui-c8e50836f8a1":"h-7","mui-1fb07b38c63b":"h-8","mui-539ae144f076":"h-9","mui-fdd2f85cad6b":"h-10","mui-a66e9985b093":"h-auto","mui-57c930dc1c31":"h-full","mui-ae2c4b060bb9":"h-px","mui-571ea69568d3":"max-h-(--filter-menu-height)","mui-1f061e70178e":"max-h-(--radix-dropdown-menu-content-available-height)","mui-4d3f1304ebb2":"max-h-(--radix-popover-content-available-height)","mui-da0beef015c9":"max-h-[400px]","mui-80baa5d03af7":"max-h-[calc(var(--filter-menu-height)-2px)]","mui-1326520533f0":"max-h-[min(6rem,calc(var(--filter-menu-height)*0.25))]","mui-fb4a3e97b5bd":"max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height,20rem))]","mui-dcd942c18ddc":"max-h-[var(--radix-dropdown-menu-content-available-height)]","mui-7bd696ca6be3":"max-h-full","mui-410da8dfa8ac":"min-h-0","mui-9974acedf3f7":"min-h-9","mui-8423dc94ee06":"min-h-10","mui-50312c3ce4a3":"min-h-[60px]","mui-d48fe95d4da8":"w-(--cell-size)","mui-d4ea834145ae":"w-2","mui-56bb14cbd1fe":"w-2/3","mui-8867d85ed290":"w-8","mui-4ac4ec8dfbce":"w-40","mui-37535002f0f7":"w-72","mui-a4cce7869436":"w-[300px]","mui-fc6a57ff7553":"w-[var(--mendy-filter-editor-width,19rem)]","mui-0b9c84552e40":"w-[var(--mendy-filter-list-width,var(--mendy-filter-anchor-width,18.75rem))]","mui-4415137b0467":"w-[var(--mendy-filter-menu-width,calc(var(--filter-list-width)_+_var(--mendy-filter-editor-width,19rem)))]","mui-8cfb5a42ef9f":"w-fit","mui-58d0413dd93c":"w-full","mui-91f82aa1df0c":"max-w-[60%]","mui-34055e6f8c1b":"max-w-[calc(100vw-2rem)]","mui-81b198a2db84":"max-w-full","mui-1458e495e3ae":"min-w-(--cell-size)","mui-184ddc11e5f9":"min-w-0","mui-e9ab1547c94d":"min-w-[8rem]","mui-2bf6510f1330":"min-w-full","mui-7bd5bab6d7f4":"flex-1","mui-66b490dd6005":"shrink","mui-27ead27a81df":"shrink-0","mui-adca5146416e":"grow","mui-215061302c50":"border-collapse","mui-3a3774477287":"origin-(--radix-dropdown-menu-content-transform-origin)","mui-5dde0fd996f0":"-translate-y-1/2","mui-4e3f08588318":"-rotate-45","mui-c80411b7591f":"rotate-45","mui-aa214ea38326":"transform","mui-393df0d154e0":"animate-none!","mui-7b3cd77eb999":"animate-pulse","mui-2c14b55d77e6":"animate-spin","mui-2194d094b585":"cursor-col-resize","mui-d343f41ba73e":"cursor-default","mui-f2e47d9c52ad":"cursor-grab","mui-d2fa8848968d":"cursor-pointer","mui-739a9a000791":"touch-none","mui-acd532d8913e":"resize","mui-ae112c903ef8":"resize-y","mui-eeb3a8b33f69":"grid-cols-[min(var(--filter-list-width),calc(100%_-_min(var(--mendy-filter-editor-width,19rem),50%)))_minmax(0,1fr)]","mui-b5985369ee35":"grid-rows-[minmax(0,1fr)]","mui-302c0d124a94":"flex-col","mui-faa8a23c68f6":"flex-wrap","mui-8fd2e2355cbc":"place-content-center","mui-71556df3b421":"items-center","mui-b9677bd1cb66":"items-start","mui-32c92bb1fde4":"justify-between","mui-a503dd374cca":"justify-center","mui-307644c34db6":"justify-end","mui-c62ec162662e":"justify-start","mui-19e97f3f40e6":"gap-1","mui-70007b876865":"gap-1.5","mui-074569488cca":"gap-2","mui-d7db3451d154":"gap-3","mui-90fc3ec35a37":"gap-4","mui-27e6c432192f":"space-y-1","mui-267171770524":"space-y-2","mui-5a3a4ee420c2":"truncate","mui-1a26a0d28420":"overflow-auto","mui-d5111d0e9f48":"overflow-hidden","mui-0fc84a692dad":"overflow-visible","mui-3b82279f859f":"overflow-x-hidden","mui-2368e909f3a5":"overflow-y-auto","mui-998780cdef87":"overscroll-contain","mui-b005d61d0953":"rounded-full","mui-3fa8c572949b":"rounded-md","mui-52417259a4f5":"rounded-none","mui-02e603944040":"rounded-sm","mui-b31810dbd8a9":"rounded-s-none","mui-10c0bae8cba9":"rounded-l-md","mui-34bbd346e74c":"rounded-r-md","mui-4f1a55de40bc":"border","mui-dad556abfe15":"border-0","mui-55860251be20":"border-s","mui-3b6d5fc7b061":"border-e","mui-894c3815a57f":"border-t","mui-bbe39cfb5cc6":"border-b","mui-8450eb0f1857":"border-dashed","mui-163a623b3716":"border-border/50","mui-1267095cdeb7":"border-input","mui-9b76f456b8c9":"border-muted-foreground/50","mui-515f9fdc6db7":"border-primary","mui-292affc1f780":"bg-accent","mui-5b272f3c5076":"bg-background","mui-a943bea85d66":"bg-border","mui-0cf6c2e8fe7e":"bg-current","mui-965cf6587342":"bg-destructive","mui-047624ec0c39":"bg-green-100","mui-87ecb59f2d2d":"bg-muted","mui-810ae775809b":"bg-muted-foreground/20","mui-e593c38256e0":"bg-popover","mui-0c2864fba576":"bg-primary","mui-d191cb569aac":"bg-secondary","mui-8fca9236d191":"bg-transparent","mui-04760bcd507f":"p-0","mui-1dee6e3ec67d":"p-1","mui-b97db4a9f432":"p-2","mui-094f5333853b":"p-3","mui-c432836760e3":"p-6","mui-c7902d77ad80":"p-8","mui-56b8f5e0fb12":"px-(--cell-size)","mui-16e909e6f01d":"px-0","mui-1da2e8f173c5":"px-1.5","mui-e7e01cc7f4df":"px-2","mui-0f9e6672913a":"px-3","mui-9513b3968002":"px-4","mui-0194c6e46323":"px-8","mui-1fcf28756bb1":"py-1","mui-a8c1dfb1d4ef":"py-1.5","mui-b5edc3ea7c91":"py-2","mui-d3cea061f2f3":"py-3","mui-96b92a971c95":"py-5","mui-078d945937da":"ps-8","mui-b2100041c585":"ps-9","mui-05d4103bd67f":"pe-2","mui-a202804a1738":"pe-3","mui-0e14c365f9e8":"pe-9","mui-559069d2c2e5":"pe-16","mui-0a702d97ed7d":"pt-3","mui-1a52da5bc88c":"pr-1","mui-f5d8e661d857":"pl-2","mui-05ab12448317":"text-center","mui-10558dbb3a24":"text-end","mui-e9347b78185f":"text-start","mui-757071a1d1c4":"text-base","mui-c74ab393b96d":"text-sm","mui-3992de70b033":"text-xs","mui-5f120ad4b50b":"text-[0.8rem]","mui-761cdb81bddb":"leading-none","mui-daaac3fbf55e":"font-medium","mui-52101fc7d8bb":"font-normal","mui-e1683b3c030a":"tracking-widest","mui-393883c1db68":"[overflow-wrap:anywhere]","mui-37cf9655f30a":"break-words","mui-726fca123972":"whitespace-normal","mui-963f6168b7d6":"whitespace-nowrap","mui-cc209238d847":"text-accent-foreground","mui-5eafab9bbefc":"text-current","mui-887b9502d5c7":"text-destructive","mui-8d4bf2704c8d":"text-destructive-foreground","mui-957a109f887f":"text-foreground","mui-35f35c41d134":"text-muted-foreground","mui-5bd2afe89f0b":"text-popover-foreground","mui-249f14ee5b6b":"text-primary","mui-abd1aaa1f5b2":"text-primary-foreground","mui-80df79ec9bb5":"text-secondary-foreground","mui-944969efb294":"underline","mui-d52f902a57e8":"underline-offset-4","mui-94f91922a10e":"opacity-0","mui-0b5a4d1257ab":"opacity-50","mui-65694092f002":"opacity-100","mui-0d4ca75de41c":"shadow-lg","mui-94ea94fde25f":"shadow-md","mui-89c3006b2722":"shadow-none","mui-7de07d413c13":"shadow-xs","mui-853be6c11609":"ring-2","mui-fd9d0b696aac":"ring-primary","mui-59edd3d33673":"outline-hidden","mui-318678825324":"outline","mui-e42932b7a79c":"blur","mui-e0122edc668b":"drop-shadow-md","mui-dfc3376b8266":"filter","mui-70dd37c11434":"transition","mui-eae178841c68":"transition-colors","mui-2cdd01663c76":"transition-opacity","mui-2b48746f4314":"transition-shadow","mui-b4b2fd95f324":"transition-none","mui-b30fc56058b6":"outline-none","mui-78905c9e865c":"select-none","mui-d80b6593dae5":"[--cell-size:--spacing(8)]","mui-82c2977beb8e":"[--cell-size:min(2rem,calc((100vw-3.5rem)/7))]","mui-d7d803c609c5":"[--filter-list-width:var(--mendy-filter-list-width,var(--mendy-filter-anchor-width,13rem))]","mui-971625533e56":"[--filter-menu-height:min(var(--mendy-filter-menu-max-height,44rem),var(--radix-dropdown-menu-content-available-height,44rem))]","mui-cacb19aa9640":"[scrollbar-width:thin]","mui-14bd99410890":"[unicode-bidi:isolate]","mui-97b1c00ff005":"group-hover:bg-accent","mui-ad936fcbed63":"group","mui-9af9a4182597":"group-data-[disabled=true]:pointer-events-none","mui-272ef88d6a0c":"group-data-[disabled=true]:opacity-50","mui-60052b901494":"group-data-[focused=true]/day:relative","mui-d9c5891363f9":"group/day","mui-3f96bf138f7b":"group-data-[focused=true]/day:z-10","mui-d39eb62b8363":"group-data-[focused=true]/day:border-ring","mui-5892a880410a":"group-data-[focused=true]/day:ring-1","mui-31b75c623c06":"group-data-[focused=true]/day:ring-ring","mui-e6020023567a":"group-data-[highlighted=true]:bg-accent","mui-f0ee83167878":"peer-disabled:cursor-not-allowed","mui-2ffc1d06387e":"peer","mui-25d26df52a1d":"peer-disabled:opacity-50","mui-32713fefe32f":"file:border-0","mui-25a74d576c42":"file:bg-transparent","mui-844abccf1fd0":"file:text-sm","mui-dc43de54f42a":"file:font-medium","mui-20315da78444":"placeholder:text-muted-foreground","mui-3deb00079b4c":"first:border-s-0","mui-37ad15a95595":"hover:bg-accent","mui-63b29dace366":"hover:bg-accent/50","mui-bb6a4b3e902d":"hover:bg-destructive/90","mui-5cbdd1b32f1a":"hover:bg-muted/50","mui-4273133a876a":"hover:bg-primary/20","mui-af9ea085901b":"hover:bg-primary/90","mui-099700a5a311":"hover:bg-secondary/80","mui-71863717995b":"hover:bg-transparent","mui-9f1f77b92dcb":"hover:text-accent-foreground","mui-4d6720d47806":"hover:text-foreground","mui-b56720602554":"hover:underline","mui-8da02faac748":"hover:opacity-100","mui-a8c1861c5d03":"focus:bg-accent","mui-a85c4c5d7465":"focus:text-accent-foreground","mui-b906a32b31ee":"focus-visible:border-ring","mui-2f669cfad5aa":"focus-visible:bg-primary/20","mui-39be5a15b766":"focus-visible:ring-1","mui-355efe22aedb":"focus-visible:ring-2","mui-365a4654f7b1":"focus-visible:ring-[3px]","mui-db549d38ff19":"focus-visible:ring-ring","mui-392a26f4c1b0":"focus-visible:ring-ring/50","mui-a47d391255f3":"focus-visible:outline","mui-1df9125eebaf":"focus-visible:outline-1","mui-a8719ed8b095":"focus-visible:-outline-offset-2","mui-2b1c7d88acff":"focus-visible:outline-primary","mui-223daa83ed2d":"focus-visible:outline-ring","mui-2e357972fc10":"focus-visible:outline-none","mui-50aafa8694bb":"focus-visible:ring-inset","mui-71998ea7a2d0":"active:cursor-grabbing","mui-8d3c1014b967":"disabled:pointer-events-none","mui-db567af109b7":"disabled:cursor-not-allowed","mui-4600b77303d6":"disabled:opacity-50","mui-7eb7501a2ef0":"has-focus:border-ring","mui-d0449753ba7b":"has-focus:ring-[3px]","mui-fc19c8471f34":"has-focus:ring-ring/50","mui-e288cffc2ef4":"has-[>svg]:px-1.5","mui-3b01ee05b16d":"has-[>svg]:px-2.5","mui-9e08353b774f":"has-[>svg]:px-3","mui-2c0115d1c32a":"aria-disabled:opacity-50","mui-1fac1d7d1df3":"aria-invalid:border-destructive","mui-2d91b4cbc3cb":"aria-invalid:ring-destructive","mui-5491fd0b4dc5":"aria-invalid:ring-destructive/20","mui-2d6703b5473b":"aria-pressed:bg-accent","mui-ff2dcda51a27":"aria-pressed:text-accent-foreground","mui-7d900a71e5ba":"aria-selected:text-muted-foreground","mui-397f5ba426a0":"data-[disabled]:pointer-events-none","mui-9beb654fcb0d":"data-[disabled]:opacity-50","mui-9d7d1760cd8e":"data-[highlighted=true]:bg-accent","mui-6fa6a8ade7c4":"data-[inset]:pl-8","mui-bbaaa5969856":"data-[more-below=true]:[mask-image:linear-gradient(#000_calc(100%_-_1rem),transparent)]","mui-dfc89afd7885":"data-[navigation=pointer]:focus-visible:ring-0","mui-96308b55e0d6":"data-[range-end=true]:rounded-md","mui-a55dbe6f3eec":"data-[range-end=true]:rounded-r-md","mui-714051e55e8e":"data-[range-end=true]:bg-primary","mui-c764cebcd540":"data-[range-end=true]:text-primary-foreground","mui-05ec0700cd48":"data-[range-middle=true]:rounded-none","mui-5fb598fb06f4":"data-[range-middle=true]:bg-accent","mui-0813905aa141":"data-[range-middle=true]:text-accent-foreground","mui-8020e31bff67":"data-[range-start=true]:rounded-md","mui-ab65911baf1d":"data-[range-start=true]:rounded-l-md","mui-f5460d79341c":"data-[range-start=true]:bg-primary","mui-421a7d3e6631":"data-[range-start=true]:text-primary-foreground","mui-a39af81d518c":"data-[selected-single=true]:bg-primary","mui-b6991ab170de":"data-[selected-single=true]:text-primary-foreground","mui-3cc0d07ef843":"data-[selected=true]:rounded-none","mui-89f6aab7a3f8":"data-[side=bottom]:slide-in-from-top-2","mui-3550f48d66b9":"data-[side=left]:slide-in-from-right-2","mui-7720fe004f5c":"data-[side=right]:slide-in-from-left-2","mui-66b560f839de":"data-[side=top]:slide-in-from-bottom-2","mui-20553d55d224":"data-[state=checked]:border-primary","mui-57d6d6401a2f":"data-[state=checked]:bg-primary","mui-7ca12016214f":"data-[state=checked]:text-primary-foreground","mui-37d8a3f448ff":"data-[state=closed]:animate-none!","mui-0cb4489c3645":"data-[state=closed]:animate-out","mui-bb5869ef903b":"data-[state=closed]:fade-out-0","mui-f4cf4be63707":"data-[state=closed]:zoom-out-95","mui-bae1e782f277":"data-[state=open]:animate-in","mui-4027d9c589b6":"data-[state=open]:bg-accent","mui-1952cd5b00aa":"data-[state=open]:text-accent-foreground","mui-6f73a280432e":"data-[state=open]:text-foreground","mui-790ed041a953":"data-[state=open]:opacity-100","mui-45464a92c1f6":"data-[state=open]:fade-in-0","mui-9ca352480f25":"data-[state=open]:zoom-in-95","mui-f3f7a9c5e1b3":"data-[variant=destructive]:text-destructive","mui-e2bb4ac97190":"data-[variant=destructive]:focus:bg-destructive/10","mui-353a727facfd":"data-[variant=destructive]:focus:text-destructive","mui-237747164b60":"motion-reduce:animate-none","mui-0cc20f4e20c8":"sm:w-[21.875rem]","mui-56760b222da0":"md:flex-row","mui-c05c9b99939d":"md:text-sm","mui-36b12e8339c7":"rtl:rotate-180","mui-d254c96aea74":"dark:bg-green-950","mui-9daa2369a41b":"dark:bg-input/30","mui-b2786f463a62":"dark:hover:text-accent-foreground","mui-c88f65aa011e":"dark:aria-invalid:ring-destructive/40","mui-bd73d819941e":"dark:data-[state=checked]:bg-primary","mui-98a28c2293f7":"dark:data-[variant=destructive]:focus:bg-destructive/20","mui-d78a8526410d":"pointer-coarse:[--cell-size:min(2.5rem,calc((100vw-3.5rem)/7))]","mui-b51243872d85":"sm:pointer-fine:h-8","mui-e771a8b4d87d":"sm:pointer-fine:h-9","mui-aa0e3c036805":"sm:pointer-fine:min-h-8","mui-0288c4ea71ea":"sm:pointer-fine:py-0.5","mui-41d1475cf71a":"sm:pointer-fine:py-1.5","mui-548a450e8e53":"[&_*]:transition-none!","mui-a1c8c43d9be2":"[&_[role^=menuitem]]:min-h-9","mui-b43343fe71c0":"sm:pointer-fine:[&_[role^=menuitem]]:min-h-8","mui-cc310a330231":"[&_button]:font-semibold","mui-b7ff49878425":"[&_button]:underline","mui-d9bdd2c94504":"[&_button]:underline-offset-4","mui-bcae9d37090c":"[&_svg]:pointer-events-none","mui-c77732bd3ab4":"[&_svg]:size-3.5","mui-040e748a3fa0":"[&_svg]:shrink-0","mui-be87a4a64d81":"[&_svg:not([class*='size-'])]:size-3","mui-eb5ef2dbc2d4":"[&_svg:not([class*='size-'])]:size-4","mui-8637dfd54fbb":"[&_svg:not([class*='text-'])]:text-muted-foreground","mui-4f05a238500e":"[&::-webkit-search-cancel-button]:appearance-none","mui-74ab31abd804":"[&:first-child[data-selected=true]_button]:rounded-l-md","mui-13858191ca50":"rtl:**:[.rdp-button\\_next>svg]:rotate-180","mui-a324a7f99932":"rtl:**:[.rdp-button\\_previous>svg]:rotate-180","mui-82b114bbff3d":"data-[variant=destructive]:*:[svg]:text-destructive!","mui-6ee0c74de40c":"[&:last-child[data-selected=true]_button]:rounded-r-md","mui-6162ab70efb5":"[&:nth-child(2)[data-selected=true]_button]:rounded-l-md","mui-f157ee6bae99":"[&>div]:w-full","mui-ba417cf466b0":"[&>span]:text-xs","mui-829c8ef4f9c5":"[&>span]:opacity-70","mui-bf95f682e553":"[&>span:first-child]:mt-[calc(0.5lh-0.4375rem)]","mui-eb740dd32318":"[&>svg]:size-3.5","mui-019fd73c95db":"[&>svg]:text-muted-foreground","mui-b8293c91796c":"[[data-slot=card-content]_&]:bg-transparent","mui-8dd7e6b42262":"[[data-slot=popover-content]_&]:bg-transparent"};
1
+ export const originalClassNames = {"mui-cb20bd519346":"pointer-events-auto","mui-33228ff7d583":"pointer-events-none","mui-b75af7ef6c4d":"invisible","mui-d42ef1497900":"visible","mui-32fb090591d9":"sr-only","mui-747355bdc2a2":"absolute","mui-d2d9e1f13413":"relative","mui-964a9431ff49":"sticky","mui-ce13093ad8c9":"inset-0","mui-3ba24c062d55":"inset-x-0","mui-eb9e48c5dda9":"inset-y-0","mui-cced28c6dc3f":"start","mui-207bd0b3f259":"start-2","mui-cea70f23972e":"start-3","mui-361e48d0308f":"end","mui-13422ddc8d83":"end-1","mui-585f4729f611":"end-9","mui-98599e4ee250":"top-0","mui-4e45f4841abb":"top-1/2","mui-a74c4477017c":"right-0","mui-30150dd033ab":"bottom-0","mui-a5c36273c0f0":"bottom-2","mui-635702706586":"left-0","mui-014aadadffad":"isolate","mui-d7efd1b0b0f9":"z-1","mui-418e44ad4f9e":"z-10","mui-4e8f0a87a0dc":"z-20","mui-fbb62f5cb6fe":"z-30","mui-3eef1ce97dba":"z-50","mui-a42d519714d6":"container","mui-a2526bc2efa3":"m-0","mui-abba77319850":"-mx-1","mui-1752f11474a6":"mx-auto","mui-d8747231f142":"my-1","mui-958e2cfcf5b6":"-ms-2","mui-291952c2525a":"-ms-px","mui-8cc46fa87f41":"-me-1.5","mui-f28fea81a5cd":"mt-2","mui-cc51bda60e7e":"ml-auto","mui-496aca80e4d8":"block","mui-d1b2a59fbea7":"contents","mui-222f930b8752":"flex","mui-0f2a693e93e2":"grid","mui-e564b4081d7a":"hidden","mui-995cf20a9c45":"inline","mui-123306850fe1":"inline-flex","mui-0d4fc4a78d37":"table","mui-3da89b3ed14b":"field-sizing-content","mui-129d6f9b1e07":"aspect-square","mui-f7d12b41bceb":"size-(--cell-size)","mui-dc797fcc7165":"size-1.5","mui-5e34f5313859":"size-3","mui-61c000c8a98a":"size-3.5","mui-100c22d5776b":"size-4","mui-2bd43fb57913":"size-5","mui-0712570dcc9f":"size-6","mui-79ede756e761":"size-7","mui-ebd37e04d422":"size-8","mui-3ee10ef4c057":"size-9","mui-d0a383a9c24f":"size-10","mui-4dad94bd15e3":"size-auto","mui-a5960ac1d283":"h-(--cell-size)","mui-c7d5500b77ab":"h-0","mui-2edce89ef182":"h-3","mui-099be97e1fa4":"h-4","mui-ce1945804664":"h-6","mui-c8e50836f8a1":"h-7","mui-1fb07b38c63b":"h-8","mui-539ae144f076":"h-9","mui-fdd2f85cad6b":"h-10","mui-a66e9985b093":"h-auto","mui-57c930dc1c31":"h-full","mui-ae2c4b060bb9":"h-px","mui-571ea69568d3":"max-h-(--filter-menu-height)","mui-1f061e70178e":"max-h-(--radix-dropdown-menu-content-available-height)","mui-4d3f1304ebb2":"max-h-(--radix-popover-content-available-height)","mui-da0beef015c9":"max-h-[400px]","mui-80baa5d03af7":"max-h-[calc(var(--filter-menu-height)-2px)]","mui-1326520533f0":"max-h-[min(6rem,calc(var(--filter-menu-height)*0.25))]","mui-fb4a3e97b5bd":"max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height,20rem))]","mui-dcd942c18ddc":"max-h-[var(--radix-dropdown-menu-content-available-height)]","mui-7bd696ca6be3":"max-h-full","mui-410da8dfa8ac":"min-h-0","mui-9974acedf3f7":"min-h-9","mui-8423dc94ee06":"min-h-10","mui-50312c3ce4a3":"min-h-[60px]","mui-d48fe95d4da8":"w-(--cell-size)","mui-d4ea834145ae":"w-2","mui-56bb14cbd1fe":"w-2/3","mui-8867d85ed290":"w-8","mui-4ac4ec8dfbce":"w-40","mui-37535002f0f7":"w-72","mui-a4cce7869436":"w-[300px]","mui-fc6a57ff7553":"w-[var(--mendy-filter-editor-width,19rem)]","mui-0b9c84552e40":"w-[var(--mendy-filter-list-width,var(--mendy-filter-anchor-width,18.75rem))]","mui-4415137b0467":"w-[var(--mendy-filter-menu-width,calc(var(--filter-list-width)_+_var(--mendy-filter-editor-width,19rem)))]","mui-8cfb5a42ef9f":"w-fit","mui-58d0413dd93c":"w-full","mui-91f82aa1df0c":"max-w-[60%]","mui-34055e6f8c1b":"max-w-[calc(100vw-2rem)]","mui-81b198a2db84":"max-w-full","mui-1458e495e3ae":"min-w-(--cell-size)","mui-184ddc11e5f9":"min-w-0","mui-e9ab1547c94d":"min-w-[8rem]","mui-2bf6510f1330":"min-w-full","mui-7bd5bab6d7f4":"flex-1","mui-66b490dd6005":"shrink","mui-27ead27a81df":"shrink-0","mui-adca5146416e":"grow","mui-215061302c50":"border-collapse","mui-3a3774477287":"origin-(--radix-dropdown-menu-content-transform-origin)","mui-5dde0fd996f0":"-translate-y-1/2","mui-4e3f08588318":"-rotate-45","mui-c80411b7591f":"rotate-45","mui-aa214ea38326":"transform","mui-393df0d154e0":"animate-none!","mui-7b3cd77eb999":"animate-pulse","mui-2c14b55d77e6":"animate-spin","mui-2194d094b585":"cursor-col-resize","mui-d343f41ba73e":"cursor-default","mui-f2e47d9c52ad":"cursor-grab","mui-d2fa8848968d":"cursor-pointer","mui-739a9a000791":"touch-none","mui-acd532d8913e":"resize","mui-ae112c903ef8":"resize-y","mui-eeb3a8b33f69":"grid-cols-[min(var(--filter-list-width),calc(100%_-_min(var(--mendy-filter-editor-width,19rem),50%)))_minmax(0,1fr)]","mui-b5985369ee35":"grid-rows-[minmax(0,1fr)]","mui-302c0d124a94":"flex-col","mui-faa8a23c68f6":"flex-wrap","mui-8fd2e2355cbc":"place-content-center","mui-71556df3b421":"items-center","mui-b9677bd1cb66":"items-start","mui-32c92bb1fde4":"justify-between","mui-a503dd374cca":"justify-center","mui-307644c34db6":"justify-end","mui-c62ec162662e":"justify-start","mui-19e97f3f40e6":"gap-1","mui-70007b876865":"gap-1.5","mui-074569488cca":"gap-2","mui-d7db3451d154":"gap-3","mui-90fc3ec35a37":"gap-4","mui-27e6c432192f":"space-y-1","mui-267171770524":"space-y-2","mui-5a3a4ee420c2":"truncate","mui-1a26a0d28420":"overflow-auto","mui-d5111d0e9f48":"overflow-hidden","mui-0fc84a692dad":"overflow-visible","mui-3b82279f859f":"overflow-x-hidden","mui-2368e909f3a5":"overflow-y-auto","mui-998780cdef87":"overscroll-contain","mui-b005d61d0953":"rounded-full","mui-3fa8c572949b":"rounded-md","mui-52417259a4f5":"rounded-none","mui-02e603944040":"rounded-sm","mui-b31810dbd8a9":"rounded-s-none","mui-10c0bae8cba9":"rounded-l-md","mui-34bbd346e74c":"rounded-r-md","mui-4f1a55de40bc":"border","mui-dad556abfe15":"border-0","mui-55860251be20":"border-s","mui-3b6d5fc7b061":"border-e","mui-894c3815a57f":"border-t","mui-bbe39cfb5cc6":"border-b","mui-8450eb0f1857":"border-dashed","mui-163a623b3716":"border-border/50","mui-1267095cdeb7":"border-input","mui-9b76f456b8c9":"border-muted-foreground/50","mui-515f9fdc6db7":"border-primary","mui-292affc1f780":"bg-accent","mui-5b272f3c5076":"bg-background","mui-a943bea85d66":"bg-border","mui-0cf6c2e8fe7e":"bg-current","mui-965cf6587342":"bg-destructive","mui-047624ec0c39":"bg-green-100","mui-6ba846e1630e":"bg-inherit","mui-87ecb59f2d2d":"bg-muted","mui-810ae775809b":"bg-muted-foreground/20","mui-e593c38256e0":"bg-popover","mui-0c2864fba576":"bg-primary","mui-d191cb569aac":"bg-secondary","mui-8fca9236d191":"bg-transparent","mui-04760bcd507f":"p-0","mui-1dee6e3ec67d":"p-1","mui-b97db4a9f432":"p-2","mui-094f5333853b":"p-3","mui-c432836760e3":"p-6","mui-c7902d77ad80":"p-8","mui-56b8f5e0fb12":"px-(--cell-size)","mui-16e909e6f01d":"px-0","mui-1da2e8f173c5":"px-1.5","mui-e7e01cc7f4df":"px-2","mui-0f9e6672913a":"px-3","mui-9513b3968002":"px-4","mui-0194c6e46323":"px-8","mui-1fcf28756bb1":"py-1","mui-a8c1dfb1d4ef":"py-1.5","mui-b5edc3ea7c91":"py-2","mui-d3cea061f2f3":"py-3","mui-96b92a971c95":"py-5","mui-078d945937da":"ps-8","mui-b2100041c585":"ps-9","mui-05d4103bd67f":"pe-2","mui-a202804a1738":"pe-3","mui-0e14c365f9e8":"pe-9","mui-559069d2c2e5":"pe-16","mui-0a702d97ed7d":"pt-3","mui-1a52da5bc88c":"pr-1","mui-f5d8e661d857":"pl-2","mui-05ab12448317":"text-center","mui-10558dbb3a24":"text-end","mui-e9347b78185f":"text-start","mui-757071a1d1c4":"text-base","mui-c74ab393b96d":"text-sm","mui-3992de70b033":"text-xs","mui-5f120ad4b50b":"text-[0.8rem]","mui-761cdb81bddb":"leading-none","mui-daaac3fbf55e":"font-medium","mui-52101fc7d8bb":"font-normal","mui-e1683b3c030a":"tracking-widest","mui-393883c1db68":"[overflow-wrap:anywhere]","mui-37cf9655f30a":"break-words","mui-726fca123972":"whitespace-normal","mui-963f6168b7d6":"whitespace-nowrap","mui-cc209238d847":"text-accent-foreground","mui-5eafab9bbefc":"text-current","mui-887b9502d5c7":"text-destructive","mui-8d4bf2704c8d":"text-destructive-foreground","mui-957a109f887f":"text-foreground","mui-35f35c41d134":"text-muted-foreground","mui-5bd2afe89f0b":"text-popover-foreground","mui-249f14ee5b6b":"text-primary","mui-abd1aaa1f5b2":"text-primary-foreground","mui-80df79ec9bb5":"text-secondary-foreground","mui-944969efb294":"underline","mui-d52f902a57e8":"underline-offset-4","mui-94f91922a10e":"opacity-0","mui-0b5a4d1257ab":"opacity-50","mui-65694092f002":"opacity-100","mui-0d4ca75de41c":"shadow-lg","mui-94ea94fde25f":"shadow-md","mui-89c3006b2722":"shadow-none","mui-7de07d413c13":"shadow-xs","mui-853be6c11609":"ring-2","mui-fd9d0b696aac":"ring-primary","mui-59edd3d33673":"outline-hidden","mui-318678825324":"outline","mui-e42932b7a79c":"blur","mui-e0122edc668b":"drop-shadow-md","mui-dfc3376b8266":"filter","mui-70dd37c11434":"transition","mui-eae178841c68":"transition-colors","mui-2cdd01663c76":"transition-opacity","mui-2b48746f4314":"transition-shadow","mui-b4b2fd95f324":"transition-none","mui-b30fc56058b6":"outline-none","mui-78905c9e865c":"select-none","mui-d80b6593dae5":"[--cell-size:--spacing(8)]","mui-82c2977beb8e":"[--cell-size:min(2rem,calc((100vw-3.5rem)/7))]","mui-d7d803c609c5":"[--filter-list-width:var(--mendy-filter-list-width,var(--mendy-filter-anchor-width,13rem))]","mui-971625533e56":"[--filter-menu-height:min(var(--mendy-filter-menu-max-height,44rem),var(--radix-dropdown-menu-content-available-height,44rem))]","mui-cacb19aa9640":"[scrollbar-width:thin]","mui-14bd99410890":"[unicode-bidi:isolate]","mui-97b1c00ff005":"group-hover:bg-accent","mui-ad936fcbed63":"group","mui-9af9a4182597":"group-data-[disabled=true]:pointer-events-none","mui-272ef88d6a0c":"group-data-[disabled=true]:opacity-50","mui-60052b901494":"group-data-[focused=true]/day:relative","mui-d9c5891363f9":"group/day","mui-3f96bf138f7b":"group-data-[focused=true]/day:z-10","mui-d39eb62b8363":"group-data-[focused=true]/day:border-ring","mui-5892a880410a":"group-data-[focused=true]/day:ring-1","mui-31b75c623c06":"group-data-[focused=true]/day:ring-ring","mui-e6020023567a":"group-data-[highlighted=true]:bg-accent","mui-f0ee83167878":"peer-disabled:cursor-not-allowed","mui-2ffc1d06387e":"peer","mui-25d26df52a1d":"peer-disabled:opacity-50","mui-32713fefe32f":"file:border-0","mui-25a74d576c42":"file:bg-transparent","mui-844abccf1fd0":"file:text-sm","mui-dc43de54f42a":"file:font-medium","mui-20315da78444":"placeholder:text-muted-foreground","mui-3deb00079b4c":"first:border-s-0","mui-37ad15a95595":"hover:bg-accent","mui-bb6a4b3e902d":"hover:bg-destructive/90","mui-5cbdd1b32f1a":"hover:bg-muted/50","mui-4273133a876a":"hover:bg-primary/20","mui-af9ea085901b":"hover:bg-primary/90","mui-099700a5a311":"hover:bg-secondary/80","mui-71863717995b":"hover:bg-transparent","mui-9f1f77b92dcb":"hover:text-accent-foreground","mui-4d6720d47806":"hover:text-foreground","mui-b56720602554":"hover:underline","mui-8da02faac748":"hover:opacity-100","mui-a8c1861c5d03":"focus:bg-accent","mui-a85c4c5d7465":"focus:text-accent-foreground","mui-b906a32b31ee":"focus-visible:border-ring","mui-2f669cfad5aa":"focus-visible:bg-primary/20","mui-39be5a15b766":"focus-visible:ring-1","mui-355efe22aedb":"focus-visible:ring-2","mui-365a4654f7b1":"focus-visible:ring-[3px]","mui-db549d38ff19":"focus-visible:ring-ring","mui-392a26f4c1b0":"focus-visible:ring-ring/50","mui-a47d391255f3":"focus-visible:outline","mui-1df9125eebaf":"focus-visible:outline-1","mui-a8719ed8b095":"focus-visible:-outline-offset-2","mui-2b1c7d88acff":"focus-visible:outline-primary","mui-223daa83ed2d":"focus-visible:outline-ring","mui-2e357972fc10":"focus-visible:outline-none","mui-50aafa8694bb":"focus-visible:ring-inset","mui-71998ea7a2d0":"active:cursor-grabbing","mui-8d3c1014b967":"disabled:pointer-events-none","mui-db567af109b7":"disabled:cursor-not-allowed","mui-4600b77303d6":"disabled:opacity-50","mui-7eb7501a2ef0":"has-focus:border-ring","mui-d0449753ba7b":"has-focus:ring-[3px]","mui-fc19c8471f34":"has-focus:ring-ring/50","mui-e288cffc2ef4":"has-[>svg]:px-1.5","mui-3b01ee05b16d":"has-[>svg]:px-2.5","mui-9e08353b774f":"has-[>svg]:px-3","mui-2c0115d1c32a":"aria-disabled:opacity-50","mui-1fac1d7d1df3":"aria-invalid:border-destructive","mui-2d91b4cbc3cb":"aria-invalid:ring-destructive","mui-5491fd0b4dc5":"aria-invalid:ring-destructive/20","mui-2d6703b5473b":"aria-pressed:bg-accent","mui-ff2dcda51a27":"aria-pressed:text-accent-foreground","mui-7d900a71e5ba":"aria-selected:text-muted-foreground","mui-397f5ba426a0":"data-[disabled]:pointer-events-none","mui-9beb654fcb0d":"data-[disabled]:opacity-50","mui-9d7d1760cd8e":"data-[highlighted=true]:bg-accent","mui-6fa6a8ade7c4":"data-[inset]:pl-8","mui-bbaaa5969856":"data-[more-below=true]:[mask-image:linear-gradient(#000_calc(100%_-_1rem),transparent)]","mui-dfc89afd7885":"data-[navigation=pointer]:focus-visible:ring-0","mui-96308b55e0d6":"data-[range-end=true]:rounded-md","mui-a55dbe6f3eec":"data-[range-end=true]:rounded-r-md","mui-714051e55e8e":"data-[range-end=true]:bg-primary","mui-c764cebcd540":"data-[range-end=true]:text-primary-foreground","mui-05ec0700cd48":"data-[range-middle=true]:rounded-none","mui-5fb598fb06f4":"data-[range-middle=true]:bg-accent","mui-0813905aa141":"data-[range-middle=true]:text-accent-foreground","mui-8020e31bff67":"data-[range-start=true]:rounded-md","mui-ab65911baf1d":"data-[range-start=true]:rounded-l-md","mui-f5460d79341c":"data-[range-start=true]:bg-primary","mui-421a7d3e6631":"data-[range-start=true]:text-primary-foreground","mui-a39af81d518c":"data-[selected-single=true]:bg-primary","mui-b6991ab170de":"data-[selected-single=true]:text-primary-foreground","mui-3cc0d07ef843":"data-[selected=true]:rounded-none","mui-89f6aab7a3f8":"data-[side=bottom]:slide-in-from-top-2","mui-3550f48d66b9":"data-[side=left]:slide-in-from-right-2","mui-7720fe004f5c":"data-[side=right]:slide-in-from-left-2","mui-66b560f839de":"data-[side=top]:slide-in-from-bottom-2","mui-20553d55d224":"data-[state=checked]:border-primary","mui-57d6d6401a2f":"data-[state=checked]:bg-primary","mui-7ca12016214f":"data-[state=checked]:text-primary-foreground","mui-37d8a3f448ff":"data-[state=closed]:animate-none!","mui-0cb4489c3645":"data-[state=closed]:animate-out","mui-bb5869ef903b":"data-[state=closed]:fade-out-0","mui-f4cf4be63707":"data-[state=closed]:zoom-out-95","mui-bae1e782f277":"data-[state=open]:animate-in","mui-4027d9c589b6":"data-[state=open]:bg-accent","mui-1952cd5b00aa":"data-[state=open]:text-accent-foreground","mui-6f73a280432e":"data-[state=open]:text-foreground","mui-790ed041a953":"data-[state=open]:opacity-100","mui-45464a92c1f6":"data-[state=open]:fade-in-0","mui-9ca352480f25":"data-[state=open]:zoom-in-95","mui-f3f7a9c5e1b3":"data-[variant=destructive]:text-destructive","mui-e2bb4ac97190":"data-[variant=destructive]:focus:bg-destructive/10","mui-353a727facfd":"data-[variant=destructive]:focus:text-destructive","mui-237747164b60":"motion-reduce:animate-none","mui-0cc20f4e20c8":"sm:w-[21.875rem]","mui-56760b222da0":"md:flex-row","mui-c05c9b99939d":"md:text-sm","mui-36b12e8339c7":"rtl:rotate-180","mui-d254c96aea74":"dark:bg-green-950","mui-9daa2369a41b":"dark:bg-input/30","mui-b2786f463a62":"dark:hover:text-accent-foreground","mui-c88f65aa011e":"dark:aria-invalid:ring-destructive/40","mui-bd73d819941e":"dark:data-[state=checked]:bg-primary","mui-98a28c2293f7":"dark:data-[variant=destructive]:focus:bg-destructive/20","mui-d78a8526410d":"pointer-coarse:[--cell-size:min(2.5rem,calc((100vw-3.5rem)/7))]","mui-b51243872d85":"sm:pointer-fine:h-8","mui-e771a8b4d87d":"sm:pointer-fine:h-9","mui-aa0e3c036805":"sm:pointer-fine:min-h-8","mui-0288c4ea71ea":"sm:pointer-fine:py-0.5","mui-41d1475cf71a":"sm:pointer-fine:py-1.5","mui-548a450e8e53":"[&_*]:transition-none!","mui-a1c8c43d9be2":"[&_[role^=menuitem]]:min-h-9","mui-b43343fe71c0":"sm:pointer-fine:[&_[role^=menuitem]]:min-h-8","mui-cc310a330231":"[&_button]:font-semibold","mui-b7ff49878425":"[&_button]:underline","mui-d9bdd2c94504":"[&_button]:underline-offset-4","mui-bcae9d37090c":"[&_svg]:pointer-events-none","mui-c77732bd3ab4":"[&_svg]:size-3.5","mui-040e748a3fa0":"[&_svg]:shrink-0","mui-be87a4a64d81":"[&_svg:not([class*='size-'])]:size-3","mui-eb5ef2dbc2d4":"[&_svg:not([class*='size-'])]:size-4","mui-8637dfd54fbb":"[&_svg:not([class*='text-'])]:text-muted-foreground","mui-4f05a238500e":"[&::-webkit-search-cancel-button]:appearance-none","mui-74ab31abd804":"[&:first-child[data-selected=true]_button]:rounded-l-md","mui-13858191ca50":"rtl:**:[.rdp-button\\_next>svg]:rotate-180","mui-a324a7f99932":"rtl:**:[.rdp-button\\_previous>svg]:rotate-180","mui-82b114bbff3d":"data-[variant=destructive]:*:[svg]:text-destructive!","mui-6ee0c74de40c":"[&:last-child[data-selected=true]_button]:rounded-r-md","mui-6162ab70efb5":"[&:nth-child(2)[data-selected=true]_button]:rounded-l-md","mui-f157ee6bae99":"[&>div]:w-full","mui-ba417cf466b0":"[&>span]:text-xs","mui-829c8ef4f9c5":"[&>span]:opacity-70","mui-bf95f682e553":"[&>span:first-child]:mt-[calc(0.5lh-0.4375rem)]","mui-eb740dd32318":"[&>svg]:size-3.5","mui-019fd73c95db":"[&>svg]:text-muted-foreground","mui-b8293c91796c":"[[data-slot=card-content]_&]:bg-transparent","mui-8dd7e6b42262":"[[data-slot=popover-content]_&]:bg-transparent"};
@@ -38,7 +38,7 @@ export declare function FilterMenu({ children, asChild, anchor, }: {
38
38
  asChild?: boolean;
39
39
  /** Align a standalone trigger to an application-owned search field. */
40
40
  anchor?: React.RefObject<HTMLDivElement | null>;
41
- }): import("react/jsx-runtime").JSX.Element;
41
+ }): import("react/jsx-runtime").JSX.Element | null;
42
42
  /** Applied chips followed by Clear all. Opt out when placing FilterClear elsewhere. */
43
43
  export declare function FilterList({ showClear }: {
44
44
  showClear?: boolean;
@@ -23,6 +23,12 @@ const subscribeHydration = () => () => { };
23
23
  const clientHydrated = () => true;
24
24
  const serverHydrated = () => false;
25
25
  const Context = createContext(null);
26
+ function availableMenuEntries(filters) {
27
+ return filters.entries.filter((entry) => !entry.field.hidden && entry.field.menu !== false);
28
+ }
29
+ function hasClearableActiveField(filters) {
30
+ return filters.entries.some(({ field, value }) => !field.hidden && !field.disabled && field.removable !== false && field.isActive(value));
31
+ }
26
32
  function useRoot() {
27
33
  const context = useContext(Context);
28
34
  if (!context)
@@ -69,7 +75,22 @@ export function FilterSearch({ label = "Search", placeholder = "Search or filter
69
75
  const anchor = useRef(null);
70
76
  const input = useRef(null);
71
77
  const shift = useRef(false);
72
- return (_jsxs(DropdownMenu, { dir: direction, modal: false, open: filters.menuOpen, onOpenChange: filters.setMenuOpen, children: [_jsxs("div", { ref: anchor, className: cn("mui-d2d9e1f13413 mui-58d0413dd93c mui-81b198a2db84 mui-27ead27a81df mui-0cc20f4e20c8", classNames?.search), children: [_jsx(Search, { className: "mui-33228ff7d583 mui-747355bdc2a2 mui-cea70f23972e mui-4e45f4841abb mui-100c22d5776b mui-5dde0fd996f0", "aria-hidden": "true" }), _jsx(Input, { ref: input, type: "text", role: "searchbox", disabled: disabled, "aria-label": label, placeholder: placeholder, value: filters.search, autoComplete: "off", autoCapitalize: "none", autoCorrect: "off", spellCheck: false, className: cn("mui-58d0413dd93c mui-b2100041c585 mui-c74ab393b96d mui-4f05a238500e", filters.search ? "mui-559069d2c2e5" : "mui-0e14c365f9e8", classNames?.searchInput), onKeyDown: (event) => {
78
+ const hasMenu = availableMenuEntries(filters).length > 0;
79
+ useLayoutEffect(() => {
80
+ if (hasMenu)
81
+ return;
82
+ const focusTarget = input.current;
83
+ trigger.current = focusTarget;
84
+ return () => {
85
+ if (trigger.current === focusTarget)
86
+ trigger.current = null;
87
+ };
88
+ }, [hasMenu, trigger]);
89
+ useEffect(() => {
90
+ if (!hasMenu && filters.menuOpen)
91
+ filters.setMenuOpen(false);
92
+ }, [filters, hasMenu]);
93
+ return (_jsxs(DropdownMenu, { dir: direction, modal: false, open: hasMenu && filters.menuOpen, onOpenChange: filters.setMenuOpen, children: [_jsxs("div", { ref: anchor, className: cn("mui-d2d9e1f13413 mui-58d0413dd93c mui-81b198a2db84 mui-27ead27a81df mui-0cc20f4e20c8", classNames?.search), children: [_jsx(Search, { className: "mui-33228ff7d583 mui-747355bdc2a2 mui-cea70f23972e mui-4e45f4841abb mui-100c22d5776b mui-5dde0fd996f0", "aria-hidden": "true" }), _jsx(Input, { ref: input, type: "text", role: "searchbox", disabled: disabled, "aria-label": label, placeholder: placeholder, value: filters.search, autoComplete: "off", autoCapitalize: "none", autoCorrect: "off", spellCheck: false, className: cn("mui-58d0413dd93c mui-b2100041c585 mui-c74ab393b96d mui-4f05a238500e", filters.search ? (hasMenu ? "mui-559069d2c2e5" : "mui-0e14c365f9e8") : hasMenu ? "mui-0e14c365f9e8" : "mui-a202804a1738", classNames?.searchInput), onKeyDown: (event) => {
73
94
  shift.current = event.shiftKey;
74
95
  if (event.key === "Enter" && !event.nativeEvent.isComposing && !event.shiftKey) {
75
96
  const classified = classifyPaste(event.currentTarget.value, filters.entries);
@@ -105,17 +126,28 @@ export function FilterSearch({ label = "Search", placeholder = "Search or filter
105
126
  after: element.value.slice(end),
106
127
  });
107
128
  setAmbiguous(result.ambiguous);
108
- } }), filters.search && (_jsx(Button, { variant: "ghost", size: "icon", type: "button", disabled: disabled, "aria-label": "Clear search", className: "mui-747355bdc2a2 mui-585f4729f611 mui-4e45f4841abb mui-222f930b8752 mui-0712570dcc9f mui-5dde0fd996f0 mui-71556df3b421 mui-a503dd374cca mui-02e603944040 mui-0b5a4d1257ab mui-8da02faac748 mui-2e357972fc10 mui-39be5a15b766 mui-db549d38ff19", onClick: () => {
129
+ } }), filters.search && (_jsx(Button, { variant: "ghost", size: "icon", type: "button", disabled: disabled, "aria-label": "Clear search", className: cn("mui-747355bdc2a2 mui-4e45f4841abb mui-222f930b8752 mui-0712570dcc9f mui-5dde0fd996f0 mui-71556df3b421 mui-a503dd374cca mui-02e603944040 mui-0b5a4d1257ab mui-8da02faac748 mui-2e357972fc10 mui-39be5a15b766 mui-db549d38ff19", hasMenu ? "mui-585f4729f611" : "mui-13422ddc8d83"), onClick: () => {
109
130
  setAmbiguous([]);
110
131
  filters.setSearch("");
111
132
  input.current?.focus();
112
- }, children: _jsx(X, { className: "mui-61c000c8a98a", "aria-hidden": "true" }) })), _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", ref: trigger, type: "button", disabled: disabled, "aria-label": "Open filters", "aria-haspopup": "dialog", className: cn("mui-747355bdc2a2 mui-13422ddc8d83 mui-4e45f4841abb mui-79ede756e761 mui-5dde0fd996f0 mui-2cdd01663c76 mui-8da02faac748 mui-2e357972fc10 mui-39be5a15b766 mui-db549d38ff19 mui-790ed041a953", filters.active.length ? "mui-65694092f002" : "mui-0b5a4d1257ab", classNames?.menuTrigger), children: _jsx(ListFilter, { className: "mui-100c22d5776b", "aria-hidden": "true" }) }) })] }), filters.menuOpen && _jsx(FilterMenuContent, { anchor: anchor })] }));
133
+ }, children: _jsx(X, { className: "mui-61c000c8a98a", "aria-hidden": "true" }) })), hasMenu && (_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", ref: (element) => {
134
+ trigger.current = element;
135
+ }, type: "button", disabled: disabled, "aria-label": "Open filters", "aria-haspopup": "dialog", className: cn("mui-747355bdc2a2 mui-13422ddc8d83 mui-4e45f4841abb mui-79ede756e761 mui-5dde0fd996f0 mui-2cdd01663c76 mui-8da02faac748 mui-2e357972fc10 mui-39be5a15b766 mui-db549d38ff19 mui-790ed041a953", filters.active.length ? "mui-65694092f002" : "mui-0b5a4d1257ab", classNames?.menuTrigger), children: _jsx(ListFilter, { className: "mui-100c22d5776b", "aria-hidden": "true" }) }) }))] }), hasMenu && filters.menuOpen && _jsx(FilterMenuContent, { anchor: anchor })] }));
113
136
  }
114
137
  /** A standalone menu button for layouts without a search field. */
115
138
  export function FilterMenu({ children = "Add filter", asChild = false, anchor, }) {
116
139
  const { filters, trigger, disabled, direction } = useRoot();
117
140
  const { classNames } = useMendyUI();
118
- return (_jsxs(DropdownMenu, { dir: direction, modal: false, open: filters.menuOpen, onOpenChange: filters.setMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { ref: trigger, asChild: asChild, className: classNames?.menuTrigger, variant: "outline", disabled: disabled, "aria-haspopup": "dialog", children: children }) }), filters.menuOpen && _jsx(FilterMenuContent, { anchor: anchor })] }));
141
+ const hasMenu = availableMenuEntries(filters).length > 0;
142
+ useEffect(() => {
143
+ if (!hasMenu && filters.menuOpen)
144
+ filters.setMenuOpen(false);
145
+ }, [filters, hasMenu]);
146
+ if (!hasMenu)
147
+ return null;
148
+ return (_jsxs(DropdownMenu, { dir: direction, modal: false, open: filters.menuOpen, onOpenChange: filters.setMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { ref: (element) => {
149
+ trigger.current = element;
150
+ }, asChild: asChild, className: classNames?.menuTrigger, variant: "outline", disabled: disabled, "aria-haspopup": "dialog", children: children }) }), filters.menuOpen && _jsx(FilterMenuContent, { anchor: anchor })] }));
119
151
  }
120
152
  const fieldIcons = {
121
153
  single: Circle,
@@ -131,7 +163,7 @@ function FilterMenuContent({ anchor }) {
131
163
  const [clearEpoch, setClearEpoch] = useState(0);
132
164
  const [drafts] = useState(() => new Map());
133
165
  const grouped = new Set(groups.flatMap((group) => group.fields));
134
- const visible = filters.entries.filter((entry) => !entry.field.hidden && entry.field.menu !== false);
166
+ const visible = availableMenuEntries(filters);
135
167
  const sections = [
136
168
  ...visible.flatMap((entry) => grouped.has(entry.id)
137
169
  ? []
@@ -190,7 +222,7 @@ export function FilterList({ showClear = true }) {
190
222
  (entry.field.isActive(entry.value) ||
191
223
  showSuggestion(entry, suggestions, filters.active.length))
192
224
  ? [_jsx(FieldChip, { entry: entry }, entry.id)]
193
- : []), showClear && _jsx(FilterClear, {})] }));
225
+ : []), showClear && hasClearableActiveField(filters) && _jsx(FilterClear, {})] }));
194
226
  }
195
227
  function summarize(field, value, choices) {
196
228
  if (field.kind === "numberRange" && Array.isArray(value))
@@ -1,7 +1,7 @@
1
1
  import type { KeyboardEvent } from "react";
2
2
  export declare function focusMenuEditor(root: HTMLDivElement | null): void;
3
3
  export declare function handleMenuTab(event: KeyboardEvent<HTMLDivElement>, { trigger, editor, onClose, hasSelection, }: {
4
- trigger: HTMLButtonElement | null;
4
+ trigger: HTMLElement | null;
5
5
  editor: HTMLDivElement | null;
6
6
  onClose(): void;
7
7
  hasSelection: boolean;
@@ -16,7 +16,7 @@ interface FilterMenuPanelProps {
16
16
  onSelect(id: string | null): void;
17
17
  onClose(): void;
18
18
  anchor?: RefObject<HTMLDivElement | null>;
19
- trigger: RefObject<HTMLButtonElement | null>;
19
+ trigger: RefObject<HTMLElement | null>;
20
20
  }
21
21
  /** One dialog contains the filter list and its editor, with a single-panel layout on phones. */
22
22
  export declare function FilterMenuPanel({ sections, selectedId, onSelect, onClose, anchor, trigger, }: FilterMenuPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import type { CSSProperties, RefObject } from "react";
2
2
  /** Position the menu against the search field and the available viewport. */
3
- export declare function useMenuPlacement(anchor: RefObject<HTMLDivElement | null> | undefined, trigger: RefObject<HTMLButtonElement | null>, desktop: boolean): {
3
+ export declare function useMenuPlacement(anchor: RefObject<HTMLDivElement | null> | undefined, trigger: RefObject<HTMLElement | null>, desktop: boolean): {
4
4
  alignOffset: number;
5
5
  side: "top" | "bottom";
6
6
  anchorStyle: CSSProperties | undefined;
package/dist/styles.css CHANGED
@@ -607,6 +607,9 @@
607
607
  .mui-047624ec0c39:where([data-mendy-ui], [data-mendy-ui] *) {
608
608
  background-color: var(--color-green-100);
609
609
  }
610
+ .mui-6ba846e1630e:where([data-mendy-ui], [data-mendy-ui] *) {
611
+ background-color: inherit;
612
+ }
610
613
  .mui-87ecb59f2d2d:where([data-mendy-ui], [data-mendy-ui] *) {
611
614
  background-color: var(--muted, #f5f5f5);
612
615
  }
@@ -1001,16 +1004,6 @@
1001
1004
  }
1002
1005
  }
1003
1006
  }
1004
- .mui-63b29dace366:where([data-mendy-ui], [data-mendy-ui] *) {
1005
- &:hover {
1006
- @media (hover: hover) {
1007
- background-color: var(--accent, #f5f5f5);
1008
- @supports (color: color-mix(in lab, red, red)) {
1009
- background-color: color-mix(in oklab, var(--accent, #f5f5f5) 50%, transparent);
1010
- }
1011
- }
1012
- }
1013
- }
1014
1007
  .mui-bb6a4b3e902d:where([data-mendy-ui], [data-mendy-ui] *) {
1015
1008
  &:hover {
1016
1009
  @media (hover: hover) {
@@ -606,6 +606,9 @@
606
606
  .mui-047624ec0c39:where([data-mendy-ui], [data-mendy-ui] *) {
607
607
  background-color: var(--color-green-100);
608
608
  }
609
+ .mui-6ba846e1630e:where([data-mendy-ui], [data-mendy-ui] *) {
610
+ background-color: inherit;
611
+ }
609
612
  .mui-87ecb59f2d2d:where([data-mendy-ui], [data-mendy-ui] *) {
610
613
  background-color: var(--muted, #f5f5f5);
611
614
  }
@@ -1000,16 +1003,6 @@
1000
1003
  }
1001
1004
  }
1002
1005
  }
1003
- .mui-63b29dace366:where([data-mendy-ui], [data-mendy-ui] *) {
1004
- &:hover {
1005
- @media (hover: hover) {
1006
- background-color: var(--accent, #f5f5f5);
1007
- @supports (color: color-mix(in lab, red, red)) {
1008
- background-color: color-mix(in oklab, var(--accent, #f5f5f5) 50%, transparent);
1009
- }
1010
- }
1011
- }
1012
- }
1013
1006
  .mui-bb6a4b3e902d:where([data-mendy-ui], [data-mendy-ui] *) {
1014
1007
  &:hover {
1015
1008
  @media (hover: hover) {
@@ -1,5 +1,5 @@
1
1
  import type { DataTableInstance } from "./use-data-table.js";
2
- export declare const interactiveSelector = "button, a, input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"checkbox\"], [role=\"button\"], [role=\"textbox\"]";
2
+ export declare const interactiveSelector = "button, a, summary, input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"checkbox\"], [role=\"button\"], [role=\"textbox\"]";
3
3
  export declare function selectedCellsText<T extends object>(table: DataTableInstance<T>): string;
4
4
  export declare function tableCsv<T extends object>(table: DataTableInstance<T>, options?: {
5
5
  selectedOnly?: boolean;
@@ -1,6 +1,6 @@
1
1
  import { constructCell } from "@tanstack/react-table";
2
2
  import { csvValue, tsvValue } from "./state.js";
3
- export const interactiveSelector = 'button, a, input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="checkbox"], [role="button"], [role="textbox"]';
3
+ export const interactiveSelector = 'button, a, summary, input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="checkbox"], [role="button"], [role="textbox"]';
4
4
  export function selectedCellsText(table) {
5
5
  const rows = table.getRowsInDisplayOrder();
6
6
  const columns = [
@@ -1,11 +1,14 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { UseDataTableOptions, DataTableInstance } from "./use-data-table.js";
3
3
  import type { TableViewProps } from "./table-view.js";
4
+ import { type TableFiltersProps } from "./table-filters.js";
4
5
  type Appearance<T extends object> = Omit<TableViewProps<T>, "table"> & {
5
6
  toolbar?: ReactNode;
6
7
  footer?: ReactNode;
7
8
  showColumnSettings?: boolean;
8
9
  showPagination?: boolean;
10
+ /** Customize the built-in filter bar, or render it yourself with false. */
11
+ filterBar?: Omit<TableFiltersProps, "filters"> | false;
9
12
  };
10
13
  export type DataTableProps<T extends object> = Appearance<T> & (UseDataTableOptions<T> | {
11
14
  table: DataTableInstance<T>;
@@ -3,8 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useDataTable } from "./use-data-table.js";
4
4
  import { TableView } from "./table-view.js";
5
5
  import { TableColumnSettings, TablePagination } from "./table-controls.js";
6
- function ControlledTable({ table, toolbar, footer, showColumnSettings = true, showPagination = false, ...view }) {
7
- return (_jsxs("div", { "data-mendy-ui": "", className: "mui-184ddc11e5f9 mui-267171770524", children: [(toolbar || showColumnSettings) && (_jsxs("div", { className: "mui-222f930b8752 mui-faa8a23c68f6 mui-b9677bd1cb66 mui-32c92bb1fde4 mui-074569488cca", children: [_jsx("div", { className: "mui-184ddc11e5f9 mui-7bd5bab6d7f4", children: toolbar }), showColumnSettings && _jsx(TableColumnSettings, { table: table })] })), _jsx(TableView, { table: table, ...view }), showPagination && (_jsx(TablePagination, { table: table, loading: view.status === "loading" || view.refreshing })), footer] }));
6
+ import { TableFilters } from "./table-filters.js";
7
+ function ControlledTable({ table, toolbar, footer, showColumnSettings = true, showPagination = false, filters, filterBar, ...view }) {
8
+ return (_jsxs("div", { "data-mendy-ui": "", className: "mui-184ddc11e5f9 mui-267171770524", children: [(toolbar || showColumnSettings || (filters && filterBar !== false)) && (_jsxs("div", { className: "mui-222f930b8752 mui-faa8a23c68f6 mui-b9677bd1cb66 mui-32c92bb1fde4 mui-074569488cca", children: [_jsxs("div", { className: "mui-184ddc11e5f9 mui-7bd5bab6d7f4 mui-267171770524", children: [filters && filterBar !== false && _jsx(TableFilters, { ...filterBar, filters: filters }), !filters && toolbar] }), filters && toolbar, showColumnSettings && _jsx(TableColumnSettings, { table: table })] })), _jsx(TableView, { table: table, filters: filters, ...view }), showPagination && (_jsx(TablePagination, { table: table, loading: view.status === "loading" || view.refreshing })), footer] }));
8
9
  }
9
10
  function ConfiguredTable(props) {
10
11
  const table = useDataTable(props);
@@ -6,4 +6,5 @@ export * from "./use-result-selection.js";
6
6
  export * from "./table-view.js";
7
7
  export * from "./table-controls.js";
8
8
  export * from "./data-table.js";
9
+ export * from "./table-filters.js";
9
10
  export * from "./clipboard.js";
@@ -6,4 +6,5 @@ export * from "./use-result-selection.js";
6
6
  export * from "./table-view.js";
7
7
  export * from "./table-controls.js";
8
8
  export * from "./data-table.js";
9
+ export * from "./table-filters.js";
9
10
  export * from "./clipboard.js";
@@ -1,7 +1,11 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { TableDataState } from "./table-view.js";
3
- export declare function TableInitialState({ status, hasRows, loadingState, emptyState, error, retry, }: Pick<TableDataState, "status" | "error" | "retry"> & {
3
+ export declare function TableInitialState({ status, hasRows, loadingState, emptyState, error, retry, hasFilters, pageIndex, clearFilters, firstPage, }: Pick<TableDataState, "status" | "error" | "retry"> & {
4
4
  hasRows: boolean;
5
5
  loadingState?: ReactNode;
6
6
  emptyState?: ReactNode;
7
+ hasFilters?: boolean;
8
+ pageIndex?: number;
9
+ clearFilters?: () => void;
10
+ firstPage?: () => void;
7
11
  }): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null;
@@ -1,11 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Button } from "../primitives/button.js";
3
- export function TableInitialState({ status, hasRows, loadingState, emptyState, error, retry, }) {
3
+ export function TableInitialState({ status, hasRows, loadingState, emptyState, error, retry, hasFilters, pageIndex = 0, clearFilters, firstPage, }) {
4
4
  if (hasRows)
5
5
  return null;
6
6
  if (status === "loading")
7
7
  return loadingState ?? null;
8
8
  if (status === "error")
9
9
  return (_jsxs("div", { role: "alert", className: "mui-c432836760e3 mui-05ab12448317", children: [error ?? "Could not load rows.", retry && (_jsx(Button, { variant: "outline", size: "sm", onClick: retry, children: "Retry" }))] }));
10
- return (_jsx("div", { role: "status", className: "mui-c7902d77ad80 mui-05ab12448317 mui-35f35c41d134", children: emptyState ?? "No results." }));
10
+ return (_jsx("div", { role: "status", className: "mui-222f930b8752 mui-302c0d124a94 mui-71556df3b421 mui-074569488cca mui-c7902d77ad80 mui-05ab12448317 mui-35f35c41d134", children: emptyState ??
11
+ (pageIndex > 0 ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "No results on this page." }), _jsx(Button, { variant: "outline", size: "sm", onClick: firstPage, children: "Go to first page" })] })) : hasFilters ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "No results match your filters." }), clearFilters && (_jsx(Button, { variant: "outline", size: "sm", onClick: clearFilters, children: "Clear filters" }))] })) : ("No rows yet.")) }));
11
12
  }
@@ -0,0 +1,8 @@
1
+ import type { ComponentProps } from "react";
2
+ import { FilterBar } from "../filters/filter-bar.js";
3
+ export type TableFiltersProps = ComponentProps<typeof FilterBar> & {
4
+ /** Hide the free-text search when the query only supports defined filters. */
5
+ showSearch?: boolean;
6
+ };
7
+ /** Use the same controller here and on TableView when composing a custom toolbar. */
8
+ export declare function TableFilters({ showSearch, ...props }: TableFiltersProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FilterBar, FilterRoot, FilterMenu, FilterList, FilterFeedback, } from "../filters/filter-bar.js";
4
+ /** Use the same controller here and on TableView when composing a custom toolbar. */
5
+ export function TableFilters({ showSearch = true, ...props }) {
6
+ if (showSearch)
7
+ return _jsx(FilterBar, { ...props });
8
+ return (_jsxs(FilterRoot, { ...props, children: [_jsx(FilterMenu, {}), _jsx(FilterList, { showClear: props.showClear }), _jsx(FilterFeedback, {})] }));
9
+ }
@@ -10,11 +10,16 @@ export declare function TableHeaderCell<T extends object>({ table, header, index
10
10
  renderHeader?: (header: Header<DataTableFeatures, T, unknown>) => ReactNode;
11
11
  contentClassName?: string;
12
12
  }): import("react/jsx-runtime").JSX.Element;
13
- declare function TableBodyRowImpl<T extends object>({ row, rowIndex, start, rowHeight, cellStyle, columns, columnGaps, columnIndexes, contentVersion, contentState, focusedId, copied, contentClassName, onRowActivate, isRowHighlighted, }: {
13
+ declare function TableBodyRowImpl<T extends object>({ row, rowIndex, start, rowHeight, autoRowHeight, measureElement, rowClassName, renderRowDetail, detailWidth, cellStyle, columns, columnGaps, columnIndexes, contentVersion, contentState, focusedId, copied, contentClassName, onRowClick, onRowActivate, isRowHighlighted, }: {
14
14
  row: Row<DataTableFeatures, T>;
15
15
  rowIndex: number;
16
16
  start: number;
17
17
  rowHeight: number;
18
+ autoRowHeight: boolean;
19
+ measureElement?: (element: HTMLDivElement | null) => void;
20
+ rowClassName?: (row: T) => string | undefined;
21
+ renderRowDetail?: (row: T) => ReactNode;
22
+ detailWidth: number;
18
23
  cellStyle: (column: Column<DataTableFeatures, T>) => CSSProperties;
19
24
  columns: Column<DataTableFeatures, T>[];
20
25
  columnGaps: Map<string, number>;
@@ -24,6 +29,7 @@ declare function TableBodyRowImpl<T extends object>({ row, rowIndex, start, rowH
24
29
  focusedId?: string;
25
30
  copied: boolean;
26
31
  contentClassName?: string;
32
+ onRowClick?: (row: T) => void;
27
33
  onRowActivate?: (row: T) => void;
28
34
  isRowHighlighted?: (row: T) => boolean;
29
35
  }): import("react/jsx-runtime").JSX.Element;
@@ -13,7 +13,7 @@ export function TableHeaderCell({ table, header, index, style, renderHeader, con
13
13
  const sorted = column.getIsSorted();
14
14
  return (_jsxs("div", { role: "columnheader", "data-column-id": column.id, "aria-colindex": index + 1, "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : undefined, style: style, className: "mui-d2d9e1f13413 mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-19e97f3f40e6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a mui-daaac3fbf55e mui-35f35c41d134", children: [_jsx("div", { className: cn("mui-184ddc11e5f9 mui-7bd5bab6d7f4 mui-d5111d0e9f48", (renderHeader || typeof definition.header === "function") && contentClassName), children: _jsx(TableHeaderContent, { header: header, renderHeader: renderHeader, title: title }) }), column.getCanResize() && (_jsx(TableResizeHandle, { table: table, header: header, title: title, width: Number(style.width) }))] }, column.id));
15
15
  }
16
- function TableBodyRowImpl({ row, rowIndex, start, rowHeight, cellStyle, columns, columnGaps, columnIndexes, contentVersion, contentState, focusedId, copied, contentClassName, onRowActivate, isRowHighlighted, }) {
16
+ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, autoRowHeight, measureElement, rowClassName, renderRowDetail, detailWidth, cellStyle, columns, columnGaps, columnIndexes, contentVersion, contentState, focusedId, copied, contentClassName, onRowClick, onRowActivate, isRowHighlighted, }) {
17
17
  // The engine's getAllCells API eagerly allocates every column. Build only the
18
18
  // viewport cells with its public constructor, and release them with this row.
19
19
  const cache = useMemo(() => new WeakMap(), [row]);
@@ -25,7 +25,12 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, cellStyle, columns,
25
25
  }
26
26
  return cell;
27
27
  });
28
- return (_jsx("div", { role: "row", "aria-rowindex": rowIndex + 2, "aria-selected": row.getIsSelected(), "data-highlighted": isRowHighlighted?.(row.original), "data-index": rowIndex, className: "mui-ad936fcbed63 mui-747355bdc2a2 mui-635702706586 mui-98599e4ee250 mui-222f930b8752 mui-2bf6510f1330 mui-63b29dace366 mui-9d7d1760cd8e", style: { height: rowHeight, top: start }, children: cells.map((cell) => {
28
+ const rowElement = (_jsx("div", { ref: renderRowDetail ? undefined : measureElement, role: "row", "aria-rowindex": renderRowDetail ? undefined : rowIndex + 2, "aria-selected": row.getIsSelected(), "data-highlighted": row.getIsSelected() || isRowHighlighted?.(row.original), "data-index": rowIndex, className: cn("mui-ad936fcbed63 mui-635702706586 mui-222f930b8752 mui-2bf6510f1330 mui-5b272f3c5076 mui-37ad15a95595 mui-9d7d1760cd8e", rowClassName?.(row.original)), style: {
29
+ height: autoRowHeight ? undefined : rowHeight,
30
+ minHeight: rowHeight,
31
+ top: renderRowDetail ? 0 : start,
32
+ position: renderRowDetail ? "relative" : "absolute",
33
+ }, children: cells.map((cell) => {
29
34
  const index = columnIndexes.get(cell.column.id);
30
35
  const selected = cell.getIsSelected();
31
36
  const definition = cell.column.columnDef;
@@ -36,7 +41,9 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, cellStyle, columns,
36
41
  : -1
37
42
  : rowIndex === 0 && index === 0
38
43
  ? 0
39
- : -1, style: cellStyle(cell.column), className: cn("mui-d2d9e1f13413 mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-bbe39cfb5cc6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a", !(selected && copied) && "mui-97b1c00ff005 mui-e6020023567a", !selected && "mui-a47d391255f3 mui-a8719ed8b095 mui-2b1c7d88acff", definition.align === "end" && "mui-307644c34db6 mui-10558dbb3a24", definition.align === "center" && "mui-a503dd374cca mui-05ab12448317", selected && "mui-292affc1f780 mui-b30fc56058b6", selected && copied && "mui-047624ec0c39 mui-d254c96aea74"), onMouseDown: (event) => {
44
+ : -1, style: autoRowHeight
45
+ ? { ...cellStyle(cell.column), height: undefined, minHeight: rowHeight }
46
+ : cellStyle(cell.column), className: cn("mui-d2d9e1f13413 mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-bbe39cfb5cc6 mui-3b6d5fc7b061 mui-6ba846e1630e mui-0f9e6672913a", !(selected && copied) && "mui-97b1c00ff005 mui-e6020023567a", !selected && "mui-a47d391255f3 mui-a8719ed8b095 mui-2b1c7d88acff", definition.align === "end" && "mui-307644c34db6 mui-10558dbb3a24", definition.align === "center" && "mui-a503dd374cca mui-05ab12448317", selected && "mui-292affc1f780 mui-b30fc56058b6", selected && copied && "mui-047624ec0c39 mui-d254c96aea74"), onMouseDown: (event) => {
40
47
  if (event.button !== 0 ||
41
48
  event.detail > 1 ||
42
49
  !cell.getCanSelect() ||
@@ -47,7 +54,10 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, cellStyle, columns,
47
54
  event.stopPropagation();
48
55
  event.currentTarget.focus({ preventScroll: true });
49
56
  cell.getSelectionStartHandler()(event);
50
- }, onMouseEnter: cell.getSelectionExtendHandler(), onDoubleClick: (event) => {
57
+ }, onMouseEnter: cell.getSelectionExtendHandler(), onClick: (event) => {
58
+ if (event.detail <= 1 && !event.target.closest(interactiveSelector))
59
+ onRowClick?.(row.original);
60
+ }, onDoubleClick: (event) => {
51
61
  if (!event.target.closest(interactiveSelector))
52
62
  onRowActivate?.(row.original);
53
63
  }, children: [selected && (_jsx("span", { "aria-hidden": "true", "data-selection-outline": "", className: "mui-33228ff7d583 mui-747355bdc2a2 mui-d7efd1b0b0f9 mui-515f9fdc6db7", style: {
@@ -59,8 +69,12 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, cellStyle, columns,
59
69
  borderBottomWidth: edge?.bottom ? 2 : 0,
60
70
  borderLeftWidth: edge?.left ? 2 : 0,
61
71
  borderRightWidth: edge?.right ? 2 : 0,
62
- } })), _jsx("div", { className: cn("mui-7bd696ca6be3 mui-184ddc11e5f9 mui-81b198a2db84 mui-5a3a4ee420c2", contentClassName), children: _jsx(TableCellContent, { cell: cell, renderer: cell.column.columnDef.cell, version: contentVersion, state: contentState }) })] }, cell.id)] }, cell.id));
72
+ } })), _jsx("div", { className: cn("mui-184ddc11e5f9 mui-81b198a2db84", autoRowHeight ? "mui-726fca123972 mui-37cf9655f30a mui-b5edc3ea7c91" : "mui-7bd696ca6be3 mui-5a3a4ee420c2", contentClassName), children: _jsx(TableCellContent, { cell: cell, renderer: cell.column.columnDef.cell, version: contentVersion, state: contentState }) })] }, cell.id)] }, cell.id));
63
73
  }) }, row.id));
74
+ if (!renderRowDetail)
75
+ return rowElement;
76
+ const detail = renderRowDetail(row.original);
77
+ return (_jsxs("div", { ref: measureElement, "data-index": rowIndex, role: "rowgroup", className: "mui-747355bdc2a2 mui-635702706586 mui-2bf6510f1330", style: { top: start }, children: [rowElement, detail != null && (_jsx("div", { role: "row", className: "mui-bbe39cfb5cc6 mui-5b272f3c5076", children: _jsx("div", { role: "gridcell", "aria-colspan": columns.length, className: "mui-964a9431ff49 mui-184ddc11e5f9 mui-094f5333853b", style: { width: detailWidth, maxWidth: "100%", insetInlineStart: 0 }, children: detail }) }))] }));
64
78
  }
65
79
  export const TableBodyRow = memo(TableBodyRowImpl);
66
80
  function TableResizeHandle({ table, header, title, width, }) {
@@ -2,6 +2,7 @@ import type { ReactNode, Ref } from "react";
2
2
  import type { Header } from "@tanstack/react-table";
3
3
  import type { DataTableFeatures } from "./features.js";
4
4
  import type { DataTableInstance } from "./use-data-table.js";
5
+ import type { FilterController } from "../filters/use-filters.js";
5
6
  export interface TableDataState {
6
7
  status?: "loading" | "ready" | "error";
7
8
  error?: ReactNode;
@@ -17,8 +18,13 @@ export interface TableDataState {
17
18
  export interface TableViewProps<T extends object> extends TableDataState {
18
19
  table: DataTableInstance<T>;
19
20
  label?: string;
21
+ /** Defaults to "auto": fit the rows, capped at 65% of the viewport height. */
20
22
  height?: number | string;
21
- rowHeight?: number;
23
+ /** Auto measures multiline rows and retains all columns to keep their height stable. */
24
+ rowHeight?: number | "auto";
25
+ rowClassName?: (row: T) => string | undefined;
26
+ /** Expanded content beneath a record. Return null for collapsed records. */
27
+ renderRowDetail?: (row: T) => ReactNode;
22
28
  className?: string;
23
29
  /** Theme adapter for application-owned renderers, not package controls. */
24
30
  contentClassName?: string;
@@ -27,9 +33,14 @@ export interface TableViewProps<T extends object> extends TableDataState {
27
33
  scrollRef?: Ref<HTMLDivElement>;
28
34
  /** Change when the result set changes, not when another page is appended. */
29
35
  queryKey?: string;
36
+ /** Shared filter state for query resets and empty-result recovery. */
37
+ filters?: FilterController;
30
38
  renderHeader?: (header: Header<DataTableFeatures, T, unknown>) => ReactNode;
39
+ /** Single-click action, also used by Enter unless onRowActivate is provided. */
40
+ onRowClick?: (row: T) => void;
41
+ /** Optional double-click and Enter action. Interactive controls keep their own behavior. */
31
42
  onRowActivate?: (row: T) => void;
32
43
  isRowHighlighted?: (row: T) => boolean;
33
44
  onCopyError?: (error: unknown) => void;
34
45
  }
35
- export declare function TableView<T extends object>({ table, label, height, rowHeight, className, contentClassName, emptyState, loadingState, scrollRef, status, refreshing, error, retry, loadMore, queryKey, renderHeader, onRowActivate, isRowHighlighted, onCopyError, }: TableViewProps<T>): import("react/jsx-runtime").JSX.Element;
46
+ export declare function TableView<T extends object>({ table, label, height, rowHeight: rowHeightOption, rowClassName, renderRowDetail, className, contentClassName, emptyState, loadingState, scrollRef, status, refreshing, error, retry, loadMore, queryKey, filters, renderHeader, onRowClick, onRowActivate, isRowHighlighted, onCopyError, }: TableViewProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -11,7 +11,11 @@ import { tableLayout } from "./table-layout.js";
11
11
  import { TableLoadingRows } from "./table-loading.js";
12
12
  import { TableInitialState } from "./table-feedback.js";
13
13
  import { useTableInteraction } from "./use-table-interaction.js";
14
- export function TableView({ table, label = "Data table", height = "min(65dvh, 640px)", rowHeight = 44, className, contentClassName, emptyState, loadingState, scrollRef, status = "ready", refreshing, error, retry, loadMore, queryKey, renderHeader, onRowActivate, isRowHighlighted, onCopyError, }) {
14
+ import { useTableResults } from "./use-table-results.js";
15
+ export function TableView({ table, label = "Data table", height = "auto", rowHeight: rowHeightOption = 44, rowClassName, renderRowDetail, className, contentClassName, emptyState, loadingState, scrollRef, status = "ready", refreshing, error, retry, loadMore, queryKey, filters, renderHeader, onRowClick, onRowActivate, isRowHighlighted, onCopyError, }) {
16
+ const { resultKey, hasFilters, clearFilters } = useTableResults(table, queryKey, filters);
17
+ const autoRowHeight = rowHeightOption === "auto" || Boolean(renderRowDetail);
18
+ const rowHeight = rowHeightOption === "auto" ? 44 : rowHeightOption;
15
19
  const container = useRef(null);
16
20
  const setContainer = useCallback((node) => {
17
21
  container.current = node;
@@ -39,14 +43,14 @@ export function TableView({ table, label = "Data table", height = "min(65dvh, 64
39
43
  const layout = useMemo(() => tableLayout(table, viewportWidth, rowHeight), [table, startColumns, centerColumns, endColumns, sizing, viewportWidth, rowHeight]);
40
44
  const { totalWidth, pinningActive } = layout;
41
45
  const focused = table.getFocusedCell();
42
- const { columns, columnGaps, cellStyle } = useColumnWindow(layout, container, viewportWidth, focused?.column.id);
46
+ const { columns, columnGaps, cellStyle } = useColumnWindow(layout, container, viewportWidth, focused?.column.id, !autoRowHeight);
43
47
  const columnIndexes = useMemo(() => new Map(layout.columns.map((column, index) => [column.id, index])), [layout.columns]);
44
48
  const { announcement, copied, onKeyDown } = useTableInteraction({
45
49
  table,
46
50
  pinningActive,
47
51
  container,
48
- queryKey,
49
- onRowActivate,
52
+ queryKey: resultKey,
53
+ onRowActivate: onRowActivate ?? onRowClick,
50
54
  onCopyError,
51
55
  scrollToIndex: (index) => virtual.scrollToIndex(index, { align: "auto" }),
52
56
  });
@@ -59,24 +63,24 @@ export function TableView({ table, label = "Data table", height = "min(65dvh, 64
59
63
  }, [loadMore]);
60
64
  useEffect(() => {
61
65
  requested.current = null;
62
- }, [queryKey]);
66
+ }, [resultKey]);
63
67
  useEffect(() => {
64
68
  const data = load.current;
65
- const requestKey = `${queryKey}:${rows.length}`;
66
69
  if (!data?.available ||
67
70
  data.loading ||
68
71
  data.error ||
69
72
  last < rows.length - 10 ||
70
- requested.current === requestKey)
73
+ (requested.current?.key === resultKey && requested.current.count === rows.length))
71
74
  return;
72
75
  const element = container.current;
73
76
  // Only measure near the end when another page can actually be requested.
74
77
  // Reading clientHeight on every scroll otherwise forces layout needlessly.
75
78
  const nearEnd = element &&
76
- element.scrollTop + element.clientHeight + rowHeight * 10 >= (rows.length + 1) * rowHeight;
79
+ element.scrollTop + element.clientHeight + rowHeight * 10 >=
80
+ virtual.getTotalSize() + rowHeight;
77
81
  if (!nearEnd)
78
82
  return;
79
- requested.current = requestKey;
83
+ requested.current = { key: resultKey, count: rows.length };
80
84
  Promise.resolve()
81
85
  .then(() => data.load())
82
86
  .catch(() => {
@@ -86,13 +90,19 @@ export function TableView({ table, label = "Data table", height = "min(65dvh, 64
86
90
  last,
87
91
  rows.length,
88
92
  rowHeight,
89
- queryKey,
93
+ resultKey,
90
94
  loadMore?.available,
91
95
  loadMore?.loading,
92
96
  loadMore?.error,
97
+ virtual,
93
98
  ]);
94
99
  const headersById = new Map(table.getFlatHeaders().map((header) => [header.column.id, header]));
95
- return (_jsxs("div", { "data-mendy-ui": "", className: "mui-184ddc11e5f9", children: [_jsx("div", { "aria-live": "polite", className: "mui-32fb090591d9", children: announcement }), _jsxs("div", { ref: setContainer, role: "grid", tabIndex: -1, "aria-label": label, "aria-rowcount": rows.length + 1, "aria-colcount": layout.columns.length, "aria-busy": status === "loading" || refreshing, style: { height }, className: cn("mui-d2d9e1f13413 mui-014aadadffad mui-1a26a0d28420 mui-3fa8c572949b mui-4f1a55de40bc mui-5b272f3c5076 mui-c74ab393b96d mui-b30fc56058b6", className), onKeyDown: onKeyDown, children: [_jsx("div", { role: "row", "aria-rowindex": 1, className: "mui-964a9431ff49 mui-98599e4ee250 mui-4e8f0a87a0dc mui-222f930b8752 mui-2bf6510f1330 mui-bbe39cfb5cc6 mui-5b272f3c5076", style: { width: totalWidth }, children: columns.map((column) => (_jsxs(Fragment, { children: [columnGaps.has(column.id) && (_jsx("div", { "aria-hidden": "true", className: "mui-27ead27a81df", style: { width: columnGaps.get(column.id) } })), _jsx(TableHeaderCell, { table: table, header: headersById.get(column.id), index: columnIndexes.get(column.id), style: cellStyle(column), renderHeader: renderHeader, contentClassName: contentClassName }, column.id)] }, column.id))) }), _jsx(TableInitialState, { status: status, hasRows: rows.length > 0, loadingState: loadingState ?? (_jsx(TableLoadingRows, { columns: columns, columnGaps: columnGaps, width: totalWidth, rowHeight: rowHeight, cellStyle: cellStyle, count: Math.max(1, Math.ceil(((virtual.scrollRect?.height ?? 400) - rowHeight) / rowHeight)) })), emptyState: emptyState, error: error, retry: retry }), _jsx("div", { role: "rowgroup", className: "mui-d2d9e1f13413 mui-2bf6510f1330", style: { height: virtual.getTotalSize(), width: totalWidth }, children: items.map((item) => (_jsx(TableBodyRow, { row: rows[item.index], rowIndex: item.index, start: item.start, rowHeight: rowHeight, cellStyle: cellStyle, columns: columns, columnGaps: columnGaps, columnIndexes: columnIndexes, contentVersion: table.options, contentState: table.state, focusedId: focused?.id, copied: copied, contentClassName: contentClassName, onRowActivate: onRowActivate, isRowHighlighted: isRowHighlighted }, item.key))) }), rows.length > 0 && status === "error" && (_jsxs("div", { role: "alert", className: "mui-964a9431ff49 mui-30150dd033ab mui-5b272f3c5076 mui-094f5333853b", children: [error ?? "Could not refresh rows.", retry && (_jsx(Button, { onClick: retry, variant: "outline", size: "sm", children: "Retry" }))] })), loadMore?.available && (_jsxs("div", { className: "mui-964a9431ff49 mui-635702706586 mui-222f930b8752 mui-71556df3b421 mui-a503dd374cca mui-074569488cca mui-96b92a971c95 mui-c74ab393b96d mui-35f35c41d134", children: [loadMore.loading ? (_jsxs("div", { role: "status", className: "mui-222f930b8752 mui-71556df3b421 mui-074569488cca", children: [_jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "mui-2bd43fb57913 mui-27ead27a81df mui-2c14b55d77e6 mui-237747164b60", children: _jsx("path", { d: "M12 3v3m6.366-.366-2.12 2.12M21 12h-3m.366 6.366-2.12-2.12M12 21v-3m-6.366.366 2.12-2.12M3 12h3m-.366-6.366 2.12 2.12" }) }), _jsx("span", { children: "Loading more\u2026" })] })) : (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
100
+ return (_jsxs("div", { "data-mendy-ui": "", className: "mui-184ddc11e5f9", children: [_jsx("div", { "aria-live": "polite", className: "mui-32fb090591d9", children: announcement }), _jsxs("div", { ref: setContainer, role: "grid", tabIndex: -1, "aria-label": label, "aria-rowcount": renderRowDetail ? -1 : rows.length + 1, "aria-colcount": layout.columns.length, "aria-busy": status === "loading" || refreshing, style: {
101
+ height: height === "auto" ? undefined : height,
102
+ maxHeight: height === "auto" ? "65dvh" : undefined,
103
+ }, className: cn("mui-d2d9e1f13413 mui-014aadadffad mui-1a26a0d28420 mui-3fa8c572949b mui-4f1a55de40bc mui-5b272f3c5076 mui-c74ab393b96d mui-b30fc56058b6", className), onKeyDown: onKeyDown, children: [_jsx("div", { role: "row", "aria-rowindex": 1, className: "mui-964a9431ff49 mui-98599e4ee250 mui-4e8f0a87a0dc mui-222f930b8752 mui-2bf6510f1330 mui-bbe39cfb5cc6 mui-5b272f3c5076", style: { width: totalWidth }, children: columns.map((column) => (_jsxs(Fragment, { children: [columnGaps.has(column.id) && (_jsx("div", { "aria-hidden": "true", className: "mui-27ead27a81df", style: { width: columnGaps.get(column.id) } })), _jsx(TableHeaderCell, { table: table, header: headersById.get(column.id), index: columnIndexes.get(column.id), style: cellStyle(column), renderHeader: renderHeader, contentClassName: contentClassName }, column.id)] }, column.id))) }), _jsx(TableInitialState, { status: status, hasRows: rows.length > 0, loadingState: loadingState ?? (_jsx(TableLoadingRows, { columns: columns, columnGaps: columnGaps, width: totalWidth, rowHeight: rowHeight, cellStyle: cellStyle, count: height === "auto"
104
+ ? 8
105
+ : Math.max(1, Math.ceil(((virtual.scrollRect?.height ?? 400) - rowHeight) / rowHeight)) })), emptyState: emptyState, hasFilters: hasFilters, pageIndex: table.state.pagination.pageIndex, clearFilters: clearFilters, firstPage: () => table.setPageIndex(0), error: error, retry: retry }), _jsx("div", { role: "rowgroup", className: "mui-d2d9e1f13413 mui-2bf6510f1330", style: { height: virtual.getTotalSize(), width: totalWidth }, children: items.map((item) => (_jsx(TableBodyRow, { row: rows[item.index], rowIndex: item.index, start: item.start, rowHeight: rowHeight, autoRowHeight: autoRowHeight, measureElement: autoRowHeight ? virtual.measureElement : undefined, rowClassName: rowClassName, renderRowDetail: renderRowDetail, detailWidth: viewportWidth ?? totalWidth, cellStyle: cellStyle, columns: columns, columnGaps: columnGaps, columnIndexes: columnIndexes, contentVersion: table.options, contentState: table.state, focusedId: focused?.id, copied: copied, contentClassName: contentClassName, onRowClick: onRowClick, onRowActivate: onRowActivate, isRowHighlighted: isRowHighlighted }, item.key))) }), rows.length > 0 && status === "error" && (_jsxs("div", { role: "alert", className: "mui-964a9431ff49 mui-30150dd033ab mui-5b272f3c5076 mui-094f5333853b", children: [error ?? "Could not refresh rows.", retry && (_jsx(Button, { onClick: retry, variant: "outline", size: "sm", children: "Retry" }))] })), loadMore?.available && (_jsxs("div", { className: "mui-964a9431ff49 mui-635702706586 mui-222f930b8752 mui-71556df3b421 mui-a503dd374cca mui-074569488cca mui-96b92a971c95 mui-c74ab393b96d mui-35f35c41d134", children: [loadMore.loading ? (_jsxs("div", { role: "status", className: "mui-222f930b8752 mui-71556df3b421 mui-074569488cca", children: [_jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "mui-2bd43fb57913 mui-27ead27a81df mui-2c14b55d77e6 mui-237747164b60", children: _jsx("path", { d: "M12 3v3m6.366-.366-2.12 2.12M21 12h-3m.366 6.366-2.12-2.12M12 21v-3m-6.366.366 2.12-2.12M3 12h3m-.366-6.366 2.12 2.12" }) }), _jsx("span", { children: "Loading more\u2026" })] })) : (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
96
106
  requested.current = null;
97
107
  void Promise.resolve()
98
108
  .then(() => loadMore.load())
@@ -3,7 +3,7 @@ import type { Column } from "@tanstack/react-table";
3
3
  import type { DataTableFeatures } from "./features.js";
4
4
  import type { tableLayout } from "./table-layout.js";
5
5
  /** Keep pinned and focused columns mounted, with two columns of overscan. */
6
- export declare function useColumnWindow<T extends object>(layout: ReturnType<typeof tableLayout<T>>, container: RefObject<HTMLDivElement | null>, viewportWidth: number | null, focusedColumn?: string): {
6
+ export declare function useColumnWindow<T extends object>(layout: ReturnType<typeof tableLayout<T>>, container: RefObject<HTMLDivElement | null>, viewportWidth: number | null, focusedColumn?: string, enabled?: boolean): {
7
7
  columns: Column<{
8
8
  cellSelectionFeature: import("@tanstack/react-table").TableFeature;
9
9
  columnResizingFeature: import("@tanstack/react-table").TableFeature;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useLayoutEffect, useMemo, useState } from "react";
3
3
  /** Keep pinned and focused columns mounted, with two columns of overscan. */
4
- export function useColumnWindow(layout, container, viewportWidth, focusedColumn) {
4
+ export function useColumnWindow(layout, container, viewportWidth, focusedColumn, enabled = true) {
5
5
  const [scrollLeft, setScrollLeft] = useState(0);
6
6
  const [activeColumn, setActiveColumn] = useState();
7
7
  useLayoutEffect(() => {
@@ -39,7 +39,8 @@ export function useColumnWindow(layout, container, viewportWidth, focusedColumn)
39
39
  const styles = new Map();
40
40
  let previousEnd = 0;
41
41
  layout.columns.forEach((column, index) => {
42
- if ((index >= start && index <= end) ||
42
+ if (!enabled ||
43
+ (index >= start && index <= end) ||
43
44
  (layout.pinningActive && column.getIsPinned()) ||
44
45
  column.id === focusedColumn ||
45
46
  column.id === activeColumn) {
@@ -60,5 +61,5 @@ export function useColumnWindow(layout, container, viewportWidth, focusedColumn)
60
61
  columnGaps,
61
62
  cellStyle: (column) => styles.get(column.id),
62
63
  };
63
- }, [layout, start, end, focusedColumn, activeColumn]);
64
+ }, [layout, start, end, focusedColumn, activeColumn, enabled]);
64
65
  }
@@ -4,7 +4,7 @@ import type { DataTableFeatures } from "./features.js";
4
4
  import type { PreferenceStorage, TablePreferences } from "./state.js";
5
5
  export type DataTableInstance<T extends object> = ReactTable<DataTableFeatures, T>;
6
6
  export interface UseDataTableOptions<T extends object> extends Omit<TableOptions<DataTableFeatures, T>, "features" | "data" | "columns" | "manualFiltering" | "manualSorting" | "manualPagination"> {
7
- rows: T[];
7
+ rows: readonly T[];
8
8
  columns: TableColumn<T>[];
9
9
  getRowId: (row: T, index: number) => string;
10
10
  processing?: {
@@ -1,2 +1,3 @@
1
1
  /** Reuse equal array shells; never deep-compare records or ignore changed callbacks. */
2
2
  export declare function useStableArray<T>(input: T[]): T[];
3
+ export declare function useStableArray<T>(input: readonly T[]): readonly T[];
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { useLayoutEffect, useMemo, useRef } from "react";
3
- /** Reuse equal array shells; never deep-compare records or ignore changed callbacks. */
4
3
  export function useStableArray(input) {
5
4
  const committed = useRef(input);
6
5
  const value = useMemo(() => {
@@ -4,7 +4,7 @@ export declare function useTableInteraction<T extends object>({ table, pinningAc
4
4
  table: DataTableInstance<T>;
5
5
  pinningActive: boolean;
6
6
  container: RefObject<HTMLDivElement | null>;
7
- queryKey?: string;
7
+ queryKey?: unknown;
8
8
  onRowActivate?: (row: T) => void;
9
9
  onCopyError?: (error: unknown) => void;
10
10
  scrollToIndex: (index: number) => void;
@@ -21,7 +21,9 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
21
21
  const remember = (event) => {
22
22
  const target = event.target;
23
23
  ownedFocus.current =
24
- element.contains(target) && target.getAttribute("role") === "gridcell" ? target : null;
24
+ target.closest('[role="grid"]') === element && target.getAttribute("role") === "gridcell"
25
+ ? target
26
+ : null;
25
27
  };
26
28
  document.addEventListener("focusin", remember);
27
29
  return () => document.removeEventListener("focusin", remember);
@@ -52,7 +54,8 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
52
54
  }, [queryKey, resetCellSelection, container]);
53
55
  useEffect(() => {
54
56
  const dismiss = (event) => {
55
- if (container.current && !container.current.contains(event.target))
57
+ if (container.current &&
58
+ event.target.closest('[role="grid"]') !== container.current)
56
59
  resetCellSelection(true);
57
60
  };
58
61
  document.addEventListener("pointerdown", dismiss);
@@ -102,7 +105,9 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
102
105
  });
103
106
  }
104
107
  const onKeyDown = (event) => {
105
- if (event.target.closest(interactiveSelector))
108
+ if (event.defaultPrevented ||
109
+ event.target.closest('[role="grid"]') !== event.currentTarget ||
110
+ event.target.closest(interactiveSelector))
106
111
  return;
107
112
  if ((event.ctrlKey || event.metaKey) &&
108
113
  event.key.toLowerCase() === "c" &&
@@ -0,0 +1,8 @@
1
+ import type { FilterController } from "../filters/use-filters.js";
2
+ import type { DataTableInstance } from "./use-data-table.js";
3
+ /** Only query state contributes to this key. Row appends and UI state never do. */
4
+ export declare function useTableResults<T extends object>(table: DataTableInstance<T>, queryKey?: string, filters?: FilterController): {
5
+ resultKey: string | any[];
6
+ hasFilters: boolean;
7
+ clearFilters: (() => void) | undefined;
8
+ };
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ function hasValue(value) {
4
+ if (value == null || value === "")
5
+ return false;
6
+ if (Array.isArray(value))
7
+ return value.some((item) => item != null && item !== "");
8
+ return true;
9
+ }
10
+ /** Only query state contributes to this key. Row appends and UI state never do. */
11
+ export function useTableResults(table, queryKey, filters) {
12
+ const { sorting, columnFilters, globalFilter, pagination } = table.state;
13
+ const entries = filters?.entries;
14
+ const search = filters?.search;
15
+ const resultKey = useMemo(() => {
16
+ const state = [
17
+ queryKey,
18
+ sorting,
19
+ columnFilters,
20
+ globalFilter,
21
+ pagination.pageIndex,
22
+ pagination.pageSize,
23
+ search,
24
+ ];
25
+ try {
26
+ return JSON.stringify([...state, entries?.map(({ id, field, value }) => [id, field.codec.serialize(value)])], (_key, value) => (typeof value === "bigint" ? { $bigint: String(value) } : value));
27
+ }
28
+ catch {
29
+ // Opaque application values may not be serializable. In that case their
30
+ // immutable references drive changes, without crashing table rendering.
31
+ return [...state, entries];
32
+ }
33
+ }, [
34
+ queryKey,
35
+ sorting,
36
+ columnFilters,
37
+ globalFilter,
38
+ pagination.pageIndex,
39
+ pagination.pageSize,
40
+ search,
41
+ entries,
42
+ ]);
43
+ const hasFilters = Boolean(columnFilters.some(({ value }) => hasValue(value)) ||
44
+ hasValue(globalFilter) ||
45
+ search?.trim() ||
46
+ filters?.active.length);
47
+ const clearFilters = () => {
48
+ if (filters)
49
+ filters.clear();
50
+ else {
51
+ if (columnFilters.length)
52
+ table.setColumnFilters([]);
53
+ if (hasValue(globalFilter))
54
+ table.setGlobalFilter(undefined);
55
+ if (pagination.pageIndex)
56
+ table.setPageIndex(0);
57
+ }
58
+ };
59
+ const canClear = !filters ||
60
+ Boolean(search?.trim()) ||
61
+ filters.entries.some(({ field, value }) => !field.hidden && !field.disabled && field.removable !== false && field.isActive(value));
62
+ return { resultKey, hasFilters, clearFilters: canClear ? clearFilters : undefined };
63
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mendylanda/ui",
3
- "version": "0.3.0-alpha.6",
3
+ "version": "0.3.0-alpha.8",
4
4
  "description": "Mendy Landa’s reusable React components. Typed filters and tables with shared interaction behavior and customizable UI.",
5
5
  "homepage": "https://ui.mendylanda.com",
6
6
  "license": "MIT",