@mortenbrudvik/waveui 0.14.1 → 0.16.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/README.md +413 -53
- package/dist/components/data-display/InfoButton.cjs +1 -1
- package/dist/components/data-display/InfoButton.cjs.map +1 -1
- package/dist/components/data-display/InfoButton.mjs +90 -82
- package/dist/components/data-display/InfoButton.mjs.map +1 -1
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +19 -18
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/data-display/List.cjs +1 -1
- package/dist/components/data-display/List.cjs.map +1 -1
- package/dist/components/data-display/List.mjs +405 -219
- package/dist/components/data-display/List.mjs.map +1 -1
- package/dist/components/data-display/List.registry.cjs +1 -1
- package/dist/components/data-display/List.registry.cjs.map +1 -1
- package/dist/components/data-display/List.registry.mjs +12 -6
- package/dist/components/data-display/List.registry.mjs.map +1 -1
- package/dist/components/feedback/MessageBarGroup.cjs +2 -0
- package/dist/components/feedback/MessageBarGroup.cjs.map +1 -0
- package/dist/components/feedback/MessageBarGroup.mjs +63 -0
- package/dist/components/feedback/MessageBarGroup.mjs.map +1 -0
- package/dist/components/feedback/ProgressBar.cjs +1 -1
- package/dist/components/feedback/ProgressBar.cjs.map +1 -1
- package/dist/components/feedback/ProgressBar.mjs +41 -39
- package/dist/components/feedback/ProgressBar.mjs.map +1 -1
- package/dist/components/feedback/Toaster.cjs +1 -1
- package/dist/components/feedback/Toaster.cjs.map +1 -1
- package/dist/components/feedback/Toaster.mjs +222 -216
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.mjs +163 -148
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +132 -117
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Listbox.cjs +1 -1
- package/dist/components/input/Listbox.cjs.map +1 -1
- package/dist/components/input/Listbox.mjs +90 -78
- package/dist/components/input/Listbox.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.data.cjs +2 -0
- package/dist/components/input/Option.data.cjs.map +1 -0
- package/dist/components/input/Option.data.mjs +114 -0
- package/dist/components/input/Option.data.mjs.map +1 -0
- package/dist/components/input/Option.mjs +21 -17
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/layout/Accordion.cjs +1 -1
- package/dist/components/layout/Accordion.cjs.map +1 -1
- package/dist/components/layout/Accordion.mjs +124 -109
- package/dist/components/layout/Accordion.mjs.map +1 -1
- package/dist/components/layout/Carousel.cjs +1 -1
- package/dist/components/layout/Carousel.cjs.map +1 -1
- package/dist/components/layout/Carousel.mjs +207 -193
- package/dist/components/layout/Carousel.mjs.map +1 -1
- package/dist/components/layout/FlatTree.cjs +2 -0
- package/dist/components/layout/FlatTree.cjs.map +1 -0
- package/dist/components/layout/FlatTree.context.cjs +2 -0
- package/dist/components/layout/FlatTree.context.cjs.map +1 -0
- package/dist/components/layout/FlatTree.context.mjs +20 -0
- package/dist/components/layout/FlatTree.context.mjs.map +1 -0
- package/dist/components/layout/FlatTree.item.cjs +2 -0
- package/dist/components/layout/FlatTree.item.cjs.map +1 -0
- package/dist/components/layout/FlatTree.item.mjs +90 -0
- package/dist/components/layout/FlatTree.item.mjs.map +1 -0
- package/dist/components/layout/FlatTree.mjs +276 -0
- package/dist/components/layout/FlatTree.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +1 -1
- package/dist/components/layout/TabList.cjs.map +1 -1
- package/dist/components/layout/TabList.mjs +149 -108
- package/dist/components/layout/TabList.mjs.map +1 -1
- package/dist/components/layout/Tree.cjs.map +1 -1
- package/dist/components/layout/Tree.context.cjs +1 -1
- package/dist/components/layout/Tree.context.cjs.map +1 -1
- package/dist/components/layout/Tree.context.mjs +2 -1
- package/dist/components/layout/Tree.context.mjs.map +1 -1
- package/dist/components/layout/Tree.core.cjs +1 -1
- package/dist/components/layout/Tree.core.cjs.map +1 -1
- package/dist/components/layout/Tree.core.mjs +162 -148
- package/dist/components/layout/Tree.core.mjs.map +1 -1
- package/dist/components/layout/Tree.mjs.map +1 -1
- package/dist/components/layout/Tree.selection.cjs +1 -1
- package/dist/components/layout/Tree.selection.cjs.map +1 -1
- package/dist/components/layout/Tree.selection.mjs +11 -57
- package/dist/components/layout/Tree.selection.mjs.map +1 -1
- package/dist/components/layout/useFlatTree.cjs +2 -0
- package/dist/components/layout/useFlatTree.cjs.map +1 -0
- package/dist/components/layout/useFlatTree.mjs +83 -0
- package/dist/components/layout/useFlatTree.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +154 -168
- package/dist/components/navigation/Menu.popover.mjs.map +1 -1
- package/dist/components/navigation/Nav.cjs +1 -1
- package/dist/components/navigation/Nav.cjs.map +1 -1
- package/dist/components/navigation/Nav.mjs +156 -136
- package/dist/components/navigation/Nav.mjs.map +1 -1
- package/dist/components/navigation/NavDrawer.cjs +1 -1
- package/dist/components/navigation/NavDrawer.cjs.map +1 -1
- package/dist/components/navigation/NavDrawer.mjs +48 -45
- package/dist/components/navigation/NavDrawer.mjs.map +1 -1
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +128 -122
- package/dist/components/overlays/Dialog.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +1 -1
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.mjs +12 -12
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -1
- package/dist/components/overlays/Drawer.cjs.map +1 -1
- package/dist/components/overlays/Drawer.mjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.cjs +1 -1
- package/dist/components/overlays/Drawer.panel.cjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.mjs +97 -81
- package/dist/components/overlays/Drawer.panel.mjs.map +1 -1
- package/dist/components/overlays/Drawer.root.cjs +1 -1
- package/dist/components/overlays/Drawer.root.cjs.map +1 -1
- package/dist/components/overlays/Drawer.root.mjs +34 -31
- package/dist/components/overlays/Drawer.root.mjs.map +1 -1
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +231 -216
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.parts.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.parts.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.parts.mjs +199 -177
- package/dist/components/overlays/TeachingPopover.parts.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.root.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.root.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.root.mjs +93 -92
- package/dist/components/overlays/TeachingPopover.root.mjs.map +1 -1
- package/dist/components/overlays/Tooltip.cjs +1 -1
- package/dist/components/overlays/Tooltip.cjs.map +1 -1
- package/dist/components/overlays/Tooltip.mjs +66 -61
- package/dist/components/overlays/Tooltip.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +26 -23
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.context.cjs +2 -0
- package/dist/components/table/DataGrid.context.cjs.map +1 -0
- package/dist/components/table/DataGrid.context.mjs +74 -0
- package/dist/components/table/DataGrid.context.mjs.map +1 -0
- package/dist/components/table/DataGrid.header.cjs +2 -0
- package/dist/components/table/DataGrid.header.cjs.map +1 -0
- package/dist/components/table/DataGrid.header.mjs +168 -0
- package/dist/components/table/DataGrid.header.mjs.map +1 -0
- package/dist/components/table/DataGrid.mjs +488 -591
- package/dist/components/table/DataGrid.mjs.map +1 -1
- package/dist/components/table/DataGrid.sizing.cjs +2 -0
- package/dist/components/table/DataGrid.sizing.cjs.map +1 -0
- package/dist/components/table/DataGrid.sizing.mjs +187 -0
- package/dist/components/table/DataGrid.sizing.mjs.map +1 -0
- package/dist/components/table/DataGrid.store.cjs +2 -0
- package/dist/components/table/DataGrid.store.cjs.map +1 -0
- package/dist/components/table/DataGrid.store.mjs +108 -0
- package/dist/components/table/DataGrid.store.mjs.map +1 -0
- package/dist/components/table/DataGrid.window.cjs +2 -0
- package/dist/components/table/DataGrid.window.cjs.map +1 -0
- package/dist/components/table/DataGrid.window.mjs +165 -0
- package/dist/components/table/DataGrid.window.mjs.map +1 -0
- package/dist/components/table/Table.cjs +1 -1
- package/dist/components/table/Table.cjs.map +1 -1
- package/dist/components/table/Table.mjs +74 -72
- package/dist/components/table/Table.mjs.map +1 -1
- package/dist/components/table/Table.resize.cjs +2 -0
- package/dist/components/table/Table.resize.cjs.map +1 -0
- package/dist/components/table/Table.resize.mjs +98 -0
- package/dist/components/table/Table.resize.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +1 -1
- package/dist/components/table/useGridNavigation.cjs.map +1 -1
- package/dist/components/table/useGridNavigation.mjs +343 -140
- package/dist/components/table/useGridNavigation.mjs.map +1 -1
- package/dist/components/table/useTableColumnSizing.cjs +2 -0
- package/dist/components/table/useTableColumnSizing.cjs.map +1 -0
- package/dist/components/table/useTableColumnSizing.mjs +76 -0
- package/dist/components/table/useTableColumnSizing.mjs.map +1 -0
- package/dist/components/table/useTableFeatures.cjs +2 -0
- package/dist/components/table/useTableFeatures.cjs.map +1 -0
- package/dist/components/table/useTableFeatures.mjs +110 -0
- package/dist/components/table/useTableFeatures.mjs.map +1 -0
- package/dist/components/table/useTableSelection.cjs +2 -0
- package/dist/components/table/useTableSelection.cjs.map +1 -0
- package/dist/components/table/useTableSelection.mjs +39 -0
- package/dist/components/table/useTableSelection.mjs.map +1 -0
- package/dist/components/table/useTableSort.cjs +2 -0
- package/dist/components/table/useTableSort.cjs.map +1 -0
- package/dist/components/table/useTableSort.mjs +58 -0
- package/dist/components/table/useTableSort.mjs.map +1 -0
- package/dist/hooks/useActiveDescendant.cjs +1 -1
- package/dist/hooks/useActiveDescendant.cjs.map +1 -1
- package/dist/hooks/useActiveDescendant.mjs +33 -25
- package/dist/hooks/useActiveDescendant.mjs.map +1 -1
- package/dist/hooks/useCollapsePresence.cjs +2 -0
- package/dist/hooks/useCollapsePresence.cjs.map +1 -0
- package/dist/hooks/useCollapsePresence.mjs +21 -0
- package/dist/hooks/useCollapsePresence.mjs.map +1 -0
- package/dist/hooks/useFocusBeforeClose.cjs +2 -0
- package/dist/hooks/useFocusBeforeClose.cjs.map +1 -0
- package/dist/hooks/useFocusBeforeClose.mjs +33 -0
- package/dist/hooks/useFocusBeforeClose.mjs.map +1 -0
- package/dist/hooks/useListbox.cjs +1 -1
- package/dist/hooks/useListbox.cjs.map +1 -1
- package/dist/hooks/useListbox.mjs +140 -130
- package/dist/hooks/useListbox.mjs.map +1 -1
- package/dist/hooks/useMotion.cjs +2 -0
- package/dist/hooks/useMotion.cjs.map +1 -0
- package/dist/hooks/useMotion.mjs +14 -0
- package/dist/hooks/useMotion.mjs.map +1 -0
- package/dist/hooks/usePresenceGroup.cjs +2 -0
- package/dist/hooks/usePresenceGroup.cjs.map +1 -0
- package/dist/hooks/usePresenceGroup.mjs +68 -0
- package/dist/hooks/usePresenceGroup.mjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +1 -1
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/hooks/useSelection.cjs +2 -0
- package/dist/hooks/useSelection.cjs.map +1 -0
- package/dist/hooks/useSelection.mjs +57 -0
- package/dist/hooks/useSelection.mjs.map +1 -0
- package/dist/hooks/useVirtualWindow.cjs +2 -0
- package/dist/hooks/useVirtualWindow.cjs.map +1 -0
- package/dist/hooks/useVirtualWindow.mjs +102 -0
- package/dist/hooks/useVirtualWindow.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2249 -179
- package/dist/index.d.ts +2249 -179
- package/dist/index.mjs +147 -135
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +125 -95
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/columnSizing.cjs +2 -0
- package/dist/lib/columnSizing.cjs.map +1 -0
- package/dist/lib/columnSizing.mjs +27 -0
- package/dist/lib/columnSizing.mjs.map +1 -0
- package/dist/lib/flatTree.cjs +2 -0
- package/dist/lib/flatTree.cjs.map +1 -0
- package/dist/lib/flatTree.mjs +118 -0
- package/dist/lib/flatTree.mjs.map +1 -0
- package/dist/lib/motion.cjs +2 -0
- package/dist/lib/motion.cjs.map +1 -0
- package/dist/lib/motion.mjs +43 -0
- package/dist/lib/motion.mjs.map +1 -0
- package/dist/lib/selection.cjs +2 -0
- package/dist/lib/selection.cjs.map +1 -0
- package/dist/lib/selection.mjs +28 -0
- package/dist/lib/selection.mjs.map +1 -0
- package/dist/lib/treeCascade.cjs +2 -0
- package/dist/lib/treeCascade.cjs.map +1 -0
- package/dist/lib/treeCascade.mjs +52 -0
- package/dist/lib/treeCascade.mjs.map +1 -0
- package/dist/lib/virtual.cjs +2 -0
- package/dist/lib/virtual.cjs.map +1 -0
- package/dist/lib/virtual.mjs +54 -0
- package/dist/lib/virtual.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../hooks/useEventCallback.cjs"),i=require("../../hooks/useControllable.cjs"),a=require("./useGridNavigation.cjs"),o=require("../../lib/styles.cjs"),s=require("./Table.resize.cjs"),c=require("../../lib/columnSizing.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime"),d=require("react-dom");var f={},p=l.createContext(null),m=l.createContext(!1);function h(){let e=new Map;return{register(t,n){return e.set(t,n),()=>{e.get(t)===n&&e.delete(t)}},get:t=>e.get(t)?.()??null,any(){for(let t of e.values()){let e=t();if(e)return e}return null}}}function g(e){let t=e?e.getBoundingClientRect().width:0;return Number.isFinite(t)&&t>0?t:0}function _(e){let{enabled:t,resizable:n,columnIds:a,selectionColumn:o,columnSizingOptions:s,columnWidths:d,defaultColumnWidths:p,onColumnWidthsChange:m,resizeColumnLabel:_,columnWidthText:v}=e,y=l.useMemo(()=>a.filter(e=>e!==void 0),[a]),b=l.useRef(void 0),[x,S,C]=i.useControllable(d,p??f,e=>{let t=b.current;t&&m?.(e,t)}),w=C||p!==void 0||x!==f,T=l.useMemo(()=>c.resolveColumnWidths(y,s,x),[y,s,x]),E=l.useMemo(()=>{let e={};for(let t of y)e[t]=c.getColumnEntry(s,t)?.minWidth??80;return e},[y,s]),[D,O]=l.useState(null),k=w?D??40:40,[A]=l.useState(h),j=()=>{let e=0,t=0,n=n=>{e+=n;let r=Math.round(e),i=r-t;return t=r,i},r=null;if(o){let e=(A.any()?.parentElement)?.querySelector(`:scope > [data-selection-cell]`);r=n(g(e)||40)}let i={};for(let e of a){if(e===void 0){n(c.initialColumnWidth());continue}i[e]=n(g(A.get(e))||T[e])}return{widths:i,selection:r}},M=r.useEventCallback((e,t,n)=>{if(!y.includes(e)||!Number.isFinite(t))return;let r=c.clampColumnWidth(t,c.getColumnEntry(s,e)),i=w?null:j();b.current={columnId:e,width:r,event:n};try{S(t=>{let n=w||t!==f,a=c.resolveColumnWidths(y,s,n?t:i?.widths??t);return n&&a[e]===r?t:(a[e]=r,a)})}finally{b.current=void 0}i&&O(i.selection)}),N=r.useEventCallback((e,t)=>{w&&M(e,c.initialColumnWidth(c.getColumnEntry(s,e)),t)}),[P,F]=l.useState(null),I=l.useCallback(e=>F(e),[]),L=l.useCallback(e=>F(t=>t===e?null:t),[]),R=l.useMemo(()=>t&&n?{isSized:w,widths:T,minWidths:E,setColumnWidth:M,resetColumnWidth:N,registerHeaderCell:A.register,startDrag:I,endDrag:L,label:_,valueText:v}:null,[t,n,w,T,E,M,N,A,I,L,_,v]);if(!t)return{colgroup:null,tableStyle:void 0,resizing:!1,resizeContext:null};let z=a.map(e=>e===void 0?c.initialColumnWidth():T[e]),B=o?k:0;for(let e of z)B+=e;return{colgroup:(0,u.jsxs)(`colgroup`,{children:[o&&(0,u.jsx)(`col`,{style:{width:k}}),z.map((e,t)=>(0,u.jsx)(`col`,{style:{width:e}},t))]},`wave-colgroup`),tableStyle:w?{tableLayout:`fixed`,width:B}:{tableLayout:`fixed`,width:`100%`,minWidth:B},resizing:n&&P!==null,resizeContext:R}}function v({columnId:e,context:r}){let{isSized:i,widths:c,minWidths:f,setColumnWidth:p,resetColumnWidth:m,registerHeaderCell:h,startDrag:_,endDrag:v,label:y,valueText:b}=r,x=l.useRef(null),S=l.useRef(null),[C,w]=l.useState(null),T=l.useCallback(()=>x.current?.closest(`th, td`)??null,[]);l.useLayoutEffect(()=>h(e,T),[h,e,T]),l.useEffect(()=>()=>v(e),[v,e]);let E=()=>{let e=g(T());e>0&&w(Math.round(e))},D=t=>{t.pointerId===S.current&&(S.current=null,v(e))},O=c[e];return(0,u.jsx)(s.TableResizeHandle,{ref:x,width:i?O:C??O,minWidth:f[e],label:y,valueText:b,className:t.cn(n.dataGridHeaderCellClassNames.resizeHandle,o.focusRingInset,`data-[dragging]:pointer-events-auto`),onResize:(t,n)=>p(e,t,n?.event??new Event(`resize`)),onReset:({event:t})=>m(e,t),onLeave:()=>{x.current&&a.returnFocusToGridCell(x.current)},onFocus:()=>{i||E()},onKeyDownCapture:e=>{!i&&e.target===e.currentTarget&&(0,d.flushSync)(E)},onPointerDown:t=>{if(t.button===0&&t.isPrimary&&S.current===null){if(S.current=t.pointerId,i){_(e);return}(0,d.flushSync)(()=>{E(),_(e)})}},onPointerUp:D,onPointerCancel:D,onLostPointerCapture:D})}v.displayName=`DataGridColumnResizeHandle`,exports.DataGridColumnResizeHandle=v,exports.DataGridFixedLayoutContext=m,exports.DataGridResizeContext=p,exports.useDataGridColumnSizing=_;
|
|
2
|
+
//# sourceMappingURL=DataGrid.sizing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataGrid.sizing.cjs","names":["React","useControllable","resolveColumnWidths","getColumnEntry","initialColumnWidth","useEventCallback","clampColumnWidth","_jsxs","TableResizeHandle","cn","dataGridHeaderCellClassNames","focusRingInset","require_runtime","require_cn","require_classNames","require_useEventCallback","require_useControllable","require_useGridNavigation","require_styles","require_Table_resize","require_columnSizing","react","react_jsx_runtime","react_dom","NO_WIDTHS","DataGridResizeContext","DataGridFixedLayoutContext","createHeaderCellRegistry","cells","columnId","getCell","cell","drawnWidth","width","el","useDataGridColumnSizing","columnWidthsProp","options","ids","columnIds","id","detailsRef","state","setState","isControlled","defaultColumnWidths","details","onColumnWidthsChange","next","isSized","widths","columnSizingOptions","minWidths","result","adoptedSelectionWidth","setAdoptedSelectionWidth","selectionWidth","measureDrawnWidths","exact","rounded","take","edge","selection","selectionColumn","drawn","setColumnWidth","clamped","sized","previous","resetColumnWidth","event","resizingColumn","setResizingColumn","startDrag","endDrag","current","resizeContext","enabled","resizable","resizeColumnLabel","columnWidthText","columnWidthsInOrder","total","index","DataGridColumnResizeHandle","context","handleRef","pointerRef","drawnWidthOfCell","setDrawnWidthOfCell","registerHeaderCell","measure","endPointer"],"sources":["../../../src/components/table/DataGrid.sizing.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flushSync } from 'react-dom';\nimport { dataGridHeaderCellClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport {\n clampColumnWidth,\n DEFAULT_MIN_COLUMN_WIDTH,\n getColumnEntry,\n initialColumnWidth,\n resolveColumnWidths,\n type ColumnSizingOption,\n} from '../../lib/columnSizing';\nimport { focusRingInset } from '../../lib/styles';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { TableResizeHandle } from './Table.resize';\nimport { returnFocusToGridCell } from './useGridNavigation';\nimport type { TableColumnWidthsChangeDetails } from './useTableColumnSizing';\n\n// The column sizing of a DataGrid (module-only): its width state, the `<colgroup>`, the table\n// style and the resize handle of a header cell. It imports nothing from `DataGrid.tsx`.\n\n/** The width of the selection column in pixels, as its cells draw it. */\nexport const SELECTION_COLUMN_WIDTH = 40;\n\n/** The state of an uncontrolled grid without defaults until a width is set (identity matters). */\nconst NO_WIDTHS: Readonly<Record<string, number>> = {};\n\n/** Options of {@link useDataGridColumnSizing}. */\nexport interface UseDataGridColumnSizingOptions {\n /** Whether the grid lays its columns out from widths (`columns`, `items` and a sizing prop). */\n enabled: boolean;\n /** Whether the header cells of the columns get a resize handle (`resizableColumns`). */\n resizable: boolean;\n /** The id of each column, in the order of `columns` (`undefined` for a column without one). */\n columnIds: readonly (string | undefined)[];\n /** Whether the grid has a selection column, which comes first. */\n selectionColumn: boolean;\n columnSizingOptions: Readonly<Record<string, ColumnSizingOption>> | undefined;\n columnWidths: Record<string, number> | undefined;\n defaultColumnWidths: Record<string, number> | undefined;\n onColumnWidthsChange:\n | ((widths: Record<string, number>, details?: TableColumnWidthsChangeDetails) => void)\n | undefined;\n /** `labels.resizeColumn` of the grid. */\n resizeColumnLabel: string | undefined;\n /** `labels.columnWidth` of the grid. */\n columnWidthText: ((width: number) => string) | undefined;\n}\n\n/** What a header cell needs to render and wire its column's resize handle. */\nexport interface DataGridResizeContextValue {\n /** Whether a width is state; until then the browser spreads the grid over its container. */\n isSized: boolean;\n /** The width of each column with an id, in pixels: its state width, else its initial width. */\n widths: Readonly<Record<string, number>>;\n /** The minimum width of each column with an id, in pixels. */\n minWidths: Readonly<Record<string, number>>;\n /** Sets a column's width; the first one of an unresized grid adopts the drawn widths. */\n setColumnWidth: (columnId: string, width: number, event: Event) => void;\n /** Sets a column back to its initial width (nothing while no width is state). */\n resetColumnWidth: (columnId: string, event: Event) => void;\n /** Registers the getter of a column's header cell, measured on the first resize. */\n registerHeaderCell: (columnId: string, getCell: () => Element | null) => () => void;\n /** A drag of the column's handle starts (`data-resizing` on the grid). */\n startDrag: (columnId: string) => void;\n /** A drag of the column's handle ends. */\n endDrag: (columnId: string) => void;\n label: string | undefined;\n valueText: ((width: number) => string) | undefined;\n}\n\n/** The handles' context; `null` in a grid whose columns are not resizable. */\nexport const DataGridResizeContext = React.createContext<DataGridResizeContextValue | null>(null);\n\n/** Whether the grid lays its columns out from widths: its cells then truncate their text. */\nexport const DataGridFixedLayoutContext = React.createContext(false);\n\n/** The result of {@link useDataGridColumnSizing}. */\nexport interface DataGridColumnSizing {\n /** The `<colgroup>`, first in the table after a caption; `null` without column sizing. */\n colgroup: React.ReactElement | null;\n /** The table's fixed layout and width; `undefined` without column sizing. */\n tableStyle: React.CSSProperties | undefined;\n /** Whether a handle is being dragged. */\n resizing: boolean;\n /** For the header cells (see {@link DataGridResizeContext}). */\n resizeContext: DataGridResizeContextValue | null;\n}\n\n/** The header cells of the columns, by column id, for the measurement of the first resize. */\ninterface HeaderCellRegistry {\n register(columnId: string, getCell: () => Element | null): () => void;\n get(columnId: string): Element | null;\n /** Any registered cell (its row holds the selection column's header cell). */\n any(): Element | null;\n}\n\nfunction createHeaderCellRegistry(): HeaderCellRegistry {\n const cells = new Map<string, () => Element | null>();\n return {\n register(columnId, getCell) {\n cells.set(columnId, getCell);\n return () => {\n if (cells.get(columnId) === getCell) cells.delete(columnId);\n };\n },\n get: (columnId) => cells.get(columnId)?.() ?? null,\n any() {\n for (const getCell of cells.values()) {\n const cell = getCell();\n if (cell) return cell;\n }\n return null;\n },\n };\n}\n\n/** The drawn width of `el`, or 0 when it has none (not rendered, hidden, or no layout). */\nfunction drawnWidth(el: Element | null | undefined): number {\n const width = el ? el.getBoundingClientRect().width : 0;\n return Number.isFinite(width) && width > 0 ? width : 0;\n}\n\n/**\n * The width state and the layout of a DataGrid's columns. Widths are controlled (`columnWidths`)\n * or not (`defaultColumnWidths`); until one is state the table is 100% wide and at least as wide\n * as its columns, so the browser spreads a wider container, and from then on it is exactly as wide\n * as its columns. The first change of an unresized grid adopts the widths the columns are drawn at\n * (their header cells measured, the selection column included, every edge rounded once), so\n * nothing moves but the changed column's end edge.\n */\nexport function useDataGridColumnSizing(\n options: UseDataGridColumnSizingOptions,\n): DataGridColumnSizing {\n const {\n enabled,\n resizable,\n columnIds,\n selectionColumn,\n columnSizingOptions,\n columnWidths: columnWidthsProp,\n defaultColumnWidths,\n onColumnWidthsChange,\n resizeColumnLabel,\n columnWidthText,\n } = options;\n\n const ids = React.useMemo(\n () => columnIds.filter((id): id is string => id !== undefined),\n [columnIds],\n );\n\n // The details of the change being made, set around the setter: useControllable calls its\n // onChange synchronously inside it, and only on change.\n const detailsRef = React.useRef<TableColumnWidthsChangeDetails | undefined>(undefined);\n const [state, setState, isControlled] = useControllable<Record<string, number>>(\n columnWidthsProp,\n defaultColumnWidths ?? NO_WIDTHS,\n (next) => {\n const details = detailsRef.current;\n if (details) onColumnWidthsChange?.(next, details);\n },\n );\n const isSized = isControlled || defaultColumnWidths !== undefined || state !== NO_WIDTHS;\n\n const widths = React.useMemo(\n () => resolveColumnWidths(ids, columnSizingOptions, state),\n [ids, columnSizingOptions, state],\n );\n const minWidths = React.useMemo(() => {\n const result: Record<string, number> = {};\n for (const id of ids) {\n result[id] = getColumnEntry(columnSizingOptions, id)?.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;\n }\n return result;\n }, [ids, columnSizingOptions]);\n\n /** The width the selection column was drawn at when the grid adopted its drawn widths. */\n const [adoptedSelectionWidth, setAdoptedSelectionWidth] = React.useState<number | null>(null);\n const selectionWidth = isSized\n ? (adoptedSelectionWidth ?? SELECTION_COLUMN_WIDTH)\n : SELECTION_COLUMN_WIDTH;\n\n const [cells] = React.useState(createHeaderCellRegistry);\n\n /**\n * The widths the columns are drawn at, from their header cells, in column order and with the\n * selection column first; each edge is rounded once, so the rounding moves none by more than\n * half a pixel. A column whose cell measures nothing keeps the width it has.\n */\n const measureDrawnWidths = () => {\n let exact = 0;\n let rounded = 0;\n const take = (width: number) => {\n exact += width;\n const edge = Math.round(exact);\n const result = edge - rounded;\n rounded = edge;\n return result;\n };\n let selection: number | null = null;\n if (selectionColumn) {\n const row = cells.any()?.parentElement;\n const cell = row?.querySelector(':scope > [data-selection-cell]');\n selection = take(drawnWidth(cell) || SELECTION_COLUMN_WIDTH);\n }\n const drawn: Record<string, number> = {};\n for (const id of columnIds) {\n if (id === undefined) {\n take(initialColumnWidth());\n continue;\n }\n drawn[id] = take(drawnWidth(cells.get(id)) || widths[id]);\n }\n return { widths: drawn, selection };\n };\n\n const setColumnWidth = useEventCallback((columnId: string, width: number, event: Event) => {\n if (!ids.includes(columnId) || !Number.isFinite(width)) return;\n const clamped = clampColumnWidth(width, getColumnEntry(columnSizingOptions, columnId));\n const drawn = isSized ? null : measureDrawnWidths();\n detailsRef.current = { columnId, width: clamped, event };\n try {\n setState((previous) => {\n // An earlier change of the same event already took the widths as state.\n const sized = isSized || previous !== NO_WIDTHS;\n const next = resolveColumnWidths(\n ids,\n columnSizingOptions,\n sized ? previous : (drawn?.widths ?? previous),\n );\n // The first width taken as state is a change even when it equals the drawn one.\n if (sized && next[columnId] === clamped) return previous;\n next[columnId] = clamped;\n return next;\n });\n } finally {\n detailsRef.current = undefined;\n }\n if (drawn) setAdoptedSelectionWidth(drawn.selection);\n });\n\n const resetColumnWidth = useEventCallback((columnId: string, event: Event) => {\n // An unresized grid is in its initial layout: there is nothing to reset.\n if (!isSized) return;\n setColumnWidth(\n columnId,\n initialColumnWidth(getColumnEntry(columnSizingOptions, columnId)),\n event,\n );\n });\n\n const [resizingColumn, setResizingColumn] = React.useState<string | null>(null);\n const startDrag = React.useCallback((columnId: string) => setResizingColumn(columnId), []);\n const endDrag = React.useCallback(\n (columnId: string) => setResizingColumn((current) => (current === columnId ? null : current)),\n [],\n );\n\n const resizeContext = React.useMemo<DataGridResizeContextValue | null>(\n () =>\n enabled && resizable\n ? {\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n registerHeaderCell: cells.register,\n startDrag,\n endDrag,\n label: resizeColumnLabel,\n valueText: columnWidthText,\n }\n : null,\n [\n enabled,\n resizable,\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n cells,\n startDrag,\n endDrag,\n resizeColumnLabel,\n columnWidthText,\n ],\n );\n\n if (!enabled) {\n return { colgroup: null, tableStyle: undefined, resizing: false, resizeContext: null };\n }\n\n const columnWidthsInOrder = columnIds.map((id) =>\n id === undefined ? initialColumnWidth() : widths[id],\n );\n let total = selectionColumn ? selectionWidth : 0;\n for (const width of columnWidthsInOrder) total += width;\n\n const colgroup = (\n <colgroup key=\"wave-colgroup\">\n {selectionColumn && <col style={{ width: selectionWidth }} />}\n {columnWidthsInOrder.map((width, index) => (\n <col key={index} style={{ width }} />\n ))}\n </colgroup>\n );\n\n return {\n colgroup,\n tableStyle: isSized\n ? { tableLayout: 'fixed', width: total }\n : { tableLayout: 'fixed', width: '100%', minWidth: total },\n resizing: resizable && resizingColumn !== null,\n resizeContext,\n };\n}\n\n/**\n * The resize handle of a column's header cell. Before any width is state the column is drawn\n * wider than its width when the browser spreads the grid, so the handle measures its cell when it\n * gets focus, at each key press and when a drag starts (before the handle reads the width), and\n * starts from there. It is an auxiliary widget of the grid's navigation (entered with F2), and\n * Enter, Space and Escape return focus to its cell's target.\n */\nexport function DataGridColumnResizeHandle({\n columnId,\n context,\n}: {\n columnId: string;\n context: DataGridResizeContextValue;\n}) {\n const {\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n registerHeaderCell,\n startDrag,\n endDrag,\n label,\n valueText,\n } = context;\n const handleRef = React.useRef<HTMLDivElement>(null);\n /** The pointer of the drag this handle reported. */\n const pointerRef = React.useRef<number | null>(null);\n const [drawnWidthOfCell, setDrawnWidthOfCell] = React.useState<number | null>(null);\n\n const getCell = React.useCallback(() => handleRef.current?.closest('th, td') ?? null, []);\n React.useLayoutEffect(\n () => registerHeaderCell(columnId, getCell),\n [registerHeaderCell, columnId, getCell],\n );\n // A drag of a handle that goes away ends with it.\n React.useEffect(() => () => endDrag(columnId), [endDrag, columnId]);\n\n const measure = () => {\n const width = drawnWidth(getCell());\n if (width > 0) setDrawnWidthOfCell(Math.round(width));\n };\n\n const endPointer = (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.pointerId !== pointerRef.current) return;\n pointerRef.current = null;\n endDrag(columnId);\n };\n\n const width = widths[columnId];\n return (\n <TableResizeHandle\n ref={handleRef}\n width={isSized ? width : (drawnWidthOfCell ?? width)}\n minWidth={minWidths[columnId]}\n label={label}\n valueText={valueText}\n className={cn(\n dataGridHeaderCellClassNames.resizeHandle,\n // The cell clips what overflows it, the outer ring included.\n focusRingInset,\n // The header ignores the pointer while the grid resizes; the dragged handle does not.\n 'data-[dragging]:pointer-events-auto',\n )}\n onResize={(next, details) =>\n // The handle always passes `details`; typed optional, as every `details` argument.\n setColumnWidth(columnId, next, details?.event ?? new Event('resize'))\n }\n onReset={({ event }) => resetColumnWidth(columnId, event)}\n onLeave={() => {\n if (handleRef.current) returnFocusToGridCell(handleRef.current);\n }}\n onFocus={() => {\n if (!isSized) measure();\n }}\n onKeyDownCapture={(event) => {\n // The container may have resized since the handle got focus. Rendered before the\n // handle's own key handler reads the width.\n if (!isSized && event.target === event.currentTarget) flushSync(measure);\n }}\n onPointerDown={(event) => {\n // A second pointer does not take over a drag under way.\n if (event.button !== 0 || !event.isPrimary || pointerRef.current !== null) return;\n pointerRef.current = event.pointerId;\n if (isSized) {\n startDrag(columnId);\n return;\n }\n // Rendered before the handle reads its width for the drag, right after this handler.\n flushSync(() => {\n measure();\n startDrag(columnId);\n });\n }}\n onPointerUp={endPointer}\n onPointerCancel={endPointer}\n onLostPointerCapture={endPointer}\n />\n );\n}\nDataGridColumnResizeHandle.displayName = 'DataGridColumnResizeHandle';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { dataGridHeaderCellClassNames as t } from "../../lib/classNames.mjs";
|
|
4
|
+
import { useEventCallback as n } from "../../hooks/useEventCallback.mjs";
|
|
5
|
+
import { useControllable as r } from "../../hooks/useControllable.mjs";
|
|
6
|
+
import { returnFocusToGridCell as i } from "./useGridNavigation.mjs";
|
|
7
|
+
import { focusRingInset as a } from "../../lib/styles.mjs";
|
|
8
|
+
import { TableResizeHandle as o } from "./Table.resize.mjs";
|
|
9
|
+
import { clampColumnWidth as s, getColumnEntry as c, initialColumnWidth as l, resolveColumnWidths as u } from "../../lib/columnSizing.mjs";
|
|
10
|
+
import * as d from "react";
|
|
11
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
12
|
+
import { flushSync as m } from "react-dom";
|
|
13
|
+
var h = {}, g = d.createContext(null), _ = d.createContext(!1);
|
|
14
|
+
function v() {
|
|
15
|
+
let e = /* @__PURE__ */ new Map();
|
|
16
|
+
return {
|
|
17
|
+
register(t, n) {
|
|
18
|
+
return e.set(t, n), () => {
|
|
19
|
+
e.get(t) === n && e.delete(t);
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
get: (t) => e.get(t)?.() ?? null,
|
|
23
|
+
any() {
|
|
24
|
+
for (let t of e.values()) {
|
|
25
|
+
let e = t();
|
|
26
|
+
if (e) return e;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function y(e) {
|
|
33
|
+
let t = e ? e.getBoundingClientRect().width : 0;
|
|
34
|
+
return Number.isFinite(t) && t > 0 ? t : 0;
|
|
35
|
+
}
|
|
36
|
+
function b(e) {
|
|
37
|
+
let { enabled: t, resizable: i, columnIds: a, selectionColumn: o, columnSizingOptions: m, columnWidths: g, defaultColumnWidths: _, onColumnWidthsChange: b, resizeColumnLabel: x, columnWidthText: S } = e, C = d.useMemo(() => a.filter((e) => e !== void 0), [a]), w = d.useRef(void 0), [T, E, D] = r(g, _ ?? h, (e) => {
|
|
38
|
+
let t = w.current;
|
|
39
|
+
t && b?.(e, t);
|
|
40
|
+
}), O = D || _ !== void 0 || T !== h, k = d.useMemo(() => u(C, m, T), [
|
|
41
|
+
C,
|
|
42
|
+
m,
|
|
43
|
+
T
|
|
44
|
+
]), A = d.useMemo(() => {
|
|
45
|
+
let e = {};
|
|
46
|
+
for (let t of C) e[t] = c(m, t)?.minWidth ?? 80;
|
|
47
|
+
return e;
|
|
48
|
+
}, [C, m]), [j, M] = d.useState(null), N = O ? j ?? 40 : 40, [P] = d.useState(v), F = () => {
|
|
49
|
+
let e = 0, t = 0, n = (n) => {
|
|
50
|
+
e += n;
|
|
51
|
+
let r = Math.round(e), i = r - t;
|
|
52
|
+
return t = r, i;
|
|
53
|
+
}, r = null;
|
|
54
|
+
if (o) {
|
|
55
|
+
let e = (P.any()?.parentElement)?.querySelector(":scope > [data-selection-cell]");
|
|
56
|
+
r = n(y(e) || 40);
|
|
57
|
+
}
|
|
58
|
+
let i = {};
|
|
59
|
+
for (let e of a) {
|
|
60
|
+
if (e === void 0) {
|
|
61
|
+
n(l());
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
i[e] = n(y(P.get(e)) || k[e]);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
widths: i,
|
|
68
|
+
selection: r
|
|
69
|
+
};
|
|
70
|
+
}, I = n((e, t, n) => {
|
|
71
|
+
if (!C.includes(e) || !Number.isFinite(t)) return;
|
|
72
|
+
let r = s(t, c(m, e)), i = O ? null : F();
|
|
73
|
+
w.current = {
|
|
74
|
+
columnId: e,
|
|
75
|
+
width: r,
|
|
76
|
+
event: n
|
|
77
|
+
};
|
|
78
|
+
try {
|
|
79
|
+
E((t) => {
|
|
80
|
+
let n = O || t !== h, a = u(C, m, n ? t : i?.widths ?? t);
|
|
81
|
+
return n && a[e] === r ? t : (a[e] = r, a);
|
|
82
|
+
});
|
|
83
|
+
} finally {
|
|
84
|
+
w.current = void 0;
|
|
85
|
+
}
|
|
86
|
+
i && M(i.selection);
|
|
87
|
+
}), L = n((e, t) => {
|
|
88
|
+
O && I(e, l(c(m, e)), t);
|
|
89
|
+
}), [R, z] = d.useState(null), B = d.useCallback((e) => z(e), []), V = d.useCallback((e) => z((t) => t === e ? null : t), []), H = d.useMemo(() => t && i ? {
|
|
90
|
+
isSized: O,
|
|
91
|
+
widths: k,
|
|
92
|
+
minWidths: A,
|
|
93
|
+
setColumnWidth: I,
|
|
94
|
+
resetColumnWidth: L,
|
|
95
|
+
registerHeaderCell: P.register,
|
|
96
|
+
startDrag: B,
|
|
97
|
+
endDrag: V,
|
|
98
|
+
label: x,
|
|
99
|
+
valueText: S
|
|
100
|
+
} : null, [
|
|
101
|
+
t,
|
|
102
|
+
i,
|
|
103
|
+
O,
|
|
104
|
+
k,
|
|
105
|
+
A,
|
|
106
|
+
I,
|
|
107
|
+
L,
|
|
108
|
+
P,
|
|
109
|
+
B,
|
|
110
|
+
V,
|
|
111
|
+
x,
|
|
112
|
+
S
|
|
113
|
+
]);
|
|
114
|
+
if (!t) return {
|
|
115
|
+
colgroup: null,
|
|
116
|
+
tableStyle: void 0,
|
|
117
|
+
resizing: !1,
|
|
118
|
+
resizeContext: null
|
|
119
|
+
};
|
|
120
|
+
let U = a.map((e) => e === void 0 ? l() : k[e]), W = o ? N : 0;
|
|
121
|
+
for (let e of U) W += e;
|
|
122
|
+
return {
|
|
123
|
+
colgroup: /* @__PURE__ */ p("colgroup", { children: [o && /* @__PURE__ */ f("col", { style: { width: N } }), U.map((e, t) => /* @__PURE__ */ f("col", { style: { width: e } }, t))] }, "wave-colgroup"),
|
|
124
|
+
tableStyle: O ? {
|
|
125
|
+
tableLayout: "fixed",
|
|
126
|
+
width: W
|
|
127
|
+
} : {
|
|
128
|
+
tableLayout: "fixed",
|
|
129
|
+
width: "100%",
|
|
130
|
+
minWidth: W
|
|
131
|
+
},
|
|
132
|
+
resizing: i && R !== null,
|
|
133
|
+
resizeContext: H
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function x({ columnId: n, context: r }) {
|
|
137
|
+
let { isSized: s, widths: c, minWidths: l, setColumnWidth: u, resetColumnWidth: p, registerHeaderCell: h, startDrag: g, endDrag: _, label: v, valueText: b } = r, x = d.useRef(null), S = d.useRef(null), [C, w] = d.useState(null), T = d.useCallback(() => x.current?.closest("th, td") ?? null, []);
|
|
138
|
+
d.useLayoutEffect(() => h(n, T), [
|
|
139
|
+
h,
|
|
140
|
+
n,
|
|
141
|
+
T
|
|
142
|
+
]), d.useEffect(() => () => _(n), [_, n]);
|
|
143
|
+
let E = () => {
|
|
144
|
+
let e = y(T());
|
|
145
|
+
e > 0 && w(Math.round(e));
|
|
146
|
+
}, D = (e) => {
|
|
147
|
+
e.pointerId === S.current && (S.current = null, _(n));
|
|
148
|
+
}, O = c[n];
|
|
149
|
+
return /* @__PURE__ */ f(o, {
|
|
150
|
+
ref: x,
|
|
151
|
+
width: s ? O : C ?? O,
|
|
152
|
+
minWidth: l[n],
|
|
153
|
+
label: v,
|
|
154
|
+
valueText: b,
|
|
155
|
+
className: e(t.resizeHandle, a, "data-[dragging]:pointer-events-auto"),
|
|
156
|
+
onResize: (e, t) => u(n, e, t?.event ?? new Event("resize")),
|
|
157
|
+
onReset: ({ event: e }) => p(n, e),
|
|
158
|
+
onLeave: () => {
|
|
159
|
+
x.current && i(x.current);
|
|
160
|
+
},
|
|
161
|
+
onFocus: () => {
|
|
162
|
+
s || E();
|
|
163
|
+
},
|
|
164
|
+
onKeyDownCapture: (e) => {
|
|
165
|
+
!s && e.target === e.currentTarget && m(E);
|
|
166
|
+
},
|
|
167
|
+
onPointerDown: (e) => {
|
|
168
|
+
if (e.button === 0 && e.isPrimary && S.current === null) {
|
|
169
|
+
if (S.current = e.pointerId, s) {
|
|
170
|
+
g(n);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
m(() => {
|
|
174
|
+
E(), g(n);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
onPointerUp: D,
|
|
179
|
+
onPointerCancel: D,
|
|
180
|
+
onLostPointerCapture: D
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
x.displayName = "DataGridColumnResizeHandle";
|
|
184
|
+
//#endregion
|
|
185
|
+
export { x as DataGridColumnResizeHandle, _ as DataGridFixedLayoutContext, g as DataGridResizeContext, b as useDataGridColumnSizing };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=DataGrid.sizing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataGrid.sizing.mjs","names":["_jsxs","React","NO_WIDTHS","DataGridResizeContext","DataGridFixedLayoutContext","createHeaderCellRegistry","cells","columnId","getCell","cell","drawnWidth","width","el","useDataGridColumnSizing","columnWidthsProp","options","ids","columnIds","id","detailsRef","state","setState","isControlled","useControllable","defaultColumnWidths","details","onColumnWidthsChange","next","isSized","widths","resolveColumnWidths","columnSizingOptions","minWidths","result","getColumnEntry","adoptedSelectionWidth","setAdoptedSelectionWidth","selectionWidth","measureDrawnWidths","exact","rounded","take","edge","selection","selectionColumn","drawn","initialColumnWidth","setColumnWidth","useEventCallback","clamped","clampColumnWidth","sized","previous","resetColumnWidth","event","resizingColumn","setResizingColumn","startDrag","endDrag","current","resizeContext","enabled","resizable","resizeColumnLabel","columnWidthText","columnWidthsInOrder","total","index","DataGridColumnResizeHandle","context","handleRef","pointerRef","drawnWidthOfCell","setDrawnWidthOfCell","registerHeaderCell","measure","endPointer","TableResizeHandle","cn","dataGridHeaderCellClassNames","focusRingInset","returnFocusToGridCell","flushSync"],"sources":["../../../src/components/table/DataGrid.sizing.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flushSync } from 'react-dom';\nimport { dataGridHeaderCellClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport {\n clampColumnWidth,\n DEFAULT_MIN_COLUMN_WIDTH,\n getColumnEntry,\n initialColumnWidth,\n resolveColumnWidths,\n type ColumnSizingOption,\n} from '../../lib/columnSizing';\nimport { focusRingInset } from '../../lib/styles';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { TableResizeHandle } from './Table.resize';\nimport { returnFocusToGridCell } from './useGridNavigation';\nimport type { TableColumnWidthsChangeDetails } from './useTableColumnSizing';\n\n// The column sizing of a DataGrid (module-only): its width state, the `<colgroup>`, the table\n// style and the resize handle of a header cell. It imports nothing from `DataGrid.tsx`.\n\n/** The width of the selection column in pixels, as its cells draw it. */\nexport const SELECTION_COLUMN_WIDTH = 40;\n\n/** The state of an uncontrolled grid without defaults until a width is set (identity matters). */\nconst NO_WIDTHS: Readonly<Record<string, number>> = {};\n\n/** Options of {@link useDataGridColumnSizing}. */\nexport interface UseDataGridColumnSizingOptions {\n /** Whether the grid lays its columns out from widths (`columns`, `items` and a sizing prop). */\n enabled: boolean;\n /** Whether the header cells of the columns get a resize handle (`resizableColumns`). */\n resizable: boolean;\n /** The id of each column, in the order of `columns` (`undefined` for a column without one). */\n columnIds: readonly (string | undefined)[];\n /** Whether the grid has a selection column, which comes first. */\n selectionColumn: boolean;\n columnSizingOptions: Readonly<Record<string, ColumnSizingOption>> | undefined;\n columnWidths: Record<string, number> | undefined;\n defaultColumnWidths: Record<string, number> | undefined;\n onColumnWidthsChange:\n | ((widths: Record<string, number>, details?: TableColumnWidthsChangeDetails) => void)\n | undefined;\n /** `labels.resizeColumn` of the grid. */\n resizeColumnLabel: string | undefined;\n /** `labels.columnWidth` of the grid. */\n columnWidthText: ((width: number) => string) | undefined;\n}\n\n/** What a header cell needs to render and wire its column's resize handle. */\nexport interface DataGridResizeContextValue {\n /** Whether a width is state; until then the browser spreads the grid over its container. */\n isSized: boolean;\n /** The width of each column with an id, in pixels: its state width, else its initial width. */\n widths: Readonly<Record<string, number>>;\n /** The minimum width of each column with an id, in pixels. */\n minWidths: Readonly<Record<string, number>>;\n /** Sets a column's width; the first one of an unresized grid adopts the drawn widths. */\n setColumnWidth: (columnId: string, width: number, event: Event) => void;\n /** Sets a column back to its initial width (nothing while no width is state). */\n resetColumnWidth: (columnId: string, event: Event) => void;\n /** Registers the getter of a column's header cell, measured on the first resize. */\n registerHeaderCell: (columnId: string, getCell: () => Element | null) => () => void;\n /** A drag of the column's handle starts (`data-resizing` on the grid). */\n startDrag: (columnId: string) => void;\n /** A drag of the column's handle ends. */\n endDrag: (columnId: string) => void;\n label: string | undefined;\n valueText: ((width: number) => string) | undefined;\n}\n\n/** The handles' context; `null` in a grid whose columns are not resizable. */\nexport const DataGridResizeContext = React.createContext<DataGridResizeContextValue | null>(null);\n\n/** Whether the grid lays its columns out from widths: its cells then truncate their text. */\nexport const DataGridFixedLayoutContext = React.createContext(false);\n\n/** The result of {@link useDataGridColumnSizing}. */\nexport interface DataGridColumnSizing {\n /** The `<colgroup>`, first in the table after a caption; `null` without column sizing. */\n colgroup: React.ReactElement | null;\n /** The table's fixed layout and width; `undefined` without column sizing. */\n tableStyle: React.CSSProperties | undefined;\n /** Whether a handle is being dragged. */\n resizing: boolean;\n /** For the header cells (see {@link DataGridResizeContext}). */\n resizeContext: DataGridResizeContextValue | null;\n}\n\n/** The header cells of the columns, by column id, for the measurement of the first resize. */\ninterface HeaderCellRegistry {\n register(columnId: string, getCell: () => Element | null): () => void;\n get(columnId: string): Element | null;\n /** Any registered cell (its row holds the selection column's header cell). */\n any(): Element | null;\n}\n\nfunction createHeaderCellRegistry(): HeaderCellRegistry {\n const cells = new Map<string, () => Element | null>();\n return {\n register(columnId, getCell) {\n cells.set(columnId, getCell);\n return () => {\n if (cells.get(columnId) === getCell) cells.delete(columnId);\n };\n },\n get: (columnId) => cells.get(columnId)?.() ?? null,\n any() {\n for (const getCell of cells.values()) {\n const cell = getCell();\n if (cell) return cell;\n }\n return null;\n },\n };\n}\n\n/** The drawn width of `el`, or 0 when it has none (not rendered, hidden, or no layout). */\nfunction drawnWidth(el: Element | null | undefined): number {\n const width = el ? el.getBoundingClientRect().width : 0;\n return Number.isFinite(width) && width > 0 ? width : 0;\n}\n\n/**\n * The width state and the layout of a DataGrid's columns. Widths are controlled (`columnWidths`)\n * or not (`defaultColumnWidths`); until one is state the table is 100% wide and at least as wide\n * as its columns, so the browser spreads a wider container, and from then on it is exactly as wide\n * as its columns. The first change of an unresized grid adopts the widths the columns are drawn at\n * (their header cells measured, the selection column included, every edge rounded once), so\n * nothing moves but the changed column's end edge.\n */\nexport function useDataGridColumnSizing(\n options: UseDataGridColumnSizingOptions,\n): DataGridColumnSizing {\n const {\n enabled,\n resizable,\n columnIds,\n selectionColumn,\n columnSizingOptions,\n columnWidths: columnWidthsProp,\n defaultColumnWidths,\n onColumnWidthsChange,\n resizeColumnLabel,\n columnWidthText,\n } = options;\n\n const ids = React.useMemo(\n () => columnIds.filter((id): id is string => id !== undefined),\n [columnIds],\n );\n\n // The details of the change being made, set around the setter: useControllable calls its\n // onChange synchronously inside it, and only on change.\n const detailsRef = React.useRef<TableColumnWidthsChangeDetails | undefined>(undefined);\n const [state, setState, isControlled] = useControllable<Record<string, number>>(\n columnWidthsProp,\n defaultColumnWidths ?? NO_WIDTHS,\n (next) => {\n const details = detailsRef.current;\n if (details) onColumnWidthsChange?.(next, details);\n },\n );\n const isSized = isControlled || defaultColumnWidths !== undefined || state !== NO_WIDTHS;\n\n const widths = React.useMemo(\n () => resolveColumnWidths(ids, columnSizingOptions, state),\n [ids, columnSizingOptions, state],\n );\n const minWidths = React.useMemo(() => {\n const result: Record<string, number> = {};\n for (const id of ids) {\n result[id] = getColumnEntry(columnSizingOptions, id)?.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;\n }\n return result;\n }, [ids, columnSizingOptions]);\n\n /** The width the selection column was drawn at when the grid adopted its drawn widths. */\n const [adoptedSelectionWidth, setAdoptedSelectionWidth] = React.useState<number | null>(null);\n const selectionWidth = isSized\n ? (adoptedSelectionWidth ?? SELECTION_COLUMN_WIDTH)\n : SELECTION_COLUMN_WIDTH;\n\n const [cells] = React.useState(createHeaderCellRegistry);\n\n /**\n * The widths the columns are drawn at, from their header cells, in column order and with the\n * selection column first; each edge is rounded once, so the rounding moves none by more than\n * half a pixel. A column whose cell measures nothing keeps the width it has.\n */\n const measureDrawnWidths = () => {\n let exact = 0;\n let rounded = 0;\n const take = (width: number) => {\n exact += width;\n const edge = Math.round(exact);\n const result = edge - rounded;\n rounded = edge;\n return result;\n };\n let selection: number | null = null;\n if (selectionColumn) {\n const row = cells.any()?.parentElement;\n const cell = row?.querySelector(':scope > [data-selection-cell]');\n selection = take(drawnWidth(cell) || SELECTION_COLUMN_WIDTH);\n }\n const drawn: Record<string, number> = {};\n for (const id of columnIds) {\n if (id === undefined) {\n take(initialColumnWidth());\n continue;\n }\n drawn[id] = take(drawnWidth(cells.get(id)) || widths[id]);\n }\n return { widths: drawn, selection };\n };\n\n const setColumnWidth = useEventCallback((columnId: string, width: number, event: Event) => {\n if (!ids.includes(columnId) || !Number.isFinite(width)) return;\n const clamped = clampColumnWidth(width, getColumnEntry(columnSizingOptions, columnId));\n const drawn = isSized ? null : measureDrawnWidths();\n detailsRef.current = { columnId, width: clamped, event };\n try {\n setState((previous) => {\n // An earlier change of the same event already took the widths as state.\n const sized = isSized || previous !== NO_WIDTHS;\n const next = resolveColumnWidths(\n ids,\n columnSizingOptions,\n sized ? previous : (drawn?.widths ?? previous),\n );\n // The first width taken as state is a change even when it equals the drawn one.\n if (sized && next[columnId] === clamped) return previous;\n next[columnId] = clamped;\n return next;\n });\n } finally {\n detailsRef.current = undefined;\n }\n if (drawn) setAdoptedSelectionWidth(drawn.selection);\n });\n\n const resetColumnWidth = useEventCallback((columnId: string, event: Event) => {\n // An unresized grid is in its initial layout: there is nothing to reset.\n if (!isSized) return;\n setColumnWidth(\n columnId,\n initialColumnWidth(getColumnEntry(columnSizingOptions, columnId)),\n event,\n );\n });\n\n const [resizingColumn, setResizingColumn] = React.useState<string | null>(null);\n const startDrag = React.useCallback((columnId: string) => setResizingColumn(columnId), []);\n const endDrag = React.useCallback(\n (columnId: string) => setResizingColumn((current) => (current === columnId ? null : current)),\n [],\n );\n\n const resizeContext = React.useMemo<DataGridResizeContextValue | null>(\n () =>\n enabled && resizable\n ? {\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n registerHeaderCell: cells.register,\n startDrag,\n endDrag,\n label: resizeColumnLabel,\n valueText: columnWidthText,\n }\n : null,\n [\n enabled,\n resizable,\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n cells,\n startDrag,\n endDrag,\n resizeColumnLabel,\n columnWidthText,\n ],\n );\n\n if (!enabled) {\n return { colgroup: null, tableStyle: undefined, resizing: false, resizeContext: null };\n }\n\n const columnWidthsInOrder = columnIds.map((id) =>\n id === undefined ? initialColumnWidth() : widths[id],\n );\n let total = selectionColumn ? selectionWidth : 0;\n for (const width of columnWidthsInOrder) total += width;\n\n const colgroup = (\n <colgroup key=\"wave-colgroup\">\n {selectionColumn && <col style={{ width: selectionWidth }} />}\n {columnWidthsInOrder.map((width, index) => (\n <col key={index} style={{ width }} />\n ))}\n </colgroup>\n );\n\n return {\n colgroup,\n tableStyle: isSized\n ? { tableLayout: 'fixed', width: total }\n : { tableLayout: 'fixed', width: '100%', minWidth: total },\n resizing: resizable && resizingColumn !== null,\n resizeContext,\n };\n}\n\n/**\n * The resize handle of a column's header cell. Before any width is state the column is drawn\n * wider than its width when the browser spreads the grid, so the handle measures its cell when it\n * gets focus, at each key press and when a drag starts (before the handle reads the width), and\n * starts from there. It is an auxiliary widget of the grid's navigation (entered with F2), and\n * Enter, Space and Escape return focus to its cell's target.\n */\nexport function DataGridColumnResizeHandle({\n columnId,\n context,\n}: {\n columnId: string;\n context: DataGridResizeContextValue;\n}) {\n const {\n isSized,\n widths,\n minWidths,\n setColumnWidth,\n resetColumnWidth,\n registerHeaderCell,\n startDrag,\n endDrag,\n label,\n valueText,\n } = context;\n const handleRef = React.useRef<HTMLDivElement>(null);\n /** The pointer of the drag this handle reported. */\n const pointerRef = React.useRef<number | null>(null);\n const [drawnWidthOfCell, setDrawnWidthOfCell] = React.useState<number | null>(null);\n\n const getCell = React.useCallback(() => handleRef.current?.closest('th, td') ?? null, []);\n React.useLayoutEffect(\n () => registerHeaderCell(columnId, getCell),\n [registerHeaderCell, columnId, getCell],\n );\n // A drag of a handle that goes away ends with it.\n React.useEffect(() => () => endDrag(columnId), [endDrag, columnId]);\n\n const measure = () => {\n const width = drawnWidth(getCell());\n if (width > 0) setDrawnWidthOfCell(Math.round(width));\n };\n\n const endPointer = (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.pointerId !== pointerRef.current) return;\n pointerRef.current = null;\n endDrag(columnId);\n };\n\n const width = widths[columnId];\n return (\n <TableResizeHandle\n ref={handleRef}\n width={isSized ? width : (drawnWidthOfCell ?? width)}\n minWidth={minWidths[columnId]}\n label={label}\n valueText={valueText}\n className={cn(\n dataGridHeaderCellClassNames.resizeHandle,\n // The cell clips what overflows it, the outer ring included.\n focusRingInset,\n // The header ignores the pointer while the grid resizes; the dragged handle does not.\n 'data-[dragging]:pointer-events-auto',\n )}\n onResize={(next, details) =>\n // The handle always passes `details`; typed optional, as every `details` argument.\n setColumnWidth(columnId, next, details?.event ?? new Event('resize'))\n }\n onReset={({ event }) => resetColumnWidth(columnId, event)}\n onLeave={() => {\n if (handleRef.current) returnFocusToGridCell(handleRef.current);\n }}\n onFocus={() => {\n if (!isSized) measure();\n }}\n onKeyDownCapture={(event) => {\n // The container may have resized since the handle got focus. Rendered before the\n // handle's own key handler reads the width.\n if (!isSized && event.target === event.currentTarget) flushSync(measure);\n }}\n onPointerDown={(event) => {\n // A second pointer does not take over a drag under way.\n if (event.button !== 0 || !event.isPrimary || pointerRef.current !== null) return;\n pointerRef.current = event.pointerId;\n if (isSized) {\n startDrag(columnId);\n return;\n }\n // Rendered before the handle reads its width for the drag, right after this handler.\n flushSync(() => {\n measure();\n startDrag(columnId);\n });\n }}\n onPointerUp={endPointer}\n onPointerCancel={endPointer}\n onLostPointerCapture={endPointer}\n />\n );\n}\nDataGridColumnResizeHandle.displayName = 'DataGridColumnResizeHandle';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";function e(e,t=!1,n=null){let r=new Set(e),i=new Map,a=new Map,o=null,s=null,c=new Set,l=new Set,u=0,d=0,f=`none`,p=t,m,h=new Set,g=new Set,_=e=>{for(let t of Array.from(e))t()},v=()=>{if(m!==void 0)return m;let e=null;for(let t of r){if(s!==null||i.has(t)){e=t;break}e??=t}return m=e,e},y=e=>{if(s!==null||r.size<2||!r.has(e))return;let t=m;m=void 0,p&&v()!==t&&_(h)},b=()=>d===0?`none`:d===u?`all`:`some`,x=()=>{let e=b();e!==f&&(f=e,_(g))},S=e=>(s===null?i.has(e):c.has(e))&&!a.has(e)&&!l.has(e),C=()=>{d=0;for(let e of r)S(e)&&(d+=1)},w=e=>{o=e,c=new Set(e?.ids),s=e?Array.from(c):null,l=e?.disabled??new Set,u=0;for(let e of s??i.keys())S(e)&&(u+=1);C()};n&&(w(n),f=b());let T=(e,t)=>{let n=S(e);t();let i=S(e);if(n===i)return;let a=i?1:-1;u+=a,r.has(e)&&(d+=a)},E=(e,t,n)=>{let r=(e.get(t)??0)+n;r>0?e.set(t,r):e.delete(t)},D=e=>t=>(e.add(t),()=>{e.delete(t)});return{subscribe:D(h),subscribeSelectAll:D(g),register(e){let t=!i.has(e);T(e,()=>E(i,e,1)),x(),t&&y(e);let n=!1;return()=>{n||(n=!0,T(e,()=>E(i,e,-1)),!i.has(e)&&(x(),y(e)))}},disable(e){T(e,()=>E(a,e,1)),x();let t=!1;return()=>{t||(t=!0,T(e,()=>E(a,e,-1)),x())}},isDisabled(e){return a.has(e)},setSelected(e){let t=new Set(e);t.size===r.size&&e.every(e=>r.has(e))||(r=t,m=void 0,C(),_(h),x())},setSingleMode(e){p=e},setUniverse(e){if(e===o)return;let t=m;w(e),x(),m=void 0,p&&t!==void 0&&v()!==t&&_(h)},isSelected(e,t=!1){return t?v()===e:r.has(e)},countRegistrations(e){return i.get(e)??0},getSelectAllState(){return f},getSelectableIds(){return Array.from(s??i.keys()).filter(S)},getUniverseIds(){return s??Array.from(i.keys())},isOutsideUniverse(e){return s!==null&&!c.has(e)},getRegistered(){return Array.from(i.keys())},prune(e){return e.filter(e=>i.has(e))}}}exports.createSelectionStore=e;
|
|
2
|
+
//# sourceMappingURL=DataGrid.store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataGrid.store.cjs","names":["createSelectionStore","selected","initial","registered","disabled","universeInput","universeIds","universeIdSet","universeDisabled","enabledCount","selectedEnabled","selectAll","singleMode","initialSingleMode","singleId","rowListeners","selectAllListeners","notify","listener","listeners","getSingleId","first","rowId","onRegistrationChange","previous","computeSelectAll","updateSelectAll","next","isEnabled","countSelected","applyUniverse","universe","initialUniverse","changeRow","wasEnabled","change","nowEnabled","step","count","counts","subscribeTo","done","items","item","single","previousSingleId"],"sources":["../../../src/components/table/DataGrid.store.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Selection store\n// ---------------------------------------------------------------------------\n\ntype SelectAllState = 'all' | 'some' | 'none';\n\n/**\n * The rows of a grid with `items`, whether rendered or not (see {@link SelectionStore.setUniverse}).\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport interface SelectionUniverse {\n /** The row ids of `items`, in their order (a repeated id counts once). */\n ids: readonly string[];\n /** The ids whose selection `isSelectionDisabled` disables. */\n disabled: ReadonlySet<string>;\n}\n\n/**\n * Selection state shared with the rows through `useSyncExternalStore`, so toggling one row\n * re-renders only that row (and the select-all header cell). The root pushes the committed\n * selection in a layout effect; rows register their ids. Select-all covers the rows of the\n * universe (a grid with `items`: every row id of `items`, rendered or not) or, without one, the\n * registered rows, whose effective selection is `selected ∩ registered`, derived on read (no\n * pruning effect).\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport interface SelectionStore {\n /**\n * Row subscription: notified only when the selection changes. Rows registering or unregistering\n * notify no row, so adding or removing k of n rows costs O(k), not O(k·n); the one exception is\n * single mode with several selected ids and no universe, where a row registering can move the\n * selected row.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Select-all subscription: notified only when {@link getSelectAllState} changes (through the\n * selection, the universe, or rows registering and unregistering).\n */\n subscribeSelectAll(listener: () => void): () => void;\n /** Registers a rendered row id; returns the unregister function. */\n register(rowId: string): () => void;\n /**\n * Marks a row's selection disabled (`selectionCellProps.disabled`): select-all skips it and its\n * state counts only the other rows. Returns the function that undoes it. A row id is disabled\n * while any row registered with it is.\n */\n disable(rowId: string): () => void;\n /** Whether the row's selection is disabled (see {@link disable}). */\n isDisabled(rowId: string): boolean;\n /** How many rendered rows are registered with `rowId` (more than one: a duplicate). */\n countRegistrations(rowId: string): number;\n /** Sets the committed selection (layout effect of the root). */\n setSelected(items: readonly string[]): void;\n /**\n * Sets whether the grid is in single mode (layout effect of the root). Only then do rows\n * registering or unregistering re-check the one selected row of single mode and notify the rows.\n */\n setSingleMode(single: boolean): void;\n /**\n * Sets the universe of a grid with `items` (layout effect of the root; `null` without `items`).\n * With a universe, select-all and its state cover the ids of the universe whose selection is\n * disabled neither by it nor by a registered row, rendered or not, and registrations change only\n * which rows are disabled; the one selected row of single mode is the first selected id. O(n);\n * notifies no row, unless it moves the one selected row of single mode.\n */\n setUniverse(universe: SelectionUniverse | null): void;\n /**\n * Whether the row is selected. With `single`, only one row is: with a universe, the first\n * selected id; without one, the first selected id (in selection order) whose row is registered,\n * else the first selected id (before any row registered: the server render and the first client\n * render).\n */\n isSelected(rowId: string, single?: boolean): boolean;\n /**\n * Whether all, some or none of the rows select-all changes are selected: those of the universe,\n * else the registered rows, whose selection is not disabled (`'none'` without such rows). A\n * selected row whose selection is disabled counts toward nothing. O(1).\n */\n getSelectAllState(): SelectAllState;\n /** The ids select-all changes (see {@link getSelectAllState}), in the order of the universe. */\n getSelectableIds(): string[];\n /** The ids of the universe in its order; without one, the registered row ids. */\n getUniverseIds(): readonly string[];\n /** Whether there is a universe and `rowId` is not in it (select-all never changes the row). */\n isOutsideUniverse(rowId: string): boolean;\n /** Registered row ids in registration order. */\n getRegistered(): string[];\n /** `items` restricted to registered rows (order of `items`). */\n prune(items: readonly string[]): string[];\n}\n\n/**\n * Creates the {@link SelectionStore} of one DataGrid; `initialUniverse` is the universe of a grid\n * with `items` (see {@link SelectionStore.setUniverse}), so its first render knows the select-all\n * state.\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport function createSelectionStore(\n initial: readonly string[],\n initialSingleMode = false,\n initialUniverse: SelectionUniverse | null = null,\n): SelectionStore {\n let selected: ReadonlySet<string> = new Set(initial);\n /** Registered row id -> number of rows registered with it. */\n const registered = new Map<string, number>();\n /** Row id -> number of `disable` calls in effect for it. */\n const disabled = new Map<string, number>();\n /** The universe last set (compared by identity, so setting it again costs nothing). */\n let universeInput: SelectionUniverse | null = null;\n /** The universe's ids in its order, without repeats; `null` without a universe. */\n let universeIds: readonly string[] | null = null;\n let universeIdSet: ReadonlySet<string> = new Set();\n let universeDisabled: ReadonlySet<string> = new Set();\n /** Row ids select-all changes: in the universe (or registered) and not disabled. */\n let enabledCount = 0;\n /** How many of those are selected (kept up to date, so select-all is O(1)). */\n let selectedEnabled = 0;\n let selectAll: SelectAllState = 'none';\n let singleMode = initialSingleMode;\n /** The one selected row of single mode (see `isSelected`); `undefined`: not computed yet. */\n let singleId: string | null | undefined;\n const rowListeners = new Set<() => void>();\n const selectAllListeners = new Set<() => void>();\n\n const notify = (listeners: Set<() => void>) => {\n for (const listener of Array.from(listeners)) listener();\n };\n\n /** Computed on read: O(selected ids) once per change, and only in single mode. */\n const getSingleId = (): string | null => {\n if (singleId !== undefined) return singleId;\n let first: string | null = null;\n for (const rowId of selected) {\n if (universeIds !== null || registered.has(rowId)) {\n first = rowId;\n break;\n }\n first ??= rowId;\n }\n singleId = first;\n return first;\n };\n\n /**\n * A row id registered or unregistered. Without a universe and with several selected ids, the\n * one selected row of single mode can move: in single mode it is re-checked and the rows are\n * notified if it moved.\n */\n const onRegistrationChange = (rowId: string) => {\n if (universeIds !== null || selected.size < 2 || !selected.has(rowId)) return;\n const previous = singleId;\n singleId = undefined;\n if (singleMode && getSingleId() !== previous) notify(rowListeners);\n };\n\n const computeSelectAll = (): SelectAllState => {\n if (selectedEnabled === 0) return 'none';\n return selectedEnabled === enabledCount ? 'all' : 'some';\n };\n\n const updateSelectAll = () => {\n const next = computeSelectAll();\n if (next === selectAll) return;\n selectAll = next;\n notify(selectAllListeners);\n };\n\n const isEnabled = (rowId: string) =>\n (universeIds !== null ? universeIdSet.has(rowId) : registered.has(rowId)) &&\n !disabled.has(rowId) &&\n !universeDisabled.has(rowId);\n\n /** Counts the selected rows select-all changes: O(selected ids). */\n const countSelected = () => {\n selectedEnabled = 0;\n for (const rowId of selected) if (isEnabled(rowId)) selectedEnabled += 1;\n };\n\n /** Takes a universe (or none) and counts again: O(n). */\n const applyUniverse = (universe: SelectionUniverse | null) => {\n universeInput = universe;\n universeIdSet = new Set(universe?.ids);\n universeIds = universe ? Array.from(universeIdSet) : null;\n universeDisabled = universe?.disabled ?? new Set();\n enabledCount = 0;\n for (const rowId of universeIds ?? registered.keys()) if (isEnabled(rowId)) enabledCount += 1;\n countSelected();\n };\n\n if (initialUniverse) {\n applyUniverse(initialUniverse);\n selectAll = computeSelectAll();\n }\n\n /**\n * Runs `change` (a registration or a `disable` of `rowId`) and keeps the counts of select-all in\n * step with whether the row is enabled before and after it.\n */\n const changeRow = (rowId: string, change: () => void) => {\n const wasEnabled = isEnabled(rowId);\n change();\n const nowEnabled = isEnabled(rowId);\n if (wasEnabled === nowEnabled) return;\n const step = nowEnabled ? 1 : -1;\n enabledCount += step;\n if (selected.has(rowId)) selectedEnabled += step;\n };\n\n /** Adds `step` to the count of `rowId` in `counts`, deleting it at zero. */\n const count = (counts: Map<string, number>, rowId: string, step: 1 | -1) => {\n const next = (counts.get(rowId) ?? 0) + step;\n if (next > 0) counts.set(rowId, next);\n else counts.delete(rowId);\n };\n\n const subscribeTo = (listeners: Set<() => void>) => (listener: () => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n return {\n subscribe: subscribeTo(rowListeners),\n subscribeSelectAll: subscribeTo(selectAllListeners),\n register(rowId) {\n const first = !registered.has(rowId);\n changeRow(rowId, () => count(registered, rowId, 1));\n updateSelectAll();\n if (first) onRegistrationChange(rowId);\n let done = false;\n return () => {\n if (done) return;\n done = true;\n changeRow(rowId, () => count(registered, rowId, -1));\n if (registered.has(rowId)) return;\n updateSelectAll();\n onRegistrationChange(rowId);\n };\n },\n disable(rowId) {\n changeRow(rowId, () => count(disabled, rowId, 1));\n updateSelectAll();\n let done = false;\n return () => {\n if (done) return;\n done = true;\n changeRow(rowId, () => count(disabled, rowId, -1));\n updateSelectAll();\n };\n },\n isDisabled(rowId) {\n return disabled.has(rowId);\n },\n setSelected(items) {\n const next = new Set(items);\n if (next.size === selected.size && items.every((item) => selected.has(item))) return;\n selected = next;\n singleId = undefined;\n countSelected();\n notify(rowListeners);\n updateSelectAll();\n },\n setSingleMode(single) {\n singleMode = single;\n },\n setUniverse(universe) {\n if (universe === universeInput) return;\n const previousSingleId = singleId;\n applyUniverse(universe);\n updateSelectAll();\n // With a universe the one selected row of single mode is the first selected id, without one\n // the first registered: it moves only when a grid gains or loses `items`.\n singleId = undefined;\n if (singleMode && previousSingleId !== undefined && getSingleId() !== previousSingleId) {\n notify(rowListeners);\n }\n },\n isSelected(rowId, single = false) {\n return single ? getSingleId() === rowId : selected.has(rowId);\n },\n countRegistrations(rowId) {\n return registered.get(rowId) ?? 0;\n },\n getSelectAllState() {\n return selectAll;\n },\n getSelectableIds() {\n return Array.from(universeIds ?? registered.keys()).filter(isEnabled);\n },\n getUniverseIds() {\n return universeIds ?? Array.from(registered.keys());\n },\n isOutsideUniverse(rowId) {\n return universeIds !== null && !universeIdSet.has(rowId);\n },\n getRegistered() {\n return Array.from(registered.keys());\n },\n prune(items) {\n return items.filter((item) => registered.has(item));\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region src/components/table/DataGrid.store.ts
|
|
3
|
+
function e(e, t = !1, n = null) {
|
|
4
|
+
let r = new Set(e), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = null, s = null, c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Set(), u = 0, d = 0, f = "none", p = t, m, h = /* @__PURE__ */ new Set(), g = /* @__PURE__ */ new Set(), _ = (e) => {
|
|
5
|
+
for (let t of Array.from(e)) t();
|
|
6
|
+
}, v = () => {
|
|
7
|
+
if (m !== void 0) return m;
|
|
8
|
+
let e = null;
|
|
9
|
+
for (let t of r) {
|
|
10
|
+
if (s !== null || i.has(t)) {
|
|
11
|
+
e = t;
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
e ??= t;
|
|
15
|
+
}
|
|
16
|
+
return m = e, e;
|
|
17
|
+
}, y = (e) => {
|
|
18
|
+
if (s !== null || r.size < 2 || !r.has(e)) return;
|
|
19
|
+
let t = m;
|
|
20
|
+
m = void 0, p && v() !== t && _(h);
|
|
21
|
+
}, b = () => d === 0 ? "none" : d === u ? "all" : "some", x = () => {
|
|
22
|
+
let e = b();
|
|
23
|
+
e !== f && (f = e, _(g));
|
|
24
|
+
}, S = (e) => (s === null ? i.has(e) : c.has(e)) && !a.has(e) && !l.has(e), C = () => {
|
|
25
|
+
d = 0;
|
|
26
|
+
for (let e of r) S(e) && (d += 1);
|
|
27
|
+
}, w = (e) => {
|
|
28
|
+
o = e, c = new Set(e?.ids), s = e ? Array.from(c) : null, l = e?.disabled ?? /* @__PURE__ */ new Set(), u = 0;
|
|
29
|
+
for (let e of s ?? i.keys()) S(e) && (u += 1);
|
|
30
|
+
C();
|
|
31
|
+
};
|
|
32
|
+
n && (w(n), f = b());
|
|
33
|
+
let T = (e, t) => {
|
|
34
|
+
let n = S(e);
|
|
35
|
+
t();
|
|
36
|
+
let i = S(e);
|
|
37
|
+
if (n === i) return;
|
|
38
|
+
let a = i ? 1 : -1;
|
|
39
|
+
u += a, r.has(e) && (d += a);
|
|
40
|
+
}, E = (e, t, n) => {
|
|
41
|
+
let r = (e.get(t) ?? 0) + n;
|
|
42
|
+
r > 0 ? e.set(t, r) : e.delete(t);
|
|
43
|
+
}, D = (e) => (t) => (e.add(t), () => {
|
|
44
|
+
e.delete(t);
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
subscribe: D(h),
|
|
48
|
+
subscribeSelectAll: D(g),
|
|
49
|
+
register(e) {
|
|
50
|
+
let t = !i.has(e);
|
|
51
|
+
T(e, () => E(i, e, 1)), x(), t && y(e);
|
|
52
|
+
let n = !1;
|
|
53
|
+
return () => {
|
|
54
|
+
n || (n = !0, T(e, () => E(i, e, -1)), !i.has(e) && (x(), y(e)));
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
disable(e) {
|
|
58
|
+
T(e, () => E(a, e, 1)), x();
|
|
59
|
+
let t = !1;
|
|
60
|
+
return () => {
|
|
61
|
+
t || (t = !0, T(e, () => E(a, e, -1)), x());
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
isDisabled(e) {
|
|
65
|
+
return a.has(e);
|
|
66
|
+
},
|
|
67
|
+
setSelected(e) {
|
|
68
|
+
let t = new Set(e);
|
|
69
|
+
t.size === r.size && e.every((e) => r.has(e)) || (r = t, m = void 0, C(), _(h), x());
|
|
70
|
+
},
|
|
71
|
+
setSingleMode(e) {
|
|
72
|
+
p = e;
|
|
73
|
+
},
|
|
74
|
+
setUniverse(e) {
|
|
75
|
+
if (e === o) return;
|
|
76
|
+
let t = m;
|
|
77
|
+
w(e), x(), m = void 0, p && t !== void 0 && v() !== t && _(h);
|
|
78
|
+
},
|
|
79
|
+
isSelected(e, t = !1) {
|
|
80
|
+
return t ? v() === e : r.has(e);
|
|
81
|
+
},
|
|
82
|
+
countRegistrations(e) {
|
|
83
|
+
return i.get(e) ?? 0;
|
|
84
|
+
},
|
|
85
|
+
getSelectAllState() {
|
|
86
|
+
return f;
|
|
87
|
+
},
|
|
88
|
+
getSelectableIds() {
|
|
89
|
+
return Array.from(s ?? i.keys()).filter(S);
|
|
90
|
+
},
|
|
91
|
+
getUniverseIds() {
|
|
92
|
+
return s ?? Array.from(i.keys());
|
|
93
|
+
},
|
|
94
|
+
isOutsideUniverse(e) {
|
|
95
|
+
return s !== null && !c.has(e);
|
|
96
|
+
},
|
|
97
|
+
getRegistered() {
|
|
98
|
+
return Array.from(i.keys());
|
|
99
|
+
},
|
|
100
|
+
prune(e) {
|
|
101
|
+
return e.filter((e) => i.has(e));
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { e as createSelectionStore };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=DataGrid.store.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataGrid.store.mjs","names":["createSelectionStore","selected","initial","registered","disabled","universeInput","universeIds","universeIdSet","universeDisabled","enabledCount","selectedEnabled","selectAll","singleMode","initialSingleMode","singleId","rowListeners","selectAllListeners","notify","listener","listeners","getSingleId","first","rowId","onRegistrationChange","previous","computeSelectAll","updateSelectAll","next","isEnabled","countSelected","applyUniverse","universe","initialUniverse","changeRow","wasEnabled","nowEnabled","step","count","counts","subscribeTo","done","items","item","single","previousSingleId"],"sources":["../../../src/components/table/DataGrid.store.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Selection store\n// ---------------------------------------------------------------------------\n\ntype SelectAllState = 'all' | 'some' | 'none';\n\n/**\n * The rows of a grid with `items`, whether rendered or not (see {@link SelectionStore.setUniverse}).\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport interface SelectionUniverse {\n /** The row ids of `items`, in their order (a repeated id counts once). */\n ids: readonly string[];\n /** The ids whose selection `isSelectionDisabled` disables. */\n disabled: ReadonlySet<string>;\n}\n\n/**\n * Selection state shared with the rows through `useSyncExternalStore`, so toggling one row\n * re-renders only that row (and the select-all header cell). The root pushes the committed\n * selection in a layout effect; rows register their ids. Select-all covers the rows of the\n * universe (a grid with `items`: every row id of `items`, rendered or not) or, without one, the\n * registered rows, whose effective selection is `selected ∩ registered`, derived on read (no\n * pruning effect).\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport interface SelectionStore {\n /**\n * Row subscription: notified only when the selection changes. Rows registering or unregistering\n * notify no row, so adding or removing k of n rows costs O(k), not O(k·n); the one exception is\n * single mode with several selected ids and no universe, where a row registering can move the\n * selected row.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Select-all subscription: notified only when {@link getSelectAllState} changes (through the\n * selection, the universe, or rows registering and unregistering).\n */\n subscribeSelectAll(listener: () => void): () => void;\n /** Registers a rendered row id; returns the unregister function. */\n register(rowId: string): () => void;\n /**\n * Marks a row's selection disabled (`selectionCellProps.disabled`): select-all skips it and its\n * state counts only the other rows. Returns the function that undoes it. A row id is disabled\n * while any row registered with it is.\n */\n disable(rowId: string): () => void;\n /** Whether the row's selection is disabled (see {@link disable}). */\n isDisabled(rowId: string): boolean;\n /** How many rendered rows are registered with `rowId` (more than one: a duplicate). */\n countRegistrations(rowId: string): number;\n /** Sets the committed selection (layout effect of the root). */\n setSelected(items: readonly string[]): void;\n /**\n * Sets whether the grid is in single mode (layout effect of the root). Only then do rows\n * registering or unregistering re-check the one selected row of single mode and notify the rows.\n */\n setSingleMode(single: boolean): void;\n /**\n * Sets the universe of a grid with `items` (layout effect of the root; `null` without `items`).\n * With a universe, select-all and its state cover the ids of the universe whose selection is\n * disabled neither by it nor by a registered row, rendered or not, and registrations change only\n * which rows are disabled; the one selected row of single mode is the first selected id. O(n);\n * notifies no row, unless it moves the one selected row of single mode.\n */\n setUniverse(universe: SelectionUniverse | null): void;\n /**\n * Whether the row is selected. With `single`, only one row is: with a universe, the first\n * selected id; without one, the first selected id (in selection order) whose row is registered,\n * else the first selected id (before any row registered: the server render and the first client\n * render).\n */\n isSelected(rowId: string, single?: boolean): boolean;\n /**\n * Whether all, some or none of the rows select-all changes are selected: those of the universe,\n * else the registered rows, whose selection is not disabled (`'none'` without such rows). A\n * selected row whose selection is disabled counts toward nothing. O(1).\n */\n getSelectAllState(): SelectAllState;\n /** The ids select-all changes (see {@link getSelectAllState}), in the order of the universe. */\n getSelectableIds(): string[];\n /** The ids of the universe in its order; without one, the registered row ids. */\n getUniverseIds(): readonly string[];\n /** Whether there is a universe and `rowId` is not in it (select-all never changes the row). */\n isOutsideUniverse(rowId: string): boolean;\n /** Registered row ids in registration order. */\n getRegistered(): string[];\n /** `items` restricted to registered rows (order of `items`). */\n prune(items: readonly string[]): string[];\n}\n\n/**\n * Creates the {@link SelectionStore} of one DataGrid; `initialUniverse` is the universe of a grid\n * with `items` (see {@link SelectionStore.setUniverse}), so its first render knows the select-all\n * state.\n *\n * @internal Not exported from the package (exported for its unit tests).\n */\nexport function createSelectionStore(\n initial: readonly string[],\n initialSingleMode = false,\n initialUniverse: SelectionUniverse | null = null,\n): SelectionStore {\n let selected: ReadonlySet<string> = new Set(initial);\n /** Registered row id -> number of rows registered with it. */\n const registered = new Map<string, number>();\n /** Row id -> number of `disable` calls in effect for it. */\n const disabled = new Map<string, number>();\n /** The universe last set (compared by identity, so setting it again costs nothing). */\n let universeInput: SelectionUniverse | null = null;\n /** The universe's ids in its order, without repeats; `null` without a universe. */\n let universeIds: readonly string[] | null = null;\n let universeIdSet: ReadonlySet<string> = new Set();\n let universeDisabled: ReadonlySet<string> = new Set();\n /** Row ids select-all changes: in the universe (or registered) and not disabled. */\n let enabledCount = 0;\n /** How many of those are selected (kept up to date, so select-all is O(1)). */\n let selectedEnabled = 0;\n let selectAll: SelectAllState = 'none';\n let singleMode = initialSingleMode;\n /** The one selected row of single mode (see `isSelected`); `undefined`: not computed yet. */\n let singleId: string | null | undefined;\n const rowListeners = new Set<() => void>();\n const selectAllListeners = new Set<() => void>();\n\n const notify = (listeners: Set<() => void>) => {\n for (const listener of Array.from(listeners)) listener();\n };\n\n /** Computed on read: O(selected ids) once per change, and only in single mode. */\n const getSingleId = (): string | null => {\n if (singleId !== undefined) return singleId;\n let first: string | null = null;\n for (const rowId of selected) {\n if (universeIds !== null || registered.has(rowId)) {\n first = rowId;\n break;\n }\n first ??= rowId;\n }\n singleId = first;\n return first;\n };\n\n /**\n * A row id registered or unregistered. Without a universe and with several selected ids, the\n * one selected row of single mode can move: in single mode it is re-checked and the rows are\n * notified if it moved.\n */\n const onRegistrationChange = (rowId: string) => {\n if (universeIds !== null || selected.size < 2 || !selected.has(rowId)) return;\n const previous = singleId;\n singleId = undefined;\n if (singleMode && getSingleId() !== previous) notify(rowListeners);\n };\n\n const computeSelectAll = (): SelectAllState => {\n if (selectedEnabled === 0) return 'none';\n return selectedEnabled === enabledCount ? 'all' : 'some';\n };\n\n const updateSelectAll = () => {\n const next = computeSelectAll();\n if (next === selectAll) return;\n selectAll = next;\n notify(selectAllListeners);\n };\n\n const isEnabled = (rowId: string) =>\n (universeIds !== null ? universeIdSet.has(rowId) : registered.has(rowId)) &&\n !disabled.has(rowId) &&\n !universeDisabled.has(rowId);\n\n /** Counts the selected rows select-all changes: O(selected ids). */\n const countSelected = () => {\n selectedEnabled = 0;\n for (const rowId of selected) if (isEnabled(rowId)) selectedEnabled += 1;\n };\n\n /** Takes a universe (or none) and counts again: O(n). */\n const applyUniverse = (universe: SelectionUniverse | null) => {\n universeInput = universe;\n universeIdSet = new Set(universe?.ids);\n universeIds = universe ? Array.from(universeIdSet) : null;\n universeDisabled = universe?.disabled ?? new Set();\n enabledCount = 0;\n for (const rowId of universeIds ?? registered.keys()) if (isEnabled(rowId)) enabledCount += 1;\n countSelected();\n };\n\n if (initialUniverse) {\n applyUniverse(initialUniverse);\n selectAll = computeSelectAll();\n }\n\n /**\n * Runs `change` (a registration or a `disable` of `rowId`) and keeps the counts of select-all in\n * step with whether the row is enabled before and after it.\n */\n const changeRow = (rowId: string, change: () => void) => {\n const wasEnabled = isEnabled(rowId);\n change();\n const nowEnabled = isEnabled(rowId);\n if (wasEnabled === nowEnabled) return;\n const step = nowEnabled ? 1 : -1;\n enabledCount += step;\n if (selected.has(rowId)) selectedEnabled += step;\n };\n\n /** Adds `step` to the count of `rowId` in `counts`, deleting it at zero. */\n const count = (counts: Map<string, number>, rowId: string, step: 1 | -1) => {\n const next = (counts.get(rowId) ?? 0) + step;\n if (next > 0) counts.set(rowId, next);\n else counts.delete(rowId);\n };\n\n const subscribeTo = (listeners: Set<() => void>) => (listener: () => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n return {\n subscribe: subscribeTo(rowListeners),\n subscribeSelectAll: subscribeTo(selectAllListeners),\n register(rowId) {\n const first = !registered.has(rowId);\n changeRow(rowId, () => count(registered, rowId, 1));\n updateSelectAll();\n if (first) onRegistrationChange(rowId);\n let done = false;\n return () => {\n if (done) return;\n done = true;\n changeRow(rowId, () => count(registered, rowId, -1));\n if (registered.has(rowId)) return;\n updateSelectAll();\n onRegistrationChange(rowId);\n };\n },\n disable(rowId) {\n changeRow(rowId, () => count(disabled, rowId, 1));\n updateSelectAll();\n let done = false;\n return () => {\n if (done) return;\n done = true;\n changeRow(rowId, () => count(disabled, rowId, -1));\n updateSelectAll();\n };\n },\n isDisabled(rowId) {\n return disabled.has(rowId);\n },\n setSelected(items) {\n const next = new Set(items);\n if (next.size === selected.size && items.every((item) => selected.has(item))) return;\n selected = next;\n singleId = undefined;\n countSelected();\n notify(rowListeners);\n updateSelectAll();\n },\n setSingleMode(single) {\n singleMode = single;\n },\n setUniverse(universe) {\n if (universe === universeInput) return;\n const previousSingleId = singleId;\n applyUniverse(universe);\n updateSelectAll();\n // With a universe the one selected row of single mode is the first selected id, without one\n // the first registered: it moves only when a grid gains or loses `items`.\n singleId = undefined;\n if (singleMode && previousSingleId !== undefined && getSingleId() !== previousSingleId) {\n notify(rowListeners);\n }\n },\n isSelected(rowId, single = false) {\n return single ? getSingleId() === rowId : selected.has(rowId);\n },\n countRegistrations(rowId) {\n return registered.get(rowId) ?? 0;\n },\n getSelectAllState() {\n return selectAll;\n },\n getSelectableIds() {\n return Array.from(universeIds ?? registered.keys()).filter(isEnabled);\n },\n getUniverseIds() {\n return universeIds ?? Array.from(registered.keys());\n },\n isOutsideUniverse(rowId) {\n return universeIds !== null && !universeIdSet.has(rowId);\n },\n getRegistered() {\n return Array.from(registered.keys());\n },\n prune(items) {\n return items.filter((item) => registered.has(item));\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/dev.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../hooks/useEventCallback.cjs"),i=require("./useGridNavigation.cjs");let a=require("react");a=e.__toESM(a,1);let o=require("react/jsx-runtime");var s=a.createContext(null),c=a.createContext(null);function l(e,t,n){if(e)return{rowCount:t,headerRowCount:n,scrollToRow:t=>e.scrollToIndex(t,{align:`auto`})}}function u({size:e,columnCount:t}){return(0,o.jsx)(`tr`,{"aria-hidden":`true`,"data-virtual-spacer":``,className:n.dataGridClassNames.spacer,style:{height:e},children:(0,o.jsx)(`td`,{colSpan:t,className:`p-0`})})}u.displayName=`DataGridSpacerRow`;function d(e,t,n){return e.virtualWindow.layout(t,{keep:e.keep}).map(t=>t.kind===`item`?n(t.index):(0,o.jsx)(u,{size:t.size,columnCount:e.columnCount},`spacer:${t.key}`))}function f(e){let t=e?.getAttribute(`data-row-index`);return t!=null&&/^\d+$/.test(t)?Number(t):null}function p(e,t){for(let n=t instanceof Element?t:null;n&&n!==e;n=n.parentElement)if((n.localName===`td`||n.localName===`th`)&&n.closest(`table`)===e)return n;return null}function m(e,t){if(!e||!e.isConnected)return!0;let n=e.ownerDocument;return e===n.body||e===n.documentElement||e===t}function h(e){let{virtualWindow:n,ignored:o,rows:s,headerRowCount:c,columnCount:l,activeRowIndex:u,pendingRowIndex:d}=e,h=n!==null,g=a.useRef(null),_=a.useRef(null),v=a.useCallback(e=>{g.current=e},[]),y=a.useCallback(e=>{_.current=e},[]),b=a.useMemo(()=>[u,d].filter(e=>e!==null),[u,d]),x=a.useMemo(()=>n?{virtualWindow:n,keep:b,headerRowCount:c,columnCount:l}:null,[n,b,c,l]);a.useEffect(()=>{o&&t.warnOnce(`DataGrid:virtual-window-requires-items`,"DataGrid: `virtualWindow` needs `items` and `columns`, with the body rows rendered from them (no `DataGrid.Body` child, or one whose child is a render function); it is ignored, and every row is rendered.")},[o]);let S=(s?.length??0)>0;a.useEffect(()=>{let e=g.current,n=_.current;if(!t.isDev||!h||!e||!n)return;let{clientHeight:r,scrollHeight:i}=e,a=Array.from(n.tBodies).some(e=>Array.from(e.rows).some(e=>e.hasAttribute(`data-virtual-spacer`))),o=n.offsetHeight>=r;r>0&&i>0&&i<=r&&o&&a&&t.warnOnce(`DataGrid:virtual-window-height`,"DataGrid: the scroll wrapper of a grid with `virtualWindow` has no bounded height (it is as tall as its rows), so the window renders every row. Give it a height or a maximum height in `containerProps` (a class or a style).")},[h,S]);let C=a.useRef(s);a.useInsertionEffect(()=>{C.current=s},[s]);let w=a.useRef(s),T=a.useRef(null),E=a.useRef(!1),D=a.useRef(null),O=a.useCallback(()=>{E.current=!1,D.current!==null&&(cancelAnimationFrame(D.current),D.current=null)},[]),k=a.useCallback(()=>{O(),E.current=!0,typeof requestAnimationFrame==`function`&&(D.current=requestAnimationFrame(()=>{D.current=null,E.current=!1}))},[O]);a.useEffect(()=>O,[O]);let A=r.useEventCallback(e=>{let t=_.current;if(!t)return;let n=C.current??[],r=Array.from(t.rows).filter(e=>f(e)!==null),a=n.findIndex(t=>t.rowId===e.rowId),o=r.find(e=>a>=0&&f(e)===a)??null;if(!o&&n.length>0){let t=Math.min(e.index,n.length-1),i=1/0;for(let e of r){let n=Math.abs((f(e)??0)-t);n<i&&(o=e,i=n)}}let s=o??t.rows[0];if(!s||s.cells.length===0)return;let c=o?Math.min(e.column,s.cells.length-1):0;i.returnFocusToGridCell(s.cells[c])});a.useLayoutEffect(()=>{let e=w.current;w.current=s;let t=_.current,n=T.current;if(e===s||!h||!t||!n)return;let r=t.ownerDocument.activeElement;r&&t.contains(r)?k():m(r,g.current)?A(n):T.current=null},[s,h,k,A]);let j=a.useRef(!1),M=r.useEventCallback(()=>{n&&(j.current=!0)});return a.useEffect(()=>{let e=_.current?.ownerDocument;if(!h||!e)return;let t=()=>{j.current=!1};return e.addEventListener(`keydown`,t,!0),()=>e.removeEventListener(`keydown`,t,!0)},[h]),{context:x,scrollerRef:v,tableRef:y,onFocus:r.useEventCallback(e=>{let t=j.current;if(j.current=!1,!n)return;O();let r=p(e.currentTarget,e.target),i=r?.parentElement??null,a=f(i),o=a===null?void 0:C.current?.[a]?.rowId;T.current=r&&i instanceof HTMLTableRowElement&&a!==null&&o!==void 0?{rowId:o,index:a,column:Array.prototype.indexOf.call(i.cells,r)}:null,a!==null&&!t&&n.scrollToIndex(a,{align:`auto`})}),onBlur:r.useEventCallback(e=>{if(!n)return;let t=e.currentTarget,r=e.relatedTarget;if(r&&t.contains(r))return;if(r){T.current=null,O();return}let i=g.current;queueMicrotask(()=>{let e=T.current;if(!e||!t.isConnected)return;let n=t.ownerDocument.activeElement;if(n&&t.contains(n))return;let r=E.current&&m(n,i);O(),r?A(e):T.current=null})}),onPointerDownCapture:M}}exports.DataGridSpacerRow=u,exports.DataGridWindowContext=s,exports.DataGridWindowRowContext=c,exports.getWindowNavigationModel=l,exports.renderWindowRows=d,exports.useDataGridWindow=h;
|
|
2
|
+
//# sourceMappingURL=DataGrid.window.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataGrid.window.cjs","names":["React","dataGridClassNames","isDev","useEventCallback","require_runtime","require_dev","require_classNames","require_useEventCallback","require_useGridNavigation","react","react_jsx_runtime","DataGridWindowContext","DataGridWindowRowContext","getWindowNavigationModel","virtualWindow","index","DataGridSpacerRow","size","columnCount","renderWindowRows","context","count","entry","renderRow","getRowIndex","value","row","getOwnCell","el","node","table","isFocusLost","active","doc","scroller","useDataGridWindow","options","enabled","scrollerElementRef","tableElementRef","scrollerRef","element","tableRef","keep","activeRowIndex","pendingRowIndex","headerRowCount","ignored","hasRows","rows","tableElement","hasSpacer","body","followsContent","clientHeight","scrollHeight","rowsRef","checkedRowsRef","focusedRef","armedRef","frameRef","disarm","arm","restore","data","dataRows","position","focused","each","target","distance","gap","column","previous","pointerPressRef","onPointerDownCapture","clear","pointerFocus","cell","event","rowId","next","restoring"],"sources":["../../../src/components/table/DataGrid.window.tsx"],"sourcesContent":["import * as React from 'react';\nimport { dataGridClassNames } from '../../lib/classNames';\nimport { isDev, warnOnce } from '../../lib/dev';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport type { VirtualWindow } from '../../hooks/useVirtualWindow';\nimport { returnFocusToGridCell, type GridNavigationModel } from './useGridNavigation';\n\n// The row window of a DataGrid with a `virtualWindow` (module-only): the navigation model, the\n// contexts of the window and of each row, the spacer rows, the scroller check, and the focus that\n// a data change must not lose. It imports nothing from `DataGrid.tsx`.\n\n/** What the body and the header of a windowed grid read; `null` in a grid that renders every row. */\nexport interface DataGridWindowContextValue {\n virtualWindow: VirtualWindow;\n /** The data rows kept rendered outside the window: the active row and a row a key awaits. */\n keep: readonly number[];\n /** The header rows above the data rows (the first data row's `aria-rowindex` is one more). */\n headerRowCount: number;\n /** The columns of the table, the selection column included: what a spacer's cell spans. */\n columnCount: number;\n}\n\n/** The window of the grid, for its body and header (reset by every grid, so nested grids own theirs). */\nexport const DataGridWindowContext = React.createContext<DataGridWindowContextValue | null>(null);\n\n/** The place of a row in a windowed grid; `null` for a row of a grid that renders every row. */\nexport interface DataGridWindowRow {\n /** A data row's 0-based position in the sorted order (`data-row-index`); `undefined` in the header. */\n index: number | undefined;\n /** The row's `aria-rowindex`: 1-based, the header rows first. */\n ariaRowIndex: number;\n /** The height of a data row in pixels (the window's `itemSize`); `undefined` in the header. */\n height: number | undefined;\n}\n\n/** The place of the row around it (see {@link DataGridWindowRow}). */\nexport const DataGridWindowRowContext = React.createContext<DataGridWindowRow | null>(null);\n\n/** The navigation model of a windowed grid (its rows by their index in the sorted data). */\nexport function getWindowNavigationModel(\n virtualWindow: VirtualWindow | null,\n rowCount: number,\n headerRowCount: number,\n): GridNavigationModel | undefined {\n if (!virtualWindow) return undefined;\n return {\n rowCount,\n headerRowCount,\n scrollToRow: (index) => virtualWindow.scrollToIndex(index, { align: 'auto' }),\n };\n}\n\n/**\n * A row that stands in for the rows of a windowed grid that are not rendered: as tall as they\n * are, out of the accessibility tree, with one cell over every column and no focus target.\n */\nexport function DataGridSpacerRow({ size, columnCount }: { size: number; columnCount: number }) {\n return (\n <tr\n aria-hidden=\"true\"\n data-virtual-spacer=\"\"\n className={dataGridClassNames.spacer}\n style={{ height: size }}\n >\n <td colSpan={columnCount} className=\"p-0\" />\n </tr>\n );\n}\nDataGridSpacerRow.displayName = 'DataGridSpacerRow';\n\n/**\n * The body rows of a windowed grid of `count` data rows: the window's layout, each of its rows\n * rendered by `renderRow(index)` (which keys it, with a `row:` prefix) and each gap as a spacer\n * row (keyed `spacer:<key>`), so no row id can give a row a spacer's key.\n */\nexport function renderWindowRows(\n context: DataGridWindowContextValue,\n count: number,\n renderRow: (index: number) => React.ReactNode,\n): React.ReactNode[] {\n return context.virtualWindow\n .layout(count, { keep: context.keep })\n .map((entry) =>\n entry.kind === 'item' ? (\n renderRow(entry.index)\n ) : (\n <DataGridSpacerRow\n key={`spacer:${entry.key}`}\n size={entry.size}\n columnCount={context.columnCount}\n />\n ),\n );\n}\n\n/** The data row index a row carries, or `null` (a header or spacer row). */\nfunction getRowIndex(row: Element | null): number | null {\n const value = row?.getAttribute('data-row-index');\n return value != null && /^\\d+$/.test(value) ? Number(value) : null;\n}\n\n/** The cell of `table` (not of a table nested in it) that holds `node`. */\nfunction getOwnCell(\n table: HTMLTableElement,\n node: EventTarget | null,\n): HTMLTableCellElement | null {\n for (let el = node instanceof Element ? node : null; el && el !== table; el = el.parentElement) {\n if ((el.localName === 'td' || el.localName === 'th') && el.closest('table') === table) {\n return el as HTMLTableCellElement;\n }\n }\n return null;\n}\n\n/** Whether focus is nowhere: on the body, on the scroller, or on an element no longer in the page. */\nfunction isFocusLost(active: Element | null, scroller: Element | null): boolean {\n if (!active || !active.isConnected) return true;\n const doc = active.ownerDocument;\n return active === doc.body || active === doc.documentElement || active === scroller;\n}\n\n/** The focused cell of a data row: the row's id, its index then and the cell's place in the row. */\ninterface FocusedCell {\n rowId: string;\n index: number;\n column: number;\n}\n\n/** Options of {@link useDataGridWindow}. */\nexport interface UseDataGridWindowOptions {\n /**\n * The grid's window while it applies (`items`, `columns`, the body rows rendered from them);\n * otherwise `null`.\n */\n virtualWindow: VirtualWindow | null;\n /** Whether a `virtualWindow` was given that does not apply (a development warning). */\n ignored: boolean;\n /** The rows of `items` in the sorted order; `null` without `items`. */\n rows: readonly { rowId: string }[] | null;\n headerRowCount: number;\n columnCount: number;\n /** `activeRowIndex` and `pendingRowIndex` of the grid navigation: the rows to keep rendered. */\n activeRowIndex: number | null;\n pendingRowIndex: number | null;\n}\n\n/** The result of {@link useDataGridWindow}. */\nexport interface DataGridWindowState {\n /** For {@link DataGridWindowContext}; `null` while the window does not apply. */\n context: DataGridWindowContextValue | null;\n /** The scroll wrapper's ref (merge it with the window's `scrollRef`). */\n scrollerRef: React.RefCallback<HTMLDivElement>;\n /** The table's ref. */\n tableRef: React.RefCallback<HTMLTableElement>;\n /** Composed after the grid navigation's own focus handlers. */\n onFocus: (event: React.FocusEvent<HTMLTableElement>) => void;\n onBlur: (event: React.FocusEvent<HTMLTableElement>) => void;\n /** The table's pointer press, composed after the consumer's (a prevented press gives no focus). */\n onPointerDownCapture: () => void;\n}\n\n/**\n * The window of a DataGrid: the context its body renders the window from, the development checks\n * (a window that does not apply, a scroller without a bounded height), a focused row that the\n * sticky header covers scrolled below it (unless a pointer press gave the focus), and focus kept\n * through data changes. A sort, a filter or new `items` move the keyed rows, and a browser blurs\n * a focused row that is moved (or removed): when focus was in a data row before such a change and\n * is lost after it, focus goes back to the same row (by id) and column, else to the mounted row\n * nearest to its old index.\n */\nexport function useDataGridWindow(options: UseDataGridWindowOptions): DataGridWindowState {\n const {\n virtualWindow,\n ignored,\n rows,\n headerRowCount,\n columnCount,\n activeRowIndex,\n pendingRowIndex,\n } = options;\n const enabled = virtualWindow !== null;\n // Written by the ref callbacks; read in effects and handlers only.\n const scrollerElementRef = React.useRef<HTMLDivElement | null>(null);\n const tableElementRef = React.useRef<HTMLTableElement | null>(null);\n const scrollerRef = React.useCallback((element: HTMLDivElement | null) => {\n scrollerElementRef.current = element;\n }, []);\n const tableRef = React.useCallback((element: HTMLTableElement | null) => {\n tableElementRef.current = element;\n }, []);\n\n const keep = React.useMemo(\n () => [activeRowIndex, pendingRowIndex].filter((index): index is number => index !== null),\n [activeRowIndex, pendingRowIndex],\n );\n const context = React.useMemo<DataGridWindowContextValue | null>(\n () => (virtualWindow ? { virtualWindow, keep, headerRowCount, columnCount } : null),\n [virtualWindow, keep, headerRowCount, columnCount],\n );\n\n React.useEffect(() => {\n if (ignored) {\n warnOnce(\n 'DataGrid:virtual-window-requires-items',\n 'DataGrid: `virtualWindow` needs `items` and `columns`, with the body rows rendered from ' +\n 'them (no `DataGrid.Body` child, or one whose child is a render function); it is ' +\n 'ignored, and every row is rendered.',\n );\n }\n }, [ignored]);\n\n // Once mounted, and again once rows arrive in a grid mounted without any (a grid with no row\n // has no spacer to tell): a scroller as tall as its rows (no bounded height) lets the window\n // measure the whole list, so it would render every row. Read while the first window still has\n // spacers.\n const hasRows = (rows?.length ?? 0) > 0;\n React.useEffect(() => {\n const scroller = scrollerElementRef.current;\n const tableElement = tableElementRef.current;\n if (!isDev || !enabled || !scroller || !tableElement) return;\n const { clientHeight, scrollHeight } = scroller;\n const hasSpacer = Array.from(tableElement.tBodies).some((body) =>\n Array.from(body.rows).some((row) => row.hasAttribute('data-virtual-spacer')),\n );\n // As tall as the table: a bounded scroller taller than all its rows is not one.\n const followsContent = tableElement.offsetHeight >= clientHeight;\n if (\n clientHeight > 0 &&\n scrollHeight > 0 &&\n scrollHeight <= clientHeight &&\n followsContent &&\n hasSpacer\n ) {\n warnOnce(\n 'DataGrid:virtual-window-height',\n 'DataGrid: the scroll wrapper of a grid with `virtualWindow` has no bounded height (it is ' +\n 'as tall as its rows), so the window renders every row. Give it a height or a maximum ' +\n 'height in `containerProps` (a class or a style).',\n );\n }\n }, [enabled, hasRows]);\n\n // --- focus through data changes ---------------------------------------------\n /**\n * The rows of the commit, for the row id of a focused row and the restore: written before the\n * layout effects, where the grid navigation may focus a row of the new rows.\n */\n const rowsRef = React.useRef(rows);\n React.useInsertionEffect(() => {\n rowsRef.current = rows;\n }, [rows]);\n /** The rows the data-change check last saw. */\n const checkedRowsRef = React.useRef(rows);\n /** The focused cell of a data row, while focus is in one (or was, until that is decided). */\n const focusedRef = React.useRef<FocusedCell | null>(null);\n /** Set by a data change that left focus on a moved row, until the next frame or focus move. */\n const armedRef = React.useRef(false);\n const frameRef = React.useRef<number | null>(null);\n\n const disarm = React.useCallback(() => {\n armedRef.current = false;\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n }, []);\n\n // A blur that comes after the change (a browser that blurs the moved row once it renders) is\n // taken as the change's, until the next frame.\n const arm = React.useCallback(() => {\n disarm();\n armedRef.current = true;\n if (typeof requestAnimationFrame === 'function') {\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n armedRef.current = false;\n });\n }\n }, [disarm]);\n\n React.useEffect(() => disarm, [disarm]);\n\n /** Focuses the cell of `focused`: its row by id, else the mounted row nearest to its index. */\n const restore = useEventCallback((focused: FocusedCell) => {\n const tableElement = tableElementRef.current;\n if (!tableElement) return;\n const data = rowsRef.current ?? [];\n const dataRows = Array.from(tableElement.rows).filter((row) => getRowIndex(row) !== null);\n const position = data.findIndex((row) => row.rowId === focused.rowId);\n let row = dataRows.find((each) => position >= 0 && getRowIndex(each) === position) ?? null;\n if (!row && data.length > 0) {\n const target = Math.min(focused.index, data.length - 1);\n let distance = Infinity;\n for (const each of dataRows) {\n const gap = Math.abs((getRowIndex(each) ?? 0) - target);\n if (gap < distance) {\n row = each;\n distance = gap;\n }\n }\n }\n // No data row left: the first cell of the grid.\n const target = row ?? tableElement.rows[0];\n if (!target || target.cells.length === 0) return;\n const column = row ? Math.min(focused.column, target.cells.length - 1) : 0;\n returnFocusToGridCell(target.cells[column]);\n });\n\n // After a data change (the rows' identity: `items`, `getRowId`, the sort).\n React.useLayoutEffect(() => {\n const previous = checkedRowsRef.current;\n checkedRowsRef.current = rows;\n const tableElement = tableElementRef.current;\n const focused = focusedRef.current;\n if (previous === rows || !enabled || !tableElement || !focused) return;\n const active = tableElement.ownerDocument.activeElement;\n if (active && tableElement.contains(active)) arm();\n else if (isFocusLost(active, scrollerElementRef.current)) restore(focused);\n else focusedRef.current = null;\n }, [rows, enabled, arm, restore]);\n\n /**\n * Set by a pointer press in the grid until the focus it gives (on mousedown; after the release\n * for a touch tap), or until a key press: keyboard focus always follows one, so a press that\n * gave no focus (on a spacer row) never keeps a later keyboard focus from being scrolled.\n */\n const pointerPressRef = React.useRef(false);\n const onPointerDownCapture = useEventCallback(() => {\n if (virtualWindow) pointerPressRef.current = true;\n });\n React.useEffect(() => {\n const doc = tableElementRef.current?.ownerDocument;\n if (!enabled || !doc) return;\n const clear = () => {\n pointerPressRef.current = false;\n };\n doc.addEventListener('keydown', clear, true);\n return () => doc.removeEventListener('keydown', clear, true);\n }, [enabled]);\n\n const onFocus = useEventCallback((event: React.FocusEvent<HTMLTableElement>) => {\n const pointerFocus = pointerPressRef.current;\n pointerPressRef.current = false;\n if (!virtualWindow) return;\n disarm();\n const cell = getOwnCell(event.currentTarget, event.target);\n const row = cell?.parentElement ?? null;\n const index = getRowIndex(row);\n const rowId = index === null ? undefined : rowsRef.current?.[index]?.rowId;\n focusedRef.current =\n cell && row instanceof HTMLTableRowElement && index !== null && rowId !== undefined\n ? { rowId, index, column: Array.prototype.indexOf.call(row.cells, cell) }\n : null;\n // A browser scrolls a focused row to the top edge of the scroller, under the sticky header:\n // bring it into the area below the header (a row in view does not move). Not for the focus\n // of a pointer press: the row would move before the release, and the click off its target.\n if (index !== null && !pointerFocus) virtualWindow.scrollToIndex(index, { align: 'auto' });\n });\n\n const onBlur = useEventCallback((event: React.FocusEvent<HTMLTableElement>) => {\n if (!virtualWindow) return;\n const tableElement = event.currentTarget;\n const next = event.relatedTarget;\n if (next && tableElement.contains(next)) return;\n if (next) {\n focusedRef.current = null;\n disarm();\n return;\n }\n // Focus went nowhere: a click on nothing focusable, or a row the browser blurred because a\n // data change moved or removed it. Decided once the change has settled.\n const scroller = scrollerElementRef.current;\n queueMicrotask(() => {\n const focused = focusedRef.current;\n if (!focused || !tableElement.isConnected) return;\n const active = tableElement.ownerDocument.activeElement;\n if (active && tableElement.contains(active)) return;\n const restoring = armedRef.current && isFocusLost(active, scroller);\n disarm();\n if (restoring) restore(focused);\n else focusedRef.current = null;\n });\n });\n\n return { context, scrollerRef, tableRef, onFocus, onBlur, onPointerDownCapture };\n}\n"],"mappings":"wSAuBA,IAAaW,EAAwBX,EAAM,cAAiD,IAAI,EAanFY,EAA2BZ,EAAM,cAAwC,IAAI,EAG1F,SAAgBa,EACd,EACA,EACA,EACiC,CACjC,GAAKC,EACL,MAAO,CACL,WACA,iBACA,YAAc,GAAUA,EAAc,cAAcC,EAAO,CAAE,MAAO,MAAO,CAAC,CAC9E,CACF,CAMA,SAAgBC,EAAkB,CAAE,OAAM,eAAsD,CAC9F,OACE,EAAAN,EAAA,IAAA,CAAC,KAAD,CACE,cAAY,OACZ,sBAAoB,GACpB,UAAWT,EAAAA,mBAAmB,OAC9B,MAAO,CAAE,OAAQgB,CAAK,EAEtB,UAAA,EAAAP,EAAA,IAAA,CAAC,KAAD,CAAI,QAASQ,EAAa,UAAU,KAAO,CAAA,CACzC,CAAA,CAER,CACA,EAAkB,YAAc,oBAOhC,SAAgBC,EACd,EACA,EACA,EACmB,CACnB,OAAOC,EAAQ,cACZ,OAAOC,EAAO,CAAE,KAAMD,EAAQ,IAAK,CAAC,CAAC,CACrC,IAAK,GACJE,EAAM,OAAS,OACbC,EAAUD,EAAM,KAAK,GAErB,EAAAZ,EAAA,IAAA,CAACM,EAAD,CAEE,KAAMM,EAAM,KACZ,YAAaF,EAAQ,WACtB,EAHM,UAAUE,EAAM,KAGtB,CAEL,CACJ,CAGA,SAASE,EAAY,EAAoC,CACvD,IAAMC,EAAQC,GAAK,aAAa,gBAAgB,EAChD,OAAOD,GAAS,MAAQ,QAAQ,KAAKA,CAAK,EAAI,OAAOA,CAAK,EAAI,IAChE,CAGA,SAASE,EACP,EACA,EAC6B,CAC7B,IAAK,IAAIC,EAAKC,aAAgB,QAAUA,EAAO,KAAMD,GAAMA,IAAOE,EAAO,EAAKF,EAAG,cAC/E,IAAKA,EAAG,YAAc,MAAQA,EAAG,YAAc,OAASA,EAAG,QAAQ,OAAO,IAAME,EAC9E,OAAOF,EAGX,OAAO,IACT,CAGA,SAASG,EAAY,EAAwB,EAAmC,CAC9E,GAAI,CAACC,GAAU,CAACA,EAAO,YAAa,MAAO,GAC3C,IAAMC,EAAMD,EAAO,cACnB,OAAOA,IAAWC,EAAI,MAAQD,IAAWC,EAAI,iBAAmBD,IAAWE,CAC7E,CAmDA,SAAgBC,EAAkB,EAAwD,CACxF,GAAM,CACJ,gBACA,UACA,OACA,iBACA,cACA,iBACA,mBACEC,EACEC,EAAUvB,IAAkB,KAE5BwB,EAAqBtC,EAAM,OAA8B,IAAI,EAC7DuC,EAAkBvC,EAAM,OAAgC,IAAI,EAC5DwC,EAAcxC,EAAM,YAAa,GAAmC,CACxE,EAAmB,QAAUyC,CAC/B,EAAG,CAAC,CAAC,EACCC,EAAW1C,EAAM,YAAa,GAAqC,CACvE,EAAgB,QAAUyC,CAC5B,EAAG,CAAC,CAAC,EAECE,EAAO3C,EAAM,YACX,CAAC4C,EAAgBC,CAAe,CAAC,CAAC,OAAQ,GAA2B9B,IAAU,IAAI,EACzF,CAAC6B,EAAgBC,CAAe,CAClC,EACMzB,EAAUpB,EAAM,YACbc,EAAgB,CAAE,gBAAe,OAAM,iBAAgB,aAAY,EAAI,KAC9E,CAACA,EAAe6B,EAAMG,EAAgB5B,CAAW,CACnD,EAEAT,EAAM,cAAgB,CAChBsC,GACF1C,EAAA,SACE,yCACA,6MAGF,CAEJ,EAAG,CAAC0C,CAAO,CAAC,EAMZ,IAAMC,GAAWC,GAAM,QAAU,GAAK,EACtCxC,EAAM,cAAgB,CACpB,IAAMyB,EAAWI,EAAmB,QAC9BY,EAAeX,EAAgB,QACrC,GAAI,CAACrC,EAAAA,OAAS,CAACmC,GAAW,CAACH,GAAY,CAACgB,EAAc,OACtD,GAAM,CAAE,eAAc,gBAAiBhB,EACjCiB,EAAY,MAAM,KAAKD,EAAa,OAAO,CAAC,CAAC,KAAM,GACvD,MAAM,KAAKE,EAAK,IAAI,CAAC,CAAC,KAAM,GAAQ1B,EAAI,aAAa,qBAAqB,CAAC,CAC7E,EAEM2B,EAAiBH,EAAa,cAAgBI,EAElDA,EAAe,GACfC,EAAe,GACfA,GAAgBD,GAChBD,GACAF,GAEA9C,EAAA,SACE,iCACA,gOAGF,CAEJ,EAAG,CAACgC,EAASW,CAAO,CAAC,EAOrB,IAAMQ,EAAUxD,EAAM,OAAOiD,CAAI,EACjCxC,EAAM,uBAAyB,CAC7B,EAAQ,QAAUwC,CACpB,EAAG,CAACA,CAAI,CAAC,EAET,IAAMQ,EAAiBzD,EAAM,OAAOiD,CAAI,EAElCS,EAAa1D,EAAM,OAA2B,IAAI,EAElD2D,EAAW3D,EAAM,OAAO,EAAK,EAC7B4D,EAAW5D,EAAM,OAAsB,IAAI,EAE3C6D,EAAS7D,EAAM,gBAAkB,CACrC,EAAS,QAAU,GACf4D,EAAS,UAAY,OACvB,qBAAqBA,EAAS,OAAO,EACrC,EAAS,QAAU,KAEvB,EAAG,CAAC,CAAC,EAICE,EAAM9D,EAAM,gBAAkB,CAClC6D,EAAO,EACP,EAAS,QAAU,GACf,OAAO,uBAA0B,aACnC,EAAS,QAAU,0BAA4B,CAC7C,EAAS,QAAU,KACnB,EAAS,QAAU,EACrB,CAAC,EAEL,EAAG,CAACA,CAAM,CAAC,EAEXpD,EAAM,cAAgBoD,EAAQ,CAACA,CAAM,CAAC,EAGtC,IAAME,EAAU5D,EAAAA,iBAAkB,GAAyB,CACzD,IAAM+C,EAAeX,EAAgB,QACrC,GAAI,CAACW,EAAc,OACnB,IAAMc,EAAOR,EAAQ,SAAW,CAAC,EAC3BS,EAAW,MAAM,KAAKf,EAAa,IAAI,CAAC,CAAC,OAAQ,GAAQ1B,EAAYE,CAAG,IAAM,IAAI,EAClFwC,EAAWF,EAAK,UAAW,GAAQtC,EAAI,QAAUyC,EAAQ,KAAK,EAChEzC,EAAMuC,EAAS,KAAM,GAASC,GAAY,GAAK1C,EAAY4C,CAAI,IAAMF,CAAQ,GAAK,KACtF,GAAI,CAACxC,GAAOsC,EAAK,OAAS,EAAG,CAC3B,IAAMK,EAAS,KAAK,IAAIF,EAAQ,MAAOH,EAAK,OAAS,CAAC,EAClDM,EAAW,IACf,IAAK,IAAMF,KAAQH,EAAU,CAC3B,IAAMM,EAAM,KAAK,KAAK/C,EAAY4C,CAAI,GAAK,GAAKC,CAAM,EAClDE,EAAMD,IACR,EAAMF,EACN,EAAWG,EAEf,CACF,CAEA,IAAMF,EAAS3C,GAAOwB,EAAa,KAAK,GACxC,GAAI,CAACmB,GAAUA,EAAO,MAAM,SAAW,EAAG,OAC1C,IAAMG,EAAS9C,EAAM,KAAK,IAAIyC,EAAQ,OAAQE,EAAO,MAAM,OAAS,CAAC,EAAI,EACzE7D,EAAA,sBAAsB6D,EAAO,MAAMG,EAAO,CAC5C,CAAC,EAGD/D,EAAM,oBAAsB,CAC1B,IAAMgE,EAAWhB,EAAe,QAChC,EAAe,QAAUR,EACzB,IAAMC,EAAeX,EAAgB,QAC/B4B,EAAUT,EAAW,QAC3B,GAAIe,IAAaxB,GAAQ,CAACZ,GAAW,CAACa,GAAgB,CAACiB,EAAS,OAChE,IAAMnC,EAASkB,EAAa,cAAc,cACtClB,GAAUkB,EAAa,SAASlB,CAAM,EAAG8B,EAAI,EACxC/B,EAAYC,EAAQM,EAAmB,OAAO,EAAGyB,EAAQI,CAAO,EACpE,EAAW,QAAU,IAC5B,EAAG,CAAClB,EAAMZ,EAASyB,EAAKC,CAAO,CAAC,EAOhC,IAAMW,EAAkB1E,EAAM,OAAO,EAAK,EACpC2E,EAAuBxE,EAAAA,qBAAuB,CAC9CW,IAAe,EAAgB,QAAU,GAC/C,CAAC,EAuDD,OAtDAL,EAAM,cAAgB,CACpB,IAAMwB,EAAMM,EAAgB,SAAS,cACrC,GAAI,CAACF,GAAW,CAACJ,EAAK,OACtB,IAAM2C,MAAc,CAClB,EAAgB,QAAU,EAC5B,EAEA,OADA3C,EAAI,iBAAiB,UAAW2C,EAAO,EAAI,MAC9B3C,EAAI,oBAAoB,UAAW2C,EAAO,EAAI,CAC7D,EAAG,CAACvC,CAAO,CAAC,EA8CL,CAAE,UAAS,cAAa,WAAU,QA5CzBlC,EAAAA,iBAAkB,GAA8C,CAC9E,IAAM0E,EAAeH,EAAgB,QAErC,GADA,EAAgB,QAAU,GACtB,CAAC5D,EAAe,OACpB+C,EAAO,EACP,IAAMiB,EAAOnD,EAAWoD,EAAM,cAAeA,EAAM,MAAM,EACnDrD,EAAMoD,GAAM,eAAiB,KAC7B/D,EAAQS,EAAYE,CAAG,EACvBsD,EAAQjE,IAAU,KAAO,IAAA,GAAYyC,EAAQ,UAAUzC,EAAM,EAAE,MACrE,EAAW,QACT+D,GAAQpD,aAAe,qBAAuBX,IAAU,MAAQiE,IAAU,IAAA,GACtE,CAAE,QAAO,QAAO,OAAQ,MAAM,UAAU,QAAQ,KAAKtD,EAAI,MAAOoD,CAAI,CAAE,EACtE,KAIF/D,IAAU,MAAQ,CAAC8D,GAAc/D,EAAc,cAAcC,EAAO,CAAE,MAAO,MAAO,CAAC,CAC3F,CA2ByC,EAAS,OAzBnCZ,EAAAA,iBAAkB,GAA8C,CAC7E,GAAI,CAACW,EAAe,OACpB,IAAMoC,EAAe6B,EAAM,cACrBE,EAAOF,EAAM,cACnB,GAAIE,GAAQ/B,EAAa,SAAS+B,CAAI,EAAG,OACzC,GAAIA,EAAM,CACR,EAAW,QAAU,KACrBpB,EAAO,EACP,MACF,CAGA,IAAM3B,EAAWI,EAAmB,QACpC,mBAAqB,CACnB,IAAM6B,EAAUT,EAAW,QAC3B,GAAI,CAACS,GAAW,CAACjB,EAAa,YAAa,OAC3C,IAAMlB,EAASkB,EAAa,cAAc,cAC1C,GAAIlB,GAAUkB,EAAa,SAASlB,CAAM,EAAG,OAC7C,IAAMkD,EAAYvB,EAAS,SAAW5B,EAAYC,EAAQE,CAAQ,EAClE2B,EAAO,EACHqB,EAAWnB,EAAQI,CAAO,EACzB,EAAW,QAAU,IAC5B,CAAC,CACH,CAEkD,EAAQ,sBAAqB,CACjF"}
|