@object-ui/plugin-grid 0.3.1 → 0.5.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,j){typeof exports=="object"&&typeof module<"u"?j(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"],j):(A=typeof globalThis<"u"?globalThis:A||self,j(A.ObjectUIPluginGrid={},A.React,A.core,A.react,A.fields,A.components,A.lucideReact,A.ReactDOM))})(this,(function(A,j,re,X,pe,P,Z,be){"use strict";function ve(t){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const e in t)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(a,e,s.get?s:{enumerable:!0,get:()=>t[e]})}}return a.default=t,Object.freeze(a)}const U=ve(j);var G={exports:{}},W={};var ie;function ye(){if(ie)return W;ie=1;var t=Symbol.for("react.transitional.element"),a=Symbol.for("react.fragment");function e(s,n,i){var o=null;if(i!==void 0&&(o=""+i),n.key!==void 0&&(o=""+n.key),"key"in n){i={};for(var l in n)l!=="key"&&(i[l]=n[l])}else i=n;return n=i.ref,{$$typeof:t,type:s,key:o,ref:n!==void 0?n:null,props:i}}return W.Fragment=a,W.jsx=e,W.jsxs=e,W}var L={};var oe;function Ee(){return oe||(oe=1,process.env.NODE_ENV!=="production"&&(function(){function t(r){if(r==null)return null;if(typeof r=="function")return r.$$typeof===ee?null:r.displayName||r.name||null;if(typeof r=="string")return r;switch(r){case _:return"Fragment";case p:return"Profiler";case z:return"StrictMode";case B:return"Suspense";case N:return"SuspenseList";case q: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 g:return"Portal";case k:return r.displayName||"Context";case C:return(r._context.displayName||"Context")+".Consumer";case D:var u=r.render;return r=r.displayName,r||(r=u.displayName||u.name||"",r=r!==""?"ForwardRef("+r+")":"ForwardRef"),r;case H:return u=r.displayName||null,u!==null?u:t(r.type)||"Memo";case V:u=r._payload,r=r._init;try{return t(r(u))}catch{}}return null}function a(r){return""+r}function e(r){try{a(r);var u=!1}catch{u=!0}if(u){u=console;var x=u.error,w=typeof Symbol=="function"&&Symbol.toStringTag&&r[Symbol.toStringTag]||r.constructor.name||"Object";return x.call(u,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",w),a(r)}}function s(r){if(r===_)return"<>";if(typeof r=="object"&&r!==null&&r.$$typeof===V)return"<...>";try{var u=t(r);return u?"<"+u+">":"<...>"}catch{return"<...>"}}function n(){var r=Y.A;return r===null?null:r.getOwner()}function i(){return Error("react-stack-top-frame")}function o(r){if(J.call(r,"key")){var u=Object.getOwnPropertyDescriptor(r,"key").get;if(u&&u.isReactWarning)return!1}return r.key!==void 0}function l(r,u){function x(){M||(M=!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)",u))}x.isReactWarning=!0,Object.defineProperty(r,"key",{get:x,configurable:!0})}function f(){var r=t(this.type);return R[r]||(R[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 v(r,u,x,w,K,ne){var O=x.ref;return r={$$typeof:T,type:r,key:u,props:x,_owner:w},(O!==void 0?O:null)!==null?Object.defineProperty(r,"ref",{enumerable:!1,get:f}):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:K}),Object.defineProperty(r,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:ne}),Object.freeze&&(Object.freeze(r.props),Object.freeze(r)),r}function d(r,u,x,w,K,ne){var O=u.children;if(O!==void 0)if(w)if(te(O)){for(w=0;w<O.length;w++)S(O[w]);Object.freeze&&Object.freeze(O)}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(O);if(J.call(u,"key")){O=t(r);var $=Object.keys(u).filter(function(De){return De!=="key"});w=0<$.length?"{key: someKey, "+$.join(": ..., ")+": ...}":"{key: someKey}",I[O+w]||($=0<$.length?"{"+$.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} />`,w,O,$,O),I[O+w]=!0)}if(O=null,x!==void 0&&(e(x),O=""+x),o(u)&&(e(u.key),O=""+u.key),"key"in u){x={};for(var se in u)se!=="key"&&(x[se]=u[se])}else x=u;return O&&l(x,typeof r=="function"?r.displayName||r.name||"Unknown":r),v(r,O,x,n(),K,ne)}function S(r){c(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===V&&(r._payload.status==="fulfilled"?c(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function c(r){return typeof r=="object"&&r!==null&&r.$$typeof===T}var m=j,T=Symbol.for("react.transitional.element"),g=Symbol.for("react.portal"),_=Symbol.for("react.fragment"),z=Symbol.for("react.strict_mode"),p=Symbol.for("react.profiler"),C=Symbol.for("react.consumer"),k=Symbol.for("react.context"),D=Symbol.for("react.forward_ref"),B=Symbol.for("react.suspense"),N=Symbol.for("react.suspense_list"),H=Symbol.for("react.memo"),V=Symbol.for("react.lazy"),q=Symbol.for("react.activity"),ee=Symbol.for("react.client.reference"),Y=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,J=Object.prototype.hasOwnProperty,te=Array.isArray,E=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(r){return r()}};var M,R={},y=m.react_stack_bottom_frame.bind(m,i)(),h=E(s(i)),I={};L.Fragment=_,L.jsx=function(r,u,x){var w=1e4>Y.recentlyCreatedOwnerStacks++;return d(r,u,x,!1,w?Error("react-stack-top-frame"):y,w?E(s(r)):h)},L.jsxs=function(r,u,x){var w=1e4>Y.recentlyCreatedOwnerStacks++;return d(r,u,x,!0,w?Error("react-stack-top-frame"):y,w?E(s(r)):h)}})()),L}var le;function xe(){return le||(le=1,process.env.NODE_ENV==="production"?G.exports=ye():G.exports=Ee()),G.exports}var b=xe();function Se(t){return t.data?Array.isArray(t.data)?{provider:"value",items:t.data}:t.data:t.staticData?{provider:"value",items:t.staticData}:t.objectName?{provider:"object",object:t.objectName}:null}function ae(t){if(!(!t||t.length===0))return typeof t[0]=="object"&&t[0]!==null,t}const ce=({schema:t,dataSource:a,onEdit:e,onDelete:s,onRowSelect:n,onRowClick:i,...o})=>{const[l,f]=j.useState([]),[v,d]=j.useState(!0),[S,c]=j.useState(null),[m,T]=j.useState(null),g=o.data,_=X.useDataScope(t.bind),z=Se(t),p=j.useMemo(()=>g&&Array.isArray(g)?{provider:"value",items:g}:_&&Array.isArray(_)?{provider:"value",items:_}:z,[JSON.stringify(z),_,g]),C=p?.provider==="value";j.useEffect(()=>{C&&p?.provider==="value"&&(f(E=>{const M=p.items;return JSON.stringify(E)!==JSON.stringify(M)?M:E}),d(!1))},[C,p]),j.useEffect(()=>{const E=async()=>{try{if(!a)throw new Error("DataSource required");const R=p?.provider==="object"&&"object"in p?p.object:t.objectName;if(!R)throw new Error("Object name required for object provider");const y=await a.getObjectSchema(R);T(y)}catch(R){c(R)}},M=ae(t.columns)||t.fields;C&&M?T({name:t.objectName,fields:{}}):t.objectName&&!C&&a&&E()},[t.objectName,t.columns,t.fields,a,C,p]);const k=j.useCallback(()=>{const E=ae(t.columns);if(E){if(E.length>0&&typeof E[0]=="object"&&E[0]!==null){const y=E[0];if("accessorKey"in y)return E;if("field"in y)return E.filter(h=>h?.field&&typeof h.field=="string").map(h=>({header:h.label||h.field.charAt(0).toUpperCase()+h.field.slice(1).replace(/_/g," "),accessorKey:h.field,...h.width&&{width:h.width},...h.align&&{align:h.align},sortable:h.sortable!==!1}))}return E.filter(y=>typeof y=="string"&&y.trim().length>0).map(y=>({header:m?.fields?.[y]?.label||y.charAt(0).toUpperCase()+y.slice(1).replace(/_/g," "),accessorKey:y}))}if(C){const y=p?.provider==="value"?p.items:[];if(y.length>0)return(t.fields||Object.keys(y[0])).map(I=>({header:I.charAt(0).toUpperCase()+I.slice(1).replace(/_/g," "),accessorKey:I}))}if(!m)return[];const M=[];return(t.fields||Object.keys(m.fields||{})).forEach(y=>{const h=m.fields?.[y];if(!h||h.permissions&&h.permissions.read===!1)return;const I=pe.getCellRenderer(h.type);M.push({header:h.label||y,accessorKey:y,cell:r=>b.jsx(I,{value:r,field:h}),sortable:h.sortable!==!1})}),M},[m,t.fields,t.columns,p,C]),D=j.useCallback(async()=>{if(!(C||!a)){d(!0);try{const E=p?.provider==="object"&&"object"in p?p.object:t.objectName;if(!E)throw new Error("Object name required for data fetching");const R={$select:(()=>{if(t.fields)return t.fields;if(t.columns&&Array.isArray(t.columns))return t.columns.map(h=>typeof h=="string"?h:h.field)})(),$top:t.pagination?.pageSize||t.pageSize||50};t.filter&&Array.isArray(t.filter)?R.$filter=t.filter:"defaultFilters"in t&&t.defaultFilters&&(R.$filter=t.defaultFilters),t.sort?typeof t.sort=="string"?R.$orderby=t.sort:Array.isArray(t.sort)&&(R.$orderby=t.sort.map(h=>`${h.field} ${h.order}`).join(", ")):"defaultSort"in t&&t.defaultSort&&(R.$orderby=`${t.defaultSort.field} ${t.defaultSort.order}`);const y=await a.find(E,R);f(y.data||[])}catch(E){c(E)}finally{d(!1)}}},[t,a,C,p]);if(j.useEffect(()=>{(m||C)&&D()},[m,C,D]),S)return b.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[b.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading grid"}),b.jsx("p",{className:"text-red-600 text-sm mt-1",children:S.message})]});if(v&&l.length===0)return b.jsxs("div",{className:"p-8 text-center",children:[b.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),b.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading grid..."})]});const B=k(),N="operations"in t?t.operations:void 0,H=N&&(N.update||N.delete),V=H?[...B,{header:"Actions",accessorKey:"_actions",cell:(E,M)=>b.jsxs(P.DropdownMenu,{children:[b.jsx(P.DropdownMenuTrigger,{asChild:!0,children:b.jsxs(P.Button,{variant:"ghost",size:"icon",className:"h-8 w-8",children:[b.jsx(Z.MoreVertical,{className:"h-4 w-4"}),b.jsx("span",{className:"sr-only",children:"Open menu"})]})}),b.jsxs(P.DropdownMenuContent,{align:"end",children:[N?.update&&e&&b.jsxs(P.DropdownMenuItem,{onClick:()=>e(M),children:[b.jsx(Z.Edit,{className:"mr-2 h-4 w-4"}),"Edit"]}),N?.delete&&s&&b.jsxs(P.DropdownMenuItem,{onClick:()=>s(M),children:[b.jsx(Z.Trash2,{className:"mr-2 h-4 w-4"}),"Delete"]})]})]}),sortable:!1}]:B;let q=!1;t.selection?.type?q=t.selection.type==="none"?!1:t.selection.type:t.selectable!==void 0&&(q=t.selectable);const ee=t.pagination!==void 0?!0:t.showPagination!==void 0?t.showPagination:!0,Y=t.pagination?.pageSize||t.pageSize||10,J=t.searchableFields!==void 0?t.searchableFields.length>0:t.showSearch!==void 0?t.showSearch:!0,te={type:"data-table",caption:t.label||t.title,columns:V,data:l,pagination:ee,pageSize:Y,searchable:J,selectable:q,sortable:!0,exportable:N?.export,rowActions:H,resizableColumns:t.resizable??t.resizableColumns??!0,reorderableColumns:t.reorderableColumns??!1,className:t.className,onSelectionChange:n,onRowClick:i};return b.jsx(X.SchemaRenderer,{schema:te})};function F(t,a,e){let s=e.initialDeps??[],n,i=!0;function o(){var l,f,v;let d;e.key&&((l=e.debug)!=null&&l.call(e))&&(d=Date.now());const S=t();if(!(S.length!==s.length||S.some((T,g)=>s[g]!==T)))return n;s=S;let m;if(e.key&&((f=e.debug)!=null&&f.call(e))&&(m=Date.now()),n=a(...S),e.key&&((v=e.debug)!=null&&v.call(e))){const T=Math.round((Date.now()-d)*100)/100,g=Math.round((Date.now()-m)*100)/100,_=g/16,z=(p,C)=>{for(p=String(p);p.length<C;)p=" "+p;return p};console.info(`%c⏱ ${z(g,5)} /${z(T,5)} ms`,`
7
+ font-size: .6rem;
8
+ font-weight: bold;
9
+ color: hsl(${Math.max(0,Math.min(120-120*_,120))}deg 100% 31%);`,e?.key)}return e?.onChange&&!(i&&e.skipInitialOnChange)&&e.onChange(n),i=!1,n}return o.updateDeps=l=>{s=l},o}function ue(t,a){if(t===void 0)throw new Error("Unexpected undefined");return t}const we=(t,a)=>Math.abs(t-a)<1.01,Oe=(t,a,e)=>{let s;return function(...n){t.clearTimeout(s),s=t.setTimeout(()=>a.apply(this,n),e)}},de=t=>{const{offsetWidth:a,offsetHeight:e}=t;return{width:a,height:e}},je=t=>t,_e=t=>{const a=Math.max(t.startIndex-t.overscan,0),e=Math.min(t.endIndex+t.overscan,t.count-1),s=[];for(let n=a;n<=e;n++)s.push(n);return s},Ce=(t,a)=>{const e=t.scrollElement;if(!e)return;const s=t.targetWindow;if(!s)return;const n=o=>{const{width:l,height:f}=o;a({width:Math.round(l),height:Math.round(f)})};if(n(de(e)),!s.ResizeObserver)return()=>{};const i=new s.ResizeObserver(o=>{const l=()=>{const f=o[0];if(f?.borderBoxSize){const v=f.borderBoxSize[0];if(v){n({width:v.inlineSize,height:v.blockSize});return}}n(de(e))};t.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(l):l()});return i.observe(e,{box:"border-box"}),()=>{i.unobserve(e)}},fe={passive:!0},he=typeof window>"u"?!0:"onscrollend"in window,Te=(t,a)=>{const e=t.scrollElement;if(!e)return;const s=t.targetWindow;if(!s)return;let n=0;const i=t.options.useScrollendEvent&&he?()=>{}:Oe(s,()=>{a(n,!1)},t.options.isScrollingResetDelay),o=d=>()=>{const{horizontal:S,isRtl:c}=t.options;n=S?e.scrollLeft*(c&&-1||1):e.scrollTop,i(),a(n,d)},l=o(!0),f=o(!1);e.addEventListener("scroll",l,fe);const v=t.options.useScrollendEvent&&he;return v&&e.addEventListener("scrollend",f,fe),()=>{e.removeEventListener("scroll",l),v&&e.removeEventListener("scrollend",f)}},Ae=(t,a,e)=>{if(a?.borderBoxSize){const s=a.borderBoxSize[0];if(s)return Math.round(s[e.options.horizontal?"inlineSize":"blockSize"])}return t[e.options.horizontal?"offsetWidth":"offsetHeight"]},Re=(t,{adjustments:a=0,behavior:e},s)=>{var n,i;const o=t+a;(i=(n=s.scrollElement)==null?void 0:n.scrollTo)==null||i.call(n,{[s.options.horizontal?"left":"top"]:o,behavior:e})};class Me{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(n=>{n.forEach(i=>{const o=()=>{this._measureElement(i.target,i)};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(o):o()})}));return{disconnect:()=>{var n;(n=s())==null||n.disconnect(),e=null},observe:n=>{var i;return(i=s())==null?void 0:i.observe(n,{box:"border-box"})},unobserve:n=>{var i;return(i=s())==null?void 0:i.unobserve(n)}}})(),this.range=null,this.setOptions=e=>{Object.entries(e).forEach(([s,n])=>{typeof n>"u"&&delete e[s]}),this.options={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:je,rangeExtractor:_e,onChange:()=>{},measureElement:Ae,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,n;(n=(s=this.options).onChange)==null||n.call(s,this,e)},this.maybeNotify=F(()=>(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(n=>{this.observer.observe(n)}),this.unsubs.push(this.options.observeElementRect(this,n=>{this.scrollRect=n,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(n,i)=>{this.scrollAdjustments=0,this.scrollDirection=i?this.getScrollOffset()<n?"forward":"backward":null,this.scrollOffset=n,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 n=new Map,i=new Map;for(let o=s-1;o>=0;o--){const l=e[o];if(n.has(l.lane))continue;const f=i.get(l.lane);if(f==null||l.end>f.end?i.set(l.lane,l):l.end<f.end&&n.set(l.lane,!0),n.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=F(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes],(e,s,n,i,o,l)=>(this.prevLanes!==void 0&&this.prevLanes!==l&&(this.lanesChangedFlag=!0),this.prevLanes=l,this.pendingMeasuredCacheIndexes=[],{count:e,paddingStart:s,scrollMargin:n,getItemKey:i,enabled:o,lanes:l}),{key:!1}),this.getMeasurements=F(()=>[this.getMeasurementOptions(),this.itemSizeCache],({count:e,paddingStart:s,scrollMargin:n,getItemKey:i,enabled:o,lanes:l},f)=>{if(!o)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>e)for(const c of this.laneAssignments.keys())c>=e&&this.laneAssignments.delete(c);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(c=>{this.itemSizeCache.set(c.key,c.size)}));const v=this.lanesSettling?0:this.pendingMeasuredCacheIndexes.length>0?Math.min(...this.pendingMeasuredCacheIndexes):0;this.pendingMeasuredCacheIndexes=[],this.lanesSettling&&this.measurementsCache.length===e&&(this.lanesSettling=!1);const d=this.measurementsCache.slice(0,v),S=new Array(l).fill(void 0);for(let c=0;c<v;c++){const m=d[c];m&&(S[m.lane]=c)}for(let c=v;c<e;c++){const m=i(c),T=this.laneAssignments.get(c);let g,_;if(T!==void 0&&this.options.lanes>1){g=T;const k=S[g],D=k!==void 0?d[k]:void 0;_=D?D.end+this.options.gap:s+n}else{const k=this.options.lanes===1?d[c-1]:this.getFurthestMeasurement(d,c);_=k?k.end+this.options.gap:s+n,g=k?k.lane:c%this.options.lanes,this.options.lanes>1&&this.laneAssignments.set(c,g)}const z=f.get(m),p=typeof z=="number"?z:this.options.estimateSize(c),C=_+p;d[c]={index:c,start:_,size:p,end:C,key:m,lane:g},S[g]=c}return this.measurementsCache=d,d},{key:process.env.NODE_ENV!=="production"&&"getMeasurements",debug:()=>this.options.debug}),this.calculateRange=F(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(e,s,n,i)=>this.range=e.length>0&&s>0?ze({measurements:e,outerSize:s,scrollOffset:n,lanes:i}):null,{key:process.env.NODE_ENV!=="production"&&"calculateRange",debug:()=>this.options.debug}),this.getVirtualIndexes=F(()=>{let e=null,s=null;const n=this.calculateRange();return n&&(e=n.startIndex,s=n.endIndex),this.maybeNotify.updateDeps([this.isScrolling,e,s]),[this.options.rangeExtractor,this.options.overscan,this.options.count,e,s]},(e,s,n,i,o)=>i===null||o===null?[]:e({startIndex:i,endIndex:o,overscan:s,count:n}),{key:process.env.NODE_ENV!=="production"&&"getVirtualIndexes",debug:()=>this.options.debug}),this.indexFromElement=e=>{const s=this.options.indexAttribute,n=e.getAttribute(s);return n?parseInt(n,10):(console.warn(`Missing attribute name '${s}={index}' on measured element.`),-1)},this._measureElement=(e,s)=>{const n=this.indexFromElement(e),i=this.measurementsCache[n];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(n,this.options.measureElement(e,s,this))},this.resizeItem=(e,s)=>{const n=this.measurementsCache[e];if(!n)return;const i=this.itemSizeCache.get(n.key)??n.size,o=s-i;o!==0&&((this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(n,o,this):n.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(n.index),this.itemSizeCache=new Map(this.itemSizeCache.set(n.key,s)),this.notify(!1))},this.measureElement=e=>{if(!e){this.elementsCache.forEach((s,n)=>{s.isConnected||(this.observer.unobserve(s),this.elementsCache.delete(n))});return}this._measureElement(e,void 0)},this.getVirtualItems=F(()=>[this.getVirtualIndexes(),this.getMeasurements()],(e,s)=>{const n=[];for(let i=0,o=e.length;i<o;i++){const l=e[i],f=s[l];n.push(f)}return n},{key:process.env.NODE_ENV!=="production"&&"getVirtualItems",debug:()=>this.options.debug}),this.getVirtualItemForOffset=e=>{const s=this.getMeasurements();if(s.length!==0)return ue(s[me(0,s.length-1,n=>ue(s[n]).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,n=0)=>{if(!this.scrollElement)return 0;const i=this.getSize(),o=this.getScrollOffset();s==="auto"&&(s=e>=o+i?"end":"start"),s==="center"?e+=(n-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 n=this.measurementsCache[e];if(!n)return;const i=this.getSize(),o=this.getScrollOffset();if(s==="auto")if(n.end>=o+i-this.options.scrollPaddingEnd)s="end";else if(n.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"?n.end+this.options.scrollPaddingEnd:n.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(l,s,n.size),s]},this.isDynamicMode=()=>this.elementsCache.size>0,this.scrollToOffset=(e,{align:s="start",behavior:n}={})=>{n==="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:n})},this.scrollToIndex=(e,{align:s="auto",behavior:n}={})=>{n==="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=v=>{if(!this.targetWindow)return;const d=this.getOffsetForIndex(e,v);if(!d){console.warn("Failed to get offset for index:",e);return}const[S,c]=d;this._scrollToOffset(S,{adjustments:void 0,behavior:n}),this.targetWindow.requestAnimationFrame(()=>{const m=()=>{if(this.currentScrollToIndex!==e)return;const T=this.getScrollOffset(),g=this.getOffsetForIndex(e,c);if(!g){console.warn("Failed to get offset for index:",e);return}we(g[0],T)||f(c)};this.isDynamicMode()?this.targetWindow.requestAnimationFrame(m):m()})},f=v=>{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(v))):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 n;if(s.length===0)n=this.options.paddingStart;else if(this.options.lanes===1)n=((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--}n=Math.max(...i.filter(l=>l!==null))}return Math.max(n-this.options.scrollMargin+this.options.paddingEnd,0)},this._scrollToOffset=(e,{adjustments:s,behavior:n})=>{this.options.scrollToFn(e,{behavior:n,adjustments:s},this)},this.measure=()=>{this.itemSizeCache=new Map,this.laneAssignments=new Map,this.notify(!1)},this.setOptions(a)}}const me=(t,a,e,s)=>{for(;t<=a;){const n=(t+a)/2|0,i=e(n);if(i<s)t=n+1;else if(i>s)a=n-1;else return n}return t>0?t-1:0};function ze({measurements:t,outerSize:a,scrollOffset:e,lanes:s}){const n=t.length-1,i=f=>t[f].start;if(t.length<=s)return{startIndex:0,endIndex:n};let o=me(0,n,i,e),l=o;if(s===1)for(;l<n&&t[l].end<e+a;)l++;else if(s>1){const f=Array(s).fill(0);for(;l<n&&f.some(d=>d<e+a);){const d=t[l];f[d.lane]=d.end,l++}const v=Array(s).fill(e+a);for(;o>=0&&v.some(d=>d>=e);){const d=t[o];v[d.lane]=d.start,o--}o=Math.max(0,o-o%s),l=Math.min(n,l+(s-1-l%s))}return{startIndex:o,endIndex:l}}const ge=typeof document<"u"?U.useLayoutEffect:U.useEffect;function ke({useFlushSync:t=!0,...a}){const e=U.useReducer(()=>({}),{})[1],s={...a,onChange:(i,o)=>{var l;t&&o?be.flushSync(e):e(),(l=a.onChange)==null||l.call(a,i,o)}},[n]=U.useState(()=>new Me(s));return n.setOptions(s),ge(()=>n._didMount(),[]),ge(()=>n._willUpdate()),n}function Ne(t){return ke({observeElementRect:Ce,observeElementOffset:Te,scrollToFn:Re,...t})}const Ie=({data:t,columns:a,rowHeight:e=40,height:s=600,className:n="",headerClassName:i="",rowClassName:o,onRowClick:l,overscan:f=5})=>{const v=j.useRef(null),d=Ne({count:t.length,getScrollElement:()=>v.current,estimateSize:()=>e,overscan:f}),S=d.getVirtualItems();return b.jsxs("div",{className:n,children:[b.jsx("div",{className:`grid border-b sticky top-0 bg-background z-10 ${i}`,style:{gridTemplateColumns:a.map(c=>c.width||"1fr").join(" ")},children:a.map((c,m)=>b.jsx("div",{className:`px-4 py-2 font-semibold text-sm ${c.align==="center"?"text-center":c.align==="right"?"text-right":"text-left"}`,children:c.header},m))}),b.jsx("div",{ref:v,className:"overflow-auto",style:{height:typeof s=="number"?`${s}px`:s,contain:"strict"},children:b.jsx("div",{style:{height:`${d.getTotalSize()}px`,width:"100%",position:"relative"},children:S.map(c=>{const m=t[c.index],T=typeof o=="function"?o(m,c.index):o||"";return b.jsx("div",{className:`grid border-b hover:bg-muted/50 cursor-pointer ${T}`,style:{position:"absolute",top:0,left:0,width:"100%",height:`${c.size}px`,transform:`translateY(${c.start}px)`,gridTemplateColumns:a.map(g=>g.width||"1fr").join(" ")},onClick:()=>l?.(m,c.index),children:a.map((g,_)=>{const z=m[g.accessorKey],p=g.cell?g.cell(z,m):z;return b.jsx("div",{className:`px-4 py-2 text-sm flex items-center ${g.align==="center"?"text-center justify-center":g.align==="right"?"text-right justify-end":"text-left justify-start"}`,children:p},_)})},c.key)})})}),b.jsxs("div",{className:"px-4 py-2 text-xs text-muted-foreground border-t",children:["Showing ",S.length," of ",t.length," rows (virtual scrolling enabled)"]})]})},Q=({schema:t,...a})=>{const{dataSource:e}=X.useSchemaContext()||{};return b.jsx(ce,{schema:t,dataSource:e,...a})};re.ComponentRegistry.register("object-grid",Q,{namespace:"plugin-grid",label:"Object Grid",category:"plugin"}),re.ComponentRegistry.register("grid",Q,{namespace:"view",label:"Data Grid",category:"view"}),A.ObjectGrid=ce,A.ObjectGridRenderer=Q,A.VirtualGrid=Ie,Object.defineProperty(A,Symbol.toStringTag,{value:"Module"})}));
@@ -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": "0.5.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": "0.5.0",
21
+ "@object-ui/core": "0.5.0",
22
+ "@object-ui/fields": "0.5.0",
23
+ "@object-ui/react": "0.5.0",
24
+ "@object-ui/types": "0.5.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.7",
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": "0.5.0"
34
37
  },
35
38
  "scripts": {
36
39
  "build": "vite build",
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect, vi, beforeAll, afterAll, afterEach } from 'vitest';
2
+ import { render, screen, waitFor, within } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import { ObjectGrid } from './ObjectGrid';
5
+ import { ObjectStackAdapter } from '@object-ui/data-objectstack';
6
+ import { setupServer } from 'msw/node';
7
+ import { http, HttpResponse } from 'msw';
8
+ import { registerAllFields } from '@object-ui/fields';
9
+ import React from 'react';
10
+ import { ContactObject } from '../../../examples/crm/src/objects/contact.object';
11
+
12
+ registerAllFields();
13
+
14
+ const BASE_URL = process.env.OBJECTSTACK_API_URL || 'http://localhost';
15
+
16
+ // --- Mock Data ---
17
+
18
+ const mockSchema = ContactObject;
19
+
20
+ const mockData = {
21
+ value: [
22
+ { _id: '1', name: 'John Doe', email: 'john@example.com', company: 'Acme Inc' },
23
+ { _id: '2', name: 'Jane Smith', email: 'jane@test.com', company: 'Globex' },
24
+ { _id: '3', name: 'Bob Wilson', email: 'bob@test.com', company: 'Acme Inc' }
25
+ ],
26
+ count: 3,
27
+ '@odata.count': 3
28
+ };
29
+
30
+ // --- MSW Setup ---
31
+
32
+ const handlers = [
33
+ // OPTIONS handler for CORS preflight
34
+ http.options(`${BASE_URL}/*`, () => {
35
+ return new HttpResponse(null, {
36
+ status: 200,
37
+ headers: {
38
+ 'Access-Control-Allow-Origin': '*',
39
+ 'Access-Control-Allow-Methods': 'GET,HEAD,POST,PUT,DELETE,CONNECT,OPTIONS,TRACE,PATCH',
40
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
41
+ },
42
+ });
43
+ }),
44
+
45
+ // Health check / Connection check
46
+ http.get(`${BASE_URL}/api/v1`, () => {
47
+ return HttpResponse.json({ status: 'ok', version: '1.0.0' });
48
+ }),
49
+
50
+ // Schema: /api/v1/meta/object/:name
51
+ http.get(`${BASE_URL}/api/v1/meta/object/contact`, () => {
52
+ return HttpResponse.json(mockSchema);
53
+ }),
54
+
55
+ // Data Query: /api/v1/data/contact
56
+ http.get(`${BASE_URL}/api/v1/data/contact`, () => {
57
+ return HttpResponse.json(mockData);
58
+ })
59
+ ];
60
+
61
+ const server = setupServer(...handlers);
62
+
63
+ // --- Test Suite ---
64
+
65
+ describe('ObjectGrid with ObjectStack/MSW', () => {
66
+ // Only start MSW if we are NOT using a real server
67
+ if (!process.env.OBJECTSTACK_API_URL) {
68
+ beforeAll(() => server.listen());
69
+ afterEach(() => server.resetHandlers());
70
+ afterAll(() => server.close());
71
+ }
72
+
73
+ const dataSource = new ObjectStackAdapter({
74
+ baseUrl: BASE_URL,
75
+ });
76
+
77
+ it('loads schema and data rows', async () => {
78
+ render(
79
+ <ObjectGrid
80
+ schema={{
81
+ type: 'object-grid',
82
+ objectName: 'contact',
83
+ columns: ['name', 'email', 'company'] // Explicit columns or auto-derived
84
+ }}
85
+ dataSource={dataSource}
86
+ />
87
+ );
88
+
89
+ // Verify Column Headers (from schema or props)
90
+ await waitFor(() => {
91
+ // Changed from 'Full Name' to 'Name' to match CRM example schema
92
+ expect(screen.getByText('Name')).toBeInTheDocument();
93
+ });
94
+ expect(screen.getByText('Email')).toBeInTheDocument();
95
+ expect(screen.getByText('Company')).toBeInTheDocument();
96
+
97
+ // Verify Data Rows
98
+ await waitFor(() => {
99
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
100
+ });
101
+ expect(screen.getByText('jane@test.com')).toBeInTheDocument();
102
+ expect(screen.getByText('Globex')).toBeInTheDocument();
103
+
104
+ // Check Row Count (if grid displays it)
105
+ // expect(screen.getByText(/3 records/i)).toBeInTheDocument();
106
+ });
107
+ });
@@ -23,7 +23,7 @@
23
23
 
24
24
  import React, { useEffect, useState, useCallback } from 'react';
25
25
  import type { ObjectGridSchema, DataSource, ListColumn, ViewData } from '@object-ui/types';
26
- import { SchemaRenderer } from '@object-ui/react';
26
+ import { SchemaRenderer, useDataScope } from '@object-ui/react';
27
27
  import { getCellRenderer } from '@object-ui/fields';
28
28
  import { Button } from '@object-ui/components';
29
29
  import {
@@ -53,6 +53,15 @@ export interface ObjectGridProps {
53
53
  function getDataConfig(schema: ObjectGridSchema): ViewData | null {
54
54
  // New format: explicit data configuration
55
55
  if (schema.data) {
56
+ // Check if data is an array (shorthand format) or already a ViewData object
57
+ if (Array.isArray(schema.data)) {
58
+ // Convert array shorthand to proper ViewData format
59
+ return {
60
+ provider: 'value',
61
+ items: schema.data,
62
+ };
63
+ }
64
+ // Already in ViewData format
56
65
  return schema.data;
57
66
  }
58
67
 
@@ -99,20 +108,55 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
99
108
  onEdit,
100
109
  onDelete,
101
110
  onRowSelect,
111
+ onRowClick,
112
+ ...rest
102
113
  }) => {
103
114
  const [data, setData] = useState<any[]>([]);
104
115
  const [loading, setLoading] = useState(true);
105
116
  const [error, setError] = useState<Error | null>(null);
106
117
  const [objectSchema, setObjectSchema] = useState<any>(null);
107
118
 
119
+ // Check if data is passed directly (from ListView)
120
+ const passedData = (rest as any).data;
121
+
122
+ // Resolve bound data if 'bind' property exists
123
+ const boundData = useDataScope(schema.bind);
124
+
108
125
  // Get data configuration (supports both new and legacy formats)
109
- const dataConfig = getDataConfig(schema);
126
+ const rawDataConfig = getDataConfig(schema);
127
+ // Memoize dataConfig using deep comparison to prevent infinite loops
128
+ const dataConfig = React.useMemo(() => {
129
+ // If we have passed data (highest priority), treat it as value provider
130
+ if (passedData && Array.isArray(passedData)) {
131
+ return {
132
+ provider: 'value',
133
+ items: passedData
134
+ };
135
+ }
136
+
137
+ // If we have bound data, it takes precedence as inline value
138
+ if (boundData && Array.isArray(boundData)) {
139
+ return {
140
+ provider: 'value',
141
+ items: boundData
142
+ };
143
+ }
144
+ return rawDataConfig;
145
+ }, [JSON.stringify(rawDataConfig), boundData, passedData]);
146
+
110
147
  const hasInlineData = dataConfig?.provider === 'value';
111
148
 
112
149
  useEffect(() => {
113
150
  if (hasInlineData && dataConfig?.provider === 'value') {
114
- setData(dataConfig.items as any[]);
115
- setLoading(false);
151
+ // Only update if data is different to avoid infinite loop
152
+ setData(prev => {
153
+ const newItems = dataConfig.items as any[];
154
+ if (JSON.stringify(prev) !== JSON.stringify(newItems)) {
155
+ return newItems;
156
+ }
157
+ return prev;
158
+ });
159
+ setLoading(false);
116
160
  }
117
161
  }, [hasInlineData, dataConfig]);
118
162
 
@@ -124,7 +168,7 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
124
168
  }
125
169
 
126
170
  // For object provider, get the object name
127
- const objectName = dataConfig?.provider === 'object'
171
+ const objectName = dataConfig?.provider === 'object' && 'object' in dataConfig
128
172
  ? dataConfig.object
129
173
  : schema.objectName;
130
174
 
@@ -154,26 +198,40 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
154
198
  const cols = normalizeColumns(schema.columns);
155
199
 
156
200
  if (cols) {
157
- // If columns are already ListColumn objects, convert them to data-table format
201
+ // Check if columns are already in data-table format (have 'accessorKey')
202
+ // vs ListColumn format (have 'field')
158
203
  if (cols.length > 0 && typeof cols[0] === 'object' && cols[0] !== null) {
159
- return (cols as ListColumn[])
160
- .filter((col) => col?.field && typeof col.field === 'string') // Filter out invalid column objects
161
- .map((col) => ({
162
- header: col.label || col.field.charAt(0).toUpperCase() + col.field.slice(1).replace(/_/g, ' '),
163
- accessorKey: col.field,
164
- ...(col.width && { width: col.width }),
165
- ...(col.align && { align: col.align }),
166
- sortable: col.sortable !== false,
167
- }));
204
+ const firstCol = cols[0] as any;
205
+
206
+ // Already in data-table format - use as-is
207
+ if ('accessorKey' in firstCol) {
208
+ return cols;
209
+ }
210
+
211
+ // ListColumn format - convert to data-table format
212
+ if ('field' in firstCol) {
213
+ return (cols as ListColumn[])
214
+ .filter((col) => col?.field && typeof col.field === 'string') // Filter out invalid column objects
215
+ .map((col) => ({
216
+ header: col.label || col.field.charAt(0).toUpperCase() + col.field.slice(1).replace(/_/g, ' '),
217
+ accessorKey: col.field,
218
+ ...(col.width && { width: col.width }),
219
+ ...(col.align && { align: col.align }),
220
+ sortable: col.sortable !== false,
221
+ }));
222
+ }
168
223
  }
169
224
 
170
225
  // String array format - filter out invalid entries
171
226
  return (cols as string[])
172
227
  .filter((fieldName) => typeof fieldName === 'string' && fieldName.trim().length > 0)
173
- .map((fieldName) => ({
174
- header: fieldName.charAt(0).toUpperCase() + fieldName.slice(1).replace(/_/g, ' '),
175
- accessorKey: fieldName,
176
- }));
228
+ .map((fieldName) => {
229
+ const fieldLabel = objectSchema?.fields?.[fieldName]?.label;
230
+ return {
231
+ header: fieldLabel || fieldName.charAt(0).toUpperCase() + fieldName.slice(1).replace(/_/g, ' '),
232
+ accessorKey: fieldName,
233
+ };
234
+ });
177
235
  }
178
236
 
179
237
  // Legacy support: use 'fields' if columns not provided
@@ -217,7 +275,7 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
217
275
  setLoading(true);
218
276
  try {
219
277
  // Get object name from data config or schema
220
- const objectName = dataConfig?.provider === 'object'
278
+ const objectName = dataConfig?.provider === 'object' && 'object' in dataConfig
221
279
  ? dataConfig.object
222
280
  : schema.objectName;
223
281
 
@@ -321,7 +379,7 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
321
379
  </DropdownMenuItem>
322
380
  )}
323
381
  {operations?.delete && onDelete && (
324
- <DropdownMenuItem variant="destructive" onClick={() => onDelete(row)}>
382
+ <DropdownMenuItem onClick={() => onDelete(row)}>
325
383
  <Trash2 className="mr-2 h-4 w-4" />
326
384
  Delete
327
385
  </DropdownMenuItem>
@@ -369,8 +427,10 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
369
427
  exportable: operations?.export,
370
428
  rowActions: hasActions,
371
429
  resizableColumns: schema.resizable ?? schema.resizableColumns ?? true,
430
+ reorderableColumns: schema.reorderableColumns ?? false,
372
431
  className: schema.className,
373
432
  onSelectionChange: onRowSelect,
433
+ onRowClick: onRowClick,
374
434
  };
375
435
 
376
436
  return <SchemaRenderer schema={dataTableSchema} />;
@@ -0,0 +1,23 @@
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
+
9
+ import { describe, it, expect } from 'vitest';
10
+ import { VirtualGrid } from './VirtualGrid';
11
+
12
+ describe('VirtualGrid', () => {
13
+ it('should be exported', () => {
14
+ expect(VirtualGrid).toBeDefined();
15
+ expect(typeof VirtualGrid).toBe('function');
16
+ });
17
+
18
+ it('should have the correct display name', () => {
19
+ // Verify it's a React component
20
+ expect(VirtualGrid.name).toBe('VirtualGrid');
21
+ });
22
+ });
23
+