@ethanhann/mantine-dataview 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ethanhann/mantine-dataview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A React library that renders server-driven, paginated datasets as a table or card grid, switchable at runtime, built on Mantine v9 and TanStack Table v8",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.cjs",
|
|
7
6
|
"module": "./dist/index.js",
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
11
10
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"
|
|
13
|
-
"require": "./dist/index.cjs"
|
|
11
|
+
"default": "./dist/index.js"
|
|
14
12
|
},
|
|
15
13
|
"./styles.css": "./dist/mantine-dataview.css",
|
|
16
14
|
"./url": {
|
|
17
15
|
"types": "./dist/url/index.d.ts",
|
|
18
|
-
"
|
|
19
|
-
"require": "./dist/url/index.cjs"
|
|
16
|
+
"default": "./dist/url/index.js"
|
|
20
17
|
}
|
|
21
18
|
},
|
|
22
19
|
"files": [
|
|
@@ -84,6 +81,9 @@
|
|
|
84
81
|
"type": "git",
|
|
85
82
|
"url": "git+https://github.com/ethanhann/mantine-dataview.git"
|
|
86
83
|
},
|
|
84
|
+
"engines": {
|
|
85
|
+
"node": ">=18"
|
|
86
|
+
},
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"registry": "https://registry.npmjs.org"
|
|
89
89
|
},
|
package/dist/index.cjs
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./serializer-CGmBq-Jz.cjs");let t=require("@tanstack/react-table"),n=require("@mantine/core"),r=require("react/jsx-runtime"),i=require("react"),a=require("@mantine/hooks"),o=require("@mantine/dates");require("@mantine/dates/styles.css");function s({view:e,slots:t,...i}){let{selection:a}=e;return a.count===0?null:(0,r.jsx)(n.Paper,{withBorder:!0,p:`xs`,radius:`sm`,role:`region`,"aria-label":`Bulk actions`,...i,children:(0,r.jsxs)(n.Group,{justify:`space-between`,wrap:`wrap`,gap:`sm`,children:[(0,r.jsxs)(n.Group,{gap:`sm`,children:[(0,r.jsxs)(n.Text,{size:`sm`,fw:500,children:[a.count,` selected`]}),(0,r.jsx)(n.Button,{variant:`subtle`,size:`xs`,onClick:a.clear,children:`Clear`})]}),t?.BulkActions&&(0,r.jsx)(n.Group,{gap:`xs`,children:t.BulkActions(a)})]})})}function c(e){let{meta:t,header:n}=e.columnDef;return t?.label?t.label:typeof n==`string`?n:e.id}function l(e,t,n){return t?t===`hidden`?null:t:e.accessorFn==null||n===`hidden`?null:n}function u(e,t={}){let n=t.fallbackRole??`meta`,r={title:[],subtitle:[],media:[],badge:[],meta:[]};e.getVisibleLeafColumns().forEach((e,t)=>{let i=e.columnDef.meta?.card,a=l(e,i?.role,n);a&&r[a].push({order:i?.order??t,index:t,field:{id:e.id,column:e,label:c(e),showLabel:i?.showLabel??a===`meta`}})});let i=e=>e.sort((e,t)=>e.order-t.order||e.index-t.index).map(e=>e.field);return{title:i(r.title),subtitle:i(r.subtitle),media:i(r.media),badge:i(r.badge),meta:i(r.meta)}}function d(e,t){let n=(0,i.useRef)([]),r=(0,i.useRef)(!1),a=(0,i.useRef)(0),o=(0,i.useRef)(!1);(0,i.useEffect)(()=>{t&&!o.current&&typeof document<`u`&&process.env.NODE_ENV!==`production`&&(Array.from(document.styleSheets).some(e=>{try{return Array.from(e.cssRules).some(e=>e instanceof CSSKeyframesRule&&e.name===`dataview-row-enter`)}catch{return!1}})||console.warn(`[@ethanhann/mantine-dataview] animateRows is enabled but the CSS keyframes are missing. Import "@ethanhann/mantine-dataview/styles.css" in your app entry.`),o.current=!0)},[t]);let s=e.map(e=>e.id),c=new Set,l=a.current;if(t&&r.current){let e=n.current,t=new Set(e);if(s.length!==e.length||s.some((t,n)=>t!==e[n]))if(l=a.current+1,s.length===e.length&&s.every(e=>t.has(e)))for(let e of s)c.add(e);else for(let e of s)t.has(e)||c.add(e)}return(0,i.useEffect)(()=>{n.current=s,r.current=!0,a.current=l}),{rows:e,entering:c,generation:l}}function f(e){e.resetColumnFilters(),e.setGlobalFilter(``)}function p({view:e,slots:t}){return t?.ErrorState?(0,r.jsx)(r.Fragment,{children:t.ErrorState({error:e.error,retry:e.refetch})}):(0,r.jsxs)(n.Stack,{align:`center`,gap:`xs`,children:[(0,r.jsx)(n.Text,{c:`red`,children:`Something went wrong.`}),(0,r.jsx)(n.Button,{variant:`light`,size:`xs`,onClick:e.refetch,children:`Retry`})]})}function m({view:e,slots:t}){let i=e.renderStatus.phase===`empty-filtered`,a=()=>f(e.table);return t?.Empty?(0,r.jsx)(r.Fragment,{children:t.Empty({filtered:i,clearFilters:a})}):i?(0,r.jsxs)(n.Stack,{align:`center`,gap:`xs`,children:[(0,r.jsx)(n.Text,{c:`dimmed`,children:`No matches.`}),(0,r.jsx)(n.Button,{variant:`subtle`,size:`xs`,onClick:a,children:`Clear filters`})]}):(0,r.jsx)(n.Text,{c:`dimmed`,children:`No results.`})}var h={base:1,sm:2,lg:3};function g({view:e,slots:t,renderCard:i,fallbackRole:a,enableSelection:o,loadingCardCount:s,animateRows:c=!1,cols:l=h,...f}){let{table:g,renderStatus:v}=e,y=o??g.options.enableRowSelection!==!1,b=s??Math.min(e.state.pagination.pageSize,6),x={cols:l,...f},S=d(g.getRowModel().rows,c),C=e=>{let o=u(g,{fallbackRole:a});return(0,r.jsx)(n.SimpleGrid,{"data-changed":c||void 0,...x,children:e.map(e=>{let a=e.getIsSelected(),s={row:e,data:e.original,selected:a,toggleSelected:()=>e.toggleSelected()},c=S.entering.has(e.id)||void 0;if(i)return(0,r.jsx)(`div`,{"data-entering":c,children:i(s)},e.id);let l=(0,r.jsx)(_,{row:e,layout:o,selectionEnabled:y});return t?.Card?(0,r.jsx)(`div`,{"data-entering":c,children:t.Card({...s,children:l})},e.id):(0,r.jsx)(n.Card,{withBorder:!0,padding:`lg`,pos:`relative`,"data-selected":a||void 0,"data-entering":c,children:l},e.id)})},S.generation)};if(c&&v.phase===`loading`&&S.rows.length>0)return C(S.rows);switch(v.phase){case`loading`:return t?.LoadingCards?t.LoadingCards():(0,r.jsx)(n.SimpleGrid,{...x,children:Array.from({length:b},(e,t)=>(0,r.jsx)(n.Card,{withBorder:!0,padding:`md`,children:(0,r.jsxs)(n.Stack,{gap:`xs`,children:[(0,r.jsx)(n.Skeleton,{height:20,width:`60%`}),(0,r.jsx)(n.Skeleton,{height:12,width:`40%`}),(0,r.jsx)(n.Skeleton,{height:12})]})},t))});case`error`:return(0,r.jsx)(n.Center,{p:`xl`,children:(0,r.jsx)(p,{view:e,slots:t})});case`empty`:case`empty-filtered`:return(0,r.jsx)(n.Center,{p:`xl`,children:(0,r.jsx)(m,{view:e,slots:t})});default:return C(S.rows)}}function _({row:e,layout:a,selectionEnabled:o}){let s=new Map(e.getAllCells().map(e=>[e.column.id,e])),c=e=>{let n=s.get(e.id);return n?(0,t.flexRender)(n.column.columnDef.cell,n.getContext()):null};return(0,r.jsxs)(r.Fragment,{children:[o&&(0,r.jsx)(n.Checkbox,{"aria-label":`Select card`,checked:e.getIsSelected(),disabled:!e.getCanSelect(),onChange:e.getToggleSelectedHandler(),style:{position:`absolute`,top:8,right:8,zIndex:1}}),a.media.length>0&&(0,r.jsx)(n.Card.Section,{mb:`xs`,children:a.media.map(e=>(0,r.jsx)(n.Box,{children:c(e)},e.id))}),(0,r.jsxs)(n.Stack,{gap:`md`,children:[(a.title.length>0||a.subtitle.length>0)&&(0,r.jsxs)(n.Stack,{gap:4,children:[a.title.map(e=>(0,r.jsx)(n.Text,{fw:600,size:`lg`,lh:1.2,pr:o?28:0,children:c(e)},e.id)),a.subtitle.map(e=>(0,r.jsx)(n.Text,{size:`sm`,c:`dimmed`,children:c(e)},e.id))]}),a.badge.length>0&&(0,r.jsx)(n.Group,{gap:`xs`,children:a.badge.map(e=>(0,r.jsx)(i.Fragment,{children:c(e)},e.id))}),a.meta.length>0&&(0,r.jsx)(n.Stack,{gap:4,children:a.meta.map(e=>(0,r.jsxs)(n.Group,{justify:`space-between`,gap:`xs`,wrap:`nowrap`,children:[e.showLabel&&(0,r.jsx)(n.Text,{size:`sm`,c:`dimmed`,children:e.label}),(0,r.jsx)(n.Text,{size:`sm`,children:c(e)})]},e.id))})]})]})}function v({view:e,pageSizeOptions:t,showPageSize:i=!0,showRange:a=!0,pageSizeLabel:o=`Rows per page`,...s}){let{table:c}=e,{pageIndex:l,pageSize:u}=e.state.pagination,d=c.getRowCount(),f=c.getPageCount(),p=t??e.pageSizeOptions,m=d===0?0:l*u+1,h=Math.min((l+1)*u,d);return(0,r.jsxs)(n.Group,{justify:`space-between`,wrap:`wrap`,gap:`sm`,...s,children:[(0,r.jsxs)(n.Group,{gap:`sm`,wrap:`wrap`,children:[i&&(0,r.jsx)(n.Select,{"aria-label":o,data:p.map(String),value:String(u),onChange:e=>e&&c.setPageSize(Number(e)),w:80,comboboxProps:{withinPortal:!0}}),a&&(0,r.jsxs)(n.Text,{size:`sm`,c:`dimmed`,children:[m,`–`,h,` of `,d]})]}),(0,r.jsx)(n.Pagination,{value:l+1,total:Math.max(f,1),onChange:e=>c.setPageIndex(e-1),getControlProps:e=>({"aria-label":`${e} page`})})]})}function y({direction:e}){return(0,r.jsxs)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,"aria-hidden":`true`,focusable:`false`,style:{flexShrink:0},children:[(0,r.jsx)(`title`,{children:`sort`}),(0,r.jsx)(`path`,{d:`M8 10l4-4 4 4`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,opacity:e===`asc`?1:.35}),(0,r.jsx)(`path`,{d:`M8 14l4 4 4-4`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,opacity:e===`desc`?1:.35})]})}function b({d:e,title:t}){return(0,r.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,focusable:`false`,style:{flexShrink:0},children:[(0,r.jsx)(`title`,{children:t}),(0,r.jsx)(`path`,{d:e})]})}function x(){return(0,r.jsx)(b,{title:`search`,d:`M21 21l-4.3-4.3M11 19a8 8 0 110-16 8 8 0 010 16z`})}function S(){return(0,r.jsx)(b,{title:`filter`,d:`M3 5h18M7 12h10M10 19h4`})}function C(){return(0,r.jsx)(b,{title:`open`,d:`M6 9l6 6 6-6`})}function w(){return(0,r.jsx)(b,{title:`close`,d:`M18 6L6 18M6 6l12 12`})}function T(){return(0,r.jsx)(b,{title:`pin left`,d:`M4 4v16M9 8h8M9 12h6M9 16h8`})}function ee(){return(0,r.jsx)(b,{title:`pin right`,d:`M20 4v16M7 8h8M9 12h6M7 16h8`})}function E(e){let t=e.getIsPinned();if(t)return{position:`sticky`,[t]:t===`left`?e.getStart(`left`):e.getAfter(`right`),zIndex:1,backgroundColor:`var(--mantine-color-body)`}}function D({view:e,slots:i,enableSelection:a,loadingRowCount:o,disableWhileLoading:s=!0,animateRows:c=!1,...l}){let{table:u,renderStatus:f}=e,h=s&&e.status===`loading`,g=d(u.getRowModel().rows,c),_=u.getVisibleLeafColumns(),v=a??u.options.enableRowSelection!==!1,y=_.length+ +!!v,b=o??Math.min(e.state.pagination.pageSize,8),x=e=>(0,r.jsx)(n.Table.Tbody,{"data-changed":c||void 0,children:e.map(e=>{let a=g.entering.has(e.id)||void 0,o=(0,r.jsxs)(r.Fragment,{children:[v&&(0,r.jsx)(n.Table.Td,{children:(0,r.jsx)(n.Checkbox,{"aria-label":`Select row`,checked:e.getIsSelected(),disabled:!e.getCanSelect(),indeterminate:e.getIsSomeSelected(),onChange:e.getToggleSelectedHandler()})}),e.getVisibleCells().map(e=>{let i=e.column.columnDef.meta?.align;return(0,r.jsx)(n.Table.Td,{style:{...E(e.column),...i?{textAlign:i}:void 0},children:(0,t.flexRender)(e.column.columnDef.cell,e.getContext())},e.id)})]});return i?.Row?(0,r.jsx)(O,{children:i.Row({row:e,cells:o})},e.id):(0,r.jsx)(n.Table.Tr,{"data-selected":e.getIsSelected()||void 0,"data-entering":a,children:o},e.id)})},g.generation),S=()=>{if(c&&f.phase===`loading`&&g.rows.length>0)return x(g.rows);switch(f.phase){case`loading`:return i?.LoadingTable?i.LoadingTable():(0,r.jsx)(n.Table.Tbody,{children:Array.from({length:b},(e,t)=>(0,r.jsxs)(n.Table.Tr,{children:[v&&(0,r.jsx)(n.Table.Td,{children:(0,r.jsx)(n.Skeleton,{height:16,width:16})}),_.map(e=>(0,r.jsx)(n.Table.Td,{children:(0,r.jsx)(n.Skeleton,{height:12})},e.id))]},t))});case`error`:return(0,r.jsx)(k,{colSpan:y,children:(0,r.jsx)(p,{view:e,slots:i})});case`empty`:case`empty-filtered`:return(0,r.jsx)(k,{colSpan:y,children:(0,r.jsx)(m,{view:e,slots:i})});default:return x(g.rows)}};return(0,r.jsx)(`div`,{style:u.getIsSomeColumnsPinned()?{overflowX:`auto`}:void 0,children:(0,r.jsxs)(n.Table,{layout:`fixed`,...l,children:[(0,r.jsx)(n.Table.Thead,{children:u.getHeaderGroups().map(e=>(0,r.jsxs)(n.Table.Tr,{children:[v&&(0,r.jsx)(n.Table.Th,{style:{width:40},children:(0,r.jsx)(n.Checkbox,{"aria-label":`Select all rows on this page`,checked:u.getIsAllPageRowsSelected(),indeterminate:u.getIsSomePageRowsSelected()&&!u.getIsAllPageRowsSelected(),onChange:u.getToggleAllPageRowsSelectedHandler()})}),e.headers.map(e=>(0,r.jsx)(A,{header:e,disabled:h},e.id))]},e.id))}),S()]})})}function O({children:e}){return(0,r.jsx)(r.Fragment,{children:e})}function k({colSpan:e,children:t}){return(0,r.jsx)(n.Table.Tbody,{children:(0,r.jsx)(n.Table.Tr,{children:(0,r.jsx)(n.Table.Td,{colSpan:e,children:(0,r.jsx)(n.Center,{p:`xl`,children:t})})})})}function A({header:e,disabled:i}){let{column:a}=e,o=a.columnDef.meta?.align,s=a.getIsSorted(),c=a.getSortIndex(),l=c>0,u=e.isPlaceholder?null:(0,t.flexRender)(a.columnDef.header,e.getContext()),d=a.getCanSort()&&!i,f=a.columnDef.size;return(0,r.jsx)(n.Table.Th,{style:{...E(a),...o?{textAlign:o}:void 0,...f==null?void 0:{width:f}},"aria-sort":s===`asc`?`ascending`:s===`desc`?`descending`:void 0,children:d?(0,r.jsxs)(n.UnstyledButton,{onClick:a.getToggleSortingHandler(),style:{display:`inline-flex`,alignItems:`center`,gap:4,font:`inherit`},children:[u,(0,r.jsx)(y,{direction:s}),l&&(0,r.jsx)(`span`,{role:`note`,style:{fontSize:`0.7em`,opacity:.6},"aria-label":`Sort priority ${c+1}`,children:c+1})]}):(0,r.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:4,...i?{opacity:.5}:{}},children:[u,s&&(0,r.jsx)(y,{direction:s})]})})}var te=`(max-width: 0px)`;function j(e){let t=/^([\d.]+)(\D*)$/.exec(e.trim());if(!t)return`(max-width: ${e})`;let n=Number(t[1]),r=t[2]||`px`;return`(max-width: ${n-(r===`em`||r===`rem`?.01:.1)}${r})`}function ne(e){let t=(0,n.useMantineTheme)(),r=e?.forceCardsBelow,i=r?t.breakpoints[r]:void 0,o=(0,a.useMediaQuery)(i?j(i):te,!1);return!!i&&!!o}var M={text:e=>e==null?``:String(e),number:e=>e==null?``:new Intl.NumberFormat().format(Number(e)),currency:e=>e==null?``:new Intl.NumberFormat(void 0,{style:`currency`,currency:`USD`}).format(Number(e)),date:e=>{if(e==null)return``;let t=e instanceof Date?e:new Date(String(e));return Number.isNaN(t.getTime())?String(e):new Intl.DateTimeFormat().format(t)},boolean:e=>e==null?``:e?`Yes`:`No`};function re(e,t){if(e===`number`||e===`currency`){let n=new Intl.NumberFormat(void 0,e===`currency`?{style:`currency`,...t}:t);return e=>e==null?``:n.format(Number(e))}if(e===`date`){let e=new Intl.DateTimeFormat(void 0,t);return t=>{if(t==null)return``;let n=t instanceof Date?t:new Date(String(t));return Number.isNaN(n.getTime())?String(t):e.format(n)}}return M[e]}function N(e,t,n){let r=t??n?.[e];return r?typeof r==`function`?r:re(e,r):M[e]}function P({facet:e,value:t,onChange:i}){let a=Array.isArray(t)?t:null;return(0,r.jsx)(n.Stack,{gap:4,children:e.ranges.map(e=>{let t=a!=null&&a[0]===e.from&&a[1]===e.to;return(0,r.jsx)(n.UnstyledButton,{onClick:()=>i(t?void 0:[e.from,e.to]),style:{padding:`4px 8px`,borderRadius:4,background:t?`var(--mantine-color-blue-light)`:void 0},children:(0,r.jsxs)(n.Group,{gap:`xs`,justify:`space-between`,wrap:`nowrap`,children:[(0,r.jsx)(n.Text,{size:`sm`,children:e.label}),(0,r.jsx)(n.Badge,{size:`sm`,variant:`light`,color:e.count===0?`gray`:`blue`,children:e.count})]})},e.label)})})}function F({label:e,onClear:t}){return(0,r.jsxs)(n.Group,{justify:`space-between`,wrap:`nowrap`,children:[(0,r.jsx)(n.Text,{size:`sm`,fw:500,children:e}),(0,r.jsx)(n.Anchor,{component:`button`,type:`button`,size:`xs`,c:`dimmed`,onClick:t,children:`clear`})]})}function I(e){return e?typeof e==`string`?e:e.toISOString().split(`T`)[0]??null:null}function L(e){return Array.isArray(e)?[e[0],e[1]]:[null,null]}function R(e,t){return e.values.length>0?e.values.map(e=>({value:e.value,label:`${e.label??e.value} (${e.count})`,disabled:e.count===0})):t??[]}function z({column:e,facet:t}){let i=e.columnDef.meta?.filter;if(!i)return null;let a=c(e),s=i.placeholder??a,l=e.getFilterValue(),u=t=>e.setFilterValue(t);if(i.component){let t=i.component;return(0,r.jsx)(n.Input.Wrapper,{label:a,children:(0,r.jsx)(t,{value:l,onChange:u,column:e})})}let d=t?.type===`values`?t:void 0,f=t?.type===`ranges`?t:void 0;switch(i.variant){case`select`:return(0,r.jsx)(n.Select,{label:a,placeholder:s,clearable:!0,data:d?R(d,i.options):i.options??[],value:l??null,onChange:e=>u(e??void 0)});case`multiselect`:return(0,r.jsx)(n.MultiSelect,{label:a,placeholder:s,data:d?R(d,i.options):i.options??[],value:l??[],onChange:e=>u(e.length>0?e:void 0)});case`boolean`:{let e=l==null?`all`:l?`yes`:`no`,t=d?.values.find(e=>e.value===`true`),i=d?.values.find(e=>e.value===`false`),o=t?`Yes (${t.count})`:`Yes`,s=i?`No (${i.count})`:`No`;return(0,r.jsx)(n.Input.Wrapper,{label:a,children:(0,r.jsx)(n.SegmentedControl,{fullWidth:!0,size:`xs`,data:[{value:`all`,label:`All`},{value:`yes`,label:o},{value:`no`,label:s}],value:e,onChange:e=>{u(e===`all`?void 0:e===`yes`)}})})}case`numberRange`:{let[t,o]=L(l),s=i.min??f?.min,c=i.max??f?.max,d=s!=null&&c!=null,p=l!=null,m=f?(0,r.jsx)(P,{facet:f,value:l,onChange:u}):null,h=p?(0,r.jsx)(F,{label:a,onClear:()=>u(void 0)}):a;if(d){let l=[t??s,o??c],d=e.columnDef.meta?.dataType,f=d?N(d,e.columnDef.meta?.format,void 0):e=>String(e);return(0,r.jsx)(n.Input.Wrapper,{label:h,children:(0,r.jsxs)(n.Stack,{gap:`xs`,children:[m,(0,r.jsx)(n.RangeSlider,{min:s,max:c,step:i.step??1,value:l,onChange:([e,t])=>{u(e===s&&t===c?void 0:[e,t])},label:e=>f(e),minRange:i.step??1,"aria-label":a})]})})}if(m)return(0,r.jsx)(n.Input.Wrapper,{label:h,children:m});let g=e=>u(e[0]==null&&e[1]==null?void 0:e),_=e=>e===``||e==null?null:Number(e);return(0,r.jsx)(n.Input.Wrapper,{label:a,children:(0,r.jsxs)(n.Group,{gap:4,wrap:`nowrap`,children:[(0,r.jsx)(n.NumberInput,{"aria-label":`${a} minimum`,placeholder:`Min`,value:t??``,onChange:e=>g([_(e),o]),w:90}),(0,r.jsx)(n.NumberInput,{"aria-label":`${a} maximum`,placeholder:`Max`,value:o??``,onChange:e=>g([t,_(e)]),w:90})]})})}case`date`:return(0,r.jsx)(o.DatePickerInput,{label:a,placeholder:s,clearable:!0,popoverProps:{withinPortal:!1},value:l?new Date(l):null,onChange:e=>u(I(e)??void 0)});case`dateRange`:{let[e,t]=L(l),i=[e?new Date(e):null,t?new Date(t):null],c=l==null?a:(0,r.jsx)(F,{label:a,onClear:()=>u(void 0)});return(0,r.jsx)(n.Input.Wrapper,{label:c,children:(0,r.jsxs)(n.Stack,{gap:`xs`,children:[f&&(0,r.jsx)(P,{facet:f,value:l,onChange:u}),(0,r.jsx)(o.DatePickerInput,{type:`range`,popoverProps:{withinPortal:!1},placeholder:s,clearable:!0,value:i,onChange:([e,t])=>{let n=I(e),r=I(t);u(n==null&&r==null?void 0:[n,r])}})]})})}default:return(0,r.jsx)(n.TextInput,{label:a,placeholder:s,value:l??``,onChange:e=>u(e.currentTarget.value||void 0)})}}function B({view:e}){return e.state.columnFilters.length>0?(0,r.jsx)(n.Button,{variant:`subtle`,size:`compact-sm`,color:`gray`,leftSection:(0,r.jsx)(w,{}),onClick:()=>e.table.resetColumnFilters(),children:`Reset filters`}):null}function V(e){return e>0?`Filters (${e})`:`Filters`}function H({view:e,controls:t}){return(0,r.jsxs)(n.Stack,{gap:`sm`,style:{minWidth:240},children:[t,(0,r.jsx)(n.Group,{justify:`flex-end`,children:(0,r.jsx)(B,{view:e})})]})}function U({view:e,inlineThreshold:t}){let i=e.filterableColumns,o=(0,a.useMediaQuery)(j((0,n.useMantineTheme)().breakpoints.sm),!1),[s,{open:c,close:l}]=(0,a.useDisclosure)(!1);if(i.length===0)return null;let u=i.map(t=>(0,r.jsx)(z,{column:t,facet:e.facets[t.id]},t.id)),d=e.state.columnFilters.length;return o?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.Button,{variant:`default`,leftSection:(0,r.jsx)(S,{}),onClick:c,children:V(d)}),(0,r.jsx)(n.Drawer,{opened:s,onClose:l,title:`Filters`,position:`bottom`,size:`auto`,children:(0,r.jsx)(H,{view:e,controls:u})})]}):i.length<=t?(0,r.jsxs)(r.Fragment,{children:[u,(0,r.jsx)(B,{view:e})]}):(0,r.jsxs)(n.Popover,{position:`bottom-start`,closeOnClickOutside:!1,children:[(0,r.jsx)(n.Popover.Target,{children:(0,r.jsx)(n.Button,{variant:`default`,leftSection:(0,r.jsx)(S,{}),children:V(d)})}),(0,r.jsx)(n.Popover.Dropdown,{children:(0,r.jsx)(H,{view:e,controls:u})})]})}function W({view:e}){let{sortableColumns:t,state:i,table:a}=e,o=i.sorting[0];return(0,r.jsxs)(n.Group,{gap:4,wrap:`nowrap`,children:[(0,r.jsx)(n.Select,{"aria-label":`Sort by`,placeholder:`Sort by`,clearable:!0,data:t.map(e=>({value:e.id,label:c(e)})),value:o?.id??null,onChange:e=>a.setSorting(e?[{id:e,desc:o?.desc??!1}]:[])}),(0,r.jsx)(n.ActionIcon,{"aria-label":`Toggle sort direction`,variant:`default`,size:`lg`,disabled:!o,onClick:()=>o&&a.setSorting([{id:o.id,desc:!o.desc}]),children:(0,r.jsx)(y,{direction:o?o.desc?`desc`:`asc`:!1})})]})}function G({view:e,lockSwitcherOnMobile:t,tableLabel:i=`Table`,cardsLabel:a=`Cards`}){return e.isMobileForced&&t?null:(0,r.jsx)(n.SegmentedControl,{"aria-label":`View`,value:e.view,disabled:e.isMobileForced,onChange:t=>{(t===`table`||t===`cards`)&&e.setView(t)},data:[{value:`table`,label:i},{value:`cards`,label:a}]})}function ie({column:e}){if(!e.getCanPin())return null;let t=e.getIsPinned();return(0,r.jsxs)(n.Group,{gap:2,children:[(0,r.jsx)(n.ActionIcon,{size:`xs`,variant:t===`left`?`filled`:`subtle`,color:t===`left`?`blue`:`gray`,"aria-label":`Pin ${c(e)} left`,onClick:()=>e.pin(t===`left`?!1:`left`),children:(0,r.jsx)(T,{})}),(0,r.jsx)(n.ActionIcon,{size:`xs`,variant:t===`right`?`filled`:`subtle`,color:t===`right`?`blue`:`gray`,"aria-label":`Pin ${c(e)} right`,onClick:()=>e.pin(t===`right`?!1:`right`),children:(0,r.jsx)(ee,{})})]})}function ae({view:e}){let t=e.table.getAllLeafColumns().filter(e=>e.getCanHide());return t.length===0?null:(0,r.jsxs)(n.Menu,{closeOnItemClick:!1,withinPortal:!0,position:`bottom-end`,children:[(0,r.jsx)(n.Menu.Target,{children:(0,r.jsx)(n.Button,{variant:`default`,rightSection:(0,r.jsx)(C,{}),children:`Columns`})}),(0,r.jsx)(n.Menu.Dropdown,{children:(0,r.jsx)(n.Stack,{gap:`xs`,p:`xs`,children:t.map(e=>(0,r.jsxs)(n.Group,{gap:`xs`,justify:`space-between`,wrap:`nowrap`,children:[(0,r.jsx)(n.Checkbox,{label:c(e),checked:e.getIsVisible(),onChange:t=>e.toggleVisibility(t.currentTarget.checked)}),(0,r.jsx)(ie,{column:e})]},e.id))})})]})}function K({view:e,searchPlaceholder:t=`Search…`,filterInlineThreshold:i=3,lockSwitcherOnMobile:a,showSearch:o,showFilters:s,showSort:c,showVisibility:l,showViewSwitcher:u,disableWhileLoading:d=!0,leftSection:f,rightSection:p,...m}){let{table:h,state:g}=e,_=d&&e.status===`loading`,v=o??h.options.enableGlobalFilter!==!1,y=s??e.filterableColumns.length>0,b=c??e.sortableColumns.length>0,S=l??!0,C=u??!0;return(0,r.jsxs)(n.Group,{justify:`space-between`,wrap:`wrap`,gap:`sm`,...m,children:[(0,r.jsxs)(n.Group,{wrap:`wrap`,gap:`sm`,children:[f,v&&(0,r.jsx)(n.TextInput,{"aria-label":`Search`,placeholder:t,leftSection:(0,r.jsx)(x,{}),value:g.globalFilter,onChange:e=>h.setGlobalFilter(e.currentTarget.value),rightSection:g.globalFilter?(0,r.jsx)(n.CloseButton,{size:`sm`,"aria-label":`Clear search`,onClick:()=>h.setGlobalFilter(``)}):void 0}),(0,r.jsxs)(`fieldset`,{disabled:_,style:{display:`contents`,border:`none`,padding:0,margin:0},children:[y&&(0,r.jsx)(U,{view:e,inlineThreshold:i}),b&&(0,r.jsx)(W,{view:e})]})]}),(0,r.jsx)(`fieldset`,{disabled:_,style:{display:`contents`,border:`none`,padding:0,margin:0},children:(0,r.jsxs)(n.Group,{wrap:`wrap`,gap:`sm`,children:[S&&(0,r.jsx)(ae,{view:e}),C&&(0,r.jsx)(G,{view:e,lockSwitcherOnMobile:a}),p]})})]})}var q=(0,i.createContext)(null),J=q.Provider;function Y(){let e=(0,i.useContext)(q);if(!e)throw Error(`DataViewer.Toolbar / DataViewer.Body / DataViewer.Pagination must be rendered inside <DataViewer>.`);return e}function X({view:e,slots:t,renderCard:a,fallbackRole:o,lockSwitcherOnMobile:s,animateRows:c,children:l,...u}){return(0,r.jsx)(J,{value:(0,i.useMemo)(()=>({view:e,slots:t,renderCard:a,fallbackRole:o,lockSwitcherOnMobile:s,animateRows:c}),[e,t,a,o,s,c]),children:(0,r.jsx)(n.Stack,{...u,children:l??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(Z,{}),(0,r.jsx)(ce,{}),(0,r.jsx)(oe,{}),(0,r.jsx)(se,{})]})})})}function Z(e){let{view:t,lockSwitcherOnMobile:n}=Y();return(0,r.jsx)(K,{view:t,lockSwitcherOnMobile:n,...e})}function oe({tableProps:e,cardsProps:t}){let{view:n,slots:i,renderCard:a,fallbackRole:o,animateRows:s}=Y();return n.view===`cards`?(0,r.jsx)(g,{view:n,slots:i,renderCard:a,fallbackRole:o,animateRows:s,...t}):(0,r.jsx)(D,{view:n,slots:i,animateRows:s,...e})}function se(e){let{view:t}=Y();return(0,r.jsx)(v,{view:t,...e})}function ce(e){let{view:t,slots:n}=Y();return(0,r.jsx)(s,{view:t,slots:n,...e})}X.Toolbar=Z,X.BulkActions=ce,X.Body=oe,X.Pagination=se;function le(e){return e.replace(/_/g,` `).replace(/([a-z])([A-Z])/g,`$1 $2`).replace(/\b\w/g,e=>e.toUpperCase())}var ue={text:{dataType:`text`,filterVariant:`text`},number:{dataType:`number`,filterVariant:`numberRange`,align:`right`},currency:{dataType:`currency`,filterVariant:`numberRange`,align:`right`},date:{dataType:`date`,filterVariant:`dateRange`},boolean:{dataType:`boolean`,filterVariant:`boolean`},select:{filterVariant:`select`},multiselect:{filterVariant:`multiselect`}},de=class{cols=[];helper=(0,t.createColumnHelper)();add(e,t,n){let r=ue[e];if(!r)throw Error(`Unknown preset: ${e}`);let i=n?.header??le(t),a=n?.align??r.align,o;if(n?.filter===!1)o=void 0;else{let e={variant:r.filterVariant,...n?.options?{options:n.options}:{}};o=n?.filter?{...e,...n.filter}:e}let s=this.helper.accessor(t,{header:i,...n?.cell?{cell:n.cell}:{},...n?.enableSorting===!1?{enableSorting:!1}:{},...n?.width==null?{}:{size:n.width},meta:{label:i,...r.dataType?{dataType:r.dataType}:{},...a?{align:a}:{},...o?{filter:o}:{},...n?.format?{format:n.format}:{},...n?.card?{card:{role:n.card,...n.cardOrder==null?{}:{order:n.cardOrder}}}:{}}});return this.cols.push(s),this}text(e,t){return this.add(`text`,e,t)}number(e,t){return this.add(`number`,e,t)}currency(e,t){return this.add(`currency`,e,t)}date(e,t){return this.add(`date`,e,t)}boolean(e,t){return this.add(`boolean`,e,t)}select(e,t){return this.add(`select`,e,t)}multiselect(e,t){return this.add(`multiselect`,e,t)}custom(e){return this.cols.push(e),this}build(){return this.cols}};function fe(){return new de}function Q(e){let t=e==null?``:String(e);return t.includes(`,`)||t.includes(`"`)||t.includes(`
|
|
2
|
-
`)?`"${t.replace(/"/g,`""`)}"`:t}function pe(e,t){let{filename:n=`export.csv`,separator:r=`,`,formatted:i=!1,formatDefaults:a}=t??{},o=e.getVisibleLeafColumns().filter(e=>e.id!==`_select`),s=[o.map(e=>Q(c(e))),...e.getRowModel().rows.map(e=>o.map(t=>{let n=e.getAllCells().find(e=>e.column.id===t.id)?.getValue();return i&&t.columnDef.meta?.dataType?Q(N(t.columnDef.meta.dataType,t.columnDef.meta.format,a)(n)):Q(n)}))].map(e=>e.join(r)).join(`
|
|
3
|
-
`),l=new Blob([s],{type:`text/csv;charset=utf-8;`}),u=URL.createObjectURL(l),d=document.createElement(`a`);d.href=u,d.download=n,d.click(),URL.revokeObjectURL(u)}function me(e){return(`table`in e?e.table:e).options.meta?.viewMode??`table`}function he(t){return t?{adapter:t.adapter,serializer:{...e.t,...t.serialize},include:e.r(t.include)}:null}function ge(t,n,r){if(!t)return{};try{return e.n(t.adapter.read(),{serializer:t.serializer,include:t.include,getFilterMeta:r,current:n})}catch{return{}}}function _e({config:t,state:n,applyPatch:r,getFilterMeta:a}){let o=(0,i.useRef)(n);o.current=n;let s=(0,i.useRef)(r);s.current=r;let c=(0,i.useRef)(a);c.current=a;let l=(0,i.useRef)(t);l.current=t;let u=t?e.i(n,{serializer:t.serializer,include:t.include,getFilterMeta:a}):null;(0,i.useEffect)(()=>{let t=l.current;if(!t||!u)return;let n=e.a(t.adapter.read(),t.serializer,t.include);t.adapter.write({...n,...u},{replace:!0})},[u?JSON.stringify(u):``]),(0,i.useEffect)(()=>{if(!t)return;let{adapter:n,serializer:r,include:i}=t;return n.subscribe?.(()=>{let t=e.n(n.read(),{serializer:r,include:i,getFilterMeta:c.current,current:o.current});s.current(t)})},[t])}function ve(e){return e.columnFilters.length>0||e.globalFilter.trim()!==``}function ye({status:e,error:t,pageRowCount:n,state:r}){return e===`error`?{phase:`error`,error:t}:e===`loading`||e===`idle`?{phase:`loading`}:n===0?ve(r)?{phase:`empty-filtered`}:{phase:`empty`}:{phase:`ready`}}var $=300,be=[10,25,50,100],xe=10;function Se(e){return e==null?{globalFilter:$,columnFilters:$}:typeof e==`number`?{globalFilter:e,columnFilters:e}:{globalFilter:e.globalFilter??$,columnFilters:e.columnFilters??$}}function Ce(e){if(e.id)return e.id;if(`accessorKey`in e&&e.accessorKey!=null)return String(e.accessorKey)}function we(e){let t=new Map;for(let n of e){let e=Ce(n),r=n.meta?.filter;e&&r&&t.set(e,r)}return e=>t.get(e)}function Te(e){return{pagination:{pageIndex:0,pageSize:e.pageSizeOptions?.[0]??xe},sorting:[],columnFilters:[],globalFilter:``,rowSelection:{},columnVisibility:{},columnPinning:{left:[],right:[]},view:e.defaultView??`table`,...e.initialState}}function Ee(e){let{columns:n,rows:r,rowCount:a,status:o,error:s,getRowId:c,onRequestChange:l,state:u,onStateChange:d,enableRowSelection:f,enableGlobalFilter:p=!0,debounce:m,responsive:h,formatDefaults:g,facets:_,params:v}=e,y=_??{},b=v?JSON.stringify(v):``,x=v??{},S=(0,i.useMemo)(()=>n.map(e=>{let t=e.meta?.dataType;if(!t||e.cell)return e;let n=N(t,e.meta?.format,g);return{...e,cell:e=>n(e.getValue())}}),[n,g]),C=(0,i.useMemo)(()=>we(S),[S]),w=(0,i.useMemo)(()=>he(e.urlSync),[e.urlSync]),[T,ee]=(0,i.useState)(()=>{let t=Te(e);return{...t,...ge(w,t,C)}}),E=(0,i.useMemo)(()=>({...T,...u}),[T,u]),D=(0,i.useRef)(E);D.current=E;let O=(0,i.useCallback)(e=>{ee(t=>({...t,...e})),d?.({...D.current,...e})},[d]);_e({config:w,state:E,applyPatch:O,getFilterMeta:C});let k=(0,i.useCallback)(()=>({...D.current.pagination,pageIndex:0}),[]),A=(0,i.useRef)(b);(0,i.useEffect)(()=>{A.current!==b&&(A.current=b,O({pagination:k()}))});let te=(0,i.useCallback)(e=>{O({pagination:(0,t.functionalUpdate)(e,D.current.pagination)})},[O]),j=(0,i.useCallback)(e=>{O({sorting:(0,t.functionalUpdate)(e,D.current.sorting),pagination:k()})},[O,k]),M=(0,i.useCallback)(e=>{O({columnFilters:(0,t.functionalUpdate)(e,D.current.columnFilters),pagination:k()})},[O,k]),re=(0,i.useCallback)(e=>{O({globalFilter:(0,t.functionalUpdate)(e,D.current.globalFilter),pagination:k()})},[O,k]),P=(0,i.useCallback)(e=>{O({rowSelection:(0,t.functionalUpdate)(e,D.current.rowSelection)})},[O]),F=(0,i.useCallback)(e=>{O({columnVisibility:(0,t.functionalUpdate)(e,D.current.columnVisibility)})},[O]),I=(0,i.useCallback)(e=>{O({columnPinning:(0,t.functionalUpdate)(e,D.current.columnPinning)})},[O]),L=ne(h),R=L?`cards`:E.view,z=(0,t.useReactTable)({data:r,meta:{viewMode:R},columns:S,getCoreRowModel:(0,t.getCoreRowModel)(),manualPagination:!0,manualSorting:!0,manualFiltering:!0,autoResetPageIndex:!1,rowCount:a,getRowId:e=>c(e),enableRowSelection:typeof f==`function`?e=>f(e.original):f??!0,enableGlobalFilter:p,state:{pagination:E.pagination,sorting:E.sorting,columnFilters:E.columnFilters,globalFilter:E.globalFilter,rowSelection:E.rowSelection,columnVisibility:E.columnVisibility,columnPinning:E.columnPinning},onPaginationChange:te,onSortingChange:j,onColumnFiltersChange:M,onGlobalFilterChange:re,onRowSelectionChange:P,onColumnVisibilityChange:F,onColumnPinningChange:I}),B=(0,i.useMemo)(()=>({pagination:E.pagination,sorting:E.sorting,filters:E.columnFilters,globalFilter:E.globalFilter,params:x}),[E.pagination,E.sorting,E.columnFilters,E.globalFilter,b]),V=(0,i.useRef)(l);V.current=l;let H=(0,i.useRef)(Se(m));H.current=Se(m);let U=(0,i.useRef)(null),W=(0,i.useRef)(void 0);(0,i.useEffect)(()=>{let e=U.current,t=e===null,n=!e||e.globalFilter!==B.globalFilter,r=!e||e.filters!==B.filters,i=()=>{U.current=B,V.current?.(B)},a=0;n&&(a=Math.max(a,H.current.globalFilter)),r&&(a=Math.max(a,H.current.columnFilters));let o=!t&&(n||r)&&a>0;return clearTimeout(W.current),o?W.current=setTimeout(i,a):i(),()=>clearTimeout(W.current)},[B]);let G=(0,i.useRef)(B);G.current=B;let ie=(0,i.useCallback)(()=>{V.current?.(G.current)},[]),ae=(0,i.useMemo)(()=>ye({status:o,error:s,pageRowCount:r.length,state:E}),[o,s,r.length,E]),K=(0,i.useCallback)(e=>O({view:e}),[O]),q=e.pageSizeOptions??be,J=z.getAllColumns(),Y=J.filter(e=>e.getCanSort()),X=J.filter(e=>e.columnDef.meta?.filter!=null),Z=(0,i.useCallback)(()=>O({rowSelection:{}}),[O]);return{table:z,request:B,state:E,view:R,setView:K,isMobileForced:L,status:o,error:s,renderStatus:ae,refetch:ie,pageSizeOptions:q,sortableColumns:Y,filterableColumns:X,selection:(0,i.useMemo)(()=>{let e=E.rowSelection,t=Object.keys(e).filter(t=>e[t]),n=r.filter(t=>e[c(t)]===!0);return{count:t.length,ids:t,rows:n,clear:Z}},[E.rowSelection,r,c,Z]),exportCsv:(0,i.useCallback)(e=>pe(z,e),[z]),facets:y,resetFilter:(0,i.useCallback)(e=>z.getColumn(e)?.setFilterValue(void 0),[z]),resetAllFilters:(0,i.useCallback)(()=>z.resetColumnFilters(),[z])}}function De({fetcher:e,deps:t,...n}){let[r,a]=(0,i.useState)({rows:[],rowCount:0}),[o,s]=(0,i.useState)(`idle`),[c,l]=(0,i.useState)(void 0),u=(0,i.useRef)(e);u.current=e;let d=(0,i.useRef)(0),f=(0,i.useRef)(null),p=(0,i.useCallback)(async e=>{f.current=e;let t=++d.current;s(`loading`);try{let n=await u.current(e);t===d.current&&(a(n),l(void 0),s(`success`))}catch(e){t===d.current&&(l(e),s(`error`))}},[]),m=t?JSON.stringify(t):``,h=(0,i.useRef)(m);return(0,i.useEffect)(()=>{h.current!==m&&(h.current=m,f.current&&p(f.current))}),Ee({...n,rows:r.rows,rowCount:r.rowCount,facets:r.facets,status:o,error:c,onRequestChange:p})}exports.ColumnBuilder=de,exports.DataBulkActions=s,exports.DataCards=g,exports.DataPagination=v,exports.DataTable=D,exports.DataToolbar=K,exports.DataViewer=X,exports.FilterControl=z,exports.ViewSwitcher=G,exports.col=fe,exports.composeCardLayout=u,Object.defineProperty(exports,"createColumnHelper",{enumerable:!0,get:function(){return t.createColumnHelper}}),exports.exportCsv=pe,exports.getViewMode=me,exports.resolveColumnLabel=c,exports.useDataView=Ee,exports.useDataViewContext=Y,exports.useDataViewFetcher=De;
|
|
4
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/components/DataBulkActions/DataBulkActions.tsx","../src/core/cardComposition.ts","../src/core/useRowTransition.ts","../src/components/StateMessage.tsx","../src/components/DataCards/DataCards.tsx","../src/components/DataPagination/DataPagination.tsx","../src/components/icons.tsx","../src/components/DataTable/DataTable.tsx","../src/core/useForceCards.ts","../src/core/formatValue.ts","../src/components/DataToolbar/FacetBuckets.tsx","../src/components/DataToolbar/FilterControl.tsx","../src/components/DataToolbar/FilterControls.tsx","../src/components/DataToolbar/SortControl.tsx","../src/components/DataToolbar/ViewSwitcher.tsx","../src/components/DataToolbar/VisibilityMenu.tsx","../src/components/DataToolbar/DataToolbar.tsx","../src/components/DataViewer/context.tsx","../src/components/DataViewer/DataViewer.tsx","../src/core/colBuilder.ts","../src/core/exportCsv.ts","../src/core/getViewMode.ts","../src/url/useUrlSync.ts","../src/core/resolveStatus.ts","../src/core/useDataView.ts","../src/core/useDataViewFetcher.ts"],"sourcesContent":["// Bulk action bar. It is derived purely from `selection`, so it is identical no matter which\n// view is active. The same selection state drives the table checkboxes and the card overlays.\n// It renders nothing when nothing is selected. Consumer actions come from the `BulkActions` slot.\n//\n// Selection is scoped to a page in v1, so there is no select all across pages. `selection.ids`\n// still spans every page the user has selected on, so actions can use the full id set even\n// though only rows on the current page are materialized in `selection.rows`.\n\nimport { Button, Group, Paper, type PaperProps, Text } from \"@mantine/core\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport type { DataViewSlots } from \"../types\";\n\nexport interface DataBulkActionsProps<TData>\n\textends Omit<PaperProps, \"children\"> {\n\t/** The `useDataView` instance to project. */\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n}\n\nexport function DataBulkActions<TData>({\n\tview,\n\tslots,\n\t...paperProps\n}: DataBulkActionsProps<TData>) {\n\tconst { selection } = view;\n\tif (selection.count === 0) return null;\n\n\treturn (\n\t\t<Paper\n\t\t\twithBorder\n\t\t\tp=\"xs\"\n\t\t\tradius=\"sm\"\n\t\t\trole=\"region\"\n\t\t\taria-label=\"Bulk actions\"\n\t\t\t{...paperProps}\n\t\t>\n\t\t\t<Group justify=\"space-between\" wrap=\"wrap\" gap=\"sm\">\n\t\t\t\t<Group gap=\"sm\">\n\t\t\t\t\t<Text size=\"sm\" fw={500}>\n\t\t\t\t\t\t{selection.count} selected\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Button variant=\"subtle\" size=\"xs\" onClick={selection.clear}>\n\t\t\t\t\t\tClear\n\t\t\t\t\t</Button>\n\t\t\t\t</Group>\n\t\t\t\t{slots?.BulkActions && (\n\t\t\t\t\t<Group gap=\"xs\">{slots.BulkActions(selection)}</Group>\n\t\t\t\t)}\n\t\t\t</Group>\n\t\t</Paper>\n\t);\n}\n","// Default card composition. It projects the column model into a layout bucketed by role that\n// `<DataCards>` renders. Reading from `table.getVisibleLeafColumns()` means card fields honor\n// `columnVisibility` on their own. The same toggle hides a table column and its card field,\n// which is the parity decision to share visibility between the two views.\n\nimport type { Column, Table } from \"@tanstack/react-table\";\nimport type { CardRole } from \"../types/column\";\n\n/** Roles that produce a rendered slot; `hidden` columns are dropped from the layout. */\nexport type CardLayoutRole = Exclude<CardRole, \"hidden\">;\n\nexport interface CardField<TData> {\n\tid: string;\n\tcolumn: Column<TData>;\n\t/** Resolved display label. It prefers meta.label, then a string header, then the column id. */\n\tlabel: string;\n\t/** Whether to render the label beside the value as a pair. */\n\tshowLabel: boolean;\n}\n\nexport interface CardLayout<TData> {\n\ttitle: CardField<TData>[];\n\tsubtitle: CardField<TData>[];\n\tmedia: CardField<TData>[];\n\tbadge: CardField<TData>[];\n\tmeta: CardField<TData>[];\n}\n\nexport interface ComposeCardOptions {\n\t/**\n\t * Role for visible accessor columns that declare no `card.role`. The default is `'meta'`.\n\t * Set it to `'hidden'` to make card fields opt in. Display columns have no accessor, such as\n\t * an actions column, and are always hidden unless they declare an explicit role.\n\t */\n\tfallbackRole?: CardLayoutRole | \"hidden\";\n}\n\n/** The label used by card fields, the sort control, and toolbar filters. It is the one source. */\nexport function resolveColumnLabel<TData>(column: Column<TData>): string {\n\tconst { meta, header } = column.columnDef;\n\tif (meta?.label) return meta.label;\n\tif (typeof header === \"string\") return header;\n\treturn column.id;\n}\n\nfunction resolveRole<TData>(\n\tcolumn: Column<TData>,\n\texplicit: CardRole | undefined,\n\tfallback: CardLayoutRole | \"hidden\",\n): CardLayoutRole | null {\n\tif (explicit) return explicit === \"hidden\" ? null : explicit;\n\t// Display columns cannot produce a value, so they stay out of the card by default.\n\tif (column.accessorFn == null) return null;\n\treturn fallback === \"hidden\" ? null : fallback;\n}\n\ninterface Ranked<TData> {\n\tfield: CardField<TData>;\n\torder: number;\n\tindex: number;\n}\n\n/**\n * Builds the card layout from the columns that are currently visible. Within each role group the\n * fields are ordered by `meta.card.order`, falling back to the column's declared position.\n */\nexport function composeCardLayout<TData>(\n\ttable: Table<TData>,\n\toptions: ComposeCardOptions = {},\n): CardLayout<TData> {\n\tconst fallback = options.fallbackRole ?? \"meta\";\n\tconst buckets: Record<CardLayoutRole, Ranked<TData>[]> = {\n\t\ttitle: [],\n\t\tsubtitle: [],\n\t\tmedia: [],\n\t\tbadge: [],\n\t\tmeta: [],\n\t};\n\n\ttable.getVisibleLeafColumns().forEach((column, index) => {\n\t\tconst card = column.columnDef.meta?.card;\n\t\tconst role = resolveRole(column, card?.role, fallback);\n\t\tif (!role) return;\n\t\tbuckets[role].push({\n\t\t\torder: card?.order ?? index,\n\t\t\tindex,\n\t\t\tfield: {\n\t\t\t\tid: column.id,\n\t\t\t\tcolumn,\n\t\t\t\tlabel: resolveColumnLabel(column),\n\t\t\t\tshowLabel: card?.showLabel ?? role === \"meta\",\n\t\t\t},\n\t\t});\n\t});\n\n\tconst extract = (ranked: Ranked<TData>[]): CardField<TData>[] =>\n\t\tranked\n\t\t\t.sort((a, b) => a.order - b.order || a.index - b.index)\n\t\t\t.map((r) => r.field);\n\n\treturn {\n\t\ttitle: extract(buckets.title),\n\t\tsubtitle: extract(buckets.subtitle),\n\t\tmedia: extract(buckets.media),\n\t\tbadge: extract(buckets.badge),\n\t\tmeta: extract(buckets.meta),\n\t};\n}\n","import type { Row } from \"@tanstack/react-table\";\nimport { useEffect, useRef } from \"react\";\n\nexport interface RowTransitionResult<TData> {\n\trows: Row<TData>[];\n\tentering: Set<string>;\n\t/** Increments each time the row set or order changes. Use as a CSS animation key. */\n\tgeneration: number;\n}\n\nexport function useRowTransition<TData>(\n\tcurrentRows: Row<TData>[],\n\tenabled: boolean,\n): RowTransitionResult<TData> {\n\tconst prevIdsRef = useRef<string[]>([]);\n\tconst hasMountedRef = useRef(false);\n\tconst generationRef = useRef(0);\n\tconst warnedRef = useRef(false);\n\n\tuseEffect(() => {\n\t\tif (\n\t\t\tenabled &&\n\t\t\t!warnedRef.current &&\n\t\t\ttypeof document !== \"undefined\" &&\n\t\t\tprocess.env.NODE_ENV !== \"production\"\n\t\t) {\n\t\t\tconst sheets = Array.from(document.styleSheets);\n\t\t\tconst hasKeyframes = sheets.some((s) => {\n\t\t\t\ttry {\n\t\t\t\t\treturn Array.from(s.cssRules).some(\n\t\t\t\t\t\t(r) =>\n\t\t\t\t\t\t\tr instanceof CSSKeyframesRule && r.name === \"dataview-row-enter\",\n\t\t\t\t\t);\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (!hasKeyframes) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"[@ethanhann/mantine-dataview] animateRows is enabled but the CSS keyframes are missing. \" +\n\t\t\t\t\t\t'Import \"@ethanhann/mantine-dataview/styles.css\" in your app entry.',\n\t\t\t\t);\n\t\t\t}\n\t\t\twarnedRef.current = true;\n\t\t}\n\t}, [enabled]);\n\n\tconst currentIds = currentRows.map((r) => r.id);\n\tconst entering = new Set<string>();\n\tlet generationSnapshot = generationRef.current;\n\n\tif (enabled && hasMountedRef.current) {\n\t\tconst prevIds = prevIdsRef.current;\n\t\tconst prevSet = new Set(prevIds);\n\n\t\tconst orderChanged =\n\t\t\tcurrentIds.length !== prevIds.length ||\n\t\t\tcurrentIds.some((id, i) => id !== prevIds[i]);\n\n\t\tif (orderChanged) {\n\t\t\tgenerationSnapshot = generationRef.current + 1;\n\n\t\t\tconst sameSet =\n\t\t\t\tcurrentIds.length === prevIds.length &&\n\t\t\t\tcurrentIds.every((id) => prevSet.has(id));\n\n\t\t\tif (sameSet) {\n\t\t\t\tfor (const id of currentIds) {\n\t\t\t\t\tentering.add(id);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const id of currentIds) {\n\t\t\t\t\tif (!prevSet.has(id)) {\n\t\t\t\t\t\tentering.add(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tuseEffect(() => {\n\t\tprevIdsRef.current = currentIds;\n\t\thasMountedRef.current = true;\n\t\tgenerationRef.current = generationSnapshot;\n\t});\n\n\treturn { rows: currentRows, entering, generation: generationSnapshot };\n}\n","// Shared empty and error content, so both presentations render identical defaults and honor the\n// same slots. Each presentation supplies its own container. For the table that is a table cell\n// spanning every column, and for the card grid it is a centered box.\n\nimport { Button, Stack, Text } from \"@mantine/core\";\nimport type { Table } from \"@tanstack/react-table\";\nimport type { UseDataViewReturn } from \"../types/options\";\nimport type { DataViewSlots } from \"./types\";\n\n/** Resets all column filters and the global search. This is the clear action for filtered empty. */\nexport function clearAllFilters<TData>(table: Table<TData>): void {\n\ttable.resetColumnFilters();\n\ttable.setGlobalFilter(\"\");\n}\n\ninterface StateProps<TData> {\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n}\n\nexport function ErrorContent<TData>({ view, slots }: StateProps<TData>) {\n\tif (slots?.ErrorState) {\n\t\treturn <>{slots.ErrorState({ error: view.error, retry: view.refetch })}</>;\n\t}\n\treturn (\n\t\t<Stack align=\"center\" gap=\"xs\">\n\t\t\t<Text c=\"red\">Something went wrong.</Text>\n\t\t\t<Button variant=\"light\" size=\"xs\" onClick={view.refetch}>\n\t\t\t\tRetry\n\t\t\t</Button>\n\t\t</Stack>\n\t);\n}\n\nexport function EmptyContent<TData>({ view, slots }: StateProps<TData>) {\n\tconst filtered = view.renderStatus.phase === \"empty-filtered\";\n\tconst clearFilters = () => clearAllFilters(view.table);\n\tif (slots?.Empty) {\n\t\treturn <>{slots.Empty({ filtered, clearFilters })}</>;\n\t}\n\tif (filtered) {\n\t\treturn (\n\t\t\t<Stack align=\"center\" gap=\"xs\">\n\t\t\t\t<Text c=\"dimmed\">No matches.</Text>\n\t\t\t\t<Button variant=\"subtle\" size=\"xs\" onClick={clearFilters}>\n\t\t\t\t\tClear filters\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t);\n\t}\n\treturn <Text c=\"dimmed\">No results.</Text>;\n}\n","// Card grid presentation. It is the second projection of the same core state. It reads the\n// identical sorting, selection, visibility, and pagination as `<DataTable>`, then renders that\n// as Mantine cards through the composition helper. Card fields come from\n// `getVisibleLeafColumns()`, so hiding a column hides its card field too. Parity holds by design.\n\nimport {\n\tBox,\n\tCard,\n\tCenter,\n\tCheckbox,\n\tGroup,\n\tSimpleGrid,\n\ttype SimpleGridProps,\n\tSkeleton,\n\tStack,\n\tText,\n} from \"@mantine/core\";\nimport { flexRender, type Row } from \"@tanstack/react-table\";\nimport { Fragment, type ReactNode } from \"react\";\nimport {\n\ttype CardField,\n\ttype ComposeCardOptions,\n\tcomposeCardLayout,\n} from \"../../core/cardComposition\";\nimport { useRowTransition } from \"../../core/useRowTransition\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { EmptyContent, ErrorContent } from \"../StateMessage\";\n// @ts-expect-error CSS import has no type declarations\nimport \"../DataTable/transitions.css\";\nimport type { DataViewSlots } from \"../types\";\n\nconst DEFAULT_COLS: SimpleGridProps[\"cols\"] = { base: 1, sm: 2, lg: 3 };\n\nexport interface DataCardsProps<TData>\n\textends Omit<SimpleGridProps, \"children\"> {\n\t/** The `useDataView` instance to project. */\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n\t/** Full per card escape hatch. It replaces the default composition. */\n\trenderCard?: (ctx: {\n\t\trow: Row<TData>;\n\t\tdata: TData;\n\t\tselected: boolean;\n\t\ttoggleSelected: () => void;\n\t}) => ReactNode;\n\t/** Role for accessor columns that declare none. It is forwarded to the composition. */\n\tfallbackRole?: ComposeCardOptions[\"fallbackRole\"];\n\tenableSelection?: boolean;\n\t/** Skeleton cards shown while loading. It defaults to the current page size, capped at 6. */\n\tloadingCardCount?: number;\n\t/** Animate card enter/exit instead of showing skeletons. Default: false. */\n\tanimateRows?: boolean;\n}\n\nexport function DataCards<TData>({\n\tview,\n\tslots,\n\trenderCard,\n\tfallbackRole,\n\tenableSelection,\n\tloadingCardCount,\n\tanimateRows = false,\n\tcols = DEFAULT_COLS,\n\t...gridProps\n}: DataCardsProps<TData>) {\n\tconst { table, renderStatus } = view;\n\tconst selectionEnabled =\n\t\tenableSelection ?? table.options.enableRowSelection !== false;\n\tconst skeletonCards =\n\t\tloadingCardCount ?? Math.min(view.state.pagination.pageSize, 6);\n\tconst grid = { cols, ...gridProps };\n\tconst transition = useRowTransition(table.getRowModel().rows, animateRows);\n\n\tconst renderCards = (rowsToRender: typeof transition.rows) => {\n\t\tconst layout = composeCardLayout(table, { fallbackRole });\n\t\treturn (\n\t\t\t<SimpleGrid\n\t\t\t\tkey={transition.generation}\n\t\t\t\tdata-changed={animateRows || undefined}\n\t\t\t\t{...grid}\n\t\t\t>\n\t\t\t\t{rowsToRender.map((row) => {\n\t\t\t\t\tconst selected = row.getIsSelected();\n\t\t\t\t\tconst toggleSelected = () => row.toggleSelected();\n\t\t\t\t\tconst ctx = { row, data: row.original, selected, toggleSelected };\n\t\t\t\t\tconst entering = transition.entering.has(row.id) || undefined;\n\n\t\t\t\t\tif (renderCard) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div key={row.id} data-entering={entering}>\n\t\t\t\t\t\t\t\t{renderCard(ctx)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst body = (\n\t\t\t\t\t\t<DefaultCardBody\n\t\t\t\t\t\t\trow={row}\n\t\t\t\t\t\t\tlayout={layout}\n\t\t\t\t\t\t\tselectionEnabled={selectionEnabled}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t\tif (slots?.Card) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div key={row.id} data-entering={entering}>\n\t\t\t\t\t\t\t\t{slots.Card({ ...ctx, children: body })}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Card\n\t\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\t\twithBorder\n\t\t\t\t\t\t\tpadding=\"lg\"\n\t\t\t\t\t\t\tpos=\"relative\"\n\t\t\t\t\t\t\tdata-selected={selected || undefined}\n\t\t\t\t\t\t\tdata-entering={entering}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{body}\n\t\t\t\t\t\t</Card>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</SimpleGrid>\n\t\t);\n\t};\n\n\tif (\n\t\tanimateRows &&\n\t\trenderStatus.phase === \"loading\" &&\n\t\ttransition.rows.length > 0\n\t) {\n\t\treturn renderCards(transition.rows);\n\t}\n\n\tswitch (renderStatus.phase) {\n\t\tcase \"loading\":\n\t\t\treturn slots?.LoadingCards ? (\n\t\t\t\tslots.LoadingCards()\n\t\t\t) : (\n\t\t\t\t<SimpleGrid {...grid}>\n\t\t\t\t\t{Array.from({ length: skeletonCards }, (_, i) => (\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: placeholders of a fixed count\n\t\t\t\t\t\t<Card key={i} withBorder padding=\"md\">\n\t\t\t\t\t\t\t<Stack gap=\"xs\">\n\t\t\t\t\t\t\t\t<Skeleton height={20} width=\"60%\" />\n\t\t\t\t\t\t\t\t<Skeleton height={12} width=\"40%\" />\n\t\t\t\t\t\t\t\t<Skeleton height={12} />\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Card>\n\t\t\t\t\t))}\n\t\t\t\t</SimpleGrid>\n\t\t\t);\n\t\tcase \"error\":\n\t\t\treturn (\n\t\t\t\t<Center p=\"xl\">\n\t\t\t\t\t<ErrorContent view={view} slots={slots} />\n\t\t\t\t</Center>\n\t\t\t);\n\t\tcase \"empty\":\n\t\tcase \"empty-filtered\":\n\t\t\treturn (\n\t\t\t\t<Center p=\"xl\">\n\t\t\t\t\t<EmptyContent view={view} slots={slots} />\n\t\t\t\t</Center>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn renderCards(transition.rows);\n\t}\n}\n\nfunction DefaultCardBody<TData>({\n\trow,\n\tlayout,\n\tselectionEnabled,\n}: {\n\trow: Row<TData>;\n\tlayout: ReturnType<typeof composeCardLayout<TData>>;\n\tselectionEnabled: boolean;\n}) {\n\tconst cellById = new Map(row.getAllCells().map((c) => [c.column.id, c]));\n\tconst renderField = (field: CardField<TData>): ReactNode => {\n\t\tconst cell = cellById.get(field.id);\n\t\treturn cell\n\t\t\t? flexRender(cell.column.columnDef.cell, cell.getContext())\n\t\t\t: null;\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t{selectionEnabled && (\n\t\t\t\t<Checkbox\n\t\t\t\t\taria-label=\"Select card\"\n\t\t\t\t\tchecked={row.getIsSelected()}\n\t\t\t\t\tdisabled={!row.getCanSelect()}\n\t\t\t\t\tonChange={row.getToggleSelectedHandler()}\n\t\t\t\t\tstyle={{ position: \"absolute\", top: 8, right: 8, zIndex: 1 }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{layout.media.length > 0 && (\n\t\t\t\t<Card.Section mb=\"xs\">\n\t\t\t\t\t{layout.media.map((field) => (\n\t\t\t\t\t\t<Box key={field.id}>{renderField(field)}</Box>\n\t\t\t\t\t))}\n\t\t\t\t</Card.Section>\n\t\t\t)}\n\t\t\t<Stack gap=\"md\">\n\t\t\t\t{(layout.title.length > 0 || layout.subtitle.length > 0) && (\n\t\t\t\t\t<Stack gap={4}>\n\t\t\t\t\t\t{layout.title.map((field) => (\n\t\t\t\t\t\t\t<Text\n\t\t\t\t\t\t\t\tkey={field.id}\n\t\t\t\t\t\t\t\tfw={600}\n\t\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\t\tlh={1.2}\n\t\t\t\t\t\t\t\tpr={selectionEnabled ? 28 : 0}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{renderField(field)}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{layout.subtitle.map((field) => (\n\t\t\t\t\t\t\t<Text key={field.id} size=\"sm\" c=\"dimmed\">\n\t\t\t\t\t\t\t\t{renderField(field)}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Stack>\n\t\t\t\t)}\n\t\t\t\t{layout.badge.length > 0 && (\n\t\t\t\t\t<Group gap=\"xs\">\n\t\t\t\t\t\t{layout.badge.map((field) => (\n\t\t\t\t\t\t\t<Fragment key={field.id}>{renderField(field)}</Fragment>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Group>\n\t\t\t\t)}\n\t\t\t\t{layout.meta.length > 0 && (\n\t\t\t\t\t<Stack gap={4}>\n\t\t\t\t\t\t{layout.meta.map((field) => (\n\t\t\t\t\t\t\t<Group\n\t\t\t\t\t\t\t\tkey={field.id}\n\t\t\t\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\t\t\t\tgap=\"xs\"\n\t\t\t\t\t\t\t\twrap=\"nowrap\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{field.showLabel && (\n\t\t\t\t\t\t\t\t\t<Text size=\"sm\" c=\"dimmed\">\n\t\t\t\t\t\t\t\t\t\t{field.label}\n\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t<Text size=\"sm\">{renderField(field)}</Text>\n\t\t\t\t\t\t\t</Group>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Stack>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</>\n\t);\n}\n","// Pagination. This single pager is shared by both presentations. It reads `pagination` state\n// and `rowCount` from the core, so the table and cards page in lockstep. Page math comes from\n// the v8 instance through `getPageCount` and `getRowCount`, which derive it from `rowCount`.\n\nimport {\n\tGroup,\n\ttype GroupProps,\n\tPagination,\n\tSelect,\n\tText,\n} from \"@mantine/core\";\nimport type { UseDataViewReturn } from \"../../types/options\";\n\nexport interface DataPaginationProps<TData>\n\textends Omit<GroupProps, \"children\"> {\n\t/** The `useDataView` instance to project. */\n\tview: UseDataViewReturn<TData>;\n\t/** Override the page size choices. It defaults to the core's `pageSizeOptions`. */\n\tpageSizeOptions?: number[];\n\tshowPageSize?: boolean;\n\t/** Show the range summary, such as \"1 to 10 of 42\". It defaults to true. */\n\tshowRange?: boolean;\n\tpageSizeLabel?: string;\n}\n\nexport function DataPagination<TData>({\n\tview,\n\tpageSizeOptions,\n\tshowPageSize = true,\n\tshowRange = true,\n\tpageSizeLabel = \"Rows per page\",\n\t...groupProps\n}: DataPaginationProps<TData>) {\n\tconst { table } = view;\n\tconst { pageIndex, pageSize } = view.state.pagination;\n\tconst total = table.getRowCount();\n\tconst pageCount = table.getPageCount();\n\tconst sizes = pageSizeOptions ?? view.pageSizeOptions;\n\n\tconst start = total === 0 ? 0 : pageIndex * pageSize + 1;\n\tconst end = Math.min((pageIndex + 1) * pageSize, total);\n\n\treturn (\n\t\t<Group justify=\"space-between\" wrap=\"wrap\" gap=\"sm\" {...groupProps}>\n\t\t\t<Group gap=\"sm\" wrap=\"wrap\">\n\t\t\t\t{showPageSize && (\n\t\t\t\t\t<Select\n\t\t\t\t\t\taria-label={pageSizeLabel}\n\t\t\t\t\t\tdata={sizes.map(String)}\n\t\t\t\t\t\tvalue={String(pageSize)}\n\t\t\t\t\t\tonChange={(v) => v && table.setPageSize(Number(v))}\n\t\t\t\t\t\tw={80}\n\t\t\t\t\t\tcomboboxProps={{ withinPortal: true }}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{showRange && (\n\t\t\t\t\t<Text size=\"sm\" c=\"dimmed\">\n\t\t\t\t\t\t{start}–{end} of {total}\n\t\t\t\t\t</Text>\n\t\t\t\t)}\n\t\t\t</Group>\n\t\t\t<Pagination\n\t\t\t\tvalue={pageIndex + 1}\n\t\t\t\ttotal={Math.max(pageCount, 1)}\n\t\t\t\tonChange={(page) => table.setPageIndex(page - 1)}\n\t\t\t\tgetControlProps={(control) => ({ \"aria-label\": `${control} page` })}\n\t\t\t/>\n\t\t</Group>\n\t);\n}\n","// Minimal inline SVG icons. The library ships no icon dependency to stay lean. Consumers are\n// free to bring something like @tabler/icons-react for their own cells and actions.\n\nimport type { SortDirection } from \"@tanstack/react-table\";\n\n/**\n * Sort indicator. It highlights the up or down chevron when active and dims both when unsorted.\n * It is decorative. The accessible sort state is conveyed by `aria-sort` on the header cell.\n */\nexport function SortIcon({ direction }: { direction: SortDirection | false }) {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"14\"\n\t\t\theight=\"14\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\taria-hidden=\"true\"\n\t\t\tfocusable=\"false\"\n\t\t\tstyle={{ flexShrink: 0 }}\n\t\t>\n\t\t\t<title>sort</title>\n\t\t\t<path\n\t\t\t\td=\"M8 10l4-4 4 4\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\topacity={direction === \"asc\" ? 1 : 0.35}\n\t\t\t/>\n\t\t\t<path\n\t\t\t\td=\"M8 14l4 4 4-4\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\topacity={direction === \"desc\" ? 1 : 0.35}\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\nfunction Glyph({ d, title }: { d: string; title: string }) {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t\tfocusable=\"false\"\n\t\t\tstyle={{ flexShrink: 0 }}\n\t\t>\n\t\t\t<title>{title}</title>\n\t\t\t<path d={d} />\n\t\t</svg>\n\t);\n}\n\nexport function SearchIcon() {\n\treturn (\n\t\t<Glyph\n\t\t\ttitle=\"search\"\n\t\t\td=\"M21 21l-4.3-4.3M11 19a8 8 0 110-16 8 8 0 010 16z\"\n\t\t/>\n\t);\n}\n\nexport function FilterIcon() {\n\treturn <Glyph title=\"filter\" d=\"M3 5h18M7 12h10M10 19h4\" />;\n}\n\nexport function ChevronDownIcon() {\n\treturn <Glyph title=\"open\" d=\"M6 9l6 6 6-6\" />;\n}\n\nexport function CloseIcon() {\n\treturn <Glyph title=\"close\" d=\"M18 6L6 18M6 6l12 12\" />;\n}\n\nexport function PinLeftIcon() {\n\treturn <Glyph title=\"pin left\" d=\"M4 4v16M9 8h8M9 12h6M9 16h8\" />;\n}\n\nexport function PinRightIcon() {\n\treturn <Glyph title=\"pin right\" d=\"M20 4v16M7 8h8M9 12h6M7 16h8\" />;\n}\n","// Table presentation. It is a thin projection of the `useDataView` return. It owns no feature\n// state, only how that state is shown. Sorting, selection, visibility, and the four data states\n// all read straight from the core.\n\nimport {\n\tCenter,\n\tCheckbox,\n\tSkeleton,\n\tTable,\n\ttype TableProps,\n\tUnstyledButton,\n} from \"@mantine/core\";\nimport { type Column, flexRender, type Header } from \"@tanstack/react-table\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useRowTransition } from \"../../core/useRowTransition\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { SortIcon } from \"../icons\";\nimport { EmptyContent, ErrorContent } from \"../StateMessage\";\nimport type { DataViewSlots } from \"../types\";\n// @ts-expect-error CSS import has no type declarations\nimport \"./transitions.css\";\n\nfunction pinningStyle<TData>(column: Column<TData>): CSSProperties | undefined {\n\tconst pinned = column.getIsPinned();\n\tif (!pinned) return undefined;\n\treturn {\n\t\tposition: \"sticky\",\n\t\t[pinned]:\n\t\t\tpinned === \"left\" ? column.getStart(\"left\") : column.getAfter(\"right\"),\n\t\tzIndex: 1,\n\t\tbackgroundColor: \"var(--mantine-color-body)\",\n\t};\n}\n\nexport interface DataTableProps<TData>\n\textends Omit<TableProps, \"data\" | \"children\"> {\n\t/** The `useDataView` instance to project. */\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n\t/** Whether to render the leading selection checkbox column. It defaults to the core setting. */\n\tenableSelection?: boolean;\n\t/** Skeleton rows shown while loading. It defaults to the current page size, capped at 8. */\n\tloadingRowCount?: number;\n\t/** Disable sorting interactions while data is loading. Default: true. */\n\tdisableWhileLoading?: boolean;\n\t/** Animate row enter/exit instead of showing skeletons. Default: false. */\n\tanimateRows?: boolean;\n}\n\nexport function DataTable<TData>({\n\tview,\n\tslots,\n\tenableSelection,\n\tloadingRowCount,\n\tdisableWhileLoading = true,\n\tanimateRows = false,\n\t...tableProps\n}: DataTableProps<TData>) {\n\tconst { table, renderStatus } = view;\n\tconst interactionDisabled = disableWhileLoading && view.status === \"loading\";\n\tconst transition = useRowTransition(table.getRowModel().rows, animateRows);\n\tconst leafColumns = table.getVisibleLeafColumns();\n\tconst selectionEnabled =\n\t\tenableSelection ?? table.options.enableRowSelection !== false;\n\tconst colCount = leafColumns.length + (selectionEnabled ? 1 : 0);\n\tconst skeletonRows =\n\t\tloadingRowCount ?? Math.min(view.state.pagination.pageSize, 8);\n\n\tconst renderDataRows = (rowsToRender: typeof transition.rows): ReactNode => (\n\t\t<Table.Tbody\n\t\t\tkey={transition.generation}\n\t\t\tdata-changed={animateRows || undefined}\n\t\t>\n\t\t\t{rowsToRender.map((row) => {\n\t\t\t\tconst isEntering = transition.entering.has(row.id) || undefined;\n\t\t\t\tconst cells = (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{selectionEnabled && (\n\t\t\t\t\t\t\t<Table.Td>\n\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\taria-label=\"Select row\"\n\t\t\t\t\t\t\t\t\tchecked={row.getIsSelected()}\n\t\t\t\t\t\t\t\t\tdisabled={!row.getCanSelect()}\n\t\t\t\t\t\t\t\t\tindeterminate={row.getIsSomeSelected()}\n\t\t\t\t\t\t\t\t\tonChange={row.getToggleSelectedHandler()}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Table.Td>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{row.getVisibleCells().map((cell) => {\n\t\t\t\t\t\t\tconst align = cell.column.columnDef.meta?.align;\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Table.Td\n\t\t\t\t\t\t\t\t\tkey={cell.id}\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t...pinningStyle(cell.column),\n\t\t\t\t\t\t\t\t\t\t...(align ? { textAlign: align } : undefined),\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{flexRender(cell.column.columnDef.cell, cell.getContext())}\n\t\t\t\t\t\t\t\t</Table.Td>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</>\n\t\t\t\t);\n\t\t\t\treturn slots?.Row ? (\n\t\t\t\t\t<RowKey key={row.id}>{slots.Row({ row, cells })}</RowKey>\n\t\t\t\t) : (\n\t\t\t\t\t<Table.Tr\n\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\tdata-selected={row.getIsSelected() || undefined}\n\t\t\t\t\t\tdata-entering={isEntering}\n\t\t\t\t\t>\n\t\t\t\t\t\t{cells}\n\t\t\t\t\t</Table.Tr>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Table.Tbody>\n\t);\n\n\tconst renderBody = (): ReactNode => {\n\t\tif (\n\t\t\tanimateRows &&\n\t\t\trenderStatus.phase === \"loading\" &&\n\t\t\ttransition.rows.length > 0\n\t\t) {\n\t\t\treturn renderDataRows(transition.rows);\n\t\t}\n\n\t\tswitch (renderStatus.phase) {\n\t\t\tcase \"loading\":\n\t\t\t\treturn slots?.LoadingTable ? (\n\t\t\t\t\tslots.LoadingTable()\n\t\t\t\t) : (\n\t\t\t\t\t<Table.Tbody>\n\t\t\t\t\t\t{Array.from({ length: skeletonRows }, (_, i) => (\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: placeholder rows of a fixed count\n\t\t\t\t\t\t\t<Table.Tr key={i}>\n\t\t\t\t\t\t\t\t{selectionEnabled && (\n\t\t\t\t\t\t\t\t\t<Table.Td>\n\t\t\t\t\t\t\t\t\t\t<Skeleton height={16} width={16} />\n\t\t\t\t\t\t\t\t\t</Table.Td>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{leafColumns.map((col) => (\n\t\t\t\t\t\t\t\t\t<Table.Td key={col.id}>\n\t\t\t\t\t\t\t\t\t\t<Skeleton height={12} />\n\t\t\t\t\t\t\t\t\t</Table.Td>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Table.Tr>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Table.Tbody>\n\t\t\t\t);\n\t\t\tcase \"error\":\n\t\t\t\treturn (\n\t\t\t\t\t<MessageBody colSpan={colCount}>\n\t\t\t\t\t\t<ErrorContent view={view} slots={slots} />\n\t\t\t\t\t</MessageBody>\n\t\t\t\t);\n\t\t\tcase \"empty\":\n\t\t\tcase \"empty-filtered\":\n\t\t\t\treturn (\n\t\t\t\t\t<MessageBody colSpan={colCount}>\n\t\t\t\t\t\t<EmptyContent view={view} slots={slots} />\n\t\t\t\t\t</MessageBody>\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\treturn renderDataRows(transition.rows);\n\t\t}\n\t};\n\n\tconst hasPinning = table.getIsSomeColumnsPinned();\n\n\treturn (\n\t\t<div style={hasPinning ? { overflowX: \"auto\" } : undefined}>\n\t\t\t<Table layout=\"fixed\" {...tableProps}>\n\t\t\t\t<Table.Thead>\n\t\t\t\t\t{table.getHeaderGroups().map((group) => (\n\t\t\t\t\t\t<Table.Tr key={group.id}>\n\t\t\t\t\t\t\t{selectionEnabled && (\n\t\t\t\t\t\t\t\t<Table.Th style={{ width: 40 }}>\n\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\taria-label=\"Select all rows on this page\"\n\t\t\t\t\t\t\t\t\t\tchecked={table.getIsAllPageRowsSelected()}\n\t\t\t\t\t\t\t\t\t\tindeterminate={\n\t\t\t\t\t\t\t\t\t\t\ttable.getIsSomePageRowsSelected() &&\n\t\t\t\t\t\t\t\t\t\t\t!table.getIsAllPageRowsSelected()\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tonChange={table.getToggleAllPageRowsSelectedHandler()}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</Table.Th>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{group.headers.map((header) => (\n\t\t\t\t\t\t\t\t<HeaderCell\n\t\t\t\t\t\t\t\t\tkey={header.id}\n\t\t\t\t\t\t\t\t\theader={header}\n\t\t\t\t\t\t\t\t\tdisabled={interactionDisabled}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</Table.Tr>\n\t\t\t\t\t))}\n\t\t\t\t</Table.Thead>\n\t\t\t\t{renderBody()}\n\t\t\t</Table>\n\t\t</div>\n\t);\n}\n\n/** Wrapper that carries the React key for a Row slot element the consumer supplies. */\nfunction RowKey({ children }: { children: ReactNode }) {\n\treturn <>{children}</>;\n}\n\nfunction MessageBody({\n\tcolSpan,\n\tchildren,\n}: {\n\tcolSpan: number;\n\tchildren: ReactNode;\n}) {\n\treturn (\n\t\t<Table.Tbody>\n\t\t\t<Table.Tr>\n\t\t\t\t<Table.Td colSpan={colSpan}>\n\t\t\t\t\t<Center p=\"xl\">{children}</Center>\n\t\t\t\t</Table.Td>\n\t\t\t</Table.Tr>\n\t\t</Table.Tbody>\n\t);\n}\n\nfunction HeaderCell<TData>({\n\theader,\n\tdisabled,\n}: {\n\theader: Header<TData, unknown>;\n\tdisabled?: boolean;\n}) {\n\tconst { column } = header;\n\tconst align = column.columnDef.meta?.align;\n\tconst sorted = column.getIsSorted();\n\tconst sortIndex = column.getSortIndex();\n\tconst multiSorted = sortIndex > 0;\n\tconst content = header.isPlaceholder\n\t\t? null\n\t\t: flexRender(column.columnDef.header, header.getContext());\n\tconst sortable = column.getCanSort() && !disabled;\n\n\tconst colSize = column.columnDef.size;\n\n\treturn (\n\t\t<Table.Th\n\t\t\tstyle={{\n\t\t\t\t...pinningStyle(column),\n\t\t\t\t...(align ? { textAlign: align } : undefined),\n\t\t\t\t...(colSize != null ? { width: colSize } : undefined),\n\t\t\t}}\n\t\t\taria-sort={\n\t\t\t\tsorted === \"asc\"\n\t\t\t\t\t? \"ascending\"\n\t\t\t\t\t: sorted === \"desc\"\n\t\t\t\t\t\t? \"descending\"\n\t\t\t\t\t\t: undefined\n\t\t\t}\n\t\t>\n\t\t\t{sortable ? (\n\t\t\t\t<UnstyledButton\n\t\t\t\t\tonClick={column.getToggleSortingHandler()}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\tgap: 4,\n\t\t\t\t\t\tfont: \"inherit\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{content}\n\t\t\t\t\t<SortIcon direction={sorted} />\n\t\t\t\t\t{multiSorted && (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\trole=\"note\"\n\t\t\t\t\t\t\tstyle={{ fontSize: \"0.7em\", opacity: 0.6 }}\n\t\t\t\t\t\t\taria-label={`Sort priority ${sortIndex + 1}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{sortIndex + 1}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t</UnstyledButton>\n\t\t\t) : (\n\t\t\t\t<span\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\tgap: 4,\n\t\t\t\t\t\t...(disabled ? { opacity: 0.5 } : {}),\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{content}\n\t\t\t\t\t{sorted && <SortIcon direction={sorted} />}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</Table.Th>\n\t);\n}\n","// Responsive forcing to cards. Below the configured Mantine breakpoint `isMobileForced` becomes\n// true and the core returns a view of cards no matter what the stored choice is. That choice is\n// preserved, so the explicit selection comes back once the viewport is wide enough again.\n\nimport { useMantineTheme } from \"@mantine/core\";\nimport { useMediaQuery } from \"@mantine/hooks\";\nimport type { ResponsiveOptions } from \"../types/options\";\n\n/** A media query that never matches, used when no responsive breakpoint is configured. */\nconst NEVER_MATCHES = \"(max-width: 0px)\";\n\n/**\n * Builds a query meaning \"strictly narrower than this breakpoint\". The small epsilon keeps the\n * boundary from overlapping a minimum width query at the same breakpoint. That matches the\n * convention Mantine itself uses.\n */\nexport function belowBreakpointQuery(value: string): string {\n\tconst match = /^([\\d.]+)(\\D*)$/.exec(value.trim());\n\tif (!match) return `(max-width: ${value})`;\n\tconst amount = Number(match[1]);\n\tconst unit = match[2] || \"px\";\n\tconst epsilon = unit === \"em\" || unit === \"rem\" ? 0.01 : 0.1;\n\treturn `(max-width: ${amount - epsilon}${unit})`;\n}\n\nexport function useForceCards(\n\tresponsive: ResponsiveOptions | undefined,\n): boolean {\n\tconst theme = useMantineTheme();\n\tconst breakpoint = responsive?.forceCardsBelow;\n\tconst raw = breakpoint ? theme.breakpoints[breakpoint] : undefined;\n\tconst query = raw ? belowBreakpointQuery(raw) : NEVER_MATCHES;\n\tconst below = useMediaQuery(query, false);\n\treturn Boolean(raw) && Boolean(below);\n}\n","import type { ColumnDataType, ColumnFormatOption } from \"../types/column\";\n\ntype Formatter = (value: unknown) => string;\n\nconst defaultFormatters: Record<ColumnDataType, Formatter> = {\n\ttext: (v) => (v == null ? \"\" : String(v)),\n\tnumber: (v) => {\n\t\tif (v == null) return \"\";\n\t\treturn new Intl.NumberFormat().format(Number(v));\n\t},\n\tcurrency: (v) => {\n\t\tif (v == null) return \"\";\n\t\treturn new Intl.NumberFormat(undefined, {\n\t\t\tstyle: \"currency\",\n\t\t\tcurrency: \"USD\",\n\t\t}).format(Number(v));\n\t},\n\tdate: (v) => {\n\t\tif (v == null) return \"\";\n\t\tconst d = v instanceof Date ? v : new Date(String(v));\n\t\tif (Number.isNaN(d.getTime())) return String(v);\n\t\treturn new Intl.DateTimeFormat().format(d);\n\t},\n\tboolean: (v) => {\n\t\tif (v == null) return \"\";\n\t\treturn v ? \"Yes\" : \"No\";\n\t},\n};\n\nfunction buildIntlFormatter(\n\tdataType: ColumnDataType,\n\toptions: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions,\n): Formatter {\n\tif (dataType === \"number\" || dataType === \"currency\") {\n\t\tconst fmt = new Intl.NumberFormat(\n\t\t\tundefined,\n\t\t\tdataType === \"currency\" ? { style: \"currency\", ...options } : options,\n\t\t);\n\t\treturn (v) => (v == null ? \"\" : fmt.format(Number(v)));\n\t}\n\tif (dataType === \"date\") {\n\t\tconst fmt = new Intl.DateTimeFormat(\n\t\t\tundefined,\n\t\t\toptions as Intl.DateTimeFormatOptions,\n\t\t);\n\t\treturn (v) => {\n\t\t\tif (v == null) return \"\";\n\t\t\tconst d = v instanceof Date ? v : new Date(String(v));\n\t\t\tif (Number.isNaN(d.getTime())) return String(v);\n\t\t\treturn fmt.format(d);\n\t\t};\n\t}\n\treturn defaultFormatters[dataType];\n}\n\nexport function resolveFormatter(\n\tdataType: ColumnDataType,\n\tcolumnFormat: ColumnFormatOption | undefined,\n\ttableDefaults:\n\t\t| Partial<Record<ColumnDataType, ColumnFormatOption>>\n\t\t| undefined,\n): Formatter {\n\tconst format = columnFormat ?? tableDefaults?.[dataType];\n\n\tif (!format) return defaultFormatters[dataType];\n\tif (typeof format === \"function\") return format as Formatter;\n\treturn buildIntlFormatter(dataType, format);\n}\n","import { Badge, Group, Stack, Text, UnstyledButton } from \"@mantine/core\";\nimport type { RangeFacet } from \"../../types/facets\";\n\nexport function FacetBuckets({\n\tfacet,\n\tvalue,\n\tonChange,\n}: {\n\tfacet: RangeFacet;\n\tvalue: unknown;\n\tonChange: (next: unknown) => void;\n}) {\n\tconst current = Array.isArray(value) ? value : null;\n\n\treturn (\n\t\t<Stack gap={4}>\n\t\t\t{facet.ranges.map((bucket) => {\n\t\t\t\tconst isActive =\n\t\t\t\t\tcurrent != null &&\n\t\t\t\t\tcurrent[0] === bucket.from &&\n\t\t\t\t\tcurrent[1] === bucket.to;\n\t\t\t\treturn (\n\t\t\t\t\t<UnstyledButton\n\t\t\t\t\t\tkey={bucket.label}\n\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\tonChange(isActive ? undefined : [bucket.from, bucket.to])\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tpadding: \"4px 8px\",\n\t\t\t\t\t\t\tborderRadius: 4,\n\t\t\t\t\t\t\tbackground: isActive\n\t\t\t\t\t\t\t\t? \"var(--mantine-color-blue-light)\"\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Group gap=\"xs\" justify=\"space-between\" wrap=\"nowrap\">\n\t\t\t\t\t\t\t<Text size=\"sm\">{bucket.label}</Text>\n\t\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\tvariant=\"light\"\n\t\t\t\t\t\t\t\tcolor={bucket.count === 0 ? \"gray\" : \"blue\"}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{bucket.count}\n\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t</Group>\n\t\t\t\t\t</UnstyledButton>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Stack>\n\t);\n}\n","// Filter control for one column. It renders the right Mantine input for the column's filter\n// variant and reads or writes the value straight through the TanStack column. The same control\n// drives state the same way for both the table and the card views. That gives one component and\n// true parity.\n//\n// When facet data is provided, controls adapt: options show counts, zero-count items are dimmed,\n// and range facets render clickable bucket chips above the slider/picker.\n\nimport {\n\tAnchor,\n\tGroup,\n\tInput,\n\tMultiSelect,\n\tNumberInput,\n\tRangeSlider,\n\tSegmentedControl,\n\tSelect,\n\tStack,\n\tText,\n\tTextInput,\n} from \"@mantine/core\";\nimport { DatePickerInput } from \"@mantine/dates\";\nimport type { Column } from \"@tanstack/react-table\";\nimport { resolveColumnLabel } from \"../../core/cardComposition\";\nimport { resolveFormatter } from \"../../core/formatValue\";\nimport type { FacetData, ValueFacet } from \"../../types/facets\";\nimport { FacetBuckets } from \"./FacetBuckets\";\n\n// @ts-expect-error CSS import has no type declarations\nimport \"@mantine/dates/styles.css\";\n\ntype NumOrNull = number | null;\n\nfunction LabelWithClear({\n\tlabel,\n\tonClear,\n}: {\n\tlabel: string;\n\tonClear: () => void;\n}) {\n\treturn (\n\t\t<Group justify=\"space-between\" wrap=\"nowrap\">\n\t\t\t<Text size=\"sm\" fw={500}>\n\t\t\t\t{label}\n\t\t\t</Text>\n\t\t\t<Anchor\n\t\t\t\tcomponent=\"button\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tsize=\"xs\"\n\t\t\t\tc=\"dimmed\"\n\t\t\t\tonClick={onClear}\n\t\t\t>\n\t\t\t\tclear\n\t\t\t</Anchor>\n\t\t</Group>\n\t);\n}\n\nfunction toIsoDate(v: Date | string | null | undefined): string | null {\n\tif (!v) return null;\n\tif (typeof v === \"string\") return v;\n\treturn v.toISOString().split(\"T\")[0] ?? null;\n}\n\nfunction asArray(value: unknown): [unknown, unknown] {\n\treturn Array.isArray(value) ? [value[0], value[1]] : [null, null];\n}\n\nfunction facetSelectData(\n\tfacet: ValueFacet,\n\tfallbackOptions?: { value: string; label: string }[],\n) {\n\tif (facet.values.length > 0) {\n\t\treturn facet.values.map((v) => ({\n\t\t\tvalue: v.value,\n\t\t\tlabel: `${v.label ?? v.value} (${v.count})`,\n\t\t\tdisabled: v.count === 0,\n\t\t}));\n\t}\n\treturn fallbackOptions ?? [];\n}\n\nexport function FilterControl<TData>({\n\tcolumn,\n\tfacet,\n}: {\n\tcolumn: Column<TData>;\n\tfacet?: FacetData;\n}) {\n\tconst meta = column.columnDef.meta?.filter;\n\tif (!meta) return null;\n\n\tconst label = resolveColumnLabel(column);\n\tconst placeholder = meta.placeholder ?? label;\n\tconst value = column.getFilterValue();\n\tconst set = (next: unknown) => column.setFilterValue(next);\n\n\tif (meta.component) {\n\t\tconst Custom = meta.component;\n\t\treturn (\n\t\t\t<Input.Wrapper label={label}>\n\t\t\t\t<Custom value={value} onChange={set} column={column} />\n\t\t\t</Input.Wrapper>\n\t\t);\n\t}\n\n\tconst valueFacet = facet?.type === \"values\" ? facet : undefined;\n\tconst rangeFacet = facet?.type === \"ranges\" ? facet : undefined;\n\n\tswitch (meta.variant) {\n\t\tcase \"select\":\n\t\t\treturn (\n\t\t\t\t<Select\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tclearable\n\t\t\t\t\tdata={\n\t\t\t\t\t\tvalueFacet\n\t\t\t\t\t\t\t? facetSelectData(valueFacet, meta.options)\n\t\t\t\t\t\t\t: (meta.options ?? [])\n\t\t\t\t\t}\n\t\t\t\t\tvalue={(value as string | undefined) ?? null}\n\t\t\t\t\tonChange={(v) => set(v ?? undefined)}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"multiselect\":\n\t\t\treturn (\n\t\t\t\t<MultiSelect\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tdata={\n\t\t\t\t\t\tvalueFacet\n\t\t\t\t\t\t\t? facetSelectData(valueFacet, meta.options)\n\t\t\t\t\t\t\t: (meta.options ?? [])\n\t\t\t\t\t}\n\t\t\t\t\tvalue={(value as string[] | undefined) ?? []}\n\t\t\t\t\tonChange={(v) => set(v.length > 0 ? v : undefined)}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"boolean\": {\n\t\t\tconst current = value == null ? \"all\" : value ? \"yes\" : \"no\";\n\t\t\tconst yesEntry = valueFacet?.values.find((v) => v.value === \"true\");\n\t\t\tconst noEntry = valueFacet?.values.find((v) => v.value === \"false\");\n\t\t\tconst yesLabel = yesEntry ? `Yes (${yesEntry.count})` : \"Yes\";\n\t\t\tconst noLabel = noEntry ? `No (${noEntry.count})` : \"No\";\n\t\t\treturn (\n\t\t\t\t<Input.Wrapper label={label}>\n\t\t\t\t\t<SegmentedControl\n\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\tdata={[\n\t\t\t\t\t\t\t{ value: \"all\", label: \"All\" },\n\t\t\t\t\t\t\t{ value: \"yes\", label: yesLabel },\n\t\t\t\t\t\t\t{ value: \"no\", label: noLabel },\n\t\t\t\t\t\t]}\n\t\t\t\t\t\tvalue={current}\n\t\t\t\t\t\tonChange={(v) => {\n\t\t\t\t\t\t\tif (v === \"all\") set(undefined);\n\t\t\t\t\t\t\telse set(v === \"yes\");\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</Input.Wrapper>\n\t\t\t);\n\t\t}\n\t\tcase \"numberRange\": {\n\t\t\tconst [min, max] = asArray(value) as [NumOrNull, NumOrNull];\n\t\t\tconst sliderMin = meta.min ?? (rangeFacet?.min as number | undefined);\n\t\t\tconst sliderMax = meta.max ?? (rangeFacet?.max as number | undefined);\n\t\t\tconst hasBounds = sliderMin != null && sliderMax != null;\n\t\t\tconst hasValue = value != null;\n\n\t\t\tconst buckets = rangeFacet ? (\n\t\t\t\t<FacetBuckets facet={rangeFacet} value={value} onChange={set} />\n\t\t\t) : null;\n\n\t\t\tconst rangeLabel = hasValue ? (\n\t\t\t\t<LabelWithClear label={label} onClear={() => set(undefined)} />\n\t\t\t) : (\n\t\t\t\tlabel\n\t\t\t);\n\n\t\t\tif (hasBounds) {\n\t\t\t\tconst sliderValue: [number, number] = [\n\t\t\t\t\tmin ?? (sliderMin as number),\n\t\t\t\t\tmax ?? (sliderMax as number),\n\t\t\t\t];\n\t\t\t\tconst dataType = column.columnDef.meta?.dataType;\n\t\t\t\tconst formatFn = dataType\n\t\t\t\t\t? resolveFormatter(dataType, column.columnDef.meta?.format, undefined)\n\t\t\t\t\t: (v: unknown) => String(v);\n\t\t\t\treturn (\n\t\t\t\t\t<Input.Wrapper label={rangeLabel}>\n\t\t\t\t\t\t<Stack gap=\"xs\">\n\t\t\t\t\t\t\t{buckets}\n\t\t\t\t\t\t\t<RangeSlider\n\t\t\t\t\t\t\t\tmin={sliderMin}\n\t\t\t\t\t\t\t\tmax={sliderMax}\n\t\t\t\t\t\t\t\tstep={meta.step ?? 1}\n\t\t\t\t\t\t\t\tvalue={sliderValue}\n\t\t\t\t\t\t\t\tonChange={([lo, hi]) => {\n\t\t\t\t\t\t\t\t\tconst isDefault = lo === sliderMin && hi === sliderMax;\n\t\t\t\t\t\t\t\t\tset(isDefault ? undefined : [lo, hi]);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tlabel={(v) => formatFn(v)}\n\t\t\t\t\t\t\t\tminRange={meta.step ?? 1}\n\t\t\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Input.Wrapper>\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (buckets) {\n\t\t\t\treturn <Input.Wrapper label={rangeLabel}>{buckets}</Input.Wrapper>;\n\t\t\t}\n\n\t\t\tconst update = (next: [NumOrNull, NumOrNull]) =>\n\t\t\t\tset(next[0] == null && next[1] == null ? undefined : next);\n\t\t\tconst toNum = (v: number | string): NumOrNull =>\n\t\t\t\tv === \"\" || v == null ? null : Number(v);\n\t\t\treturn (\n\t\t\t\t<Input.Wrapper label={label}>\n\t\t\t\t\t<Group gap={4} wrap=\"nowrap\">\n\t\t\t\t\t\t<NumberInput\n\t\t\t\t\t\t\taria-label={`${label} minimum`}\n\t\t\t\t\t\t\tplaceholder=\"Min\"\n\t\t\t\t\t\t\tvalue={min ?? \"\"}\n\t\t\t\t\t\t\tonChange={(v) => update([toNum(v), max])}\n\t\t\t\t\t\t\tw={90}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NumberInput\n\t\t\t\t\t\t\taria-label={`${label} maximum`}\n\t\t\t\t\t\t\tplaceholder=\"Max\"\n\t\t\t\t\t\t\tvalue={max ?? \"\"}\n\t\t\t\t\t\t\tonChange={(v) => update([min, toNum(v)])}\n\t\t\t\t\t\t\tw={90}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Group>\n\t\t\t\t</Input.Wrapper>\n\t\t\t);\n\t\t}\n\t\tcase \"date\": {\n\t\t\tconst dateValue = value ? new Date(value as string) : null;\n\t\t\treturn (\n\t\t\t\t<DatePickerInput\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tclearable\n\t\t\t\t\tpopoverProps={{ withinPortal: false }}\n\t\t\t\t\tvalue={dateValue}\n\t\t\t\t\tonChange={(d) => set(toIsoDate(d) ?? undefined)}\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\t\tcase \"dateRange\": {\n\t\t\tconst [start, end] = asArray(value) as [string | null, string | null];\n\t\t\tconst rangeValue: [Date | null, Date | null] = [\n\t\t\t\tstart ? new Date(start) : null,\n\t\t\t\tend ? new Date(end) : null,\n\t\t\t];\n\t\t\tconst dateRangeLabel =\n\t\t\t\tvalue != null ? (\n\t\t\t\t\t<LabelWithClear label={label} onClear={() => set(undefined)} />\n\t\t\t\t) : (\n\t\t\t\t\tlabel\n\t\t\t\t);\n\t\t\treturn (\n\t\t\t\t<Input.Wrapper label={dateRangeLabel}>\n\t\t\t\t\t<Stack gap=\"xs\">\n\t\t\t\t\t\t{rangeFacet && (\n\t\t\t\t\t\t\t<FacetBuckets facet={rangeFacet} value={value} onChange={set} />\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<DatePickerInput\n\t\t\t\t\t\t\ttype=\"range\"\n\t\t\t\t\t\t\tpopoverProps={{ withinPortal: false }}\n\t\t\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\t\t\tclearable\n\t\t\t\t\t\t\tvalue={rangeValue}\n\t\t\t\t\t\t\tonChange={([s, e]) => {\n\t\t\t\t\t\t\t\tconst sv = toIsoDate(s);\n\t\t\t\t\t\t\t\tconst ev = toIsoDate(e);\n\t\t\t\t\t\t\t\tset(sv == null && ev == null ? undefined : [sv, ev]);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t</Input.Wrapper>\n\t\t\t);\n\t\t}\n\t\tdefault:\n\t\t\t// text\n\t\t\treturn (\n\t\t\t\t<TextInput\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tvalue={(value as string | undefined) ?? \"\"}\n\t\t\t\t\tonChange={(e) => set(e.currentTarget.value || undefined)}\n\t\t\t\t/>\n\t\t\t);\n\t}\n}\n","// Filter surface. Up to `inlineThreshold` filterable columns render inline on desktop. Beyond\n// that they collapse into a popover. On mobile, filters open in a bottom drawer.\n\nimport {\n\tButton,\n\tDrawer,\n\tGroup,\n\tPopover,\n\tStack,\n\tuseMantineTheme,\n} from \"@mantine/core\";\nimport { useDisclosure, useMediaQuery } from \"@mantine/hooks\";\nimport { belowBreakpointQuery } from \"../../core/useForceCards\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { CloseIcon, FilterIcon } from \"../icons\";\nimport { FilterControl } from \"./FilterControl\";\n\nfunction ClearFiltersButton<TData>({\n\tview,\n}: {\n\tview: UseDataViewReturn<TData>;\n}) {\n\tconst active = view.state.columnFilters.length > 0;\n\tif (!active) return null;\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"subtle\"\n\t\t\tsize=\"compact-sm\"\n\t\t\tcolor=\"gray\"\n\t\t\tleftSection={<CloseIcon />}\n\t\t\tonClick={() => view.table.resetColumnFilters()}\n\t\t>\n\t\t\tReset filters\n\t\t</Button>\n\t);\n}\n\nfunction filterButtonLabel(activeCount: number): string {\n\treturn activeCount > 0 ? `Filters (${activeCount})` : \"Filters\";\n}\n\nfunction FilterStack<TData>({\n\tview,\n\tcontrols,\n}: {\n\tview: UseDataViewReturn<TData>;\n\tcontrols: React.ReactNode;\n}) {\n\treturn (\n\t\t<Stack gap=\"sm\" style={{ minWidth: 240 }}>\n\t\t\t{controls}\n\t\t\t<Group justify=\"flex-end\">\n\t\t\t\t<ClearFiltersButton view={view} />\n\t\t\t</Group>\n\t\t</Stack>\n\t);\n}\n\nexport function FilterControls<TData>({\n\tview,\n\tinlineThreshold,\n}: {\n\tview: UseDataViewReturn<TData>;\n\tinlineThreshold: number;\n}) {\n\tconst columns = view.filterableColumns;\n\tconst theme = useMantineTheme();\n\tconst isMobile = useMediaQuery(\n\t\tbelowBreakpointQuery(theme.breakpoints.sm),\n\t\tfalse,\n\t);\n\tconst [modalOpen, { open, close }] = useDisclosure(false);\n\n\tif (columns.length === 0) return null;\n\n\tconst controls = columns.map((column) => (\n\t\t<FilterControl\n\t\t\tkey={column.id}\n\t\t\tcolumn={column}\n\t\t\tfacet={view.facets[column.id]}\n\t\t/>\n\t));\n\tconst activeCount = view.state.columnFilters.length;\n\n\tif (isMobile) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<Button variant=\"default\" leftSection={<FilterIcon />} onClick={open}>\n\t\t\t\t\t{filterButtonLabel(activeCount)}\n\t\t\t\t</Button>\n\t\t\t\t<Drawer\n\t\t\t\t\topened={modalOpen}\n\t\t\t\t\tonClose={close}\n\t\t\t\t\ttitle=\"Filters\"\n\t\t\t\t\tposition=\"bottom\"\n\t\t\t\t\tsize=\"auto\"\n\t\t\t\t>\n\t\t\t\t\t<FilterStack view={view} controls={controls} />\n\t\t\t\t</Drawer>\n\t\t\t</>\n\t\t);\n\t}\n\n\tif (columns.length <= inlineThreshold) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{controls}\n\t\t\t\t<ClearFiltersButton view={view} />\n\t\t\t</>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Popover position=\"bottom-start\" closeOnClickOutside={false}>\n\t\t\t<Popover.Target>\n\t\t\t\t<Button variant=\"default\" leftSection={<FilterIcon />}>\n\t\t\t\t\t{filterButtonLabel(activeCount)}\n\t\t\t\t</Button>\n\t\t\t</Popover.Target>\n\t\t\t<Popover.Dropdown>\n\t\t\t\t<FilterStack view={view} controls={controls} />\n\t\t\t</Popover.Dropdown>\n\t\t</Popover>\n\t);\n}\n","// Sort control. It is a Select of sortable columns plus a direction toggle. It drives the same\n// `sorting` state the table headers do, so cards, which have no headers, sort the same way.\n\nimport { ActionIcon, Group, Select } from \"@mantine/core\";\nimport { resolveColumnLabel } from \"../../core/cardComposition\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { SortIcon } from \"../icons\";\n\nexport function SortControl<TData>({\n\tview,\n}: {\n\tview: UseDataViewReturn<TData>;\n}) {\n\tconst { sortableColumns, state, table } = view;\n\tconst primary = state.sorting[0];\n\tconst data = sortableColumns.map((c) => ({\n\t\tvalue: c.id,\n\t\tlabel: resolveColumnLabel(c),\n\t}));\n\n\treturn (\n\t\t<Group gap={4} wrap=\"nowrap\">\n\t\t\t<Select\n\t\t\t\taria-label=\"Sort by\"\n\t\t\t\tplaceholder=\"Sort by\"\n\t\t\t\tclearable\n\t\t\t\tdata={data}\n\t\t\t\tvalue={primary?.id ?? null}\n\t\t\t\tonChange={(id) =>\n\t\t\t\t\ttable.setSorting(id ? [{ id, desc: primary?.desc ?? false }] : [])\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ActionIcon\n\t\t\t\taria-label=\"Toggle sort direction\"\n\t\t\t\tvariant=\"default\"\n\t\t\t\tsize=\"lg\"\n\t\t\t\tdisabled={!primary}\n\t\t\t\tonClick={() =>\n\t\t\t\t\tprimary && table.setSorting([{ id: primary.id, desc: !primary.desc }])\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<SortIcon\n\t\t\t\t\tdirection={primary ? (primary.desc ? \"desc\" : \"asc\") : false}\n\t\t\t\t/>\n\t\t\t</ActionIcon>\n\t\t</Group>\n\t);\n}\n","// View switcher. It is hidden when the responsive rule forces cards and the switcher is locked.\n// Otherwise it is disabled while forced, so the control never lies about the active view.\n\nimport { SegmentedControl } from \"@mantine/core\";\nimport type { ReactNode } from \"react\";\nimport type { UseDataViewReturn } from \"../../types/options\";\n\nexport interface ViewSwitcherProps<TData> {\n\tview: UseDataViewReturn<TData>;\n\tlockSwitcherOnMobile?: boolean;\n\t/** Custom label for the table option. Default: \"Table\". */\n\ttableLabel?: ReactNode;\n\t/** Custom label for the cards option. Default: \"Cards\". */\n\tcardsLabel?: ReactNode;\n}\n\nexport function ViewSwitcher<TData>({\n\tview,\n\tlockSwitcherOnMobile,\n\ttableLabel = \"Table\",\n\tcardsLabel = \"Cards\",\n}: ViewSwitcherProps<TData>) {\n\tif (view.isMobileForced && lockSwitcherOnMobile) return null;\n\n\treturn (\n\t\t<SegmentedControl\n\t\t\taria-label=\"View\"\n\t\t\tvalue={view.view}\n\t\t\tdisabled={view.isMobileForced}\n\t\t\tonChange={(value) => {\n\t\t\t\tif (value === \"table\" || value === \"cards\") view.setView(value);\n\t\t\t}}\n\t\t\tdata={[\n\t\t\t\t{ value: \"table\", label: tableLabel as string },\n\t\t\t\t{ value: \"cards\", label: cardsLabel as string },\n\t\t\t]}\n\t\t/>\n\t);\n}\n","// Column visibility and pinning menu. Toggling a column hides both its table column and its\n// card field. Pin controls let users freeze columns to the left or right edge of the table.\n\nimport {\n\tActionIcon,\n\tButton,\n\tCheckbox,\n\tGroup,\n\tMenu,\n\tStack,\n} from \"@mantine/core\";\nimport type { Column } from \"@tanstack/react-table\";\nimport { resolveColumnLabel } from \"../../core/cardComposition\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { ChevronDownIcon, PinLeftIcon, PinRightIcon } from \"../icons\";\n\nfunction PinControls<TData>({ column }: { column: Column<TData> }) {\n\tif (!column.getCanPin()) return null;\n\tconst pinned = column.getIsPinned();\n\treturn (\n\t\t<Group gap={2}>\n\t\t\t<ActionIcon\n\t\t\t\tsize=\"xs\"\n\t\t\t\tvariant={pinned === \"left\" ? \"filled\" : \"subtle\"}\n\t\t\t\tcolor={pinned === \"left\" ? \"blue\" : \"gray\"}\n\t\t\t\taria-label={`Pin ${resolveColumnLabel(column)} left`}\n\t\t\t\tonClick={() => column.pin(pinned === \"left\" ? false : \"left\")}\n\t\t\t>\n\t\t\t\t<PinLeftIcon />\n\t\t\t</ActionIcon>\n\t\t\t<ActionIcon\n\t\t\t\tsize=\"xs\"\n\t\t\t\tvariant={pinned === \"right\" ? \"filled\" : \"subtle\"}\n\t\t\t\tcolor={pinned === \"right\" ? \"blue\" : \"gray\"}\n\t\t\t\taria-label={`Pin ${resolveColumnLabel(column)} right`}\n\t\t\t\tonClick={() => column.pin(pinned === \"right\" ? false : \"right\")}\n\t\t\t>\n\t\t\t\t<PinRightIcon />\n\t\t\t</ActionIcon>\n\t\t</Group>\n\t);\n}\n\nexport function VisibilityMenu<TData>({\n\tview,\n}: {\n\tview: UseDataViewReturn<TData>;\n}) {\n\tconst columns = view.table.getAllLeafColumns().filter((c) => c.getCanHide());\n\tif (columns.length === 0) return null;\n\n\treturn (\n\t\t<Menu closeOnItemClick={false} withinPortal position=\"bottom-end\">\n\t\t\t<Menu.Target>\n\t\t\t\t<Button variant=\"default\" rightSection={<ChevronDownIcon />}>\n\t\t\t\t\tColumns\n\t\t\t\t</Button>\n\t\t\t</Menu.Target>\n\t\t\t<Menu.Dropdown>\n\t\t\t\t<Stack gap=\"xs\" p=\"xs\">\n\t\t\t\t\t{columns.map((column) => (\n\t\t\t\t\t\t<Group\n\t\t\t\t\t\t\tkey={column.id}\n\t\t\t\t\t\t\tgap=\"xs\"\n\t\t\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\t\t\twrap=\"nowrap\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\tlabel={resolveColumnLabel(column)}\n\t\t\t\t\t\t\t\tchecked={column.getIsVisible()}\n\t\t\t\t\t\t\t\tonChange={(e) =>\n\t\t\t\t\t\t\t\t\tcolumn.toggleVisibility(e.currentTarget.checked)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<PinControls column={column} />\n\t\t\t\t\t\t</Group>\n\t\t\t\t\t))}\n\t\t\t\t</Stack>\n\t\t\t</Menu.Dropdown>\n\t\t</Menu>\n\t);\n}\n","// Toolbar. Search, filters, sort, column visibility, and the view switch are all shared\n// affordances that drive one core state, so they behave the same for the table and the cards.\n// Each section can be turned off, and sensible defaults derive from the column model.\n\nimport { CloseButton, Group, type GroupProps, TextInput } from \"@mantine/core\";\nimport type { ReactNode } from \"react\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { SearchIcon } from \"../icons\";\nimport { FilterControls } from \"./FilterControls\";\nimport { SortControl } from \"./SortControl\";\nimport { ViewSwitcher } from \"./ViewSwitcher\";\nimport { VisibilityMenu } from \"./VisibilityMenu\";\n\nexport interface DataToolbarProps<TData> extends Omit<GroupProps, \"children\"> {\n\t/** The `useDataView` instance to drive. */\n\tview: UseDataViewReturn<TData>;\n\tsearchPlaceholder?: string;\n\t/** Filterable columns up to this count render inline. More than that collapse into a popover. */\n\tfilterInlineThreshold?: number;\n\tlockSwitcherOnMobile?: boolean;\n\tshowSearch?: boolean;\n\tshowFilters?: boolean;\n\tshowSort?: boolean;\n\tshowVisibility?: boolean;\n\tshowViewSwitcher?: boolean;\n\t/** Disable search, filter, and sort controls while data is loading. Default: true. */\n\tdisableWhileLoading?: boolean;\n\t/** Content injected at the start of the left control group (before search). */\n\tleftSection?: ReactNode;\n\t/** Content injected at the end of the right control group (after view switcher). */\n\trightSection?: ReactNode;\n}\n\nexport function DataToolbar<TData>({\n\tview,\n\tsearchPlaceholder = \"Search…\",\n\tfilterInlineThreshold = 3,\n\tlockSwitcherOnMobile,\n\tshowSearch,\n\tshowFilters,\n\tshowSort,\n\tshowVisibility,\n\tshowViewSwitcher,\n\tdisableWhileLoading = true,\n\tleftSection,\n\trightSection,\n\t...groupProps\n}: DataToolbarProps<TData>) {\n\tconst { table, state } = view;\n\tconst loading = disableWhileLoading && view.status === \"loading\";\n\tconst searchOn = showSearch ?? table.options.enableGlobalFilter !== false;\n\tconst filtersOn = showFilters ?? view.filterableColumns.length > 0;\n\tconst sortOn = showSort ?? view.sortableColumns.length > 0;\n\tconst visibilityOn = showVisibility ?? true;\n\tconst switcherOn = showViewSwitcher ?? true;\n\n\treturn (\n\t\t<Group justify=\"space-between\" wrap=\"wrap\" gap=\"sm\" {...groupProps}>\n\t\t\t<Group wrap=\"wrap\" gap=\"sm\">\n\t\t\t\t{leftSection}\n\t\t\t\t{searchOn && (\n\t\t\t\t\t<TextInput\n\t\t\t\t\t\taria-label=\"Search\"\n\t\t\t\t\t\tplaceholder={searchPlaceholder}\n\t\t\t\t\t\tleftSection={<SearchIcon />}\n\t\t\t\t\t\tvalue={state.globalFilter}\n\t\t\t\t\t\tonChange={(e) => table.setGlobalFilter(e.currentTarget.value)}\n\t\t\t\t\t\trightSection={\n\t\t\t\t\t\t\tstate.globalFilter ? (\n\t\t\t\t\t\t\t\t<CloseButton\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\taria-label=\"Clear search\"\n\t\t\t\t\t\t\t\t\tonClick={() => table.setGlobalFilter(\"\")}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t) : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<fieldset\n\t\t\t\t\tdisabled={loading}\n\t\t\t\t\tstyle={{ display: \"contents\", border: \"none\", padding: 0, margin: 0 }}\n\t\t\t\t>\n\t\t\t\t\t{filtersOn && (\n\t\t\t\t\t\t<FilterControls\n\t\t\t\t\t\t\tview={view}\n\t\t\t\t\t\t\tinlineThreshold={filterInlineThreshold}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{sortOn && <SortControl view={view} />}\n\t\t\t\t</fieldset>\n\t\t\t</Group>\n\t\t\t<fieldset\n\t\t\t\tdisabled={loading}\n\t\t\t\tstyle={{ display: \"contents\", border: \"none\", padding: 0, margin: 0 }}\n\t\t\t>\n\t\t\t\t<Group wrap=\"wrap\" gap=\"sm\">\n\t\t\t\t\t{visibilityOn && <VisibilityMenu view={view} />}\n\t\t\t\t\t{switcherOn && (\n\t\t\t\t\t\t<ViewSwitcher\n\t\t\t\t\t\t\tview={view}\n\t\t\t\t\t\t\tlockSwitcherOnMobile={lockSwitcherOnMobile}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{rightSection}\n\t\t\t\t</Group>\n\t\t\t</fieldset>\n\t\t</Group>\n\t);\n}\n","// Shared context for the compound <DataViewer> API. The root provides the `useDataView` instance\n// once, along with the config that cuts across parts such as slots and card options. The\n// subcomponents read it, so a consumer writes `<DataViewer.Body />` instead of threading `view`\n// through every child.\n\nimport { createContext, useContext } from \"react\";\nimport type { ComposeCardOptions } from \"../../core/cardComposition\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport type { DataCardsProps } from \"../DataCards\";\nimport type { DataViewSlots } from \"../types\";\n\nexport interface DataViewContextValue<TData> {\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n\trenderCard?: DataCardsProps<TData>[\"renderCard\"];\n\tfallbackRole?: ComposeCardOptions[\"fallbackRole\"];\n\tlockSwitcherOnMobile?: boolean;\n\tanimateRows?: boolean;\n}\n\n// React context cannot be generic. Store it as `unknown` and narrow it again in the hook.\nconst DataViewContext = createContext<DataViewContextValue<unknown> | null>(\n\tnull,\n);\n\nexport const DataViewProvider = DataViewContext.Provider;\n\nexport function useDataViewContext<TData>(): DataViewContextValue<TData> {\n\tconst ctx = useContext(DataViewContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"DataViewer.Toolbar / DataViewer.Body / DataViewer.Pagination must be rendered inside <DataViewer>.\",\n\t\t);\n\t}\n\treturn ctx as DataViewContextValue<TData>;\n}\n","// Orchestrator. `<DataViewer view={dv}>` provides context and a default vertical layout. The\n// compound parts, `DataViewer.Toolbar`, `.BulkActions`, `.Body`, and `.Pagination`, project the\n// shared state. With no children it renders the full default layout. Pass children to compose\n// your own.\n\nimport { Stack, type StackProps } from \"@mantine/core\";\nimport { type ReactNode, useMemo } from \"react\";\nimport type { UseDataViewReturn } from \"../../types/options\";\nimport { DataBulkActions, type DataBulkActionsProps } from \"../DataBulkActions\";\nimport { DataCards, type DataCardsProps } from \"../DataCards\";\nimport { DataPagination, type DataPaginationProps } from \"../DataPagination\";\nimport { DataTable, type DataTableProps } from \"../DataTable\";\nimport { DataToolbar, type DataToolbarProps } from \"../DataToolbar\";\nimport type { DataViewSlots } from \"../types\";\nimport {\n\ttype DataViewContextValue,\n\tDataViewProvider,\n\tuseDataViewContext,\n} from \"./context\";\n\nexport interface DataViewerProps<TData> extends Omit<StackProps, \"children\"> {\n\t/** The `useDataView` instance to project. */\n\tview: UseDataViewReturn<TData>;\n\tslots?: DataViewSlots<TData>;\n\trenderCard?: DataCardsProps<TData>[\"renderCard\"];\n\tfallbackRole?: DataCardsProps<TData>[\"fallbackRole\"];\n\tlockSwitcherOnMobile?: boolean;\n\t/** Animate row enter/exit instead of showing skeletons. Default: false. */\n\tanimateRows?: boolean;\n\t/** Custom composition. It defaults to Toolbar, BulkActions, Body, and Pagination. */\n\tchildren?: ReactNode;\n}\n\nexport function DataViewer<TData>({\n\tview,\n\tslots,\n\trenderCard,\n\tfallbackRole,\n\tlockSwitcherOnMobile,\n\tanimateRows,\n\tchildren,\n\t...stackProps\n}: DataViewerProps<TData>) {\n\tconst ctx = useMemo<DataViewContextValue<TData>>(\n\t\t() => ({\n\t\t\tview,\n\t\t\tslots,\n\t\t\trenderCard,\n\t\t\tfallbackRole,\n\t\t\tlockSwitcherOnMobile,\n\t\t\tanimateRows,\n\t\t}),\n\t\t[view, slots, renderCard, fallbackRole, lockSwitcherOnMobile, animateRows],\n\t);\n\n\treturn (\n\t\t<DataViewProvider value={ctx as DataViewContextValue<unknown>}>\n\t\t\t<Stack {...stackProps}>\n\t\t\t\t{children ?? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<DataViewToolbar />\n\t\t\t\t\t\t<DataViewBulkActions />\n\t\t\t\t\t\t<DataViewBody />\n\t\t\t\t\t\t<DataViewPagination />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</DataViewProvider>\n\t);\n}\n\nexport type DataViewerToolbarProps<TData> = Omit<\n\tDataToolbarProps<TData>,\n\t\"view\"\n>;\n\nfunction DataViewToolbar<TData>(props: DataViewerToolbarProps<TData>) {\n\tconst { view, lockSwitcherOnMobile } = useDataViewContext<TData>();\n\treturn (\n\t\t<DataToolbar\n\t\t\tview={view}\n\t\t\tlockSwitcherOnMobile={lockSwitcherOnMobile}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport interface DataViewerBodyProps<TData> {\n\ttableProps?: Omit<DataTableProps<TData>, \"view\" | \"slots\">;\n\tcardsProps?: Omit<\n\t\tDataCardsProps<TData>,\n\t\t\"view\" | \"slots\" | \"renderCard\" | \"fallbackRole\"\n\t>;\n}\n\nfunction DataViewBody<TData>({\n\ttableProps,\n\tcardsProps,\n}: DataViewerBodyProps<TData>) {\n\tconst { view, slots, renderCard, fallbackRole, animateRows } =\n\t\tuseDataViewContext<TData>();\n\treturn view.view === \"cards\" ? (\n\t\t<DataCards\n\t\t\tview={view}\n\t\t\tslots={slots}\n\t\t\trenderCard={renderCard}\n\t\t\tfallbackRole={fallbackRole}\n\t\t\tanimateRows={animateRows}\n\t\t\t{...cardsProps}\n\t\t/>\n\t) : (\n\t\t<DataTable\n\t\t\tview={view}\n\t\t\tslots={slots}\n\t\t\tanimateRows={animateRows}\n\t\t\t{...tableProps}\n\t\t/>\n\t);\n}\n\nfunction DataViewPagination<TData>(\n\tprops: Omit<DataPaginationProps<TData>, \"view\">,\n) {\n\tconst { view } = useDataViewContext<TData>();\n\treturn <DataPagination view={view} {...props} />;\n}\n\nfunction DataViewBulkActions<TData>(\n\tprops: Omit<DataBulkActionsProps<TData>, \"view\" | \"slots\">,\n) {\n\tconst { view, slots } = useDataViewContext<TData>();\n\treturn <DataBulkActions view={view} slots={slots} {...props} />;\n}\n\nDataViewer.Toolbar = DataViewToolbar;\nDataViewer.BulkActions = DataViewBulkActions;\nDataViewer.Body = DataViewBody;\nDataViewer.Pagination = DataViewPagination;\n","import { createColumnHelper } from \"@tanstack/react-table\";\nimport type {\n\tCardRole,\n\tColumnAlign,\n\tColumnDataType,\n\tColumnFilterMeta,\n\tColumnFormatOption,\n\tDataColumnDef,\n\tFilterOption,\n} from \"../types/column\";\n\ntype Field<TData> = keyof TData & string;\n\n// biome-ignore lint/suspicious/noExplicitAny: cell renderer generic varies per column\ntype CellFn<TData> = DataColumnDef<TData> extends { cell?: infer C } ? C : any;\n\nexport interface ColOptions<TData> {\n\theader?: string;\n\tcard?: CardRole;\n\tcardOrder?: number;\n\tfilter?: false | Partial<ColumnFilterMeta>;\n\tformat?: ColumnFormatOption;\n\talign?: ColumnAlign;\n\tcell?: CellFn<TData>;\n\tenableSorting?: boolean;\n\toptions?: FilterOption[];\n\t/** Column width in pixels. Sets TanStack's `size` property. */\n\twidth?: number;\n}\n\nexport function humanize(field: string): string {\n\treturn field\n\t\t.replace(/_/g, \" \")\n\t\t.replace(/([a-z])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\ninterface PresetConfig {\n\tdataType?: ColumnDataType;\n\tfilterVariant?: ColumnFilterMeta[\"variant\"];\n\talign?: ColumnAlign;\n}\n\nconst PRESETS: Record<string, PresetConfig> = {\n\ttext: { dataType: \"text\", filterVariant: \"text\" },\n\tnumber: { dataType: \"number\", filterVariant: \"numberRange\", align: \"right\" },\n\tcurrency: {\n\t\tdataType: \"currency\",\n\t\tfilterVariant: \"numberRange\",\n\t\talign: \"right\",\n\t},\n\tdate: { dataType: \"date\", filterVariant: \"dateRange\" },\n\tboolean: { dataType: \"boolean\", filterVariant: \"boolean\" },\n\tselect: { filterVariant: \"select\" },\n\tmultiselect: { filterVariant: \"multiselect\" },\n};\n\nexport class ColumnBuilder<TData> {\n\tprivate cols: DataColumnDef<TData>[] = [];\n\tprivate helper = createColumnHelper<TData>();\n\n\tprivate add(\n\t\tpreset: string,\n\t\tfield: Field<TData>,\n\t\topts?: ColOptions<TData>,\n\t): this {\n\t\tconst config = PRESETS[preset];\n\t\tif (!config) throw new Error(`Unknown preset: ${preset}`);\n\n\t\tconst label = opts?.header ?? humanize(field);\n\t\tconst align = opts?.align ?? config.align;\n\n\t\tlet filter: ColumnFilterMeta | undefined;\n\t\tif (opts?.filter === false) {\n\t\t\tfilter = undefined;\n\t\t} else {\n\t\t\tconst base = {\n\t\t\t\tvariant: config.filterVariant,\n\t\t\t\t...(opts?.options ? { options: opts.options } : {}),\n\t\t\t} as ColumnFilterMeta;\n\t\t\tfilter = opts?.filter\n\t\t\t\t? ({ ...base, ...opts.filter } as ColumnFilterMeta)\n\t\t\t\t: base;\n\t\t}\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: TanStack accessor expects any for heterogeneous columns\n\t\tconst colDef = (this.helper as any).accessor(field, {\n\t\t\theader: label,\n\t\t\t...(opts?.cell ? { cell: opts.cell } : {}),\n\t\t\t...(opts?.enableSorting === false ? { enableSorting: false } : {}),\n\t\t\t...(opts?.width != null ? { size: opts.width } : {}),\n\t\t\tmeta: {\n\t\t\t\tlabel,\n\t\t\t\t...(config.dataType ? { dataType: config.dataType } : {}),\n\t\t\t\t...(align ? { align } : {}),\n\t\t\t\t...(filter ? { filter } : {}),\n\t\t\t\t...(opts?.format ? { format: opts.format } : {}),\n\t\t\t\t...(opts?.card\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcard: {\n\t\t\t\t\t\t\t\trole: opts.card,\n\t\t\t\t\t\t\t\t...(opts.cardOrder != null ? { order: opts.cardOrder } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t});\n\n\t\tthis.cols.push(colDef);\n\t\treturn this;\n\t}\n\n\ttext(field: Field<TData>, opts?: ColOptions<TData>): this {\n\t\treturn this.add(\"text\", field, opts);\n\t}\n\n\tnumber(field: Field<TData>, opts?: ColOptions<TData>): this {\n\t\treturn this.add(\"number\", field, opts);\n\t}\n\n\tcurrency(field: Field<TData>, opts?: ColOptions<TData>): this {\n\t\treturn this.add(\"currency\", field, opts);\n\t}\n\n\tdate(field: Field<TData>, opts?: ColOptions<TData>): this {\n\t\treturn this.add(\"date\", field, opts);\n\t}\n\n\tboolean(field: Field<TData>, opts?: ColOptions<TData>): this {\n\t\treturn this.add(\"boolean\", field, opts);\n\t}\n\n\tselect(\n\t\tfield: Field<TData>,\n\t\topts: ColOptions<TData> & { options: FilterOption[] },\n\t): this {\n\t\treturn this.add(\"select\", field, opts);\n\t}\n\n\tmultiselect(\n\t\tfield: Field<TData>,\n\t\topts: ColOptions<TData> & { options: FilterOption[] },\n\t): this {\n\t\treturn this.add(\"multiselect\", field, opts);\n\t}\n\n\tcustom(colDef: DataColumnDef<TData>): this {\n\t\tthis.cols.push(colDef);\n\t\treturn this;\n\t}\n\n\tbuild(): DataColumnDef<TData>[] {\n\t\treturn this.cols;\n\t}\n}\n\nexport function col<TData>(): ColumnBuilder<TData> {\n\treturn new ColumnBuilder<TData>();\n}\n","import type { Table } from \"@tanstack/react-table\";\nimport type { ColumnDataType, ColumnFormatOption } from \"../types/column\";\nimport { resolveColumnLabel } from \"./cardComposition\";\nimport { resolveFormatter } from \"./formatValue\";\n\nfunction escapeCsv(value: unknown): string {\n\tconst str = value == null ? \"\" : String(value);\n\tif (str.includes(\",\") || str.includes('\"') || str.includes(\"\\n\")) {\n\t\treturn `\"${str.replace(/\"/g, '\"\"')}\"`;\n\t}\n\treturn str;\n}\n\nexport interface ExportCsvOptions {\n\tfilename?: string;\n\tseparator?: string;\n\t/** When true, applies column dataType formatters to exported values. Default: false (raw values). */\n\tformatted?: boolean;\n\tformatDefaults?: Partial<Record<ColumnDataType, ColumnFormatOption>>;\n}\n\nexport function exportCsv<TData>(\n\ttable: Table<TData>,\n\toptions?: ExportCsvOptions,\n): void {\n\tconst {\n\t\tfilename = \"export.csv\",\n\t\tseparator = \",\",\n\t\tformatted = false,\n\t\tformatDefaults,\n\t} = options ?? {};\n\tconst columns = table\n\t\t.getVisibleLeafColumns()\n\t\t.filter((c) => c.id !== \"_select\");\n\tconst header = columns.map((c) => escapeCsv(resolveColumnLabel(c)));\n\tconst rows = table.getRowModel().rows.map((row) =>\n\t\tcolumns.map((col) => {\n\t\t\tconst cell = row.getAllCells().find((c) => c.column.id === col.id);\n\t\t\tconst raw = cell?.getValue();\n\t\t\tif (formatted && col.columnDef.meta?.dataType) {\n\t\t\t\tconst formatter = resolveFormatter(\n\t\t\t\t\tcol.columnDef.meta.dataType,\n\t\t\t\t\tcol.columnDef.meta.format,\n\t\t\t\t\tformatDefaults,\n\t\t\t\t);\n\t\t\t\treturn escapeCsv(formatter(raw));\n\t\t\t}\n\t\t\treturn escapeCsv(raw);\n\t\t}),\n\t);\n\n\tconst csv = [header, ...rows].map((r) => r.join(separator)).join(\"\\n\");\n\tconst blob = new Blob([csv], { type: \"text/csv;charset=utf-8;\" });\n\tconst url = URL.createObjectURL(blob);\n\tconst link = document.createElement(\"a\");\n\tlink.href = url;\n\tlink.download = filename;\n\tlink.click();\n\tURL.revokeObjectURL(url);\n}\n","import type { CellContext, HeaderContext, Table } from \"@tanstack/react-table\";\nimport type { ViewMode } from \"../types/state\";\n\n/** Get the current view mode from a cell context. */\nexport function getViewMode<TData>(\n\tctx:\n\t\t| CellContext<TData, unknown>\n\t\t| HeaderContext<TData, unknown>\n\t\t| Table<TData>,\n): ViewMode {\n\tconst table = \"table\" in ctx ? ctx.table : ctx;\n\treturn (table.options.meta?.viewMode as ViewMode) ?? \"table\";\n}\n","// The loop between the URL and state. Hydration runs synchronously in the state initializer of\n// `useDataView`, so the first request already reflects the URL. This hook owns the rest. It\n// writes on every change and subscribes to back and forward navigation.\n\nimport { useEffect, useRef } from \"react\";\nimport type { ColumnFilterMeta } from \"../types/column\";\nimport type { UrlSyncOptions } from \"../types/options\";\nimport type { DataViewState } from \"../types/state\";\nimport {\n\tdefaultUrlSerializer,\n\tdeserializeParams,\n\tresolveInclude,\n\ttype SyncableKey,\n\tserializeState,\n\tstripManagedParams,\n} from \"./serializer\";\nimport type { UrlSerializer, UrlStateAdapter } from \"./types\";\n\ntype FilterMetaLookup = (id: string) => ColumnFilterMeta | undefined;\n\nexport interface ResolvedUrlConfig {\n\tadapter: UrlStateAdapter;\n\tserializer: UrlSerializer;\n\tinclude: SyncableKey[];\n}\n\n/** Merges the consumer's `urlSync` options with defaults, or returns `null` when sync is off. */\nexport function resolveUrlConfig(\n\turlSync: UrlSyncOptions | undefined,\n): ResolvedUrlConfig | null {\n\tif (!urlSync) return null;\n\treturn {\n\t\tadapter: urlSync.adapter,\n\t\tserializer: { ...defaultUrlSerializer, ...urlSync.serialize },\n\t\tinclude: resolveInclude(urlSync.include),\n\t};\n}\n\n/** Reads the URL once and produces the initial state patch. It is safe to call during render. */\nexport function hydrateFromUrl(\n\tconfig: ResolvedUrlConfig | null,\n\tcurrent: DataViewState,\n\tgetFilterMeta: FilterMetaLookup,\n): Partial<DataViewState> {\n\tif (!config) return {};\n\ttry {\n\t\treturn deserializeParams(config.adapter.read(), {\n\t\t\tserializer: config.serializer,\n\t\t\tinclude: config.include,\n\t\t\tgetFilterMeta,\n\t\t\tcurrent,\n\t\t});\n\t} catch {\n\t\t// An adapter that touches `window` on the server or first render must not crash this.\n\t\treturn {};\n\t}\n}\n\ninterface UseUrlSyncArgs {\n\tconfig: ResolvedUrlConfig | null;\n\tstate: DataViewState;\n\tapplyPatch: (patch: Partial<DataViewState>) => void;\n\tgetFilterMeta: FilterMetaLookup;\n}\n\nexport function useUrlSync({\n\tconfig,\n\tstate,\n\tapplyPatch,\n\tgetFilterMeta,\n}: UseUrlSyncArgs): void {\n\t// Keep the latest closures in refs so the effects do not bind again on every render. This\n\t// matters because a consumer may pass a freshly built adapter or urlSync object each render.\n\tconst stateRef = useRef(state);\n\tstateRef.current = state;\n\tconst applyPatchRef = useRef(applyPatch);\n\tapplyPatchRef.current = applyPatch;\n\tconst getFilterMetaRef = useRef(getFilterMeta);\n\tgetFilterMetaRef.current = getFilterMeta;\n\tconst configRef = useRef(config);\n\tconfigRef.current = config;\n\n\t// Write managed params on change. Merge them over any unrelated params already in the URL and\n\t// drop managed params that no longer apply, such as a cleared filter. The `replace` flag keeps\n\t// the history clean, and back and forward still restore entries created by real navigation.\n\tconst params = config\n\t\t? serializeState(state, {\n\t\t\t\tserializer: config.serializer,\n\t\t\t\tinclude: config.include,\n\t\t\t\tgetFilterMeta,\n\t\t\t})\n\t\t: null;\n\t// `paramsKey` is the only trigger. Writes happen only when the managed params actually change,\n\t// no matter how often `config` or `params` are created again.\n\tconst paramsKey = params ? JSON.stringify(params) : \"\";\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: paramsKey is the intended trigger; params/config are read via closure/ref\n\tuseEffect(() => {\n\t\tconst cfg = configRef.current;\n\t\tif (!cfg || !params) return;\n\t\tconst current = cfg.adapter.read();\n\t\tconst preserved = stripManagedParams(current, cfg.serializer, cfg.include);\n\t\tcfg.adapter.write({ ...preserved, ...params }, { replace: true });\n\t}, [paramsKey]);\n\n\t// On back, forward, or any external navigation, read the URL again and apply it.\n\tuseEffect(() => {\n\t\tif (!config) return;\n\t\tconst { adapter, serializer, include } = config;\n\t\treturn adapter.subscribe?.(() => {\n\t\t\tconst patch = deserializeParams(adapter.read(), {\n\t\t\t\tserializer,\n\t\t\t\tinclude,\n\t\t\t\tgetFilterMeta: getFilterMetaRef.current,\n\t\t\t\tcurrent: stateRef.current,\n\t\t\t});\n\t\t\tapplyPatchRef.current(patch);\n\t\t});\n\t}, [config]);\n}\n","// Derives the renderer facing status from the raw fetch lifecycle plus the current page and\n// filter state. Both presentations switch over this value. That keeps the four states (loading,\n// empty, filtered empty, and error) rendering consistently. The logic lives here so both views\n// share it.\n\nimport type { DataViewState, DataViewStatus, Status } from \"../types/state\";\n\nexport function isFiltered(state: DataViewState): boolean {\n\treturn state.columnFilters.length > 0 || state.globalFilter.trim() !== \"\";\n}\n\ninterface ResolveArgs {\n\tstatus: Status;\n\terror: unknown;\n\t/** Number of rows on the current page after a successful fetch. */\n\tpageRowCount: number;\n\tstate: DataViewState;\n}\n\nexport function resolveDataViewStatus({\n\tstatus,\n\terror,\n\tpageRowCount,\n\tstate,\n}: ResolveArgs): DataViewStatus {\n\tif (status === \"error\") return { phase: \"error\", error };\n\t// Before the first fetch the status is `idle`. It shows the same skeleton as `loading` because\n\t// a request is about to happen.\n\tif (status === \"loading\" || status === \"idle\") return { phase: \"loading\" };\n\tif (pageRowCount === 0) {\n\t\treturn isFiltered(state) ? { phase: \"empty-filtered\" } : { phase: \"empty\" };\n\t}\n\treturn { phase: \"ready\" };\n}\n","// The headless core. It owns all feature state and wraps TanStack Table v8 with every `manual*`\n// flag turned on. It emits a normalized `DataViewRequest` whenever the state the server cares\n// about changes. The presentations and the toolbar are pure projections of what it returns.\n\nimport {\n\ttype ColumnFiltersState,\n\ttype ColumnPinningState,\n\tfunctionalUpdate,\n\tgetCoreRowModel,\n\ttype OnChangeFn,\n\ttype PaginationState,\n\ttype RowSelectionState,\n\ttype SortingState,\n\tuseReactTable,\n\ttype VisibilityState,\n} from \"@tanstack/react-table\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ColumnFilterMeta, DataColumnDef } from \"../types/column\";\nimport type {\n\tDebounceOptions,\n\tUseDataViewOptions,\n\tUseDataViewReturn,\n} from \"../types/options\";\nimport type { DataViewRequest } from \"../types/request\";\nimport type { DataViewState, ViewMode } from \"../types/state\";\nimport {\n\thydrateFromUrl,\n\tresolveUrlConfig,\n\tuseUrlSync,\n} from \"../url/useUrlSync\";\nimport { exportCsv as exportCsvFn } from \"./exportCsv\";\nimport { resolveFormatter } from \"./formatValue\";\nimport { resolveDataViewStatus } from \"./resolveStatus\";\nimport { useForceCards } from \"./useForceCards\";\n\n/** Default debounce in milliseconds for each field when emitting filter and search requests. */\nconst DEFAULT_DEBOUNCE_MS = 300;\nconst DEFAULT_PAGE_SIZES = [10, 25, 50, 100];\nconst DEFAULT_PAGE_SIZE = 10;\n\ninterface ResolvedDebounce {\n\tglobalFilter: number;\n\tcolumnFilters: number;\n}\n\nfunction resolveDebounce(\n\tdebounce: DebounceOptions | undefined,\n): ResolvedDebounce {\n\tif (debounce == null) {\n\t\treturn {\n\t\t\tglobalFilter: DEFAULT_DEBOUNCE_MS,\n\t\t\tcolumnFilters: DEFAULT_DEBOUNCE_MS,\n\t\t};\n\t}\n\tif (typeof debounce === \"number\") {\n\t\treturn { globalFilter: debounce, columnFilters: debounce };\n\t}\n\treturn {\n\t\tglobalFilter: debounce.globalFilter ?? DEFAULT_DEBOUNCE_MS,\n\t\tcolumnFilters: debounce.columnFilters ?? DEFAULT_DEBOUNCE_MS,\n\t};\n}\n\nfunction resolveColumnId<TData>(col: DataColumnDef<TData>): string | undefined {\n\tif (col.id) return col.id;\n\tif (\"accessorKey\" in col && col.accessorKey != null) {\n\t\treturn String(col.accessorKey);\n\t}\n\treturn undefined;\n}\n\n/** Maps a column id to its filter meta so the URL serializer can pick the codec for each variant. */\nfunction buildFilterMetaLookup<TData>(\n\tcolumns: DataColumnDef<TData>[],\n): (id: string) => ColumnFilterMeta | undefined {\n\tconst map = new Map<string, ColumnFilterMeta>();\n\tfor (const col of columns) {\n\t\tconst id = resolveColumnId(col);\n\t\tconst filter = col.meta?.filter;\n\t\tif (id && filter) map.set(id, filter);\n\t}\n\treturn (id) => map.get(id);\n}\n\nfunction buildDefaultState<TData>(\n\toptions: UseDataViewOptions<TData>,\n): DataViewState {\n\tconst pageSize = options.pageSizeOptions?.[0] ?? DEFAULT_PAGE_SIZE;\n\treturn {\n\t\tpagination: { pageIndex: 0, pageSize },\n\t\tsorting: [],\n\t\tcolumnFilters: [],\n\t\tglobalFilter: \"\",\n\t\trowSelection: {},\n\t\tcolumnVisibility: {},\n\t\tcolumnPinning: { left: [], right: [] },\n\t\tview: options.defaultView ?? \"table\",\n\t\t...options.initialState,\n\t};\n}\n\nexport function useDataView<TData>(\n\toptions: UseDataViewOptions<TData>,\n): UseDataViewReturn<TData> {\n\tconst {\n\t\tcolumns: rawColumns,\n\t\trows,\n\t\trowCount,\n\t\tstatus,\n\t\terror,\n\t\tgetRowId,\n\t\tonRequestChange,\n\t\tstate: controlledState,\n\t\tonStateChange,\n\t\tenableRowSelection,\n\t\tenableGlobalFilter = true,\n\t\tdebounce,\n\t\tresponsive,\n\t\tformatDefaults,\n\t\tfacets: facetsInput,\n\t\tparams: paramsInput,\n\t} = options;\n\n\tconst facets = facetsInput ?? {};\n\tconst paramsKey = paramsInput ? JSON.stringify(paramsInput) : \"\";\n\tconst params = paramsInput ?? {};\n\n\tconst columns = useMemo(\n\t\t() =>\n\t\t\trawColumns.map((col) => {\n\t\t\t\tconst dataType = col.meta?.dataType;\n\t\t\t\tif (!dataType || col.cell) return col;\n\t\t\t\tconst formatter = resolveFormatter(\n\t\t\t\t\tdataType,\n\t\t\t\t\tcol.meta?.format,\n\t\t\t\t\tformatDefaults,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\t...col,\n\t\t\t\t\tcell: (ctx: { getValue: () => unknown }) => formatter(ctx.getValue()),\n\t\t\t\t};\n\t\t\t}),\n\t\t[rawColumns, formatDefaults],\n\t);\n\n\t// URL sync setup. Both pieces must exist before the state initializer runs. That way the\n\t// first render already reflects the URL, and so does the first request it emits.\n\tconst getFilterMeta = useMemo(\n\t\t() => buildFilterMetaLookup(columns),\n\t\t[columns],\n\t);\n\tconst urlConfig = useMemo(\n\t\t() => resolveUrlConfig(options.urlSync),\n\t\t[options.urlSync],\n\t);\n\n\t// State ownership. The hook keeps internal state that controlled slices can override. On the\n\t// first render it also hydrates that state from the URL when sync is enabled.\n\tconst [internalState, setInternalState] = useState<DataViewState>(() => {\n\t\tconst base = buildDefaultState(options);\n\t\treturn { ...base, ...hydrateFromUrl(urlConfig, base, getFilterMeta) };\n\t});\n\n\tconst resolvedState = useMemo<DataViewState>(\n\t\t() => ({ ...internalState, ...controlledState }),\n\t\t[internalState, controlledState],\n\t);\n\n\t// A patch updates internal state and notifies the controlled consumer with the next full\n\t// state. `resolvedStateRef` keeps the latest snapshot for the change handlers.\n\tconst resolvedStateRef = useRef(resolvedState);\n\tresolvedStateRef.current = resolvedState;\n\n\tconst applyPatch = useCallback(\n\t\t(patch: Partial<DataViewState>) => {\n\t\t\tsetInternalState((prev) => ({ ...prev, ...patch }));\n\t\t\tonStateChange?.({ ...resolvedStateRef.current, ...patch });\n\t\t},\n\t\t[onStateChange],\n\t);\n\n\t// Ongoing URL writes plus the back and forward subscription. Hydration already happened above.\n\tuseUrlSync({\n\t\tconfig: urlConfig,\n\t\tstate: resolvedState,\n\t\tapplyPatch,\n\t\tgetFilterMeta,\n\t});\n\n\t// Changing what the server sees (sort, filter, or search) resets to the first page. This\n\t// keeps a filtered result set from stranding the user on a page that is now empty.\n\tconst resetPagination = useCallback(\n\t\t(): PaginationState => ({\n\t\t\t...resolvedStateRef.current.pagination,\n\t\t\tpageIndex: 0,\n\t\t}),\n\t\t[],\n\t);\n\n\tconst prevParamsKeyRef = useRef(paramsKey);\n\tuseEffect(() => {\n\t\tif (prevParamsKeyRef.current === paramsKey) return;\n\t\tprevParamsKeyRef.current = paramsKey;\n\t\tapplyPatch({ pagination: resetPagination() });\n\t});\n\n\tconst onPaginationChange = useCallback<OnChangeFn<PaginationState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tpagination: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.pagination,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\t[applyPatch],\n\t);\n\n\tconst onSortingChange = useCallback<OnChangeFn<SortingState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tsorting: functionalUpdate(updater, resolvedStateRef.current.sorting),\n\t\t\t\tpagination: resetPagination(),\n\t\t\t});\n\t\t},\n\t\t[applyPatch, resetPagination],\n\t);\n\n\tconst onColumnFiltersChange = useCallback<OnChangeFn<ColumnFiltersState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tcolumnFilters: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.columnFilters,\n\t\t\t\t),\n\t\t\t\tpagination: resetPagination(),\n\t\t\t});\n\t\t},\n\t\t[applyPatch, resetPagination],\n\t);\n\n\tconst onGlobalFilterChange = useCallback<OnChangeFn<string>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tglobalFilter: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.globalFilter,\n\t\t\t\t),\n\t\t\t\tpagination: resetPagination(),\n\t\t\t});\n\t\t},\n\t\t[applyPatch, resetPagination],\n\t);\n\n\tconst onRowSelectionChange = useCallback<OnChangeFn<RowSelectionState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\trowSelection: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.rowSelection,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\t[applyPatch],\n\t);\n\n\tconst onColumnVisibilityChange = useCallback<OnChangeFn<VisibilityState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tcolumnVisibility: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.columnVisibility,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\t[applyPatch],\n\t);\n\n\tconst onColumnPinningChange = useCallback<OnChangeFn<ColumnPinningState>>(\n\t\t(updater) => {\n\t\t\tapplyPatch({\n\t\t\t\tcolumnPinning: functionalUpdate(\n\t\t\t\t\tupdater,\n\t\t\t\t\tresolvedStateRef.current.columnPinning,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\t[applyPatch],\n\t);\n\n\tconst isMobileForced = useForceCards(responsive);\n\tconst view: ViewMode = isMobileForced ? \"cards\" : resolvedState.view;\n\n\tconst table = useReactTable<TData>({\n\t\tdata: rows,\n\t\tmeta: { viewMode: view },\n\t\tcolumns,\n\t\tgetCoreRowModel: getCoreRowModel(),\n\t\t// The server owns sorting, filtering, and pagination. The core never processes data.\n\t\tmanualPagination: true,\n\t\tmanualSorting: true,\n\t\tmanualFiltering: true,\n\t\tautoResetPageIndex: false,\n\t\trowCount,\n\t\tgetRowId: (originalRow) => getRowId(originalRow),\n\t\tenableRowSelection:\n\t\t\ttypeof enableRowSelection === \"function\"\n\t\t\t\t? (row) => enableRowSelection(row.original)\n\t\t\t\t: (enableRowSelection ?? true),\n\t\tenableGlobalFilter,\n\t\tstate: {\n\t\t\tpagination: resolvedState.pagination,\n\t\t\tsorting: resolvedState.sorting,\n\t\t\tcolumnFilters: resolvedState.columnFilters,\n\t\t\tglobalFilter: resolvedState.globalFilter,\n\t\t\trowSelection: resolvedState.rowSelection,\n\t\t\tcolumnVisibility: resolvedState.columnVisibility,\n\t\t\tcolumnPinning: resolvedState.columnPinning,\n\t\t},\n\t\tonPaginationChange,\n\t\tonSortingChange,\n\t\tonColumnFiltersChange,\n\t\tonGlobalFilterChange,\n\t\tonRowSelectionChange,\n\t\tonColumnVisibilityChange,\n\t\tonColumnPinningChange,\n\t});\n\n\t// The normalized request holds only the slices the server cares about. View, selection, and\n\t// column visibility deliberately stay out of it, so toggling them never triggers a refetch.\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: params is stable when paramsKey is stable\n\tconst request = useMemo<DataViewRequest>(\n\t\t() => ({\n\t\t\tpagination: resolvedState.pagination,\n\t\t\tsorting: resolvedState.sorting,\n\t\t\tfilters: resolvedState.columnFilters,\n\t\t\tglobalFilter: resolvedState.globalFilter,\n\t\t\tparams,\n\t\t}),\n\t\t[\n\t\t\tresolvedState.pagination,\n\t\t\tresolvedState.sorting,\n\t\t\tresolvedState.columnFilters,\n\t\t\tresolvedState.globalFilter,\n\t\t\tparamsKey,\n\t\t],\n\t);\n\n\t// Emit `onRequestChange` immediately for pagination, sorting, and the initial mount. Search\n\t// and filter changes are debounced instead. Reference equality on the memoized slices tells\n\t// us which part changed without serializing values.\n\tconst onRequestChangeRef = useRef(onRequestChange);\n\tonRequestChangeRef.current = onRequestChange;\n\tconst debounceRef = useRef<ResolvedDebounce>(resolveDebounce(debounce));\n\tdebounceRef.current = resolveDebounce(debounce);\n\tconst lastEmittedRef = useRef<DataViewRequest | null>(null);\n\tconst timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n\tuseEffect(() => {\n\t\tconst prev = lastEmittedRef.current;\n\t\tconst isFirst = prev === null;\n\t\tconst searchChanged = !prev || prev.globalFilter !== request.globalFilter;\n\t\tconst filtersChanged = !prev || prev.filters !== request.filters;\n\n\t\tconst emit = () => {\n\t\t\tlastEmittedRef.current = request;\n\t\t\tonRequestChangeRef.current?.(request);\n\t\t};\n\n\t\tlet delay = 0;\n\t\tif (searchChanged)\n\t\t\tdelay = Math.max(delay, debounceRef.current.globalFilter);\n\t\tif (filtersChanged)\n\t\t\tdelay = Math.max(delay, debounceRef.current.columnFilters);\n\t\tconst shouldDebounce =\n\t\t\t!isFirst && (searchChanged || filtersChanged) && delay > 0;\n\n\t\tclearTimeout(timerRef.current);\n\t\tif (shouldDebounce) {\n\t\t\ttimerRef.current = setTimeout(emit, delay);\n\t\t} else {\n\t\t\temit();\n\t\t}\n\t\treturn () => clearTimeout(timerRef.current);\n\t}, [request]);\n\n\t// Emit the current request again right away and skip the debounce. This drives the error retry.\n\tconst requestRef = useRef(request);\n\trequestRef.current = request;\n\tconst refetch = useCallback(() => {\n\t\tonRequestChangeRef.current?.(requestRef.current);\n\t}, []);\n\n\t// Renderer facing status for both presentations.\n\tconst renderStatus = useMemo(\n\t\t() =>\n\t\t\tresolveDataViewStatus({\n\t\t\t\tstatus,\n\t\t\t\terror,\n\t\t\t\tpageRowCount: rows.length,\n\t\t\t\tstate: resolvedState,\n\t\t\t}),\n\t\t[status, error, rows.length, resolvedState],\n\t);\n\n\tconst setView = useCallback(\n\t\t(next: ViewMode) => applyPatch({ view: next }),\n\t\t[applyPatch],\n\t);\n\n\tconst pageSizeOptions = options.pageSizeOptions ?? DEFAULT_PAGE_SIZES;\n\n\t// Derived helpers for the toolbar and presentations. The TanStack `table` is a stable\n\t// reference that mutates internally. These are computed every render (cheap over a small\n\t// column set) instead of memoized on `table`, which would never notice column changes.\n\tconst allColumns = table.getAllColumns();\n\tconst sortableColumns = allColumns.filter((c) => c.getCanSort());\n\tconst filterableColumns = allColumns.filter(\n\t\t(c) => c.columnDef.meta?.filter != null,\n\t);\n\n\tconst clearSelection = useCallback(\n\t\t() => applyPatch({ rowSelection: {} }),\n\t\t[applyPatch],\n\t);\n\tconst selection = useMemo(() => {\n\t\tconst map = resolvedState.rowSelection;\n\t\t// Ids span every page because they are keyed by id. Rows are only the ones currently on\n\t\t// the page, taken straight from `rows`, since the core never holds data for other pages.\n\t\tconst selectedIds = Object.keys(map).filter((k) => map[k]);\n\t\tconst selectedRows = rows.filter((row) => map[getRowId(row)] === true);\n\t\treturn {\n\t\t\tcount: selectedIds.length,\n\t\t\tids: selectedIds,\n\t\t\trows: selectedRows,\n\t\t\tclear: clearSelection,\n\t\t};\n\t}, [resolvedState.rowSelection, rows, getRowId, clearSelection]);\n\n\tconst exportCsv = useCallback(\n\t\t(opts?: Parameters<typeof exportCsvFn>[1]) => exportCsvFn(table, opts),\n\t\t[table],\n\t);\n\n\tconst resetFilter = useCallback(\n\t\t(columnId: string) => table.getColumn(columnId)?.setFilterValue(undefined),\n\t\t[table],\n\t);\n\n\tconst resetAllFilters = useCallback(\n\t\t() => table.resetColumnFilters(),\n\t\t[table],\n\t);\n\n\treturn {\n\t\ttable,\n\t\trequest,\n\t\tstate: resolvedState,\n\t\tview,\n\t\tsetView,\n\t\tisMobileForced,\n\t\tstatus,\n\t\terror,\n\t\trenderStatus,\n\t\trefetch,\n\t\tpageSizeOptions,\n\t\tsortableColumns,\n\t\tfilterableColumns,\n\t\tselection,\n\t\texportCsv,\n\t\tfacets,\n\t\tresetFilter,\n\t\tresetAllFilters,\n\t};\n}\n","// Optional convenience wrapper around `useDataView`. It owns the fetch lifecycle by calling the\n// consumer's `fetcher` on each request and feeding `rows`, `rowCount`, and `status` back in. The\n// simple case then needs no extra wiring. The core itself stays agnostic about how data is\n// fetched and ships no query or caching dependency. This is just the controlled pattern, ready\n// to use.\n//\n// It is named `useDataViewFetcher` because it calls hooks internally. That means the name must\n// begin with `use`.\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { UseDataViewOptions, UseDataViewReturn } from \"../types/options\";\nimport type { DataViewRequest, DataViewResponse } from \"../types/request\";\nimport type { Status } from \"../types/state\";\nimport { useDataView } from \"./useDataView\";\n\nexport interface UseDataViewFetcherOptions<TData>\n\textends Omit<\n\t\tUseDataViewOptions<TData>,\n\t\t\"rows\" | \"rowCount\" | \"status\" | \"error\" | \"onRequestChange\"\n\t> {\n\t/** Maps a request to a response, using any transport or data layer. */\n\tfetcher: (\n\t\trequest: DataViewRequest,\n\t) => Promise<DataViewResponse<NoInfer<TData>>>;\n\t/** External dependencies that should trigger a refetch when they change. */\n\tdeps?: unknown[];\n}\n\nexport function useDataViewFetcher<TData>({\n\tfetcher,\n\tdeps,\n\t...options\n}: UseDataViewFetcherOptions<TData>): UseDataViewReturn<TData> {\n\tconst [response, setResponse] = useState<DataViewResponse<TData>>({\n\t\trows: [],\n\t\trowCount: 0,\n\t});\n\tconst [status, setStatus] = useState<Status>(\"idle\");\n\tconst [error, setError] = useState<unknown>(undefined);\n\n\tconst fetcherRef = useRef(fetcher);\n\tfetcherRef.current = fetcher;\n\t// An id that only ever increases. It keeps a slow earlier request from overwriting a newer one.\n\tconst requestIdRef = useRef(0);\n\n\tconst lastRequestRef = useRef<DataViewRequest | null>(null);\n\n\tconst onRequestChange = useCallback(async (request: DataViewRequest) => {\n\t\tlastRequestRef.current = request;\n\t\tconst id = ++requestIdRef.current;\n\t\tsetStatus(\"loading\");\n\t\ttry {\n\t\t\tconst data = await fetcherRef.current(request);\n\t\t\tif (id === requestIdRef.current) {\n\t\t\t\tsetResponse(data);\n\t\t\t\tsetError(undefined);\n\t\t\t\tsetStatus(\"success\");\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tif (id === requestIdRef.current) {\n\t\t\t\tsetError(err);\n\t\t\t\tsetStatus(\"error\");\n\t\t\t}\n\t\t}\n\t}, []);\n\n\tconst depsKey = deps ? JSON.stringify(deps) : \"\";\n\tconst prevDepsKeyRef = useRef(depsKey);\n\tuseEffect(() => {\n\t\tif (prevDepsKeyRef.current === depsKey) return;\n\t\tprevDepsKeyRef.current = depsKey;\n\t\tif (lastRequestRef.current) {\n\t\t\tonRequestChange(lastRequestRef.current);\n\t\t}\n\t});\n\n\treturn useDataView<TData>({\n\t\t...options,\n\t\trows: response.rows,\n\t\trowCount: response.rowCount,\n\t\tfacets: response.facets,\n\t\tstatus,\n\t\terror,\n\t\tonRequestChange,\n\t});\n}\n"],"mappings":"iUAmBA,SAAgB,EAAuB,CACtC,OACA,QACA,GAAG,GAC4B,CAC/B,GAAM,CAAE,aAAc,EAGtB,OAFI,EAAU,QAAU,EAAU,MAGjC,EAAA,EAAA,KAAC,EAAA,MAAD,CACC,WAAA,GACA,EAAE,KACF,OAAO,KACP,KAAK,SACL,aAAW,eACX,GAAI,YAEJ,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,QAAQ,gBAAgB,KAAK,OAAO,IAAI,cAA/C,EACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,cAAX,EACC,EAAA,EAAA,MAAC,EAAA,KAAD,CAAM,KAAK,KAAK,GAAI,aAApB,CACE,EAAU,MAAM,WACZ,KACN,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,SAAS,KAAK,KAAK,QAAS,EAAU,eAAO,OAErD,CAAA,CACF,IACN,GAAO,cACP,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,IAAI,cAAM,EAAM,YAAY,CAAS,CAAS,CAAA,CAEhD,GACD,CAAA,CAET,CCbA,SAAgB,EAA0B,EAA+B,CACxE,GAAM,CAAE,OAAM,UAAW,EAAO,UAGhC,OAFI,GAAM,MAAc,EAAK,MACzB,OAAO,GAAW,SAAiB,EAChC,EAAO,EACf,CAEA,SAAS,EACR,EACA,EACA,EACwB,CAIxB,OAHI,EAAiB,IAAa,SAAW,KAAO,EAEhD,EAAO,YAAc,MAClB,IAAa,SADkB,KACA,CACvC,CAYA,SAAgB,EACf,EACA,EAA8B,CAAC,EACX,CACpB,IAAM,EAAW,EAAQ,cAAgB,OACnC,EAAmD,CACxD,MAAO,CAAC,EACR,SAAU,CAAC,EACX,MAAO,CAAC,EACR,MAAO,CAAC,EACR,KAAM,CAAC,CACR,EAEA,EAAM,sBAAsB,EAAE,SAAS,EAAQ,IAAU,CACxD,IAAM,EAAO,EAAO,UAAU,MAAM,KAC9B,EAAO,EAAY,EAAQ,GAAM,KAAM,CAAQ,EAChD,GACL,EAAQ,GAAM,KAAK,CAClB,MAAO,GAAM,OAAS,EACtB,QACA,MAAO,CACN,GAAI,EAAO,GACX,SACA,MAAO,EAAmB,CAAM,EAChC,UAAW,GAAM,WAAa,IAAS,MACxC,CACD,CAAC,CACF,CAAC,EAED,IAAM,EAAW,GAChB,EACE,MAAM,EAAG,IAAM,EAAE,MAAQ,EAAE,OAAS,EAAE,MAAQ,EAAE,KAAK,EACrD,IAAK,GAAM,EAAE,KAAK,EAErB,MAAO,CACN,MAAO,EAAQ,EAAQ,KAAK,EAC5B,SAAU,EAAQ,EAAQ,QAAQ,EAClC,MAAO,EAAQ,EAAQ,KAAK,EAC5B,MAAO,EAAQ,EAAQ,KAAK,EAC5B,KAAM,EAAQ,EAAQ,IAAI,CAC3B,CACD,CCjGA,SAAgB,EACf,EACA,EAC6B,CAC7B,IAAM,GAAA,EAAA,EAAA,QAA8B,CAAC,CAAC,EAChC,GAAA,EAAA,EAAA,QAAuB,EAAK,EAC5B,GAAA,EAAA,EAAA,QAAuB,CAAC,EACxB,GAAA,EAAA,EAAA,QAAmB,EAAK,GAE9B,EAAA,EAAA,eAAgB,CAEd,GACA,CAAC,EAAU,SACX,OAAO,SAAa,KAAA,QAAA,IAAA,WACK,eAEV,MAAM,KAAK,SAAS,WACd,EAAO,KAAM,GAAM,CACvC,GAAI,CACH,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,KAC5B,GACA,aAAa,kBAAoB,EAAE,OAAS,oBAC9C,CACD,MAAQ,CACP,MAAO,EACR,CACD,CACK,GACJ,QAAQ,KACP,4JAED,EAED,EAAU,QAAU,GAEtB,EAAG,CAAC,CAAO,CAAC,EAEZ,IAAM,EAAa,EAAY,IAAK,GAAM,EAAE,EAAE,EACxC,EAAW,IAAI,IACjB,EAAqB,EAAc,QAEvC,GAAI,GAAW,EAAc,QAAS,CACrC,IAAM,EAAU,EAAW,QACrB,EAAU,IAAI,IAAI,CAAO,EAM/B,GAHC,EAAW,SAAW,EAAQ,QAC9B,EAAW,MAAM,EAAI,IAAM,IAAO,EAAQ,EAAE,EAS5C,GANA,EAAqB,EAAc,QAAU,EAG5C,EAAW,SAAW,EAAQ,QAC9B,EAAW,MAAO,GAAO,EAAQ,IAAI,CAAE,CAAC,EAGxC,IAAK,IAAM,KAAM,EAChB,EAAS,IAAI,CAAE,OAGhB,IAAK,IAAM,KAAM,EACX,EAAQ,IAAI,CAAE,GAClB,EAAS,IAAI,CAAE,CAKpB,CAQA,OANA,EAAA,EAAA,eAAgB,CACf,EAAW,QAAU,EACrB,EAAc,QAAU,GACxB,EAAc,QAAU,CACzB,CAAC,EAEM,CAAE,KAAM,EAAa,WAAU,WAAY,CAAmB,CACtE,CC7EA,SAAgB,EAAuB,EAA2B,CACjE,EAAM,mBAAmB,EACzB,EAAM,gBAAgB,EAAE,CACzB,CAOA,SAAgB,EAAoB,CAAE,OAAM,SAA4B,CAIvE,OAHI,GAAO,YACH,EAAA,EAAA,KAAA,EAAA,SAAA,CAAA,SAAG,EAAM,WAAW,CAAE,MAAO,EAAK,MAAO,MAAO,EAAK,OAAQ,CAAC,CAAI,CAAA,GAGzE,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,MAAM,SAAS,IAAI,cAA1B,EACC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,EAAE,eAAM,uBAA2B,CAAA,GACzC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,QAAQ,KAAK,KAAK,QAAS,EAAK,iBAAS,OAEjD,CAAA,CACF,GAET,CAEA,SAAgB,EAAoB,CAAE,OAAM,SAA4B,CACvE,IAAM,EAAW,EAAK,aAAa,QAAU,iBACvC,MAAqB,EAAgB,EAAK,KAAK,EAcrD,OAbI,GAAO,OACH,EAAA,EAAA,KAAA,EAAA,SAAA,CAAA,SAAG,EAAM,MAAM,CAAE,WAAU,cAAa,CAAC,CAAI,CAAA,EAEjD,GAEF,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,MAAM,SAAS,IAAI,cAA1B,EACC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,EAAE,kBAAS,aAAiB,CAAA,GAClC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,SAAS,KAAK,KAAK,QAAS,WAAc,eAElD,CAAA,CACF,KAGF,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,EAAE,kBAAS,aAAiB,CAAA,CAC1C,CCpBA,IAAM,EAAwC,CAAE,KAAM,EAAG,GAAI,EAAG,GAAI,CAAE,EAuBtE,SAAgB,EAAiB,CAChC,OACA,QACA,aACA,eACA,kBACA,mBACA,cAAc,GACd,OAAO,EACP,GAAG,GACsB,CACzB,GAAM,CAAE,QAAO,gBAAiB,EAC1B,EACL,GAAmB,EAAM,QAAQ,qBAAuB,GACnD,EACL,GAAoB,KAAK,IAAI,EAAK,MAAM,WAAW,SAAU,CAAC,EACzD,EAAO,CAAE,OAAM,GAAG,CAAU,EAC5B,EAAa,EAAiB,EAAM,YAAY,EAAE,KAAM,CAAW,EAEnE,EAAe,GAAyC,CAC7D,IAAM,EAAS,EAAkB,EAAO,CAAE,cAAa,CAAC,EACxD,OACC,EAAA,EAAA,KAAC,EAAA,WAAD,CAEC,eAAc,GAAe,IAAA,GAC7B,GAAI,WAEH,EAAa,IAAK,GAAQ,CAC1B,IAAM,EAAW,EAAI,cAAc,EAE7B,EAAM,CAAE,MAAK,KAAM,EAAI,SAAU,WAAU,mBADpB,EAAI,eAAe,CACgB,EAC1D,EAAW,EAAW,SAAS,IAAI,EAAI,EAAE,GAAK,IAAA,GAEpD,GAAI,EACH,OACC,EAAA,EAAA,KAAC,MAAD,CAAkB,gBAAe,WAC/B,EAAW,CAAG,CACX,EAFK,EAAI,EAET,EAIP,IAAM,GACL,EAAA,EAAA,KAAC,EAAD,CACM,MACG,SACU,kBAClB,CAAA,EASF,OAPI,GAAO,MAET,EAAA,EAAA,KAAC,MAAD,CAAkB,gBAAe,WAC/B,EAAM,KAAK,CAAE,GAAG,EAAK,SAAU,CAAK,CAAC,CAClC,EAFK,EAAI,EAET,GAIN,EAAA,EAAA,KAAC,EAAA,KAAD,CAEC,WAAA,GACA,QAAQ,KACR,IAAI,WACJ,gBAAe,GAAY,IAAA,GAC3B,gBAAe,WAEd,CACI,EARA,EAAI,EAQJ,CAER,CAAC,CACU,EA7CN,EAAW,UA6CL,CAEd,EAEA,GACC,GACA,EAAa,QAAU,WACvB,EAAW,KAAK,OAAS,EAEzB,OAAO,EAAY,EAAW,IAAI,EAGnC,OAAQ,EAAa,MAArB,CACC,IAAK,UACJ,OAAO,GAAO,aACb,EAAM,aAAa,GAEnB,EAAA,EAAA,KAAC,EAAA,WAAD,CAAY,GAAI,WACd,MAAM,KAAK,CAAE,OAAQ,CAAc,GAAI,EAAG,KAE1C,EAAA,EAAA,KAAC,EAAA,KAAD,CAAc,WAAA,GAAW,QAAQ,eAChC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,cAAX,EACC,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,OAAQ,GAAI,MAAM,KAAO,CAAA,GACnC,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,OAAQ,GAAI,MAAM,KAAO,CAAA,GACnC,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,OAAQ,EAAK,CAAA,CACjB,GACF,EANK,CAML,CACN,CACU,CAAA,EAEd,IAAK,QACJ,OACC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,EAAE,eACT,EAAA,EAAA,KAAC,EAAD,CAAoB,OAAa,OAAQ,CAAA,CAClC,CAAA,EAEV,IAAK,QACL,IAAK,iBACJ,OACC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,EAAE,eACT,EAAA,EAAA,KAAC,EAAD,CAAoB,OAAa,OAAQ,CAAA,CAClC,CAAA,EAEV,QACC,OAAO,EAAY,EAAW,IAAI,CACpC,CACD,CAEA,SAAS,EAAuB,CAC/B,MACA,SACA,oBAKE,CACF,IAAM,EAAW,IAAI,IAAI,EAAI,YAAY,EAAE,IAAK,GAAM,CAAC,EAAE,OAAO,GAAI,CAAC,CAAC,CAAC,EACjE,EAAe,GAAuC,CAC3D,IAAM,EAAO,EAAS,IAAI,EAAM,EAAE,EAClC,OAAO,GAAA,EAAA,EAAA,YACO,EAAK,OAAO,UAAU,KAAM,EAAK,WAAW,CAAC,EACxD,IACJ,EAEA,OACC,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACE,IACA,EAAA,EAAA,KAAC,EAAA,SAAD,CACC,aAAW,cACX,QAAS,EAAI,cAAc,EAC3B,SAAU,CAAC,EAAI,aAAa,EAC5B,SAAU,EAAI,yBAAyB,EACvC,MAAO,CAAE,SAAU,WAAY,IAAK,EAAG,MAAO,EAAG,OAAQ,CAAE,CAC3D,CAAA,EAED,EAAO,MAAM,OAAS,IACtB,EAAA,EAAA,KAAC,EAAA,KAAK,QAAN,CAAc,GAAG,cACf,EAAO,MAAM,IAAK,IAClB,EAAA,EAAA,KAAC,EAAA,IAAD,CAAA,SAAqB,EAAY,CAAK,CAAO,EAAnC,EAAM,EAA6B,CAC7C,CACY,CAAA,GAEf,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,cAAX,EACG,EAAO,MAAM,OAAS,GAAK,EAAO,SAAS,OAAS,KACrD,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAK,WAAZ,CACE,EAAO,MAAM,IAAK,IAClB,EAAA,EAAA,KAAC,EAAA,KAAD,CAEC,GAAI,IACJ,KAAK,KACL,GAAI,IACJ,GAAI,EAAmB,GAAK,WAE3B,EAAY,CAAK,CACb,EAPA,EAAM,EAON,CACN,EACA,EAAO,SAAS,IAAK,IACrB,EAAA,EAAA,KAAC,EAAA,KAAD,CAAqB,KAAK,KAAK,EAAE,kBAC/B,EAAY,CAAK,CACb,EAFK,EAAM,EAEX,CACN,CACK,IAEP,EAAO,MAAM,OAAS,IACtB,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,IAAI,cACT,EAAO,MAAM,IAAK,IAClB,EAAA,EAAA,KAAC,EAAA,SAAD,CAAA,SAA0B,EAAY,CAAK,CAAY,EAAxC,EAAM,EAAkC,CACvD,CACK,CAAA,EAEP,EAAO,KAAK,OAAS,IACrB,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,IAAK,WACV,EAAO,KAAK,IAAK,IACjB,EAAA,EAAA,MAAC,EAAA,MAAD,CAEC,QAAQ,gBACR,IAAI,KACJ,KAAK,kBAJN,CAME,EAAM,YACN,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,KAAK,EAAE,kBAChB,EAAM,KACF,CAAA,GAEP,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,cAAM,EAAY,CAAK,CAAQ,CAAA,CACpC,GAXD,EAAM,EAWL,CACP,CACK,CAAA,CAEF,GACN,CAAA,CAAA,CAEJ,CCtOA,SAAgB,EAAsB,CACrC,OACA,kBACA,eAAe,GACf,YAAY,GACZ,gBAAgB,gBAChB,GAAG,GAC2B,CAC9B,GAAM,CAAE,SAAU,EACZ,CAAE,YAAW,YAAa,EAAK,MAAM,WACrC,EAAQ,EAAM,YAAY,EAC1B,EAAY,EAAM,aAAa,EAC/B,EAAQ,GAAmB,EAAK,gBAEhC,EAAQ,IAAU,EAAI,EAAI,EAAY,EAAW,EACjD,EAAM,KAAK,KAAK,EAAY,GAAK,EAAU,CAAK,EAEtD,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,QAAQ,gBAAgB,KAAK,OAAO,IAAI,KAAK,GAAI,WAAxD,EACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,KAAK,KAAK,gBAArB,CACE,IACA,EAAA,EAAA,KAAC,EAAA,OAAD,CACC,aAAY,EACZ,KAAM,EAAM,IAAI,MAAM,EACtB,MAAO,OAAO,CAAQ,EACtB,SAAW,GAAM,GAAK,EAAM,YAAY,OAAO,CAAC,CAAC,EACjD,EAAG,GACH,cAAe,CAAE,aAAc,EAAK,CACpC,CAAA,EAED,IACA,EAAA,EAAA,MAAC,EAAA,KAAD,CAAM,KAAK,KAAK,EAAE,kBAAlB,CACE,EAAM,IAAE,EAAI,OAAK,CACb,GAED,KACP,EAAA,EAAA,KAAC,EAAA,WAAD,CACC,MAAO,EAAY,EACnB,MAAO,KAAK,IAAI,EAAW,CAAC,EAC5B,SAAW,GAAS,EAAM,aAAa,EAAO,CAAC,EAC/C,gBAAkB,IAAa,CAAE,aAAc,GAAG,EAAQ,MAAO,EACjE,CAAA,CACK,GAET,CC5DA,SAAgB,EAAS,CAAE,aAAmD,CAC7E,OACC,EAAA,EAAA,MAAC,MAAD,CACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,cAAY,OACZ,UAAU,QACV,MAAO,CAAE,WAAY,CAAE,WAPxB,EASC,EAAA,EAAA,KAAC,QAAD,CAAA,SAAO,MAAW,CAAA,GAClB,EAAA,EAAA,KAAC,OAAD,CACC,EAAE,gBACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,QAAS,IAAc,MAAQ,EAAI,GACnC,CAAA,GACD,EAAA,EAAA,KAAC,OAAD,CACC,EAAE,gBACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,QAAS,IAAc,OAAS,EAAI,GACpC,CAAA,CACG,GAEP,CAEA,SAAS,EAAM,CAAE,IAAG,SAAuC,CAC1D,OACC,EAAA,EAAA,MAAC,MAAD,CACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,cAAY,OACZ,UAAU,QACV,MAAO,CAAE,WAAY,CAAE,WAXxB,EAaC,EAAA,EAAA,KAAC,QAAD,CAAA,SAAQ,CAAa,CAAA,GACrB,EAAA,EAAA,KAAC,OAAD,CAAS,GAAI,CAAA,CACT,GAEP,CAEA,SAAgB,GAAa,CAC5B,OACC,EAAA,EAAA,KAAC,EAAD,CACC,MAAM,SACN,EAAE,kDACF,CAAA,CAEH,CAEA,SAAgB,GAAa,CAC5B,OAAO,EAAA,EAAA,KAAC,EAAD,CAAO,MAAM,SAAS,EAAE,yBAA2B,CAAA,CAC3D,CAEA,SAAgB,GAAkB,CACjC,OAAO,EAAA,EAAA,KAAC,EAAD,CAAO,MAAM,OAAO,EAAE,cAAgB,CAAA,CAC9C,CAEA,SAAgB,GAAY,CAC3B,OAAO,EAAA,EAAA,KAAC,EAAD,CAAO,MAAM,QAAQ,EAAE,sBAAwB,CAAA,CACvD,CAEA,SAAgB,GAAc,CAC7B,OAAO,EAAA,EAAA,KAAC,EAAD,CAAO,MAAM,WAAW,EAAE,6BAA+B,CAAA,CACjE,CAEA,SAAgB,IAAe,CAC9B,OAAO,EAAA,EAAA,KAAC,EAAD,CAAO,MAAM,YAAY,EAAE,8BAAgC,CAAA,CACnE,CCnEA,SAAS,EAAoB,EAAkD,CAC9E,IAAM,EAAS,EAAO,YAAY,EAC7B,KACL,MAAO,CACN,SAAU,UACT,GACA,IAAW,OAAS,EAAO,SAAS,MAAM,EAAI,EAAO,SAAS,OAAO,EACtE,OAAQ,EACR,gBAAiB,2BAClB,CACD,CAiBA,SAAgB,EAAiB,CAChC,OACA,QACA,kBACA,kBACA,sBAAsB,GACtB,cAAc,GACd,GAAG,GACsB,CACzB,GAAM,CAAE,QAAO,gBAAiB,EAC1B,EAAsB,GAAuB,EAAK,SAAW,UAC7D,EAAa,EAAiB,EAAM,YAAY,EAAE,KAAM,CAAW,EACnE,EAAc,EAAM,sBAAsB,EAC1C,EACL,GAAmB,EAAM,QAAQ,qBAAuB,GACnD,EAAW,EAAY,QAAU,KACjC,EACL,GAAmB,KAAK,IAAI,EAAK,MAAM,WAAW,SAAU,CAAC,EAExD,EAAkB,IACvB,EAAA,EAAA,KAAC,EAAA,MAAM,MAAP,CAEC,eAAc,GAAe,IAAA,YAE5B,EAAa,IAAK,GAAQ,CAC1B,IAAM,EAAa,EAAW,SAAS,IAAI,EAAI,EAAE,GAAK,IAAA,GAChD,GACL,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACE,IACA,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,SAAD,CACC,aAAW,aACX,QAAS,EAAI,cAAc,EAC3B,SAAU,CAAC,EAAI,aAAa,EAC5B,cAAe,EAAI,kBAAkB,EACrC,SAAU,EAAI,yBAAyB,CACvC,CAAA,CACQ,CAAA,EAEV,EAAI,gBAAgB,EAAE,IAAK,GAAS,CACpC,IAAM,EAAQ,EAAK,OAAO,UAAU,MAAM,MAC1C,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAEC,MAAO,CACN,GAAG,EAAa,EAAK,MAAM,EAC3B,GAAI,EAAQ,CAAE,UAAW,CAAM,EAAI,IAAA,EACpC,4BAEY,EAAK,OAAO,UAAU,KAAM,EAAK,WAAW,CAAC,CAChD,EAPJ,EAAK,EAOD,CAEZ,CAAC,CACA,CAAA,CAAA,EAEH,OAAO,GAAO,KACb,EAAA,EAAA,KAAC,EAAD,CAAA,SAAsB,EAAM,IAAI,CAAE,MAAK,OAAM,CAAC,CAAU,EAA3C,EAAI,EAAuC,GAExD,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAEC,gBAAe,EAAI,cAAc,GAAK,IAAA,GACtC,gBAAe,WAEd,CACQ,EALJ,EAAI,EAKA,CAEZ,CAAC,CACW,EA9CP,EAAW,UA8CJ,EAGR,MAA8B,CACnC,GACC,GACA,EAAa,QAAU,WACvB,EAAW,KAAK,OAAS,EAEzB,OAAO,EAAe,EAAW,IAAI,EAGtC,OAAQ,EAAa,MAArB,CACC,IAAK,UACJ,OAAO,GAAO,aACb,EAAM,aAAa,GAEnB,EAAA,EAAA,KAAC,EAAA,MAAM,MAAP,CAAA,SACE,MAAM,KAAK,CAAE,OAAQ,CAAa,GAAI,EAAG,KAEzC,EAAA,EAAA,MAAC,EAAA,MAAM,GAAP,CAAA,SAAA,CACE,IACA,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,OAAQ,GAAI,MAAO,EAAK,CAAA,CACzB,CAAA,EAEV,EAAY,IAAK,IACjB,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,OAAQ,EAAK,CAAA,CACd,EAFK,EAAI,EAET,CACV,CACQ,CAAA,EAXK,CAWL,CACV,CACW,CAAA,EAEf,IAAK,QACJ,OACC,EAAA,EAAA,KAAC,EAAD,CAAa,QAAS,YACrB,EAAA,EAAA,KAAC,EAAD,CAAoB,OAAa,OAAQ,CAAA,CAC7B,CAAA,EAEf,IAAK,QACL,IAAK,iBACJ,OACC,EAAA,EAAA,KAAC,EAAD,CAAa,QAAS,YACrB,EAAA,EAAA,KAAC,EAAD,CAAoB,OAAa,OAAQ,CAAA,CAC7B,CAAA,EAEf,QACC,OAAO,EAAe,EAAW,IAAI,CACvC,CACD,EAIA,OACC,EAAA,EAAA,KAAC,MAAD,CAAK,MAHa,EAAM,uBAGZ,EAAa,CAAE,UAAW,MAAO,EAAI,IAAA,aAChD,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,OAAO,QAAQ,GAAI,WAA1B,EACC,EAAA,EAAA,KAAC,EAAA,MAAM,MAAP,CAAA,SACE,EAAM,gBAAgB,EAAE,IAAK,IAC7B,EAAA,EAAA,MAAC,EAAA,MAAM,GAAP,CAAA,SAAA,CACE,IACA,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAU,MAAO,CAAE,MAAO,EAAG,YAC5B,EAAA,EAAA,KAAC,EAAA,SAAD,CACC,aAAW,+BACX,QAAS,EAAM,yBAAyB,EACxC,cACC,EAAM,0BAA0B,GAChC,CAAC,EAAM,yBAAyB,EAEjC,SAAU,EAAM,oCAAoC,CACpD,CAAA,CACQ,CAAA,EAEV,EAAM,QAAQ,IAAK,IACnB,EAAA,EAAA,KAAC,EAAD,CAES,SACR,SAAU,CACV,EAHK,EAAO,EAGZ,CACD,CACQ,CAAA,EArBK,EAAM,EAqBX,CACV,CACW,CAAA,EACZ,EAAW,CACN,GACH,CAAA,CAEP,CAGA,SAAS,EAAO,CAAE,YAAqC,CACtD,OAAO,EAAA,EAAA,KAAA,EAAA,SAAA,CAAG,UAAW,CAAA,CACtB,CAEA,SAAS,EAAY,CACpB,UACA,YAIE,CACF,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,MAAP,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CAAmB,oBAClB,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,EAAE,KAAM,UAAiB,CAAA,CACxB,CAAA,CACD,CAAA,CACE,CAAA,CAEf,CAEA,SAAS,EAAkB,CAC1B,SACA,YAIE,CACF,GAAM,CAAE,UAAW,EACb,EAAQ,EAAO,UAAU,MAAM,MAC/B,EAAS,EAAO,YAAY,EAC5B,EAAY,EAAO,aAAa,EAChC,EAAc,EAAY,EAC1B,EAAU,EAAO,cACpB,MAAA,EAAA,EAAA,YACW,EAAO,UAAU,OAAQ,EAAO,WAAW,CAAC,EACpD,EAAW,EAAO,WAAW,GAAK,CAAC,EAEnC,EAAU,EAAO,UAAU,KAEjC,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,GAAP,CACC,MAAO,CACN,GAAG,EAAa,CAAM,EACtB,GAAI,EAAQ,CAAE,UAAW,CAAM,EAAI,IAAA,GACnC,GAAI,GAAW,KAA4B,IAAA,GAArB,CAAE,MAAO,CAAQ,CACxC,EACA,YACC,IAAW,MACR,YACA,IAAW,OACV,aACA,IAAA,YAGJ,GACA,EAAA,EAAA,MAAC,EAAA,eAAD,CACC,QAAS,EAAO,wBAAwB,EACxC,MAAO,CACN,QAAS,cACT,WAAY,SACZ,IAAK,EACL,KAAM,SACP,WAPD,CASE,GACD,EAAA,EAAA,KAAC,EAAD,CAAU,UAAW,CAAS,CAAA,EAC7B,IACA,EAAA,EAAA,KAAC,OAAD,CACC,KAAK,OACL,MAAO,CAAE,SAAU,QAAS,QAAS,EAAI,EACzC,aAAY,iBAAiB,EAAY,aAExC,EAAY,CACR,CAAA,CAEQ,KAEhB,EAAA,EAAA,MAAC,OAAD,CACC,MAAO,CACN,QAAS,cACT,WAAY,SACZ,IAAK,EACL,GAAI,EAAW,CAAE,QAAS,EAAI,EAAI,CAAC,CACpC,WAND,CAQE,EACA,IAAU,EAAA,EAAA,KAAC,EAAD,CAAU,UAAW,CAAS,CAAA,CACpC,GAEE,CAAA,CAEZ,CCnSA,IAAM,GAAgB,mBAOtB,SAAgB,EAAqB,EAAuB,CAC3D,IAAM,EAAQ,kBAAkB,KAAK,EAAM,KAAK,CAAC,EACjD,GAAI,CAAC,EAAO,MAAO,eAAe,EAAM,GACxC,IAAM,EAAS,OAAO,EAAM,EAAE,EACxB,EAAO,EAAM,IAAM,KAEzB,MAAO,eAAe,GADN,IAAS,MAAQ,IAAS,MAAQ,IAAO,MAChB,EAAK,EAC/C,CAEA,SAAgB,GACf,EACU,CACV,IAAM,GAAA,EAAA,EAAA,iBAAwB,EACxB,EAAa,GAAY,gBACzB,EAAM,EAAa,EAAM,YAAY,GAAc,IAAA,GAEnD,GAAA,EAAA,EAAA,eADQ,EAAM,EAAqB,CAAG,EAAI,GACb,EAAK,EACxC,MAAO,EAAQ,GAAQ,EAAQ,CAChC,CC9BA,IAAM,EAAuD,CAC5D,KAAO,GAAO,GAAK,KAAO,GAAK,OAAO,CAAC,EACvC,OAAS,GACJ,GAAK,KAAa,GACf,IAAI,KAAK,aAAa,EAAE,OAAO,OAAO,CAAC,CAAC,EAEhD,SAAW,GACN,GAAK,KAAa,GACf,IAAI,KAAK,aAAa,IAAA,GAAW,CACvC,MAAO,WACP,SAAU,KACX,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC,EAEpB,KAAO,GAAM,CACZ,GAAI,GAAK,KAAM,MAAO,GACtB,IAAM,EAAI,aAAa,KAAO,EAAI,IAAI,KAAK,OAAO,CAAC,CAAC,EAEpD,OADI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAU,OAAO,CAAC,EACvC,IAAI,KAAK,eAAe,EAAE,OAAO,CAAC,CAC1C,EACA,QAAU,GACL,GAAK,KAAa,GACf,EAAI,MAAQ,IAErB,EAEA,SAAS,GACR,EACA,EACY,CACZ,GAAI,IAAa,UAAY,IAAa,WAAY,CACrD,IAAM,EAAM,IAAI,KAAK,aACpB,IAAA,GACA,IAAa,WAAa,CAAE,MAAO,WAAY,GAAG,CAAQ,EAAI,CAC/D,EACA,MAAQ,IAAO,GAAK,KAAO,GAAK,EAAI,OAAO,OAAO,CAAC,CAAC,CACrD,CACA,GAAI,IAAa,OAAQ,CACxB,IAAM,EAAM,IAAI,KAAK,eACpB,IAAA,GACA,CACD,EACA,MAAQ,IAAM,CACb,GAAI,GAAK,KAAM,MAAO,GACtB,IAAM,EAAI,aAAa,KAAO,EAAI,IAAI,KAAK,OAAO,CAAC,CAAC,EAEpD,OADI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAU,OAAO,CAAC,EACvC,EAAI,OAAO,CAAC,CACpB,CACD,CACA,OAAO,EAAkB,EAC1B,CAEA,SAAgB,EACf,EACA,EACA,EAGY,CACZ,IAAM,EAAS,GAAgB,IAAgB,GAI/C,OAFK,EACD,OAAO,GAAW,WAAmB,EAClC,GAAmB,EAAU,CAAM,EAFtB,EAAkB,EAGvC,CChEA,SAAgB,EAAa,CAC5B,QACA,QACA,YAKE,CACF,IAAM,EAAU,MAAM,QAAQ,CAAK,EAAI,EAAQ,KAE/C,OACC,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,IAAK,WACV,EAAM,OAAO,IAAK,GAAW,CAC7B,IAAM,EACL,GAAW,MACX,EAAQ,KAAO,EAAO,MACtB,EAAQ,KAAO,EAAO,GACvB,OACC,EAAA,EAAA,KAAC,EAAA,eAAD,CAEC,YACC,EAAS,EAAW,IAAA,GAAY,CAAC,EAAO,KAAM,EAAO,EAAE,CAAC,EAEzD,MAAO,CACN,QAAS,UACT,aAAc,EACd,WAAY,EACT,kCACA,IAAA,EACJ,YAEA,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,KAAK,QAAQ,gBAAgB,KAAK,kBAA7C,EACC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,cAAM,EAAO,KAAY,CAAA,GACpC,EAAA,EAAA,KAAC,EAAA,MAAD,CACC,KAAK,KACL,QAAQ,QACR,MAAO,EAAO,QAAU,EAAI,OAAS,gBAEpC,EAAO,KACF,CAAA,CACD,GACQ,EAtBV,EAAO,KAsBG,CAElB,CAAC,CACK,CAAA,CAET,CCjBA,SAAS,EAAe,CACvB,QACA,WAIE,CACF,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,QAAQ,gBAAgB,KAAK,kBAApC,EACC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,KAAK,GAAI,aAClB,CACI,CAAA,GACN,EAAA,EAAA,KAAC,EAAA,OAAD,CACC,UAAU,SACV,KAAK,SACL,KAAK,KACL,EAAE,SACF,QAAS,WACT,OAEO,CAAA,CACF,GAET,CAEA,SAAS,EAAU,EAAoD,CAGtE,OAFK,EACD,OAAO,GAAM,SAAiB,EAC3B,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,IAAM,KAFzB,IAGhB,CAEA,SAAS,EAAQ,EAAoC,CACpD,OAAO,MAAM,QAAQ,CAAK,EAAI,CAAC,EAAM,GAAI,EAAM,EAAE,EAAI,CAAC,KAAM,IAAI,CACjE,CAEA,SAAS,EACR,EACA,EACC,CAQD,OAPI,EAAM,OAAO,OAAS,EAClB,EAAM,OAAO,IAAK,IAAO,CAC/B,MAAO,EAAE,MACT,MAAO,GAAG,EAAE,OAAS,EAAE,MAAM,IAAI,EAAE,MAAM,GACzC,SAAU,EAAE,QAAU,CACvB,EAAE,EAEI,GAAmB,CAAC,CAC5B,CAEA,SAAgB,EAAqB,CACpC,SACA,SAIE,CACF,IAAM,EAAO,EAAO,UAAU,MAAM,OACpC,GAAI,CAAC,EAAM,OAAO,KAElB,IAAM,EAAQ,EAAmB,CAAM,EACjC,EAAc,EAAK,aAAe,EAClC,EAAQ,EAAO,eAAe,EAC9B,EAAO,GAAkB,EAAO,eAAe,CAAI,EAEzD,GAAI,EAAK,UAAW,CACnB,IAAM,EAAS,EAAK,UACpB,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAsB,kBACrB,EAAA,EAAA,KAAC,EAAD,CAAe,QAAO,SAAU,EAAa,QAAS,CAAA,CACxC,CAAA,CAEjB,CAEA,IAAM,EAAa,GAAO,OAAS,SAAW,EAAQ,IAAA,GAChD,EAAa,GAAO,OAAS,SAAW,EAAQ,IAAA,GAEtD,OAAQ,EAAK,QAAb,CACC,IAAK,SACJ,OACC,EAAA,EAAA,KAAC,EAAA,OAAD,CACQ,QACM,cACb,UAAA,GACA,KACC,EACG,EAAgB,EAAY,EAAK,OAAO,EACvC,EAAK,SAAW,CAAC,EAEtB,MAAQ,GAAgC,KACxC,SAAW,GAAM,EAAI,GAAK,IAAA,EAAS,CACnC,CAAA,EAEH,IAAK,cACJ,OACC,EAAA,EAAA,KAAC,EAAA,YAAD,CACQ,QACM,cACb,KACC,EACG,EAAgB,EAAY,EAAK,OAAO,EACvC,EAAK,SAAW,CAAC,EAEtB,MAAQ,GAAkC,CAAC,EAC3C,SAAW,GAAM,EAAI,EAAE,OAAS,EAAI,EAAI,IAAA,EAAS,CACjD,CAAA,EAEH,IAAK,UAAW,CACf,IAAM,EAAU,GAAS,KAAO,MAAQ,EAAQ,MAAQ,KAClD,EAAW,GAAY,OAAO,KAAM,GAAM,EAAE,QAAU,MAAM,EAC5D,EAAU,GAAY,OAAO,KAAM,GAAM,EAAE,QAAU,OAAO,EAC5D,EAAW,EAAW,QAAQ,EAAS,MAAM,GAAK,MAClD,EAAU,EAAU,OAAO,EAAQ,MAAM,GAAK,KACpD,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAsB,kBACrB,EAAA,EAAA,KAAC,EAAA,iBAAD,CACC,UAAA,GACA,KAAK,KACL,KAAM,CACL,CAAE,MAAO,MAAO,MAAO,KAAM,EAC7B,CAAE,MAAO,MAAO,MAAO,CAAS,EAChC,CAAE,MAAO,KAAM,MAAO,CAAQ,CAC/B,EACA,MAAO,EACP,SAAW,GAAM,CACC,EAAb,IAAM,MAAW,IAAA,GACZ,IAAM,KAAK,CACrB,CACA,CAAA,CACa,CAAA,CAEjB,CACA,IAAK,cAAe,CACnB,GAAM,CAAC,EAAK,GAAO,EAAQ,CAAK,EAC1B,EAAY,EAAK,KAAQ,GAAY,IACrC,EAAY,EAAK,KAAQ,GAAY,IACrC,EAAY,GAAa,MAAQ,GAAa,KAC9C,EAAW,GAAS,KAEpB,EAAU,GACf,EAAA,EAAA,KAAC,EAAD,CAAc,MAAO,EAAmB,QAAO,SAAU,CAAM,CAAA,EAC5D,KAEE,EAAa,GAClB,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAO,YAAe,EAAI,IAAA,EAAS,CAAI,CAAA,EAE9D,EAGD,GAAI,EAAW,CACd,IAAM,EAAgC,CACrC,GAAQ,EACR,GAAQ,CACT,EACM,EAAW,EAAO,UAAU,MAAM,SAClC,EAAW,EACd,EAAiB,EAAU,EAAO,UAAU,MAAM,OAAQ,IAAA,EAAS,EAClE,GAAe,OAAO,CAAC,EAC3B,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAe,MAAO,YACrB,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,cAAX,CACE,GACD,EAAA,EAAA,KAAC,EAAA,YAAD,CACC,IAAK,EACL,IAAK,EACL,KAAM,EAAK,MAAQ,EACnB,MAAO,EACP,UAAW,CAAC,EAAI,KAAQ,CAEvB,EADkB,IAAO,GAAa,IAAO,EAC7B,IAAA,GAAY,CAAC,EAAI,CAAE,CAAC,CACrC,EACA,MAAQ,GAAM,EAAS,CAAC,EACxB,SAAU,EAAK,MAAQ,EACvB,aAAY,CACZ,CAAA,CACK,GACO,CAAA,CAEjB,CAEA,GAAI,EACH,OAAO,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAe,MAAO,WAAa,CAAuB,CAAA,EAGlE,IAAM,EAAU,GACf,EAAI,EAAK,IAAM,MAAQ,EAAK,IAAM,KAAO,IAAA,GAAY,CAAI,EACpD,EAAS,GACd,IAAM,IAAM,GAAK,KAAO,KAAO,OAAO,CAAC,EACxC,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAsB,kBACrB,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAK,EAAG,KAAK,kBAApB,EACC,EAAA,EAAA,KAAC,EAAA,YAAD,CACC,aAAY,GAAG,EAAM,UACrB,YAAY,MACZ,MAAO,GAAO,GACd,SAAW,GAAM,EAAO,CAAC,EAAM,CAAC,EAAG,CAAG,CAAC,EACvC,EAAG,EACH,CAAA,GACD,EAAA,EAAA,KAAC,EAAA,YAAD,CACC,aAAY,GAAG,EAAM,UACrB,YAAY,MACZ,MAAO,GAAO,GACd,SAAW,GAAM,EAAO,CAAC,EAAK,EAAM,CAAC,CAAC,CAAC,EACvC,EAAG,EACH,CAAA,CACK,GACO,CAAA,CAEjB,CACA,IAAK,OAEJ,OACC,EAAA,EAAA,KAAC,EAAA,gBAAD,CACQ,QACM,cACb,UAAA,GACA,aAAc,CAAE,aAAc,EAAM,EACpC,MAPgB,EAAQ,IAAI,KAAK,CAAe,EAAI,KAQpD,SAAW,GAAM,EAAI,EAAU,CAAC,GAAK,IAAA,EAAS,CAC9C,CAAA,EAGH,IAAK,YAAa,CACjB,GAAM,CAAC,EAAO,GAAO,EAAQ,CAAK,EAC5B,EAAyC,CAC9C,EAAQ,IAAI,KAAK,CAAK,EAAI,KAC1B,EAAM,IAAI,KAAK,CAAG,EAAI,IACvB,EACM,EACL,GAAS,KAGR,GAFA,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAO,YAAe,EAAI,IAAA,EAAS,CAAI,CAAA,EAIhE,OACC,EAAA,EAAA,KAAC,EAAA,MAAM,QAAP,CAAe,MAAO,YACrB,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,cAAX,CACE,IACA,EAAA,EAAA,KAAC,EAAD,CAAc,MAAO,EAAmB,QAAO,SAAU,CAAM,CAAA,GAEhE,EAAA,EAAA,KAAC,EAAA,gBAAD,CACC,KAAK,QACL,aAAc,CAAE,aAAc,EAAM,EACvB,cACb,UAAA,GACA,MAAO,EACP,UAAW,CAAC,EAAG,KAAO,CACrB,IAAM,EAAK,EAAU,CAAC,EAChB,EAAK,EAAU,CAAC,EACtB,EAAI,GAAM,MAAQ,GAAM,KAAO,IAAA,GAAY,CAAC,EAAI,CAAE,CAAC,CACpD,CACA,CAAA,CACK,GACO,CAAA,CAEjB,CACA,QAEC,OACC,EAAA,EAAA,KAAC,EAAA,UAAD,CACQ,QACM,cACb,MAAQ,GAAgC,GACxC,SAAW,GAAM,EAAI,EAAE,cAAc,OAAS,IAAA,EAAS,CACvD,CAAA,CAEJ,CACD,CC1RA,SAAS,EAA0B,CAClC,QAGE,CAGF,OAFe,EAAK,MAAM,cAAc,OAAS,GAGhD,EAAA,EAAA,KAAC,EAAA,OAAD,CACC,QAAQ,SACR,KAAK,aACL,MAAM,OACN,aAAa,EAAA,EAAA,KAAC,EAAD,CAAY,CAAA,EACzB,YAAe,EAAK,MAAM,mBAAmB,WAC7C,eAEO,CAAA,EAVW,IAYrB,CAEA,SAAS,EAAkB,EAA6B,CACvD,OAAO,EAAc,EAAI,YAAY,EAAY,GAAK,SACvD,CAEA,SAAS,EAAmB,CAC3B,OACA,YAIE,CACF,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAI,KAAK,MAAO,CAAE,SAAU,GAAI,WAAvC,CACE,GACD,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,QAAQ,qBACd,EAAA,EAAA,KAAC,EAAD,CAA0B,MAAO,CAAA,CAC3B,CAAA,CACD,GAET,CAEA,SAAgB,EAAsB,CACrC,OACA,mBAIE,CACF,IAAM,EAAU,EAAK,kBAEf,GAAA,EAAA,EAAA,eACL,GAAA,EAAA,EAAA,iBAAqB,EAAM,YAAY,EAAE,EACzC,EACD,EACM,CAAC,EAAW,CAAE,OAAM,WAAA,EAAA,EAAA,eAAyB,EAAK,EAExD,GAAI,EAAQ,SAAW,EAAG,OAAO,KAEjC,IAAM,EAAW,EAAQ,IAAK,IAC7B,EAAA,EAAA,KAAC,EAAD,CAES,SACR,MAAO,EAAK,OAAO,EAAO,GAC1B,EAHK,EAAO,EAGZ,CACD,EACK,EAAc,EAAK,MAAM,cAAc,OA8B7C,OA5BI,GAEF,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,UAAU,aAAa,EAAA,EAAA,KAAC,EAAD,CAAa,CAAA,EAAG,QAAS,WAC9D,EAAkB,CAAW,CACvB,CAAA,GACR,EAAA,EAAA,KAAC,EAAA,OAAD,CACC,OAAQ,EACR,QAAS,EACT,MAAM,UACN,SAAS,SACT,KAAK,iBAEL,EAAA,EAAA,KAAC,EAAD,CAAmB,OAAgB,UAAW,CAAA,CACvC,CAAA,CACP,CAAA,CAAA,EAIA,EAAQ,QAAU,GAEpB,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACE,GACD,EAAA,EAAA,KAAC,EAAD,CAA0B,MAAO,CAAA,CAChC,CAAA,CAAA,GAKH,EAAA,EAAA,MAAC,EAAA,QAAD,CAAS,SAAS,eAAe,oBAAqB,YAAtD,EACC,EAAA,EAAA,KAAC,EAAA,QAAQ,OAAT,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,UAAU,aAAa,EAAA,EAAA,KAAC,EAAD,CAAa,CAAA,WAClD,EAAkB,CAAW,CACvB,CAAA,CACO,CAAA,GAChB,EAAA,EAAA,KAAC,EAAA,QAAQ,SAAT,CAAA,UACC,EAAA,EAAA,KAAC,EAAD,CAAmB,OAAgB,UAAW,CAAA,CAC7B,CAAA,CACV,GAEX,CCpHA,SAAgB,EAAmB,CAClC,QAGE,CACF,GAAM,CAAE,kBAAiB,QAAO,SAAU,EACpC,EAAU,EAAM,QAAQ,GAM9B,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAK,EAAG,KAAK,kBAApB,EACC,EAAA,EAAA,KAAC,EAAA,OAAD,CACC,aAAW,UACX,YAAY,UACZ,UAAA,GACM,KAXI,EAAgB,IAAK,IAAO,CACxC,MAAO,EAAE,GACT,MAAO,EAAmB,CAAC,CAC5B,EAQS,EACN,MAAO,GAAS,IAAM,KACtB,SAAW,GACV,EAAM,WAAW,EAAK,CAAC,CAAE,KAAI,KAAM,GAAS,MAAQ,EAAM,CAAC,EAAI,CAAC,CAAC,CAElE,CAAA,GACD,EAAA,EAAA,KAAC,EAAA,WAAD,CACC,aAAW,wBACX,QAAQ,UACR,KAAK,KACL,SAAU,CAAC,EACX,YACC,GAAW,EAAM,WAAW,CAAC,CAAE,GAAI,EAAQ,GAAI,KAAM,CAAC,EAAQ,IAAK,CAAC,CAAC,YAGtE,EAAA,EAAA,KAAC,EAAD,CACC,UAAW,EAAW,EAAQ,KAAO,OAAS,MAAS,EACvD,CAAA,CACU,CAAA,CACN,GAET,CC/BA,SAAgB,EAAoB,CACnC,OACA,uBACA,aAAa,QACb,aAAa,SACe,CAG5B,OAFI,EAAK,gBAAkB,EAA6B,MAGvD,EAAA,EAAA,KAAC,EAAA,iBAAD,CACC,aAAW,OACX,MAAO,EAAK,KACZ,SAAU,EAAK,eACf,SAAW,GAAU,EAChB,IAAU,SAAW,IAAU,UAAS,EAAK,QAAQ,CAAK,CAC/D,EACA,KAAM,CACL,CAAE,MAAO,QAAS,MAAO,CAAqB,EAC9C,CAAE,MAAO,QAAS,MAAO,CAAqB,CAC/C,CACA,CAAA,CAEH,CCtBA,SAAS,GAAmB,CAAE,UAAqC,CAClE,GAAI,CAAC,EAAO,UAAU,EAAG,OAAO,KAChC,IAAM,EAAS,EAAO,YAAY,EAClC,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,IAAK,WAAZ,EACC,EAAA,EAAA,KAAC,EAAA,WAAD,CACC,KAAK,KACL,QAAS,IAAW,OAAS,SAAW,SACxC,MAAO,IAAW,OAAS,OAAS,OACpC,aAAY,OAAO,EAAmB,CAAM,EAAE,OAC9C,YAAe,EAAO,IAAI,IAAW,OAAS,GAAQ,MAAM,YAE5D,EAAA,EAAA,KAAC,EAAD,CAAc,CAAA,CACH,CAAA,GACZ,EAAA,EAAA,KAAC,EAAA,WAAD,CACC,KAAK,KACL,QAAS,IAAW,QAAU,SAAW,SACzC,MAAO,IAAW,QAAU,OAAS,OACrC,aAAY,OAAO,EAAmB,CAAM,EAAE,QAC9C,YAAe,EAAO,IAAI,IAAW,QAAU,GAAQ,OAAO,YAE9D,EAAA,EAAA,KAAC,GAAD,CAAe,CAAA,CACJ,CAAA,CACN,GAET,CAEA,SAAgB,GAAsB,CACrC,QAGE,CACF,IAAM,EAAU,EAAK,MAAM,kBAAkB,EAAE,OAAQ,GAAM,EAAE,WAAW,CAAC,EAG3E,OAFI,EAAQ,SAAW,EAAU,MAGhC,EAAA,EAAA,MAAC,EAAA,KAAD,CAAM,iBAAkB,GAAO,aAAA,GAAa,SAAS,sBAArD,EACC,EAAA,EAAA,KAAC,EAAA,KAAK,OAAN,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,UAAU,cAAc,EAAA,EAAA,KAAC,EAAD,CAAkB,CAAA,WAAG,SAErD,CAAA,CACI,CAAA,GACb,EAAA,EAAA,KAAC,EAAA,KAAK,SAAN,CAAA,UACC,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,IAAI,KAAK,EAAE,cAChB,EAAQ,IAAK,IACb,EAAA,EAAA,MAAC,EAAA,MAAD,CAEC,IAAI,KACJ,QAAQ,gBACR,KAAK,kBAJN,EAMC,EAAA,EAAA,KAAC,EAAA,SAAD,CACC,MAAO,EAAmB,CAAM,EAChC,QAAS,EAAO,aAAa,EAC7B,SAAW,GACV,EAAO,iBAAiB,EAAE,cAAc,OAAO,CAEhD,CAAA,GACD,EAAA,EAAA,KAAC,GAAD,CAAqB,QAAS,CAAA,CACxB,GAbD,EAAO,EAaN,CACP,CACK,CAAA,CACO,CAAA,CACV,GAER,CChDA,SAAgB,EAAmB,CAClC,OACA,oBAAoB,UACpB,wBAAwB,EACxB,uBACA,aACA,cACA,WACA,iBACA,mBACA,sBAAsB,GACtB,cACA,eACA,GAAG,GACwB,CAC3B,GAAM,CAAE,QAAO,SAAU,EACnB,EAAU,GAAuB,EAAK,SAAW,UACjD,EAAW,GAAc,EAAM,QAAQ,qBAAuB,GAC9D,EAAY,GAAe,EAAK,kBAAkB,OAAS,EAC3D,EAAS,GAAY,EAAK,gBAAgB,OAAS,EACnD,EAAe,GAAkB,GACjC,EAAa,GAAoB,GAEvC,OACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,QAAQ,gBAAgB,KAAK,OAAO,IAAI,KAAK,GAAI,WAAxD,EACC,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,KAAK,OAAO,IAAI,cAAvB,CACE,EACA,IACA,EAAA,EAAA,KAAC,EAAA,UAAD,CACC,aAAW,SACX,YAAa,EACb,aAAa,EAAA,EAAA,KAAC,EAAD,CAAa,CAAA,EAC1B,MAAO,EAAM,aACb,SAAW,GAAM,EAAM,gBAAgB,EAAE,cAAc,KAAK,EAC5D,aACC,EAAM,cACL,EAAA,EAAA,KAAC,EAAA,YAAD,CACC,KAAK,KACL,aAAW,eACX,YAAe,EAAM,gBAAgB,EAAE,CACvC,CAAA,EACE,IAAA,EAEL,CAAA,GAEF,EAAA,EAAA,MAAC,WAAD,CACC,SAAU,EACV,MAAO,CAAE,QAAS,WAAY,OAAQ,OAAQ,QAAS,EAAG,OAAQ,CAAE,WAFrE,CAIE,IACA,EAAA,EAAA,KAAC,EAAD,CACO,OACN,gBAAiB,CACjB,CAAA,EAED,IAAU,EAAA,EAAA,KAAC,EAAD,CAAmB,MAAO,CAAA,CAC5B,GACJ,KACP,EAAA,EAAA,KAAC,WAAD,CACC,SAAU,EACV,MAAO,CAAE,QAAS,WAAY,OAAQ,OAAQ,QAAS,EAAG,OAAQ,CAAE,YAEpE,EAAA,EAAA,MAAC,EAAA,MAAD,CAAO,KAAK,OAAO,IAAI,cAAvB,CACE,IAAgB,EAAA,EAAA,KAAC,GAAD,CAAsB,MAAO,CAAA,EAC7C,IACA,EAAA,EAAA,KAAC,EAAD,CACO,OACgB,sBACtB,CAAA,EAED,CACK,GACE,CAAA,CACJ,GAET,CCvFA,IAAM,GAAA,EAAA,EAAA,eACL,IACD,EAEa,EAAmB,EAAgB,SAEhD,SAAgB,GAAyD,CACxE,IAAM,GAAA,EAAA,EAAA,YAAiB,CAAe,EACtC,GAAI,CAAC,EACJ,MAAU,MACT,oGACD,EAED,OAAO,CACR,CCFA,SAAgB,EAAkB,CACjC,OACA,QACA,aACA,eACA,uBACA,cACA,WACA,GAAG,GACuB,CAa1B,OACC,EAAA,EAAA,KAAC,EAAD,CAAkB,OAAA,EAAA,EAAA,cAZX,CACN,OACA,QACA,aACA,eACA,uBACA,aACD,GACA,CAAC,EAAM,EAAO,EAAY,EAAc,EAAsB,CAAW,CAIhD,YACxB,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,GAAI,WACT,IACA,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACC,EAAA,EAAA,KAAC,EAAD,CAAkB,CAAA,GAClB,EAAA,EAAA,KAAC,GAAD,CAAsB,CAAA,GACtB,EAAA,EAAA,KAAC,GAAD,CAAe,CAAA,GACf,EAAA,EAAA,KAAC,GAAD,CAAqB,CAAA,CACpB,CAAA,CAAA,CAEG,CAAA,CACU,CAAA,CAEpB,CAOA,SAAS,EAAuB,EAAsC,CACrE,GAAM,CAAE,OAAM,wBAAyB,EAA0B,EACjE,OACC,EAAA,EAAA,KAAC,EAAD,CACO,OACgB,uBACtB,GAAI,CACJ,CAAA,CAEH,CAUA,SAAS,GAAoB,CAC5B,aACA,cAC8B,CAC9B,GAAM,CAAE,OAAM,QAAO,aAAY,eAAc,eAC9C,EAA0B,EAC3B,OAAO,EAAK,OAAS,SACpB,EAAA,EAAA,KAAC,EAAD,CACO,OACC,QACK,aACE,eACD,cACb,GAAI,CACJ,CAAA,GAED,EAAA,EAAA,KAAC,EAAD,CACO,OACC,QACM,cACb,GAAI,CACJ,CAAA,CAEH,CAEA,SAAS,GACR,EACC,CACD,GAAM,CAAE,QAAS,EAA0B,EAC3C,OAAO,EAAA,EAAA,KAAC,EAAD,CAAsB,OAAM,GAAI,CAAQ,CAAA,CAChD,CAEA,SAAS,GACR,EACC,CACD,GAAM,CAAE,OAAM,SAAU,EAA0B,EAClD,OAAO,EAAA,EAAA,KAAC,EAAD,CAAuB,OAAa,QAAO,GAAI,CAAQ,CAAA,CAC/D,CAEA,EAAW,QAAU,EACrB,EAAW,YAAc,GACzB,EAAW,KAAO,GAClB,EAAW,WAAa,GC3GxB,SAAgB,GAAS,EAAuB,CAC/C,OAAO,EACL,QAAQ,KAAM,GAAG,EACjB,QAAQ,kBAAmB,OAAO,EAClC,QAAQ,QAAU,GAAM,EAAE,YAAY,CAAC,CAC1C,CAQA,IAAM,GAAwC,CAC7C,KAAM,CAAE,SAAU,OAAQ,cAAe,MAAO,EAChD,OAAQ,CAAE,SAAU,SAAU,cAAe,cAAe,MAAO,OAAQ,EAC3E,SAAU,CACT,SAAU,WACV,cAAe,cACf,MAAO,OACR,EACA,KAAM,CAAE,SAAU,OAAQ,cAAe,WAAY,EACrD,QAAS,CAAE,SAAU,UAAW,cAAe,SAAU,EACzD,OAAQ,CAAE,cAAe,QAAS,EAClC,YAAa,CAAE,cAAe,aAAc,CAC7C,EAEa,GAAb,KAAkC,CACjC,KAAuC,CAAC,EACxC,QAAA,EAAA,EAAA,oBAA2C,EAE3C,IACC,EACA,EACA,EACO,CACP,IAAM,EAAS,GAAQ,GACvB,GAAI,CAAC,EAAQ,MAAU,MAAM,mBAAmB,GAAQ,EAExD,IAAM,EAAQ,GAAM,QAAU,GAAS,CAAK,EACtC,EAAQ,GAAM,OAAS,EAAO,MAEhC,EACJ,GAAI,GAAM,SAAW,GACpB,EAAS,IAAA,OACH,CACN,IAAM,EAAO,CACZ,QAAS,EAAO,cAChB,GAAI,GAAM,QAAU,CAAE,QAAS,EAAK,OAAQ,EAAI,CAAC,CAClD,EACA,EAAS,GAAM,OACX,CAAE,GAAG,EAAM,GAAG,EAAK,MAAO,EAC3B,CACJ,CAGA,IAAM,EAAU,KAAK,OAAe,SAAS,EAAO,CACnD,OAAQ,EACR,GAAI,GAAM,KAAO,CAAE,KAAM,EAAK,IAAK,EAAI,CAAC,EACxC,GAAI,GAAM,gBAAkB,GAAQ,CAAE,cAAe,EAAM,EAAI,CAAC,EAChE,GAAI,GAAM,OAAS,KAA8B,CAAC,EAAxB,CAAE,KAAM,EAAK,KAAM,EAC7C,KAAM,CACL,QACA,GAAI,EAAO,SAAW,CAAE,SAAU,EAAO,QAAS,EAAI,CAAC,EACvD,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,EACzB,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,EAC3B,GAAI,GAAM,OAAS,CAAE,OAAQ,EAAK,MAAO,EAAI,CAAC,EAC9C,GAAI,GAAM,KACP,CACA,KAAM,CACL,KAAM,EAAK,KACX,GAAI,EAAK,WAAa,KAAmC,CAAC,EAA7B,CAAE,MAAO,EAAK,SAAU,CACtD,CACD,EACC,CAAC,CACL,CACD,CAAC,EAGD,OADA,KAAK,KAAK,KAAK,CAAM,EACd,IACR,CAEA,KAAK,EAAqB,EAAgC,CACzD,OAAO,KAAK,IAAI,OAAQ,EAAO,CAAI,CACpC,CAEA,OAAO,EAAqB,EAAgC,CAC3D,OAAO,KAAK,IAAI,SAAU,EAAO,CAAI,CACtC,CAEA,SAAS,EAAqB,EAAgC,CAC7D,OAAO,KAAK,IAAI,WAAY,EAAO,CAAI,CACxC,CAEA,KAAK,EAAqB,EAAgC,CACzD,OAAO,KAAK,IAAI,OAAQ,EAAO,CAAI,CACpC,CAEA,QAAQ,EAAqB,EAAgC,CAC5D,OAAO,KAAK,IAAI,UAAW,EAAO,CAAI,CACvC,CAEA,OACC,EACA,EACO,CACP,OAAO,KAAK,IAAI,SAAU,EAAO,CAAI,CACtC,CAEA,YACC,EACA,EACO,CACP,OAAO,KAAK,IAAI,cAAe,EAAO,CAAI,CAC3C,CAEA,OAAO,EAAoC,CAE1C,OADA,KAAK,KAAK,KAAK,CAAM,EACd,IACR,CAEA,OAAgC,CAC/B,OAAO,KAAK,IACb,CACD,EAEA,SAAgB,IAAmC,CAClD,OAAO,IAAI,EACZ,CCzJA,SAAS,EAAU,EAAwB,CAC1C,IAAM,EAAM,GAAS,KAAO,GAAK,OAAO,CAAK,EAI7C,OAHI,EAAI,SAAS,GAAG,GAAK,EAAI,SAAS,GAAG,GAAK,EAAI,SAAS;CAAI,EACvD,IAAI,EAAI,QAAQ,KAAM,IAAI,EAAE,GAE7B,CACR,CAUA,SAAgB,GACf,EACA,EACO,CACP,GAAM,CACL,WAAW,aACX,YAAY,IACZ,YAAY,GACZ,kBACG,GAAW,CAAC,EACV,EAAU,EACd,sBAAsB,EACtB,OAAQ,GAAM,EAAE,KAAO,SAAS,EAkB5B,EAAM,CAjBG,EAAQ,IAAK,GAAM,EAAU,EAAmB,CAAC,CAAC,CAiBpD,EAAQ,GAhBR,EAAM,YAAY,EAAE,KAAK,IAAK,GAC1C,EAAQ,IAAK,GAAQ,CAEpB,IAAM,EADO,EAAI,YAAY,EAAE,KAAM,GAAM,EAAE,OAAO,KAAO,EAAI,EACnD,GAAM,SAAS,EAS3B,OARI,GAAa,EAAI,UAAU,MAAM,SAM7B,EALW,EACjB,EAAI,UAAU,KAAK,SACnB,EAAI,UAAU,KAAK,OACnB,CAEgB,EAAU,CAAG,CAAC,EAEzB,EAAU,CAAG,CACrB,CAAC,CAGsB,CAAI,EAAE,IAAK,GAAM,EAAE,KAAK,CAAS,CAAC,EAAE,KAAK;CAAI,EAC/D,EAAO,IAAI,KAAK,CAAC,CAAG,EAAG,CAAE,KAAM,yBAA0B,CAAC,EAC1D,EAAM,IAAI,gBAAgB,CAAI,EAC9B,EAAO,SAAS,cAAc,GAAG,EACvC,EAAK,KAAO,EACZ,EAAK,SAAW,EAChB,EAAK,MAAM,EACX,IAAI,gBAAgB,CAAG,CACxB,CCvDA,SAAgB,GACf,EAIW,CAEX,OADc,UAAW,EAAM,EAAI,MAAQ,GAC7B,QAAQ,MAAM,UAAyB,OACtD,CCeA,SAAgB,GACf,EAC2B,CAE3B,OADK,EACE,CACN,QAAS,EAAQ,QACjB,WAAY,CAAE,GAAG,EAAA,EAAsB,GAAG,EAAQ,SAAU,EAC5D,QAAS,EAAA,EAAe,EAAQ,OAAO,CACxC,EALqB,IAMtB,CAGA,SAAgB,GACf,EACA,EACA,EACyB,CACzB,GAAI,CAAC,EAAQ,MAAO,CAAC,EACrB,GAAI,CACH,OAAO,EAAA,EAAkB,EAAO,QAAQ,KAAK,EAAG,CAC/C,WAAY,EAAO,WACnB,QAAS,EAAO,QAChB,gBACA,SACD,CAAC,CACF,MAAQ,CAEP,MAAO,CAAC,CACT,CACD,CASA,SAAgB,GAAW,CAC1B,SACA,QACA,aACA,iBACwB,CAGxB,IAAM,GAAA,EAAA,EAAA,QAAkB,CAAK,EAC7B,EAAS,QAAU,EACnB,IAAM,GAAA,EAAA,EAAA,QAAuB,CAAU,EACvC,EAAc,QAAU,EACxB,IAAM,GAAA,EAAA,EAAA,QAA0B,CAAa,EAC7C,EAAiB,QAAU,EAC3B,IAAM,GAAA,EAAA,EAAA,QAAmB,CAAM,EAC/B,EAAU,QAAU,EAKpB,IAAM,EAAS,EACZ,EAAA,EAAe,EAAO,CACtB,WAAY,EAAO,WACnB,QAAS,EAAO,QAChB,eACD,CAAC,EACA,MAMH,EAAA,EAAA,eAAgB,CACf,IAAM,EAAM,EAAU,QACtB,GAAI,CAAC,GAAO,CAAC,EAAQ,OAErB,IAAM,EAAY,EAAA,EADF,EAAI,QAAQ,KACS,EAAS,EAAI,WAAY,EAAI,OAAO,EACzE,EAAI,QAAQ,MAAM,CAAE,GAAG,EAAW,GAAG,CAAO,EAAG,CAAE,QAAS,EAAK,CAAC,CACjE,EAAG,CATe,EAAS,KAAK,UAAU,CAAM,EAAI,EASvC,CAAC,GAGd,EAAA,EAAA,eAAgB,CACf,GAAI,CAAC,EAAQ,OACb,GAAM,CAAE,UAAS,aAAY,WAAY,EACzC,OAAO,EAAQ,gBAAkB,CAChC,IAAM,EAAQ,EAAA,EAAkB,EAAQ,KAAK,EAAG,CAC/C,aACA,UACA,cAAe,EAAiB,QAChC,QAAS,EAAS,OACnB,CAAC,EACD,EAAc,QAAQ,CAAK,CAC5B,CAAC,CACF,EAAG,CAAC,CAAM,CAAC,CACZ,CChHA,SAAgB,GAAW,EAA+B,CACzD,OAAO,EAAM,cAAc,OAAS,GAAK,EAAM,aAAa,KAAK,IAAM,EACxE,CAUA,SAAgB,GAAsB,CACrC,SACA,QACA,eACA,SAC+B,CAQ/B,OAPI,IAAW,QAAgB,CAAE,MAAO,QAAS,OAAM,EAGnD,IAAW,WAAa,IAAW,OAAe,CAAE,MAAO,SAAU,EACrE,IAAiB,EACb,GAAW,CAAK,EAAI,CAAE,MAAO,gBAAiB,EAAI,CAAE,MAAO,OAAQ,EAEpE,CAAE,MAAO,OAAQ,CACzB,CCGA,IAAM,EAAsB,IACtB,GAAqB,CAAC,GAAI,GAAI,GAAI,GAAG,EACrC,GAAoB,GAO1B,SAAS,GACR,EACmB,CAUnB,OATI,GAAY,KACR,CACN,aAAc,EACd,cAAe,CAChB,EAEG,OAAO,GAAa,SAChB,CAAE,aAAc,EAAU,cAAe,CAAS,EAEnD,CACN,aAAc,EAAS,cAAgB,EACvC,cAAe,EAAS,eAAiB,CAC1C,CACD,CAEA,SAAS,GAAuB,EAA+C,CAC9E,GAAI,EAAI,GAAI,OAAO,EAAI,GACvB,GAAI,gBAAiB,GAAO,EAAI,aAAe,KAC9C,OAAO,OAAO,EAAI,WAAW,CAG/B,CAGA,SAAS,GACR,EAC+C,CAC/C,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAO,EAAS,CAC1B,IAAM,EAAK,GAAgB,CAAG,EACxB,EAAS,EAAI,MAAM,OACrB,GAAM,GAAQ,EAAI,IAAI,EAAI,CAAM,CACrC,CACA,MAAQ,IAAO,EAAI,IAAI,CAAE,CAC1B,CAEA,SAAS,GACR,EACgB,CAEhB,MAAO,CACN,WAAY,CAAE,UAAW,EAAG,SAFZ,EAAQ,kBAAkB,IAAM,EAEX,EACrC,QAAS,CAAC,EACV,cAAe,CAAC,EAChB,aAAc,GACd,aAAc,CAAC,EACf,iBAAkB,CAAC,EACnB,cAAe,CAAE,KAAM,CAAC,EAAG,MAAO,CAAC,CAAE,EACrC,KAAM,EAAQ,aAAe,QAC7B,GAAG,EAAQ,YACZ,CACD,CAEA,SAAgB,GACf,EAC2B,CAC3B,GAAM,CACL,QAAS,EACT,OACA,WACA,SACA,QACA,WACA,kBACA,MAAO,EACP,gBACA,qBACA,qBAAqB,GACrB,WACA,aACA,iBACA,OAAQ,EACR,OAAQ,GACL,EAEE,EAAS,GAAe,CAAC,EACzB,EAAY,EAAc,KAAK,UAAU,CAAW,EAAI,GACxD,EAAS,GAAe,CAAC,EAEzB,GAAA,EAAA,EAAA,aAEJ,EAAW,IAAK,GAAQ,CACvB,IAAM,EAAW,EAAI,MAAM,SAC3B,GAAI,CAAC,GAAY,EAAI,KAAM,OAAO,EAClC,IAAM,EAAY,EACjB,EACA,EAAI,MAAM,OACV,CACD,EACA,MAAO,CACN,GAAG,EACH,KAAO,GAAqC,EAAU,EAAI,SAAS,CAAC,CACrE,CACD,CAAC,EACF,CAAC,EAAY,CAAc,CAC5B,EAIM,GAAA,EAAA,EAAA,aACC,GAAsB,CAAO,EACnC,CAAC,CAAO,CACT,EACM,GAAA,EAAA,EAAA,aACC,GAAiB,EAAQ,OAAO,EACtC,CAAC,EAAQ,OAAO,CACjB,EAIM,CAAC,EAAe,KAAA,EAAA,EAAA,cAAkD,CACvE,IAAM,EAAO,GAAkB,CAAO,EACtC,MAAO,CAAE,GAAG,EAAM,GAAG,GAAe,EAAW,EAAM,CAAa,CAAE,CACrE,CAAC,EAEK,GAAA,EAAA,EAAA,cACE,CAAE,GAAG,EAAe,GAAG,CAAgB,GAC9C,CAAC,EAAe,CAAe,CAChC,EAIM,GAAA,EAAA,EAAA,QAA0B,CAAa,EAC7C,EAAiB,QAAU,EAE3B,IAAM,GAAA,EAAA,EAAA,aACJ,GAAkC,CAClC,GAAkB,IAAU,CAAE,GAAG,EAAM,GAAG,CAAM,EAAE,EAClD,IAAgB,CAAE,GAAG,EAAiB,QAAS,GAAG,CAAM,CAAC,CAC1D,EACA,CAAC,CAAa,CACf,EAGA,GAAW,CACV,OAAQ,EACR,MAAO,EACP,aACA,eACD,CAAC,EAID,IAAM,GAAA,EAAA,EAAA,kBACmB,CACvB,GAAG,EAAiB,QAAQ,WAC5B,UAAW,CACZ,GACA,CAAC,CACF,EAEM,GAAA,EAAA,EAAA,QAA0B,CAAS,GACzC,EAAA,EAAA,eAAgB,CACX,EAAiB,UAAY,IACjC,EAAiB,QAAU,EAC3B,EAAW,CAAE,WAAY,EAAgB,CAAE,CAAC,EAC7C,CAAC,EAED,IAAM,IAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,YAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,UAC1B,CACD,CAAC,CACF,EACA,CAAC,CAAU,CACZ,EAEM,GAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,SAAA,EAAA,EAAA,kBAA0B,EAAS,EAAiB,QAAQ,OAAO,EACnE,WAAY,EAAgB,CAC7B,CAAC,CACF,EACA,CAAC,EAAY,CAAe,CAC7B,EAEM,GAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,eAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,aAC1B,EACA,WAAY,EAAgB,CAC7B,CAAC,CACF,EACA,CAAC,EAAY,CAAe,CAC7B,EAEM,IAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,cAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,YAC1B,EACA,WAAY,EAAgB,CAC7B,CAAC,CACF,EACA,CAAC,EAAY,CAAe,CAC7B,EAEM,GAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,cAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,YAC1B,CACD,CAAC,CACF,EACA,CAAC,CAAU,CACZ,EAEM,GAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,kBAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,gBAC1B,CACD,CAAC,CACF,EACA,CAAC,CAAU,CACZ,EAEM,GAAA,EAAA,EAAA,aACJ,GAAY,CACZ,EAAW,CACV,eAAA,EAAA,EAAA,kBACC,EACA,EAAiB,QAAQ,aAC1B,CACD,CAAC,CACF,EACA,CAAC,CAAU,CACZ,EAEM,EAAiB,GAAc,CAAU,EACzC,EAAiB,EAAiB,QAAU,EAAc,KAE1D,GAAA,EAAA,EAAA,eAA6B,CAClC,KAAM,EACN,KAAM,CAAE,SAAU,CAAK,EACvB,UACA,iBAAA,EAAA,EAAA,iBAAiC,EAEjC,iBAAkB,GAClB,cAAe,GACf,gBAAiB,GACjB,mBAAoB,GACpB,WACA,SAAW,GAAgB,EAAS,CAAW,EAC/C,mBACC,OAAO,GAAuB,WAC1B,GAAQ,EAAmB,EAAI,QAAQ,EACvC,GAAsB,GAC3B,qBACA,MAAO,CACN,WAAY,EAAc,WAC1B,QAAS,EAAc,QACvB,cAAe,EAAc,cAC7B,aAAc,EAAc,aAC5B,aAAc,EAAc,aAC5B,iBAAkB,EAAc,iBAChC,cAAe,EAAc,aAC9B,EACA,sBACA,kBACA,wBACA,wBACA,uBACA,2BACA,uBACD,CAAC,EAKK,GAAA,EAAA,EAAA,cACE,CACN,WAAY,EAAc,WAC1B,QAAS,EAAc,QACvB,QAAS,EAAc,cACvB,aAAc,EAAc,aAC5B,QACD,GACA,CACC,EAAc,WACd,EAAc,QACd,EAAc,cACd,EAAc,aACd,CACD,CACD,EAKM,GAAA,EAAA,EAAA,QAA4B,CAAe,EACjD,EAAmB,QAAU,EAC7B,IAAM,GAAA,EAAA,EAAA,QAAuC,GAAgB,CAAQ,CAAC,EACtE,EAAY,QAAU,GAAgB,CAAQ,EAC9C,IAAM,GAAA,EAAA,EAAA,QAAgD,IAAI,EACpD,GAAA,EAAA,EAAA,QAA6D,IAAA,EAAS,GAE5E,EAAA,EAAA,eAAgB,CACf,IAAM,EAAO,EAAe,QACtB,EAAU,IAAS,KACnB,EAAgB,CAAC,GAAQ,EAAK,eAAiB,EAAQ,aACvD,EAAiB,CAAC,GAAQ,EAAK,UAAY,EAAQ,QAEnD,MAAa,CAClB,EAAe,QAAU,EACzB,EAAmB,UAAU,CAAO,CACrC,EAEI,EAAQ,EACR,IACH,EAAQ,KAAK,IAAI,EAAO,EAAY,QAAQ,YAAY,GACrD,IACH,EAAQ,KAAK,IAAI,EAAO,EAAY,QAAQ,aAAa,GAC1D,IAAM,EACL,CAAC,IAAY,GAAiB,IAAmB,EAAQ,EAQ1D,OANA,aAAa,EAAS,OAAO,EACzB,EACH,EAAS,QAAU,WAAW,EAAM,CAAK,EAEzC,EAAK,MAEO,aAAa,EAAS,OAAO,CAC3C,EAAG,CAAC,CAAO,CAAC,EAGZ,IAAM,GAAA,EAAA,EAAA,QAAoB,CAAO,EACjC,EAAW,QAAU,EACrB,IAAM,IAAA,EAAA,EAAA,iBAA4B,CACjC,EAAmB,UAAU,EAAW,OAAO,CAChD,EAAG,CAAC,CAAC,EAGC,IAAA,EAAA,EAAA,aAEJ,GAAsB,CACrB,SACA,QACA,aAAc,EAAK,OACnB,MAAO,CACR,CAAC,EACF,CAAC,EAAQ,EAAO,EAAK,OAAQ,CAAa,CAC3C,EAEM,GAAA,EAAA,EAAA,aACJ,GAAmB,EAAW,CAAE,KAAM,CAAK,CAAC,EAC7C,CAAC,CAAU,CACZ,EAEM,EAAkB,EAAQ,iBAAmB,GAK7C,EAAa,EAAM,cAAc,EACjC,EAAkB,EAAW,OAAQ,GAAM,EAAE,WAAW,CAAC,EACzD,EAAoB,EAAW,OACnC,GAAM,EAAE,UAAU,MAAM,QAAU,IACpC,EAEM,GAAA,EAAA,EAAA,iBACC,EAAW,CAAE,aAAc,CAAC,CAAE,CAAC,EACrC,CAAC,CAAU,CACZ,EA8BA,MAAO,CACN,QACA,UACA,MAAO,EACP,OACA,UACA,iBACA,SACA,QACA,gBACA,WACA,kBACA,kBACA,oBACA,WAAA,EAAA,EAAA,aA3C+B,CAC/B,IAAM,EAAM,EAAc,aAGpB,EAAc,OAAO,KAAK,CAAG,EAAE,OAAQ,GAAM,EAAI,EAAE,EACnD,EAAe,EAAK,OAAQ,GAAQ,EAAI,EAAS,CAAG,KAAO,EAAI,EACrE,MAAO,CACN,MAAO,EAAY,OACnB,IAAK,EACL,KAAM,EACN,MAAO,CACR,CACD,EAAG,CAAC,EAAc,aAAc,EAAM,EAAU,CAAc,CA+B7D,EACA,WAAA,EAAA,EAAA,aA7BC,GAA6C,GAAY,EAAO,CAAI,EACrE,CAAC,CAAK,CA4BN,EACA,SACA,aAAA,EAAA,EAAA,aA1BC,GAAqB,EAAM,UAAU,CAAQ,GAAG,eAAe,IAAA,EAAS,EACzE,CAAC,CAAK,CAyBN,EACA,iBAAA,EAAA,EAAA,iBAtBM,EAAM,mBAAmB,EAC/B,CAAC,CAAK,CAqBN,CACD,CACD,CC9bA,SAAgB,GAA0B,CACzC,UACA,OACA,GAAG,GAC2D,CAC9D,GAAM,CAAC,EAAU,IAAA,EAAA,EAAA,UAAiD,CACjE,KAAM,CAAC,EACP,SAAU,CACX,CAAC,EACK,CAAC,EAAQ,IAAA,EAAA,EAAA,UAA8B,MAAM,EAC7C,CAAC,EAAO,IAAA,EAAA,EAAA,UAA8B,IAAA,EAAS,EAE/C,GAAA,EAAA,EAAA,QAAoB,CAAO,EACjC,EAAW,QAAU,EAErB,IAAM,GAAA,EAAA,EAAA,QAAsB,CAAC,EAEvB,GAAA,EAAA,EAAA,QAAgD,IAAI,EAEpD,GAAA,EAAA,EAAA,aAA8B,KAAO,IAA6B,CACvE,EAAe,QAAU,EACzB,IAAM,EAAK,EAAE,EAAa,QAC1B,EAAU,SAAS,EACnB,GAAI,CACH,IAAM,EAAO,MAAM,EAAW,QAAQ,CAAO,EACzC,IAAO,EAAa,UACvB,EAAY,CAAI,EAChB,EAAS,IAAA,EAAS,EAClB,EAAU,SAAS,EAErB,OAAS,EAAK,CACT,IAAO,EAAa,UACvB,EAAS,CAAG,EACZ,EAAU,OAAO,EAEnB,CACD,EAAG,CAAC,CAAC,EAEC,EAAU,EAAO,KAAK,UAAU,CAAI,EAAI,GACxC,GAAA,EAAA,EAAA,QAAwB,CAAO,EASrC,OARA,EAAA,EAAA,eAAgB,CACX,EAAe,UAAY,IAC/B,EAAe,QAAU,EACrB,EAAe,SAClB,EAAgB,EAAe,OAAO,EAExC,CAAC,EAEM,GAAmB,CACzB,GAAG,EACH,KAAM,EAAS,KACf,SAAU,EAAS,SACnB,OAAQ,EAAS,OACjB,SACA,QACA,iBACD,CAAC,CACF"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=[`pagination`,`sorting`,`columnFilters`,`globalFilter`,`view`],t={page:`page`,size:`size`,sort:`sort`,search:`q`,view:`view`,filterPrefix:`f.`,encodeFilter(e,t,r){switch(r?.variant){case`multiselect`:return Array.isArray(t)?t.map(String).join(`,`):``;case`numberRange`:case`dateRange`:{let[e,r]=Array.isArray(t)?t:[],i=e==null?``:n(e),a=r==null?``:n(r);return i===``&&a===``?``:`${i}..${a}`}case`boolean`:return t==null||t===``?``:t?`true`:`false`;case`date`:return t==null?``:n(t);default:return t==null?``:String(t)}},decodeFilter(e,t,n){switch(n?.variant){case`multiselect`:return t===``?[]:t.split(`,`);case`numberRange`:{let[e,n]=t.split(`..`);return[e?Number(e):null,n?Number(n):null]}case`dateRange`:{let[e,n]=t.split(`..`);return[e||null,n||null]}case`boolean`:return t===`true`;default:return t}}};function n(e){return e instanceof Date?e.toISOString():String(e)}function r(t){return t?e.filter(e=>t.includes(e)):[...e]}function i(e){return e.map(e=>`${e.id}:${e.desc?`desc`:`asc`}`).join(`,`)}function a(e){if(e===``)return[];let t=[];for(let n of e.split(`,`)){let[e,r]=n.split(`:`);e&&t.push({id:e,desc:r===`desc`})}return t}function o(e){return e===`table`||e===`cards`}function s(e,{serializer:t,include:n,getFilterMeta:r}){let a={};if(n.includes(`pagination`)&&(e.pagination.pageIndex>0&&(a[t.page]=String(e.pagination.pageIndex+1)),a[t.size]=String(e.pagination.pageSize)),n.includes(`sorting`)){let n=i(e.sorting);n&&(a[t.sort]=n)}if(n.includes(`globalFilter`)&&e.globalFilter&&(a[t.search]=e.globalFilter),n.includes(`view`)&&(a[t.view]=e.view),n.includes(`columnFilters`))for(let{id:n,value:i}of e.columnFilters){let e=t.encodeFilter(n,i,r?.(n));e!==``&&(a[`${t.filterPrefix}${n}`]=e)}return a}function c(e,{serializer:t,include:n,getFilterMeta:r,current:i}){let s={};if(n.includes(`pagination`)){let n=e[t.page],r=e[t.size],a=n?Number(n):1;s.pagination={pageIndex:Number.isFinite(a)?Math.max(0,Math.trunc(a)-1):0,pageSize:r&&Number.isFinite(Number(r))?Number(r):i.pagination.pageSize}}if(n.includes(`sorting`)&&(s.sorting=a(e[t.sort]??``)),n.includes(`globalFilter`)&&(s.globalFilter=e[t.search]??``),n.includes(`view`)){let n=e[t.view];s.view=n&&o(n)?n:i.view}if(n.includes(`columnFilters`)){let n=[];for(let[i,a]of Object.entries(e)){if(!i.startsWith(t.filterPrefix))continue;let e=i.slice(t.filterPrefix.length);n.push({id:e,value:t.decodeFilter(e,a,r?.(e))})}s.columnFilters=n}return s}function l(e,t,n){let r=new Set;n.includes(`pagination`)&&(r.add(t.page),r.add(t.size)),n.includes(`sorting`)&&r.add(t.sort),n.includes(`globalFilter`)&&r.add(t.search),n.includes(`view`)&&r.add(t.view);let i=n.includes(`columnFilters`),a={};for(let[n,o]of Object.entries(e))r.has(n)||i&&n.startsWith(t.filterPrefix)||(a[n]=o);return a}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return t}});
|
|
2
|
-
//# sourceMappingURL=serializer-CGmBq-Jz.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serializer-CGmBq-Jz.cjs","names":[],"sources":["../src/url/serializer.ts"],"sourcesContent":["// URL serializer. It maps the syncable slices of `DataViewState` to and from a flat record of\n// query params. The values here are logical strings that are not encoded. The `UrlStateAdapter`\n// handles encoding and decoding on the wire, for example through `URLSearchParams`. That keeps\n// this layer neutral about the transport.\n//\n// Example shape:\n// ?page=2&size=25&sort=name:asc,createdAt:desc&q=ada&view=cards&f.status=active,pending\n//\n// Selection and column visibility are intentionally left out of the URL. There is no canonical\n// representation for them, and selection is ephemeral. Only the slices below participate.\n\nimport type { ColumnFilterMeta } from \"../types/column\";\nimport type { DataViewState, ViewMode } from \"../types/state\";\nimport type { UrlSerializer } from \"./types\";\n\nexport type SyncableKey =\n\t| \"pagination\"\n\t| \"sorting\"\n\t| \"columnFilters\"\n\t| \"globalFilter\"\n\t| \"view\";\n\nexport const SYNCABLE_KEYS: readonly SyncableKey[] = [\n\t\"pagination\",\n\t\"sorting\",\n\t\"columnFilters\",\n\t\"globalFilter\",\n\t\"view\",\n];\n\ntype FilterMetaLookup = (id: string) => ColumnFilterMeta | undefined;\n\n/** Default param names and a filter codec for each variant. Every field can be overridden. */\nexport const defaultUrlSerializer: UrlSerializer = {\n\tpage: \"page\",\n\tsize: \"size\",\n\tsort: \"sort\",\n\tsearch: \"q\",\n\tview: \"view\",\n\tfilterPrefix: \"f.\",\n\n\tencodeFilter(_id, value, meta) {\n\t\tswitch (meta?.variant) {\n\t\t\tcase \"multiselect\":\n\t\t\t\treturn Array.isArray(value) ? value.map(String).join(\",\") : \"\";\n\t\t\tcase \"numberRange\":\n\t\t\tcase \"dateRange\": {\n\t\t\t\tconst [a, b] = Array.isArray(value) ? value : [];\n\t\t\t\tconst left = a == null ? \"\" : encodeScalar(a);\n\t\t\t\tconst right = b == null ? \"\" : encodeScalar(b);\n\t\t\t\treturn left === \"\" && right === \"\" ? \"\" : `${left}..${right}`;\n\t\t\t}\n\t\t\tcase \"boolean\":\n\t\t\t\treturn value == null || value === \"\" ? \"\" : value ? \"true\" : \"false\";\n\t\t\tcase \"date\":\n\t\t\t\treturn value == null ? \"\" : encodeScalar(value);\n\t\t\tdefault:\n\t\t\t\t// text, select\n\t\t\t\treturn value == null ? \"\" : String(value);\n\t\t}\n\t},\n\n\tdecodeFilter(_id, raw, meta) {\n\t\tswitch (meta?.variant) {\n\t\t\tcase \"multiselect\":\n\t\t\t\treturn raw === \"\" ? [] : raw.split(\",\");\n\t\t\tcase \"numberRange\": {\n\t\t\t\tconst [a, b] = raw.split(\"..\");\n\t\t\t\treturn [a ? Number(a) : null, b ? Number(b) : null];\n\t\t\t}\n\t\t\tcase \"dateRange\": {\n\t\t\t\tconst [a, b] = raw.split(\"..\");\n\t\t\t\treturn [a || null, b || null];\n\t\t\t}\n\t\t\tcase \"boolean\":\n\t\t\t\treturn raw === \"true\";\n\t\t\tdefault:\n\t\t\t\t// text, select, date (kept as an ISO string)\n\t\t\t\treturn raw;\n\t\t}\n\t},\n};\n\nfunction encodeScalar(value: unknown): string {\n\treturn value instanceof Date ? value.toISOString() : String(value);\n}\n\n/** Resolves the `include` option to the supported, syncable subset. The default is all of them. */\nexport function resolveInclude(\n\tinclude?: Array<keyof DataViewState>,\n): SyncableKey[] {\n\tif (!include) return [...SYNCABLE_KEYS];\n\treturn SYNCABLE_KEYS.filter((k) => include.includes(k));\n}\n\nfunction encodeSort(sorting: DataViewState[\"sorting\"]): string {\n\treturn sorting.map((s) => `${s.id}:${s.desc ? \"desc\" : \"asc\"}`).join(\",\");\n}\n\nfunction decodeSort(raw: string): DataViewState[\"sorting\"] {\n\tif (raw === \"\") return [];\n\tconst result: DataViewState[\"sorting\"] = [];\n\tfor (const token of raw.split(\",\")) {\n\t\tconst [id, dir] = token.split(\":\");\n\t\tif (id) result.push({ id, desc: dir === \"desc\" });\n\t}\n\treturn result;\n}\n\nfunction isViewMode(value: string): value is ViewMode {\n\treturn value === \"table\" || value === \"cards\";\n}\n\nexport interface SerializeContext {\n\tserializer: UrlSerializer;\n\tinclude: SyncableKey[];\n\tgetFilterMeta?: FilterMetaLookup;\n}\n\n/**\n * Serializes the included slices to query params. Empty or default values are omitted to keep\n * the URL clean. The page is emitted only past the first page, counting from one. Empty search,\n * sort, and filter values drop out entirely.\n */\nexport function serializeState(\n\tstate: DataViewState,\n\t{ serializer, include, getFilterMeta }: SerializeContext,\n): Record<string, string> {\n\tconst params: Record<string, string> = {};\n\n\tif (include.includes(\"pagination\")) {\n\t\tif (state.pagination.pageIndex > 0) {\n\t\t\tparams[serializer.page] = String(state.pagination.pageIndex + 1);\n\t\t}\n\t\tparams[serializer.size] = String(state.pagination.pageSize);\n\t}\n\tif (include.includes(\"sorting\")) {\n\t\tconst sort = encodeSort(state.sorting);\n\t\tif (sort) params[serializer.sort] = sort;\n\t}\n\tif (include.includes(\"globalFilter\") && state.globalFilter) {\n\t\tparams[serializer.search] = state.globalFilter;\n\t}\n\tif (include.includes(\"view\")) {\n\t\tparams[serializer.view] = state.view;\n\t}\n\tif (include.includes(\"columnFilters\")) {\n\t\tfor (const { id, value } of state.columnFilters) {\n\t\t\tconst encoded = serializer.encodeFilter(id, value, getFilterMeta?.(id));\n\t\t\tif (encoded !== \"\") params[`${serializer.filterPrefix}${id}`] = encoded;\n\t\t}\n\t}\n\treturn params;\n}\n\nexport interface DeserializeContext extends SerializeContext {\n\t/** Fallback for slices not present in the URL (defaults on hydrate, current on popstate). */\n\tcurrent: DataViewState;\n}\n\n/**\n * Parses query params into a state patch. The URL is authoritative for every included slice. An\n * absent sort, search, or filter means none, and an absent page means the first page.\n */\nexport function deserializeParams(\n\tparams: Record<string, string>,\n\t{ serializer, include, getFilterMeta, current }: DeserializeContext,\n): Partial<DataViewState> {\n\tconst patch: Partial<DataViewState> = {};\n\n\tif (include.includes(\"pagination\")) {\n\t\tconst rawPage = params[serializer.page];\n\t\tconst rawSize = params[serializer.size];\n\t\tconst pageNumber = rawPage ? Number(rawPage) : 1;\n\t\tconst pageIndex = Number.isFinite(pageNumber)\n\t\t\t? Math.max(0, Math.trunc(pageNumber) - 1)\n\t\t\t: 0;\n\t\tconst pageSize =\n\t\t\trawSize && Number.isFinite(Number(rawSize))\n\t\t\t\t? Number(rawSize)\n\t\t\t\t: current.pagination.pageSize;\n\t\tpatch.pagination = { pageIndex, pageSize };\n\t}\n\tif (include.includes(\"sorting\")) {\n\t\tpatch.sorting = decodeSort(params[serializer.sort] ?? \"\");\n\t}\n\tif (include.includes(\"globalFilter\")) {\n\t\tpatch.globalFilter = params[serializer.search] ?? \"\";\n\t}\n\tif (include.includes(\"view\")) {\n\t\tconst rawView = params[serializer.view];\n\t\tpatch.view = rawView && isViewMode(rawView) ? rawView : current.view;\n\t}\n\tif (include.includes(\"columnFilters\")) {\n\t\tconst filters: DataViewState[\"columnFilters\"] = [];\n\t\tfor (const [key, raw] of Object.entries(params)) {\n\t\t\tif (!key.startsWith(serializer.filterPrefix)) continue;\n\t\t\tconst id = key.slice(serializer.filterPrefix.length);\n\t\t\tfilters.push({\n\t\t\t\tid,\n\t\t\t\tvalue: serializer.decodeFilter(id, raw, getFilterMeta?.(id)),\n\t\t\t});\n\t\t}\n\t\tpatch.columnFilters = filters;\n\t}\n\treturn patch;\n}\n\n/** Remove the params this serializer manages (for the included slices), preserving the rest. */\nexport function stripManagedParams(\n\tparams: Record<string, string>,\n\tserializer: UrlSerializer,\n\tinclude: SyncableKey[],\n): Record<string, string> {\n\tconst managed = new Set<string>();\n\tif (include.includes(\"pagination\")) {\n\t\tmanaged.add(serializer.page);\n\t\tmanaged.add(serializer.size);\n\t}\n\tif (include.includes(\"sorting\")) managed.add(serializer.sort);\n\tif (include.includes(\"globalFilter\")) managed.add(serializer.search);\n\tif (include.includes(\"view\")) managed.add(serializer.view);\n\n\tconst stripFilters = include.includes(\"columnFilters\");\n\tconst result: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (managed.has(key)) continue;\n\t\tif (stripFilters && key.startsWith(serializer.filterPrefix)) continue;\n\t\tresult[key] = value;\n\t}\n\treturn result;\n}\n"],"mappings":"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"}
|
package/dist/url/index.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../serializer-CGmBq-Jz.cjs");function t(){return{read(){return Object.fromEntries(new URLSearchParams(window.location.search).entries())},write(e,t){let n=new URLSearchParams(e),r=`${window.location.pathname}?${n.toString()}${window.location.hash}`;t?.replace?window.history.replaceState(null,``,r):window.history.pushState(null,``,r)},subscribe(e){return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)}}}exports.defaultUrlSerializer=e.t,exports.deserializeParams=e.n,exports.resolveInclude=e.r,exports.serializeState=e.i,exports.windowHistoryAdapter=t;
|
|
2
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/url/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/url/index.ts"],"sourcesContent":["// Subpath entry for @ethanhann/mantine-dataview/url.\n// It exports windowHistoryAdapter and the serializer utilities.\n\nimport type { UrlStateAdapter } from \"./types\";\n\n// Serializer utilities for consumers building custom adapters or param schemes.\nexport {\n\tdefaultUrlSerializer,\n\tdeserializeParams,\n\tresolveInclude,\n\ttype SyncableKey,\n\tserializeState,\n} from \"./serializer\";\nexport type { UrlSerializer, UrlStateAdapter } from \"./types\";\n\n/** Default adapter built on the History API. It has no dependencies. */\nexport function windowHistoryAdapter(): UrlStateAdapter {\n\treturn {\n\t\tread() {\n\t\t\treturn Object.fromEntries(\n\t\t\t\tnew URLSearchParams(window.location.search).entries(),\n\t\t\t);\n\t\t},\n\t\twrite(next, opts) {\n\t\t\tconst params = new URLSearchParams(next);\n\t\t\tconst url = `${window.location.pathname}?${params.toString()}${window.location.hash}`;\n\t\t\tif (opts?.replace) {\n\t\t\t\twindow.history.replaceState(null, \"\", url);\n\t\t\t} else {\n\t\t\t\twindow.history.pushState(null, \"\", url);\n\t\t\t}\n\t\t},\n\t\tsubscribe(onChange) {\n\t\t\twindow.addEventListener(\"popstate\", onChange);\n\t\t\treturn () => window.removeEventListener(\"popstate\", onChange);\n\t\t},\n\t};\n}\n"],"mappings":"iHAgBA,SAAgB,GAAwC,CACvD,MAAO,CACN,MAAO,CACN,OAAO,OAAO,YACb,IAAI,gBAAgB,OAAO,SAAS,MAAM,EAAE,QAAQ,CACrD,CACD,EACA,MAAM,EAAM,EAAM,CACjB,IAAM,EAAS,IAAI,gBAAgB,CAAI,EACjC,EAAM,GAAG,OAAO,SAAS,SAAS,GAAG,EAAO,SAAS,IAAI,OAAO,SAAS,OAC3E,GAAM,QACT,OAAO,QAAQ,aAAa,KAAM,GAAI,CAAG,EAEzC,OAAO,QAAQ,UAAU,KAAM,GAAI,CAAG,CAExC,EACA,UAAU,EAAU,CAEnB,OADA,OAAO,iBAAiB,WAAY,CAAQ,MAC/B,OAAO,oBAAoB,WAAY,CAAQ,CAC7D,CACD,CACD"}
|