@object-ui/plugin-grid 0.3.1 → 2.0.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.
@@ -1,6 +1,9 @@
1
- (function(v,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/fields"),require("@object-ui/components"),require("lucide-react")):typeof define=="function"&&define.amd?define(["exports","react","@object-ui/core","@object-ui/react","@object-ui/fields","@object-ui/components","lucide-react"],d):(v=typeof globalThis<"u"?globalThis:v||self,d(v.ObjectUIPluginGrid={},v.React,v.core,v.react,v.fields,v.components,v.lucideReact))})(this,(function(v,d,K,se,le,x,W){"use strict";var Y={exports:{}},A={};var H;function ce(){if(H)return A;H=1;var r=Symbol.for("react.transitional.element"),g=Symbol.for("react.fragment");function y(R,p,j){var T=null;if(j!==void 0&&(T=""+j),p.key!==void 0&&(T=""+p.key),"key"in p){j={};for(var S in p)S!=="key"&&(j[S]=p[S])}else j=p;return p=j.ref,{$$typeof:r,type:R,key:T,ref:p!==void 0?p:null,props:j}}return A.Fragment=g,A.jsx=y,A.jsxs=y,A}var h={};var Z;function ue(){return Z||(Z=1,process.env.NODE_ENV!=="production"&&(function(){function r(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===E?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case O:return"Fragment";case w:return"Profiler";case M:return"StrictMode";case J:return"Suspense";case $:return"SuspenseList";case u:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case G:return"Portal";case V:return e.displayName||"Context";case z:return(e._context.displayName||"Context")+".Consumer";case D:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case q:return t=e.displayName||null,t!==null?t:r(e.type)||"Memo";case F:t=e._payload,e=e._init;try{return r(e(t))}catch{}}return null}function g(e){return""+e}function y(e){try{g(e);var t=!1}catch{t=!0}if(t){t=console;var o=t.error,i=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return o.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",i),g(e)}}function R(e){if(e===O)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===F)return"<...>";try{var t=r(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function p(){var e=f.A;return e===null?null:e.getOwner()}function j(){return Error("react-stack-top-frame")}function T(e){if(n.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function S(e,t){function o(){U||(U=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}o.isReactWarning=!0,Object.defineProperty(e,"key",{get:o,configurable:!0})}function C(){var e=r(this.type);return ne[e]||(ne[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function I(e,t,o,i,L,X){var s=o.ref;return e={$$typeof:b,type:e,key:t,props:o,_owner:i},(s!==void 0?s:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:C}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:L}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:X}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function N(e,t,o,i,L,X){var s=t.children;if(s!==void 0)if(i)if(c(s)){for(i=0;i<s.length;i++)_(s[i]);Object.freeze&&Object.freeze(s)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else _(s);if(n.call(t,"key")){s=r(e);var k=Object.keys(t).filter(function(be){return be!=="key"});i=0<k.length?"{key: someKey, "+k.join(": ..., ")+": ...}":"{key: someKey}",ie[s+i]||(k=0<k.length?"{"+k.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
1
+ (function(A,R){typeof exports=="object"&&typeof module<"u"?R(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/fields"),require("@object-ui/components"),require("lucide-react"),require("react-dom")):typeof define=="function"&&define.amd?define(["exports","react","@object-ui/core","@object-ui/react","@object-ui/fields","@object-ui/components","lucide-react","react-dom"],R):(A=typeof globalThis<"u"?globalThis:A||self,R(A.ObjectUIPluginGrid={},A.React,A.core,A.react,A.fields,A.components,A.lucideReact,A.ReactDOM))})(this,(function(A,R,he,B,me,q,de,Ce){"use strict";function _e(n){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const e in n)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(a,e,s.get?s:{enumerable:!0,get:()=>n[e]})}}return a.default=n,Object.freeze(a)}const le=_e(R);var ae={exports:{}},Q={};var pe;function Ae(){if(pe)return Q;pe=1;var n=Symbol.for("react.transitional.element"),a=Symbol.for("react.fragment");function e(s,t,i){var o=null;if(i!==void 0&&(o=""+i),t.key!==void 0&&(o=""+t.key),"key"in t){i={};for(var l in t)l!=="key"&&(i[l]=t[l])}else i=t;return t=i.ref,{$$typeof:n,type:s,key:o,ref:t!==void 0?t:null,props:i}}return Q.Fragment=a,Q.jsx=e,Q.jsxs=e,Q}var ee={};var ge;function Re(){return ge||(ge=1,process.env.NODE_ENV!=="production"&&(function(){function n(r){if(r==null)return null;if(typeof r=="function")return r.$$typeof===U?null:r.displayName||r.name||null;if(typeof r=="string")return r;switch(r){case w:return"Fragment";case O:return"Profiler";case z:return"StrictMode";case Y:return"Suspense";case $:return"SuspenseList";case J:return"Activity"}if(typeof r=="object")switch(typeof r.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),r.$$typeof){case v:return"Portal";case M:return r.displayName||"Context";case F:return(r._context.displayName||"Context")+".Consumer";case C:var h=r.render;return r=r.displayName,r||(r=h.displayName||h.name||"",r=r!==""?"ForwardRef("+r+")":"ForwardRef"),r;case L:return h=r.displayName||null,h!==null?h:n(r.type)||"Memo";case I:h=r._payload,r=r._init;try{return n(r(h))}catch{}}return null}function a(r){return""+r}function e(r){try{a(r);var h=!1}catch{h=!0}if(h){h=console;var y=h.error,S=typeof Symbol=="function"&&Symbol.toStringTag&&r[Symbol.toStringTag]||r.constructor.name||"Object";return y.call(h,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",S),a(r)}}function s(r){if(r===w)return"<>";if(typeof r=="object"&&r!==null&&r.$$typeof===I)return"<...>";try{var h=n(r);return h?"<"+h+">":"<...>"}catch{return"<...>"}}function t(){var r=K.A;return r===null?null:r.getOwner()}function i(){return Error("react-stack-top-frame")}function o(r){if(te.call(r,"key")){var h=Object.getOwnPropertyDescriptor(r,"key").get;if(h&&h.isReactWarning)return!1}return r.key!==void 0}function l(r,h){function y(){ce||(ce=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",h))}y.isReactWarning=!0,Object.defineProperty(r,"key",{get:y,configurable:!0})}function p(){var r=n(this.type);return ne[r]||(ne[r]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),r=this.props.ref,r!==void 0?r:null}function g(r,h,y,S,G,Z){var f=y.ref;return r={$$typeof:_,type:r,key:h,props:y,_owner:S},(f!==void 0?f:null)!==null?Object.defineProperty(r,"ref",{enumerable:!1,get:p}):Object.defineProperty(r,"ref",{enumerable:!1,value:null}),r._store={},Object.defineProperty(r._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(r,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(r,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:G}),Object.defineProperty(r,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Z}),Object.freeze&&(Object.freeze(r.props),Object.freeze(r)),r}function m(r,h,y,S,G,Z){var f=h.children;if(f!==void 0)if(S)if(D(f)){for(S=0;S<f.length;S++)E(f[S]);Object.freeze&&Object.freeze(f)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else E(f);if(te.call(h,"key")){f=n(r);var x=Object.keys(h).filter(function(j){return j!=="key"});S=0<x.length?"{key: someKey, "+x.join(": ..., ")+": ...}":"{key: someKey}",ue[f+S]||(x=0<x.length?"{"+x.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
2
  let props = %s;
3
3
  <%s {...props} />
4
4
  React keys must be passed directly to JSX without using spread:
5
5
  let props = %s;
6
- <%s key={someKey} {...props} />`,i,s,k,s),ie[s+i]=!0)}if(s=null,o!==void 0&&(y(o),s=""+o),T(t)&&(y(t.key),s=""+t.key),"key"in t){o={};for(var B in t)B!=="key"&&(o[B]=t[B])}else o=t;return s&&S(o,typeof e=="function"?e.displayName||e.name||"Unknown":e),I(e,s,o,p(),L,X)}function _(e){P(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===F&&(e._payload.status==="fulfilled"?P(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function P(e){return typeof e=="object"&&e!==null&&e.$$typeof===b}var l=d,b=Symbol.for("react.transitional.element"),G=Symbol.for("react.portal"),O=Symbol.for("react.fragment"),M=Symbol.for("react.strict_mode"),w=Symbol.for("react.profiler"),z=Symbol.for("react.consumer"),V=Symbol.for("react.context"),D=Symbol.for("react.forward_ref"),J=Symbol.for("react.suspense"),$=Symbol.for("react.suspense_list"),q=Symbol.for("react.memo"),F=Symbol.for("react.lazy"),u=Symbol.for("react.activity"),E=Symbol.for("react.client.reference"),f=l.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,n=Object.prototype.hasOwnProperty,c=Array.isArray,m=console.createTask?console.createTask:function(){return null};l={react_stack_bottom_frame:function(e){return e()}};var U,ne={},oe=l.react_stack_bottom_frame.bind(l,j)(),ae=m(R(j)),ie={};h.Fragment=O,h.jsx=function(e,t,o){var i=1e4>f.recentlyCreatedOwnerStacks++;return N(e,t,o,!1,i?Error("react-stack-top-frame"):oe,i?m(R(e)):ae)},h.jsxs=function(e,t,o){var i=1e4>f.recentlyCreatedOwnerStacks++;return N(e,t,o,!0,i?Error("react-stack-top-frame"):oe,i?m(R(e)):ae)}})()),h}var Q;function fe(){return Q||(Q=1,process.env.NODE_ENV==="production"?Y.exports=ce():Y.exports=ue()),Y.exports}var a=fe();function de(r){return r.data?r.data:r.staticData?{provider:"value",items:r.staticData}:r.objectName?{provider:"object",object:r.objectName}:null}function ee(r){if(!(!r||r.length===0))return typeof r[0]=="object"&&r[0]!==null,r}const re=({schema:r,dataSource:g,onEdit:y,onDelete:R,onRowSelect:p})=>{const[j,T]=d.useState([]),[S,C]=d.useState(!0),[I,N]=d.useState(null),[_,P]=d.useState(null),l=de(r),b=l?.provider==="value";d.useEffect(()=>{b&&l?.provider==="value"&&(T(l.items),C(!1))},[b,l]),d.useEffect(()=>{const u=async()=>{try{if(!g)throw new Error("DataSource required");const f=l?.provider==="object"?l.object:r.objectName;if(!f)throw new Error("Object name required for object provider");const n=await g.getObjectSchema(f);P(n)}catch(f){N(f)}},E=ee(r.columns)||r.fields;b&&E?P({name:r.objectName,fields:{}}):r.objectName&&!b&&g&&u()},[r.objectName,r.columns,r.fields,g,b,l]);const G=d.useCallback(()=>{const u=ee(r.columns);if(u)return u.length>0&&typeof u[0]=="object"&&u[0]!==null?u.filter(n=>n?.field&&typeof n.field=="string").map(n=>({header:n.label||n.field.charAt(0).toUpperCase()+n.field.slice(1).replace(/_/g," "),accessorKey:n.field,...n.width&&{width:n.width},...n.align&&{align:n.align},sortable:n.sortable!==!1})):u.filter(n=>typeof n=="string"&&n.trim().length>0).map(n=>({header:n.charAt(0).toUpperCase()+n.slice(1).replace(/_/g," "),accessorKey:n}));if(b){const n=l?.provider==="value"?l.items:[];if(n.length>0)return(r.fields||Object.keys(n[0])).map(m=>({header:m.charAt(0).toUpperCase()+m.slice(1).replace(/_/g," "),accessorKey:m}))}if(!_)return[];const E=[];return(r.fields||Object.keys(_.fields||{})).forEach(n=>{const c=_.fields?.[n];if(!c||c.permissions&&c.permissions.read===!1)return;const m=le.getCellRenderer(c.type);E.push({header:c.label||n,accessorKey:n,cell:U=>a.jsx(m,{value:U,field:c}),sortable:c.sortable!==!1})}),E},[_,r.fields,r.columns,l,b]),O=d.useCallback(async()=>{if(!(b||!g)){C(!0);try{const u=l?.provider==="object"?l.object:r.objectName;if(!u)throw new Error("Object name required for data fetching");const f={$select:(()=>{if(r.fields)return r.fields;if(r.columns&&Array.isArray(r.columns))return r.columns.map(c=>typeof c=="string"?c:c.field)})(),$top:r.pagination?.pageSize||r.pageSize||50};r.filter&&Array.isArray(r.filter)?f.$filter=r.filter:"defaultFilters"in r&&r.defaultFilters&&(f.$filter=r.defaultFilters),r.sort?typeof r.sort=="string"?f.$orderby=r.sort:Array.isArray(r.sort)&&(f.$orderby=r.sort.map(c=>`${c.field} ${c.order}`).join(", ")):"defaultSort"in r&&r.defaultSort&&(f.$orderby=`${r.defaultSort.field} ${r.defaultSort.order}`);const n=await g.find(u,f);T(n.data||[])}catch(u){N(u)}finally{C(!1)}}},[r,g,b,l]);if(d.useEffect(()=>{(_||b)&&O()},[_,b,O]),I)return a.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[a.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading grid"}),a.jsx("p",{className:"text-red-600 text-sm mt-1",children:I.message})]});if(S&&j.length===0)return a.jsxs("div",{className:"p-8 text-center",children:[a.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),a.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading grid..."})]});const M=G(),w="operations"in r?r.operations:void 0,z=w&&(w.update||w.delete),V=z?[...M,{header:"Actions",accessorKey:"_actions",cell:(u,E)=>a.jsxs(x.DropdownMenu,{children:[a.jsx(x.DropdownMenuTrigger,{asChild:!0,children:a.jsxs(x.Button,{variant:"ghost",size:"icon",className:"h-8 w-8",children:[a.jsx(W.MoreVertical,{className:"h-4 w-4"}),a.jsx("span",{className:"sr-only",children:"Open menu"})]})}),a.jsxs(x.DropdownMenuContent,{align:"end",children:[w?.update&&y&&a.jsxs(x.DropdownMenuItem,{onClick:()=>y(E),children:[a.jsx(W.Edit,{className:"mr-2 h-4 w-4"}),"Edit"]}),w?.delete&&R&&a.jsxs(x.DropdownMenuItem,{variant:"destructive",onClick:()=>R(E),children:[a.jsx(W.Trash2,{className:"mr-2 h-4 w-4"}),"Delete"]})]})]}),sortable:!1}]:M;let D=!1;r.selection?.type?D=r.selection.type==="none"?!1:r.selection.type:r.selectable!==void 0&&(D=r.selectable);const J=r.pagination!==void 0?!0:r.showPagination!==void 0?r.showPagination:!0,$=r.pagination?.pageSize||r.pageSize||10,q=r.searchableFields!==void 0?r.searchableFields.length>0:r.showSearch!==void 0?r.showSearch:!0,F={type:"data-table",caption:r.label||r.title,columns:V,data:j,pagination:J,pageSize:$,searchable:q,selectable:D,sortable:!0,exportable:w?.export,rowActions:z,resizableColumns:r.resizable??r.resizableColumns??!0,className:r.className,onSelectionChange:p};return a.jsx(se.SchemaRenderer,{schema:F})},te=({schema:r})=>a.jsx(re,{schema:r,dataSource:null});K.ComponentRegistry.register("object-grid",te),K.ComponentRegistry.register("grid",te),v.ObjectGrid=re,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"})}));
6
+ <%s key={someKey} {...props} />`,S,f,x,f),ue[f+S]=!0)}if(f=null,y!==void 0&&(e(y),f=""+y),o(h)&&(e(h.key),f=""+h.key),"key"in h){y={};for(var N in h)N!=="key"&&(y[N]=h[N])}else y=h;return f&&l(y,typeof r=="function"?r.displayName||r.name||"Unknown":r),g(r,f,y,t(),G,Z)}function E(r){u(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===I&&(r._payload.status==="fulfilled"?u(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function u(r){return typeof r=="object"&&r!==null&&r.$$typeof===_}var b=R,_=Symbol.for("react.transitional.element"),v=Symbol.for("react.portal"),w=Symbol.for("react.fragment"),z=Symbol.for("react.strict_mode"),O=Symbol.for("react.profiler"),F=Symbol.for("react.consumer"),M=Symbol.for("react.context"),C=Symbol.for("react.forward_ref"),Y=Symbol.for("react.suspense"),$=Symbol.for("react.suspense_list"),L=Symbol.for("react.memo"),I=Symbol.for("react.lazy"),J=Symbol.for("react.activity"),U=Symbol.for("react.client.reference"),K=b.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,te=Object.prototype.hasOwnProperty,D=Array.isArray,X=console.createTask?console.createTask:function(){return null};b={react_stack_bottom_frame:function(r){return r()}};var ce,ne={},V=b.react_stack_bottom_frame.bind(b,i)(),se=X(s(i)),ue={};ee.Fragment=w,ee.jsx=function(r,h,y){var S=1e4>K.recentlyCreatedOwnerStacks++;return m(r,h,y,!1,S?Error("react-stack-top-frame"):V,S?X(s(r)):se)},ee.jsxs=function(r,h,y){var S=1e4>K.recentlyCreatedOwnerStacks++;return m(r,h,y,!0,S?Error("react-stack-top-frame"):V,S?X(s(r)):se)}})()),ee}var be;function Te(){return be||(be=1,process.env.NODE_ENV==="production"?ae.exports=Ae():ae.exports=Re()),ae.exports}var c=Te();function Ne(n){return n.data?Array.isArray(n.data)?{provider:"value",items:n.data}:n.data:n.staticData?{provider:"value",items:n.staticData}:n.objectName?{provider:"object",object:n.objectName}:null}function ve(n){if(!(!n||n.length===0))return typeof n[0]=="object"&&n[0]!==null,n}const ye=({schema:n,dataSource:a,onEdit:e,onDelete:s,onRowSelect:t,onRowClick:i,onCellChange:o,onRowSave:l,onBatchSave:p,...g})=>{const[m,E]=R.useState([]),[u,b]=R.useState(!0),[_,v]=R.useState(null),[w,z]=R.useState(null),O=g.data,F=B.useDataScope(n.bind),M=Ne(n),C=R.useMemo(()=>O&&Array.isArray(O)?{provider:"value",items:O}:F&&Array.isArray(F)?{provider:"value",items:F}:M,[JSON.stringify(M),F,O]),Y=C?.provider==="value",$=C?.provider==="object"&&C&&"object"in C?C.object:n.objectName,L=n.fields,I=n.columns,J=n.filter,U=n.sort,K=n.pagination,te=n.pageSize;R.useEffect(()=>{Y&&C?.provider==="value"&&(E(f=>{const x=C.items;return JSON.stringify(f)!==JSON.stringify(x)?x:f}),b(!1))},[Y,C]),R.useEffect(()=>{if(Y)return;let f=!1;return(async()=>{b(!0),v(null);try{let N=null;if((ve(I)||L)&&$)N={name:$,fields:{}};else if($&&a){const d=await a.getObjectSchema($);if(f)return;N=d}else throw $?new Error("DataSource required"):new Error("Object name required for data fetching");if(f||z(N),a&&$){const k={$select:(()=>{if(L)return L;if(I&&Array.isArray(I))return I.map(T=>typeof T=="string"?T:T.field)})(),$top:K?.pageSize||te||50};J&&Array.isArray(J)?k.$filter=J:n.defaultFilters&&(k.$filter=n.defaultFilters),U?typeof U=="string"?k.$orderby=U:Array.isArray(U)&&(k.$orderby=U.map(T=>`${T.field} ${T.order}`).join(", ")):n.defaultSort&&(k.$orderby=`${n.defaultSort.field} ${n.defaultSort.order}`);const W=await a.find($,k);if(f)return;E(W.data||[])}}catch(N){f||v(N)}finally{f||b(!1)}})(),()=>{f=!0}},[$,L,I,J,U,K,te,a,Y,C]);const D=B.useNavigationOverlay({navigation:n.navigation,objectName:n.objectName,onNavigate:n.onNavigate,onRowClick:i}),{execute:X}=B.useAction(),ce=R.useCallback(()=>{const f=ve(I);if(f){if(f.length>0&&typeof f[0]=="object"&&f[0]!==null){const j=f[0];if("accessorKey"in j)return f;if("field"in j)return f.filter(d=>d?.field&&typeof d.field=="string"&&!d.hidden).map(d=>{const k=d.label||d.field.charAt(0).toUpperCase()+d.field.slice(1).replace(/_/g," ");let W;const T=d.type?me.getCellRenderer(d.type):null;return d.link&&d.action?W=(P,re)=>{const ie=T?c.jsx(T,{value:P,field:{name:d.field,type:d.type||"text"}}):String(P??"");return c.jsx("button",{type:"button",className:"text-primary underline-offset-4 hover:underline cursor-pointer bg-transparent border-none p-0 text-left font-inherit",onClick:oe=>{oe.stopPropagation(),D.handleClick(re)},children:ie})}:d.link?W=(P,re)=>{const ie=T?c.jsx(T,{value:P,field:{name:d.field,type:d.type||"text"}}):String(P??"");return c.jsx("button",{type:"button",className:"text-primary underline-offset-4 hover:underline cursor-pointer bg-transparent border-none p-0 text-left font-inherit",onClick:oe=>{oe.stopPropagation(),D.handleClick(re)},children:ie})}:d.action?W=(P,re)=>{const ie=T?c.jsx(T,{value:P,field:{name:d.field,type:d.type||"text"}}):String(P??"");return c.jsx("button",{type:"button",className:"text-primary underline-offset-4 hover:underline cursor-pointer bg-transparent border-none p-0 text-left font-inherit",onClick:oe=>{oe.stopPropagation(),X({type:d.action,params:{record:re,field:d.field,value:P}})},children:ie})}:T&&(W=P=>c.jsx(T,{value:P,field:{name:d.field,type:d.type||"text"}})),{header:k,accessorKey:d.field,...d.width&&{width:d.width},...d.align&&{align:d.align},sortable:d.sortable!==!1,...d.resizable!==void 0&&{resizable:d.resizable},...d.wrap!==void 0&&{wrap:d.wrap},...W&&{cell:W}}})}return f.filter(j=>typeof j=="string"&&j.trim().length>0).map(j=>({header:w?.fields?.[j]?.label||j.charAt(0).toUpperCase()+j.slice(1).replace(/_/g," "),accessorKey:j}))}if(Y){const j=C?.provider==="value"?C.items:[];if(j.length>0)return(L||Object.keys(j[0])).map(k=>({header:k.charAt(0).toUpperCase()+k.slice(1).replace(/_/g," "),accessorKey:k}))}if(!w)return[];const x=[];return(L||Object.keys(w.fields||{})).forEach(j=>{const d=w.fields?.[j];if(!d||d.permissions&&d.permissions.read===!1)return;const k=me.getCellRenderer(d.type);x.push({header:d.label||j,accessorKey:j,cell:W=>c.jsx(k,{value:W,field:d}),sortable:d.sortable!==!1})}),x},[w,L,I,C,Y,D.handleClick,X]);if(_)return c.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[c.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading grid"}),c.jsx("p",{className:"text-red-600 text-sm mt-1",children:_.message})]});if(u&&m.length===0)return c.jsxs("div",{className:"p-8 text-center",children:[c.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading grid..."})]});const ne=ce(),V="operations"in n?n.operations:void 0,se=V&&(V.update||V.delete),ue=se?[...ne,{header:"Actions",accessorKey:"_actions",cell:(f,x)=>c.jsxs(q.DropdownMenu,{children:[c.jsx(q.DropdownMenuTrigger,{asChild:!0,children:c.jsxs(q.Button,{variant:"ghost",size:"icon",className:"h-8 w-8",children:[c.jsx(de.MoreVertical,{className:"h-4 w-4"}),c.jsx("span",{className:"sr-only",children:"Open menu"})]})}),c.jsxs(q.DropdownMenuContent,{align:"end",children:[V?.update&&e&&c.jsxs(q.DropdownMenuItem,{onClick:()=>e(x),children:[c.jsx(de.Edit,{className:"mr-2 h-4 w-4"}),"Edit"]}),V?.delete&&s&&c.jsxs(q.DropdownMenuItem,{onClick:()=>s(x),children:[c.jsx(de.Trash2,{className:"mr-2 h-4 w-4"}),"Delete"]})]})]}),sortable:!1}]:ne;let r=!1;n.selection?.type?r=n.selection.type==="none"?!1:n.selection.type:n.selectable!==void 0&&(r=n.selectable);const h=n.pagination!==void 0?!0:n.showPagination!==void 0?n.showPagination:!0,y=n.pagination?.pageSize||n.pageSize||10,S=n.searchableFields!==void 0?n.searchableFields.length>0:n.showSearch!==void 0?n.showSearch:!0,G={type:"data-table",caption:n.label||n.title,columns:ue,data:m,pagination:h,pageSize:y,searchable:S,selectable:r,sortable:!0,exportable:V?.export,rowActions:se,resizableColumns:n.resizable??n.resizableColumns??!0,reorderableColumns:n.reorderableColumns??!1,editable:n.editable??!1,className:n.className,onSelectionChange:t,onRowClick:D.handleClick,onCellChange:o,onRowSave:l,onBatchSave:p},Z=n.label?`${n.label} Detail`:n.objectName?`${n.objectName.charAt(0).toUpperCase()+n.objectName.slice(1)} Detail`:"Record Detail";return D.isOverlay&&D.mode==="split"?c.jsx(q.NavigationOverlay,{...D,title:Z,mainContent:c.jsx(B.SchemaRenderer,{schema:G}),children:f=>c.jsx("div",{className:"space-y-3",children:Object.entries(f).map(([x,N])=>c.jsxs("div",{className:"flex flex-col",children:[c.jsx("span",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wide",children:x.replace(/_/g," ")}),c.jsx("span",{className:"text-sm",children:String(N??"—")})]},x))})}):c.jsxs(c.Fragment,{children:[c.jsx(B.SchemaRenderer,{schema:G}),D.isOverlay&&c.jsx(q.NavigationOverlay,{...D,title:Z,children:f=>c.jsx("div",{className:"space-y-3",children:Object.entries(f).map(([x,N])=>c.jsxs("div",{className:"flex flex-col",children:[c.jsx("span",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wide",children:x.replace(/_/g," ")}),c.jsx("span",{className:"text-sm",children:String(N??"—")})]},x))})})]})};function H(n,a,e){let s=e.initialDeps??[],t,i=!0;function o(){var l,p,g;let m;e.key&&((l=e.debug)!=null&&l.call(e))&&(m=Date.now());const E=n();if(!(E.length!==s.length||E.some((_,v)=>s[v]!==_)))return t;s=E;let b;if(e.key&&((p=e.debug)!=null&&p.call(e))&&(b=Date.now()),t=a(...E),e.key&&((g=e.debug)!=null&&g.call(e))){const _=Math.round((Date.now()-m)*100)/100,v=Math.round((Date.now()-b)*100)/100,w=v/16,z=(O,F)=>{for(O=String(O);O.length<F;)O=" "+O;return O};console.info(`%c⏱ ${z(v,5)} /${z(_,5)} ms`,`
7
+ font-size: .6rem;
8
+ font-weight: bold;
9
+ color: hsl(${Math.max(0,Math.min(120-120*w,120))}deg 100% 31%);`,e?.key)}return e?.onChange&&!(i&&e.skipInitialOnChange)&&e.onChange(t),i=!1,t}return o.updateDeps=l=>{s=l},o}function xe(n,a){if(n===void 0)throw new Error("Unexpected undefined");return n}const ke=(n,a)=>Math.abs(n-a)<1.01,ze=(n,a,e)=>{let s;return function(...t){n.clearTimeout(s),s=n.setTimeout(()=>a.apply(this,t),e)}},Ee=n=>{const{offsetWidth:a,offsetHeight:e}=n;return{width:a,height:e}},Me=n=>n,Ie=n=>{const a=Math.max(n.startIndex-n.overscan,0),e=Math.min(n.endIndex+n.overscan,n.count-1),s=[];for(let t=a;t<=e;t++)s.push(t);return s},De=(n,a)=>{const e=n.scrollElement;if(!e)return;const s=n.targetWindow;if(!s)return;const t=o=>{const{width:l,height:p}=o;a({width:Math.round(l),height:Math.round(p)})};if(t(Ee(e)),!s.ResizeObserver)return()=>{};const i=new s.ResizeObserver(o=>{const l=()=>{const p=o[0];if(p?.borderBoxSize){const g=p.borderBoxSize[0];if(g){t({width:g.inlineSize,height:g.blockSize});return}}t(Ee(e))};n.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(l):l()});return i.observe(e,{box:"border-box"}),()=>{i.unobserve(e)}},Se={passive:!0},je=typeof window>"u"?!0:"onscrollend"in window,Pe=(n,a)=>{const e=n.scrollElement;if(!e)return;const s=n.targetWindow;if(!s)return;let t=0;const i=n.options.useScrollendEvent&&je?()=>{}:ze(s,()=>{a(t,!1)},n.options.isScrollingResetDelay),o=m=>()=>{const{horizontal:E,isRtl:u}=n.options;t=E?e.scrollLeft*(u&&-1||1):e.scrollTop,i(),a(t,m)},l=o(!0),p=o(!1);e.addEventListener("scroll",l,Se);const g=n.options.useScrollendEvent&&je;return g&&e.addEventListener("scrollend",p,Se),()=>{e.removeEventListener("scroll",l),g&&e.removeEventListener("scrollend",p)}},Fe=(n,a,e)=>{if(a?.borderBoxSize){const s=a.borderBoxSize[0];if(s)return Math.round(s[e.options.horizontal?"inlineSize":"blockSize"])}return n[e.options.horizontal?"offsetWidth":"offsetHeight"]},$e=(n,{adjustments:a=0,behavior:e},s)=>{var t,i;const o=n+a;(i=(t=s.scrollElement)==null?void 0:t.scrollTo)==null||i.call(t,{[s.options.horizontal?"left":"top"]:o,behavior:e})};class We{constructor(a){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.currentScrollToIndex=null,this.measurementsCache=[],this.itemSizeCache=new Map,this.laneAssignments=new Map,this.pendingMeasuredCacheIndexes=[],this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this.elementsCache=new Map,this.observer=(()=>{let e=null;const s=()=>e||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:e=new this.targetWindow.ResizeObserver(t=>{t.forEach(i=>{const o=()=>{this._measureElement(i.target,i)};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(o):o()})}));return{disconnect:()=>{var t;(t=s())==null||t.disconnect(),e=null},observe:t=>{var i;return(i=s())==null?void 0:i.observe(t,{box:"border-box"})},unobserve:t=>{var i;return(i=s())==null?void 0:i.unobserve(t)}}})(),this.range=null,this.setOptions=e=>{Object.entries(e).forEach(([s,t])=>{typeof t>"u"&&delete e[s]}),this.options={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:Me,rangeExtractor:Ie,onChange:()=>{},measureElement:Fe,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,...e}},this.notify=e=>{var s,t;(t=(s=this.options).onChange)==null||t.call(s,this,e)},this.maybeNotify=H(()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]),e=>{this.notify(e)},{key:process.env.NODE_ENV!=="production"&&"maybeNotify",debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(e=>e()),this.unsubs=[],this.observer.disconnect(),this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var e;const s=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==s){if(this.cleanup(),!s){this.maybeNotify();return}this.scrollElement=s,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((e=this.scrollElement)==null?void 0:e.window)??null,this.elementsCache.forEach(t=>{this.observer.observe(t)}),this.unsubs.push(this.options.observeElementRect(this,t=>{this.scrollRect=t,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(t,i)=>{this.scrollAdjustments=0,this.scrollDirection=i?this.getScrollOffset()<t?"forward":"backward":null,this.scrollOffset=t,this.isScrolling=i,this.maybeNotify()})),this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}},this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getFurthestMeasurement=(e,s)=>{const t=new Map,i=new Map;for(let o=s-1;o>=0;o--){const l=e[o];if(t.has(l.lane))continue;const p=i.get(l.lane);if(p==null||l.end>p.end?i.set(l.lane,l):l.end<p.end&&t.set(l.lane,!0),t.size===this.options.lanes)break}return i.size===this.options.lanes?Array.from(i.values()).sort((o,l)=>o.end===l.end?o.index-l.index:o.end-l.end)[0]:void 0},this.getMeasurementOptions=H(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes],(e,s,t,i,o,l)=>(this.prevLanes!==void 0&&this.prevLanes!==l&&(this.lanesChangedFlag=!0),this.prevLanes=l,this.pendingMeasuredCacheIndexes=[],{count:e,paddingStart:s,scrollMargin:t,getItemKey:i,enabled:o,lanes:l}),{key:!1}),this.getMeasurements=H(()=>[this.getMeasurementOptions(),this.itemSizeCache],({count:e,paddingStart:s,scrollMargin:t,getItemKey:i,enabled:o,lanes:l},p)=>{if(!o)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>e)for(const u of this.laneAssignments.keys())u>=e&&this.laneAssignments.delete(u);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMeasuredCacheIndexes=[]),this.measurementsCache.length===0&&!this.lanesSettling&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(u=>{this.itemSizeCache.set(u.key,u.size)}));const g=this.lanesSettling?0:this.pendingMeasuredCacheIndexes.length>0?Math.min(...this.pendingMeasuredCacheIndexes):0;this.pendingMeasuredCacheIndexes=[],this.lanesSettling&&this.measurementsCache.length===e&&(this.lanesSettling=!1);const m=this.measurementsCache.slice(0,g),E=new Array(l).fill(void 0);for(let u=0;u<g;u++){const b=m[u];b&&(E[b.lane]=u)}for(let u=g;u<e;u++){const b=i(u),_=this.laneAssignments.get(u);let v,w;if(_!==void 0&&this.options.lanes>1){v=_;const M=E[v],C=M!==void 0?m[M]:void 0;w=C?C.end+this.options.gap:s+t}else{const M=this.options.lanes===1?m[u-1]:this.getFurthestMeasurement(m,u);w=M?M.end+this.options.gap:s+t,v=M?M.lane:u%this.options.lanes,this.options.lanes>1&&this.laneAssignments.set(u,v)}const z=p.get(b),O=typeof z=="number"?z:this.options.estimateSize(u),F=w+O;m[u]={index:u,start:w,size:O,end:F,key:b,lane:v},E[v]=u}return this.measurementsCache=m,m},{key:process.env.NODE_ENV!=="production"&&"getMeasurements",debug:()=>this.options.debug}),this.calculateRange=H(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(e,s,t,i)=>this.range=e.length>0&&s>0?Le({measurements:e,outerSize:s,scrollOffset:t,lanes:i}):null,{key:process.env.NODE_ENV!=="production"&&"calculateRange",debug:()=>this.options.debug}),this.getVirtualIndexes=H(()=>{let e=null,s=null;const t=this.calculateRange();return t&&(e=t.startIndex,s=t.endIndex),this.maybeNotify.updateDeps([this.isScrolling,e,s]),[this.options.rangeExtractor,this.options.overscan,this.options.count,e,s]},(e,s,t,i,o)=>i===null||o===null?[]:e({startIndex:i,endIndex:o,overscan:s,count:t}),{key:process.env.NODE_ENV!=="production"&&"getVirtualIndexes",debug:()=>this.options.debug}),this.indexFromElement=e=>{const s=this.options.indexAttribute,t=e.getAttribute(s);return t?parseInt(t,10):(console.warn(`Missing attribute name '${s}={index}' on measured element.`),-1)},this._measureElement=(e,s)=>{const t=this.indexFromElement(e),i=this.measurementsCache[t];if(!i)return;const o=i.key,l=this.elementsCache.get(o);l!==e&&(l&&this.observer.unobserve(l),this.observer.observe(e),this.elementsCache.set(o,e)),e.isConnected&&this.resizeItem(t,this.options.measureElement(e,s,this))},this.resizeItem=(e,s)=>{const t=this.measurementsCache[e];if(!t)return;const i=this.itemSizeCache.get(t.key)??t.size,o=s-i;o!==0&&((this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(t,o,this):t.start<this.getScrollOffset()+this.scrollAdjustments)&&(process.env.NODE_ENV!=="production"&&this.options.debug&&console.info("correction",o),this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=o,behavior:void 0})),this.pendingMeasuredCacheIndexes.push(t.index),this.itemSizeCache=new Map(this.itemSizeCache.set(t.key,s)),this.notify(!1))},this.measureElement=e=>{if(!e){this.elementsCache.forEach((s,t)=>{s.isConnected||(this.observer.unobserve(s),this.elementsCache.delete(t))});return}this._measureElement(e,void 0)},this.getVirtualItems=H(()=>[this.getVirtualIndexes(),this.getMeasurements()],(e,s)=>{const t=[];for(let i=0,o=e.length;i<o;i++){const l=e[i],p=s[l];t.push(p)}return t},{key:process.env.NODE_ENV!=="production"&&"getVirtualItems",debug:()=>this.options.debug}),this.getVirtualItemForOffset=e=>{const s=this.getMeasurements();if(s.length!==0)return xe(s[we(0,s.length-1,t=>xe(s[t]).start,e)])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if("scrollHeight"in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{const e=this.scrollElement.document.documentElement;return this.options.horizontal?e.scrollWidth-this.scrollElement.innerWidth:e.scrollHeight-this.scrollElement.innerHeight}},this.getOffsetForAlignment=(e,s,t=0)=>{if(!this.scrollElement)return 0;const i=this.getSize(),o=this.getScrollOffset();s==="auto"&&(s=e>=o+i?"end":"start"),s==="center"?e+=(t-i)/2:s==="end"&&(e-=i);const l=this.getMaxScrollOffset();return Math.max(Math.min(l,e),0)},this.getOffsetForIndex=(e,s="auto")=>{e=Math.max(0,Math.min(e,this.options.count-1));const t=this.measurementsCache[e];if(!t)return;const i=this.getSize(),o=this.getScrollOffset();if(s==="auto")if(t.end>=o+i-this.options.scrollPaddingEnd)s="end";else if(t.start<=o+this.options.scrollPaddingStart)s="start";else return[o,s];if(s==="end"&&e===this.options.count-1)return[this.getMaxScrollOffset(),s];const l=s==="end"?t.end+this.options.scrollPaddingEnd:t.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(l,s,t.size),s]},this.isDynamicMode=()=>this.elementsCache.size>0,this.scrollToOffset=(e,{align:s="start",behavior:t}={})=>{t==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getOffsetForAlignment(e,s),{adjustments:void 0,behavior:t})},this.scrollToIndex=(e,{align:s="auto",behavior:t}={})=>{t==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),e=Math.max(0,Math.min(e,this.options.count-1)),this.currentScrollToIndex=e;let i=0;const o=10,l=g=>{if(!this.targetWindow)return;const m=this.getOffsetForIndex(e,g);if(!m){console.warn("Failed to get offset for index:",e);return}const[E,u]=m;this._scrollToOffset(E,{adjustments:void 0,behavior:t}),this.targetWindow.requestAnimationFrame(()=>{const b=()=>{if(this.currentScrollToIndex!==e)return;const _=this.getScrollOffset(),v=this.getOffsetForIndex(e,u);if(!v){console.warn("Failed to get offset for index:",e);return}ke(v[0],_)||p(u)};this.isDynamicMode()?this.targetWindow.requestAnimationFrame(b):b()})},p=g=>{this.targetWindow&&this.currentScrollToIndex===e&&(i++,i<o?(process.env.NODE_ENV!=="production"&&this.options.debug&&console.info("Schedule retry",i,o),this.targetWindow.requestAnimationFrame(()=>l(g))):console.warn(`Failed to scroll to index ${e} after ${o} attempts.`))};l(s)},this.scrollBy=(e,{behavior:s}={})=>{s==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getScrollOffset()+e,{adjustments:void 0,behavior:s})},this.getTotalSize=()=>{var e;const s=this.getMeasurements();let t;if(s.length===0)t=this.options.paddingStart;else if(this.options.lanes===1)t=((e=s[s.length-1])==null?void 0:e.end)??0;else{const i=Array(this.options.lanes).fill(null);let o=s.length-1;for(;o>=0&&i.some(l=>l===null);){const l=s[o];i[l.lane]===null&&(i[l.lane]=l.end),o--}t=Math.max(...i.filter(l=>l!==null))}return Math.max(t-this.options.scrollMargin+this.options.paddingEnd,0)},this._scrollToOffset=(e,{adjustments:s,behavior:t})=>{this.options.scrollToFn(e,{behavior:t,adjustments:s},this)},this.measure=()=>{this.itemSizeCache=new Map,this.laneAssignments=new Map,this.notify(!1)},this.setOptions(a)}}const we=(n,a,e,s)=>{for(;n<=a;){const t=(n+a)/2|0,i=e(t);if(i<s)n=t+1;else if(i>s)a=t-1;else return t}return n>0?n-1:0};function Le({measurements:n,outerSize:a,scrollOffset:e,lanes:s}){const t=n.length-1,i=p=>n[p].start;if(n.length<=s)return{startIndex:0,endIndex:t};let o=we(0,t,i,e),l=o;if(s===1)for(;l<t&&n[l].end<e+a;)l++;else if(s>1){const p=Array(s).fill(0);for(;l<t&&p.some(m=>m<e+a);){const m=n[l];p[m.lane]=m.end,l++}const g=Array(s).fill(e+a);for(;o>=0&&g.some(m=>m>=e);){const m=n[o];g[m.lane]=m.start,o--}o=Math.max(0,o-o%s),l=Math.min(t,l+(s-1-l%s))}return{startIndex:o,endIndex:l}}const Oe=typeof document<"u"?le.useLayoutEffect:le.useEffect;function Ve({useFlushSync:n=!0,...a}){const e=le.useReducer(()=>({}),{})[1],s={...a,onChange:(i,o)=>{var l;n&&o?Ce.flushSync(e):e(),(l=a.onChange)==null||l.call(a,i,o)}},[t]=le.useState(()=>new We(s));return t.setOptions(s),Oe(()=>t._didMount(),[]),Oe(()=>t._willUpdate()),t}function qe(n){return Ve({observeElementRect:De,observeElementOffset:Pe,scrollToFn:$e,...n})}const Ye=({data:n,columns:a,rowHeight:e=40,height:s=600,className:t="",headerClassName:i="",rowClassName:o,onRowClick:l,overscan:p=5})=>{const g=R.useRef(null),m=qe({count:n.length,getScrollElement:()=>g.current,estimateSize:()=>e,overscan:p}),E=m.getVirtualItems();return c.jsxs("div",{className:t,children:[c.jsx("div",{className:`grid border-b sticky top-0 bg-background z-10 ${i}`,style:{gridTemplateColumns:a.map(u=>u.width||"1fr").join(" ")},children:a.map((u,b)=>c.jsx("div",{className:`px-4 py-2 font-semibold text-sm ${u.align==="center"?"text-center":u.align==="right"?"text-right":"text-left"}`,children:u.header},b))}),c.jsx("div",{ref:g,className:"overflow-auto",style:{height:typeof s=="number"?`${s}px`:s,contain:"strict"},children:c.jsx("div",{style:{height:`${m.getTotalSize()}px`,width:"100%",position:"relative"},children:E.map(u=>{const b=n[u.index],_=typeof o=="function"?o(b,u.index):o||"";return c.jsx("div",{className:`grid border-b hover:bg-muted/50 cursor-pointer ${_}`,style:{position:"absolute",top:0,left:0,width:"100%",height:`${u.size}px`,transform:`translateY(${u.start}px)`,gridTemplateColumns:a.map(v=>v.width||"1fr").join(" ")},onClick:()=>l?.(b,u.index),children:a.map((v,w)=>{const z=b[v.accessorKey],O=v.cell?v.cell(z,b):z;return c.jsx("div",{className:`px-4 py-2 text-sm flex items-center ${v.align==="center"?"text-center justify-center":v.align==="right"?"text-right justify-end":"text-left justify-start"}`,children:O},w)})},u.key)})})}),c.jsxs("div",{className:"px-4 py-2 text-xs text-muted-foreground border-t",children:["Showing ",E.length," of ",n.length," rows (virtual scrolling enabled)"]})]})},fe=({schema:n,...a})=>{const{dataSource:e}=B.useSchemaContext()||{};return c.jsx(ye,{schema:n,dataSource:e,...a})};he.ComponentRegistry.register("object-grid",fe,{namespace:"plugin-grid",label:"Object Grid",category:"plugin",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"columns",type:"array",label:"Columns"},{name:"filters",type:"array",label:"Filters"}]}),he.ComponentRegistry.register("grid",fe,{namespace:"view",label:"Data Grid",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"columns",type:"array",label:"Columns"},{name:"filters",type:"array",label:"Filters"}]}),A.ObjectGrid=ye,A.ObjectGridRenderer=fe,A.VirtualGrid=Ye,Object.defineProperty(A,Symbol.toStringTag,{value:"Module"})}));
@@ -8,7 +8,13 @@ export interface ObjectGridProps {
8
8
  onEdit?: (record: any) => void;
9
9
  onDelete?: (record: any) => void;
10
10
  onBulkDelete?: (records: any[]) => void;
11
- onCellChange?: (rowIndex: number, columnKey: string, newValue: any) => void;
11
+ onCellChange?: (rowIndex: number, columnKey: string, newValue: any, row: any) => void;
12
+ onRowSave?: (rowIndex: number, changes: Record<string, any>, row: any) => void | Promise<void>;
13
+ onBatchSave?: (changes: Array<{
14
+ rowIndex: number;
15
+ changes: Record<string, any>;
16
+ row: any;
17
+ }>) => void | Promise<void>;
12
18
  onRowSelect?: (selectedRows: any[]) => void;
13
19
  }
14
20
  export declare const ObjectGrid: React.FC<ObjectGridProps>;
@@ -0,0 +1,35 @@
1
+ import { default as React } from 'react';
2
+ export interface VirtualGridColumn {
3
+ header: string;
4
+ accessorKey: string;
5
+ cell?: (value: any, row: any) => React.ReactNode;
6
+ width?: number | string;
7
+ align?: 'left' | 'center' | 'right';
8
+ }
9
+ export interface VirtualGridProps {
10
+ data: any[];
11
+ columns: VirtualGridColumn[];
12
+ rowHeight?: number;
13
+ height?: number | string;
14
+ className?: string;
15
+ headerClassName?: string;
16
+ rowClassName?: string | ((row: any, index: number) => string);
17
+ onRowClick?: (row: any, index: number) => void;
18
+ overscan?: number;
19
+ }
20
+ /**
21
+ * Virtual scrolling grid component
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <VirtualGrid
26
+ * data={items}
27
+ * columns={[
28
+ * { header: 'Name', accessorKey: 'name' },
29
+ * { header: 'Age', accessorKey: 'age' },
30
+ * ]}
31
+ * rowHeight={40}
32
+ * />
33
+ * ```
34
+ */
35
+ export declare const VirtualGrid: React.FC<VirtualGridProps>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ export {};
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ import { ObjectGrid } from './ObjectGrid';
3
+ import { VirtualGrid } from './VirtualGrid';
4
+ export { ObjectGrid, VirtualGrid };
5
+ export type { ObjectGridProps } from './ObjectGrid';
6
+ export type { VirtualGridProps, VirtualGridColumn } from './VirtualGrid';
7
+ export declare const ObjectGridRenderer: React.FC<{
8
+ schema: any;
9
+ [key: string]: any;
10
+ }>;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-grid",
3
- "version": "0.3.1",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Grid plugin for Object UI",
@@ -15,22 +15,25 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
+ "@tanstack/react-virtual": "^3.11.3",
18
19
  "lucide-react": "^0.563.0",
19
- "@object-ui/components": "0.3.1",
20
- "@object-ui/core": "0.3.1",
21
- "@object-ui/fields": "0.3.1",
22
- "@object-ui/react": "0.3.1",
23
- "@object-ui/types": "0.3.1"
20
+ "@object-ui/components": "2.0.0",
21
+ "@object-ui/core": "2.0.0",
22
+ "@object-ui/fields": "2.0.0",
23
+ "@object-ui/react": "2.0.0",
24
+ "@object-ui/types": "2.0.0"
24
25
  },
25
26
  "peerDependencies": {
26
27
  "react": "^18.0.0 || ^19.0.0",
27
28
  "react-dom": "^18.0.0 || ^19.0.0"
28
29
  },
29
30
  "devDependencies": {
30
- "@vitejs/plugin-react": "^4.2.1",
31
+ "@vitejs/plugin-react": "^5.1.3",
32
+ "msw": "^2.12.9",
31
33
  "typescript": "^5.9.3",
32
34
  "vite": "^7.3.1",
33
- "vite-plugin-dts": "^4.5.4"
35
+ "vite-plugin-dts": "^4.5.4",
36
+ "@object-ui/data-objectstack": "2.0.0"
34
37
  },
35
38
  "scripts": {
36
39
  "build": "vite build",
@@ -0,0 +1,374 @@
1
+ /**
2
+ * ListColumn Extensions Tests
3
+ *
4
+ * Tests for link, action, hidden, type, wrap, and resizable properties
5
+ * on ListColumn when rendered through ObjectGrid → data-table.
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
8
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
9
+ import '@testing-library/jest-dom';
10
+ import React from 'react';
11
+ import { ObjectGrid } from './ObjectGrid';
12
+ import { registerAllFields } from '@object-ui/fields';
13
+ import { ActionProvider } from '@object-ui/react';
14
+ import type { ListColumn } from '@object-ui/types';
15
+
16
+ registerAllFields();
17
+
18
+ // --- Mock Data ---
19
+ const mockData = [
20
+ { _id: '1', name: 'Alice', email: 'alice@test.com', amount: 1500, status: 'active' },
21
+ { _id: '2', name: 'Bob', email: 'bob@test.com', amount: 2300, status: 'inactive' },
22
+ { _id: '3', name: 'Charlie', email: 'charlie@test.com', amount: 800, status: 'active' },
23
+ ];
24
+
25
+ // --- Helper: Render ObjectGrid with static data and ListColumn[] ---
26
+ function renderGrid(columns: ListColumn[], opts?: { onNavigate?: any; navigation?: any }) {
27
+ const schema: any = {
28
+ type: 'object-grid' as const,
29
+ objectName: 'test_object',
30
+ columns,
31
+ data: { provider: 'value', items: mockData },
32
+ navigation: opts?.navigation,
33
+ onNavigate: opts?.onNavigate,
34
+ };
35
+
36
+ return render(
37
+ <ActionProvider>
38
+ <ObjectGrid schema={schema} />
39
+ </ActionProvider>
40
+ );
41
+ }
42
+
43
+ // =========================================================================
44
+ // 1. Hidden columns
45
+ // =========================================================================
46
+ describe('ListColumn: hidden', () => {
47
+ it('should not render hidden columns', async () => {
48
+ renderGrid([
49
+ { field: 'name', label: 'Name' },
50
+ { field: 'email', label: 'Email', hidden: true },
51
+ { field: 'amount', label: 'Amount' },
52
+ ]);
53
+
54
+ await waitFor(() => {
55
+ expect(screen.getByText('Name')).toBeInTheDocument();
56
+ });
57
+ expect(screen.getByText('Amount')).toBeInTheDocument();
58
+ // Email column should NOT be rendered
59
+ expect(screen.queryByText('Email')).not.toBeInTheDocument();
60
+ expect(screen.queryByText('alice@test.com')).not.toBeInTheDocument();
61
+ });
62
+
63
+ it('should render non-hidden columns normally', async () => {
64
+ renderGrid([
65
+ { field: 'name', label: 'Name', hidden: false },
66
+ { field: 'email', label: 'Email' },
67
+ ]);
68
+
69
+ await waitFor(() => {
70
+ expect(screen.getByText('Name')).toBeInTheDocument();
71
+ });
72
+ expect(screen.getByText('Email')).toBeInTheDocument();
73
+ });
74
+ });
75
+
76
+ // =========================================================================
77
+ // 2. Link columns
78
+ // =========================================================================
79
+ describe('ListColumn: link', () => {
80
+ it('should render link columns as clickable text', async () => {
81
+ renderGrid([
82
+ { field: 'name', label: 'Name', link: true },
83
+ { field: 'email', label: 'Email' },
84
+ ]);
85
+
86
+ await waitFor(() => {
87
+ expect(screen.getByText('Name')).toBeInTheDocument();
88
+ });
89
+
90
+ // The name cells should be rendered as buttons (clickable links)
91
+ const aliceLink = screen.getByRole('button', { name: 'Alice' });
92
+ expect(aliceLink).toBeInTheDocument();
93
+ expect(aliceLink).toHaveClass('text-primary');
94
+
95
+ const bobLink = screen.getByRole('button', { name: 'Bob' });
96
+ expect(bobLink).toBeInTheDocument();
97
+ });
98
+
99
+ it('should trigger navigation when link column is clicked', async () => {
100
+ const onNavigate = vi.fn();
101
+
102
+ renderGrid(
103
+ [
104
+ { field: 'name', label: 'Name', link: true },
105
+ { field: 'email', label: 'Email' },
106
+ ],
107
+ {
108
+ navigation: { mode: 'page' },
109
+ onNavigate,
110
+ }
111
+ );
112
+
113
+ await waitFor(() => {
114
+ expect(screen.getByRole('button', { name: 'Alice' })).toBeInTheDocument();
115
+ });
116
+
117
+ fireEvent.click(screen.getByRole('button', { name: 'Alice' }));
118
+
119
+ expect(onNavigate).toHaveBeenCalledTimes(1);
120
+ expect(onNavigate).toHaveBeenCalledWith('1', 'view');
121
+ });
122
+
123
+ it('should not render non-link columns as buttons', async () => {
124
+ renderGrid([
125
+ { field: 'name', label: 'Name', link: true },
126
+ { field: 'email', label: 'Email' },
127
+ ]);
128
+
129
+ await waitFor(() => {
130
+ expect(screen.getByText('Name')).toBeInTheDocument();
131
+ });
132
+
133
+ // Email values should NOT be buttons
134
+ expect(screen.queryByRole('button', { name: 'alice@test.com' })).not.toBeInTheDocument();
135
+ // But the text should still render
136
+ expect(screen.getByText('alice@test.com')).toBeInTheDocument();
137
+ });
138
+ });
139
+
140
+ // =========================================================================
141
+ // 3. Action columns
142
+ // =========================================================================
143
+ describe('ListColumn: action', () => {
144
+ it('should render action columns as clickable text', async () => {
145
+ renderGrid([
146
+ { field: 'name', label: 'Name' },
147
+ { field: 'status', label: 'Status', action: 'toggleStatus' },
148
+ ]);
149
+
150
+ await waitFor(() => {
151
+ expect(screen.getByText('Name')).toBeInTheDocument();
152
+ });
153
+
154
+ // Status cells should be buttons
155
+ const activeBtn = screen.getAllByRole('button', { name: 'active' });
156
+ expect(activeBtn.length).toBeGreaterThanOrEqual(1);
157
+ expect(activeBtn[0]).toHaveClass('text-primary');
158
+ });
159
+
160
+ it('should execute action when action column is clicked', async () => {
161
+ const actionHandler = vi.fn().mockResolvedValue({ success: true });
162
+
163
+ const schema: any = {
164
+ type: 'object-grid' as const,
165
+ objectName: 'test_object',
166
+ columns: [
167
+ { field: 'name', label: 'Name' },
168
+ { field: 'status', label: 'Status', action: 'toggleStatus' },
169
+ ],
170
+ data: { provider: 'value', items: mockData },
171
+ };
172
+
173
+ render(
174
+ <ActionProvider handlers={{ toggleStatus: actionHandler }}>
175
+ <ObjectGrid schema={schema} />
176
+ </ActionProvider>
177
+ );
178
+
179
+ await waitFor(() => {
180
+ expect(screen.getByText('Name')).toBeInTheDocument();
181
+ });
182
+
183
+ const statusBtns = screen.getAllByRole('button', { name: 'active' });
184
+ fireEvent.click(statusBtns[0]);
185
+
186
+ await waitFor(() => {
187
+ expect(actionHandler).toHaveBeenCalledTimes(1);
188
+ });
189
+ expect(actionHandler).toHaveBeenCalledWith(
190
+ expect.objectContaining({
191
+ type: 'toggleStatus',
192
+ params: expect.objectContaining({
193
+ field: 'status',
194
+ value: 'active',
195
+ record: expect.objectContaining({ _id: '1', name: 'Alice' }),
196
+ }),
197
+ }),
198
+ expect.any(Object) // ActionCtx
199
+ );
200
+ });
201
+ });
202
+
203
+ // =========================================================================
204
+ // 4. Type-based cell rendering
205
+ // =========================================================================
206
+ describe('ListColumn: type', () => {
207
+ it('should use getCellRenderer for typed columns', async () => {
208
+ renderGrid([
209
+ { field: 'name', label: 'Name' },
210
+ { field: 'email', label: 'Email', type: 'email' },
211
+ ]);
212
+
213
+ await waitFor(() => {
214
+ expect(screen.getByText('Name')).toBeInTheDocument();
215
+ });
216
+
217
+ // Email type should render as a mailto link
218
+ const emailLink = screen.getByText('alice@test.com');
219
+ expect(emailLink).toBeInTheDocument();
220
+ // The email cell renderer wraps in an anchor
221
+ expect(emailLink.closest('a')).toHaveAttribute('href', 'mailto:alice@test.com');
222
+ });
223
+
224
+ it('should render boolean type columns correctly', async () => {
225
+ const boolData = [
226
+ { _id: '1', name: 'Alice', active: true },
227
+ { _id: '2', name: 'Bob', active: false },
228
+ ];
229
+
230
+ const schema: any = {
231
+ type: 'object-grid' as const,
232
+ objectName: 'test_object',
233
+ columns: [
234
+ { field: 'name', label: 'Name' },
235
+ { field: 'active', label: 'Active', type: 'boolean' },
236
+ ],
237
+ data: { provider: 'value', items: boolData },
238
+ };
239
+
240
+ render(
241
+ <ActionProvider>
242
+ <ObjectGrid schema={schema} />
243
+ </ActionProvider>
244
+ );
245
+
246
+ await waitFor(() => {
247
+ expect(screen.getByText('Name')).toBeInTheDocument();
248
+ });
249
+
250
+ // Boolean renderer should show check/x icons or text representation
251
+ expect(screen.getByText('Active')).toBeInTheDocument();
252
+ });
253
+ });
254
+
255
+ // =========================================================================
256
+ // 5. Combined: link + type
257
+ // =========================================================================
258
+ describe('ListColumn: link + type', () => {
259
+ it('should render typed content inside a clickable link', async () => {
260
+ const onNavigate = vi.fn();
261
+
262
+ renderGrid(
263
+ [
264
+ { field: 'email', label: 'Email', link: true, type: 'email' },
265
+ { field: 'name', label: 'Name' },
266
+ ],
267
+ {
268
+ navigation: { mode: 'page' },
269
+ onNavigate,
270
+ }
271
+ );
272
+
273
+ await waitFor(() => {
274
+ expect(screen.getByText('Email')).toBeInTheDocument();
275
+ });
276
+
277
+ // Should be a button wrapping the email content
278
+ const emailBtn = screen.getByRole('button', { name: /alice@test.com/ });
279
+ expect(emailBtn).toBeInTheDocument();
280
+ expect(emailBtn).toHaveClass('text-primary');
281
+
282
+ fireEvent.click(emailBtn);
283
+ expect(onNavigate).toHaveBeenCalledWith('1', 'view');
284
+ });
285
+ });
286
+
287
+ // =========================================================================
288
+ // 6. Column properties passthrough
289
+ // =========================================================================
290
+ describe('ListColumn: property passthrough', () => {
291
+ it('should auto-generate header from field name if no label', async () => {
292
+ renderGrid([
293
+ { field: 'first_name' },
294
+ ]);
295
+
296
+ await waitFor(() => {
297
+ // Should convert snake_case to title case
298
+ expect(screen.getByText('First name')).toBeInTheDocument();
299
+ });
300
+ });
301
+
302
+ it('should use label when provided', async () => {
303
+ renderGrid([
304
+ { field: 'name', label: 'Full Name' },
305
+ ]);
306
+
307
+ await waitFor(() => {
308
+ expect(screen.getByText('Full Name')).toBeInTheDocument();
309
+ });
310
+ });
311
+
312
+ it('should handle all columns hidden gracefully', async () => {
313
+ const { container } = renderGrid([
314
+ { field: 'name', hidden: true },
315
+ { field: 'email', hidden: true },
316
+ ]);
317
+
318
+ // Should render without error, just no columns
319
+ await waitFor(() => {
320
+ expect(container).toBeInTheDocument();
321
+ });
322
+ });
323
+ });
324
+
325
+ // =========================================================================
326
+ // 7. Type definitions alignment
327
+ // =========================================================================
328
+ describe('ListColumn type definitions', () => {
329
+ it('should accept link property on ListColumn', () => {
330
+ const col: ListColumn = {
331
+ field: 'name',
332
+ link: true,
333
+ };
334
+ expect(col.link).toBe(true);
335
+ });
336
+
337
+ it('should accept action property on ListColumn', () => {
338
+ const col: ListColumn = {
339
+ field: 'status',
340
+ action: 'toggleStatus',
341
+ };
342
+ expect(col.action).toBe('toggleStatus');
343
+ });
344
+
345
+ it('should accept both link and action together', () => {
346
+ const col: ListColumn = {
347
+ field: 'name',
348
+ link: true,
349
+ action: 'viewDetail',
350
+ };
351
+ expect(col.link).toBe(true);
352
+ expect(col.action).toBe('viewDetail');
353
+ });
354
+
355
+ it('should accept all ListColumn properties', () => {
356
+ const col: ListColumn = {
357
+ field: 'amount',
358
+ label: 'Total Amount',
359
+ width: 150,
360
+ align: 'right',
361
+ hidden: false,
362
+ sortable: true,
363
+ resizable: true,
364
+ wrap: false,
365
+ type: 'currency',
366
+ link: false,
367
+ action: 'editAmount',
368
+ };
369
+ expect(col.field).toBe('amount');
370
+ expect(col.type).toBe('currency');
371
+ expect(col.link).toBe(false);
372
+ expect(col.action).toBe('editAmount');
373
+ });
374
+ });