@object-ui/plugin-view 2.0.0 → 3.0.1

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,5 +1,5 @@
1
1
 
2
- > @object-ui/plugin-view@2.0.0 build /home/runner/work/objectui/objectui/packages/plugin-view
2
+ > @object-ui/plugin-view@3.0.1 build /home/runner/work/objectui/objectui/packages/plugin-view
3
3
  > vite build
4
4
 
5
5
  vite v7.3.1 building client environment for production...
@@ -8,186 +8,9 @@ transforming...
8
8
  rendering chunks...
9
9
  
10
10
  [vite:dts] Start generate declaration files...
11
- src/__tests__/FilterUI.test.tsx:183:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
12
-
13
- 183 expect(screen.getByText('Status')).toBeInTheDocument();
14
-    ~~~~~~~~~~~~~~~~~
15
- src/__tests__/FilterUI.test.tsx:184:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
16
-
17
- 184 expect(screen.getByText('Name')).toBeInTheDocument();
18
-    ~~~~~~~~~~~~~~~~~
19
- src/__tests__/FilterUI.test.tsx:187:51 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
20
-
21
- 187 expect(screen.queryByTestId('popover')).not.toBeInTheDocument();
22
-    ~~~~~~~~~~~~~~~~~
23
- src/__tests__/FilterUI.test.tsx:188:50 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
24
-
25
- 188 expect(screen.queryByTestId('drawer')).not.toBeInTheDocument();
26
-    ~~~~~~~~~~~~~~~~~
27
- src/__tests__/FilterUI.test.tsx:194:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
28
-
29
- 194 expect(screen.getByText('Status')).toBeInTheDocument();
30
-    ~~~~~~~~~~~~~~~~~
31
- src/__tests__/FilterUI.test.tsx:195:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
32
-
33
- 195 expect(screen.getByText('Name')).toBeInTheDocument();
34
-    ~~~~~~~~~~~~~~~~~
35
- src/__tests__/FilterUI.test.tsx:206:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
36
-
37
- 206 expect(screen.getByText('Status')).toBeInTheDocument();
38
-    ~~~~~~~~~~~~~~~~~
39
- src/__tests__/FilterUI.test.tsx:207:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
40
-
41
- 207 expect(screen.getByText('Name')).toBeInTheDocument();
42
-    ~~~~~~~~~~~~~~~~~
43
- src/__tests__/FilterUI.test.tsx:219:41 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
44
-
45
- 219 expect(screen.getByText('email')).toBeInTheDocument();
46
-    ~~~~~~~~~~~~~~~~~
47
- src/__tests__/FilterUI.test.tsx:225:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
48
-
49
- 225 expect(screen.getByText('Active')).toBeInTheDocument();
50
-    ~~~~~~~~~~~~~~~~~
51
- src/__tests__/FilterUI.test.tsx:226:44 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
52
-
53
- 226 expect(screen.getByText('Inactive')).toBeInTheDocument();
54
-    ~~~~~~~~~~~~~~~~~
55
- src/__tests__/FilterUI.test.tsx:239:21 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
56
-
57
- 239 expect(input).toBeInTheDocument();
58
-    ~~~~~~~~~~~~~~~~~
59
- src/__tests__/FilterUI.test.tsx:320:26 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
60
-
61
- 320 expect(selectRoot).toHaveAttribute('data-value', 'inactive');
62
-    ~~~~~~~~~~~~~~~
63
- src/__tests__/FilterUI.test.tsx:331:45 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
64
-
65
- 331 expect(screen.getByTestId('popover')).toBeInTheDocument();
66
-    ~~~~~~~~~~~~~~~~~
67
- src/__tests__/FilterUI.test.tsx:332:43 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
68
-
69
- 332 expect(screen.getByText('Filters')).toBeInTheDocument();
70
-    ~~~~~~~~~~~~~~~~~
71
- src/__tests__/FilterUI.test.tsx:339:30 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
72
-
73
- 339 expect(popoverContent).toBeInTheDocument();
74
-    ~~~~~~~~~~~~~~~~~
75
- src/__tests__/FilterUI.test.tsx:342:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
76
-
77
- 342 expect(screen.getByText('Status')).toBeInTheDocument();
78
-    ~~~~~~~~~~~~~~~~~
79
- src/__tests__/FilterUI.test.tsx:343:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
80
-
81
- 343 expect(screen.getByText('Name')).toBeInTheDocument();
82
-    ~~~~~~~~~~~~~~~~~
83
- src/__tests__/FilterUI.test.tsx:357:37 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
84
-
85
- 357 expect(screen.getByText('1')).toBeInTheDocument();
86
-    ~~~~~~~~~~~~~~~~~
87
- src/__tests__/FilterUI.test.tsx:369:48 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
88
-
89
- 369 expect(screen.queryByText('Status')).not.toBeInTheDocument();
90
-    ~~~~~~~~~~~~~~~~~
91
- src/__tests__/FilterUI.test.tsx:370:46 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
92
-
93
- 370 expect(screen.queryByText('Name')).not.toBeInTheDocument();
94
-    ~~~~~~~~~~~~~~~~~
95
- src/__tests__/FilterUI.test.tsx:376:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
96
-
97
- 376 expect(screen.getByText('Status')).toBeInTheDocument();
98
-    ~~~~~~~~~~~~~~~~~
99
- src/__tests__/FilterUI.test.tsx:377:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
100
-
101
- 377 expect(screen.getByText('Name')).toBeInTheDocument();
102
-    ~~~~~~~~~~~~~~~~~
103
- src/__tests__/FilterUI.test.tsx:383:42 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
104
-
105
- 383 expect(screen.getByText('Status')).toBeInTheDocument();
106
-    ~~~~~~~~~~~~~~~~~
107
- src/__tests__/FilterUI.test.tsx:402:43 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
108
-
109
- 402 expect(screen.queryByText('1')).not.toBeInTheDocument();
110
-    ~~~~~~~~~~~~~~~~~
111
- src/__tests__/FilterUI.test.tsx:415:43 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
112
-
113
- 415 expect(screen.queryByText('1')).not.toBeInTheDocument();
114
-    ~~~~~~~~~~~~~~~~~
115
- src/__tests__/FilterUI.test.tsx:428:43 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
116
-
117
- 428 expect(screen.queryByText('1')).not.toBeInTheDocument();
118
-    ~~~~~~~~~~~~~~~~~
119
- src/__tests__/FilterUI.test.tsx:441:43 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
120
-
121
- 441 expect(screen.queryByText('1')).not.toBeInTheDocument();
122
-    ~~~~~~~~~~~~~~~~~
123
- src/__tests__/FilterUI.test.tsx:454:37 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
124
-
125
- 454 expect(screen.getByText('2')).toBeInTheDocument();
126
-    ~~~~~~~~~~~~~~~~~
127
- src/__tests__/SortUI.test.tsx:98:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
128
-
129
- 98 expect(screen.getByText('Name')).toBeInTheDocument();
130
-    ~~~~~~~~~~~~~~~~~
131
- src/__tests__/SortUI.test.tsx:99:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
132
-
133
- 99 expect(screen.getByText('Date')).toBeInTheDocument();
134
-    ~~~~~~~~~~~~~~~~~
135
- src/__tests__/SortUI.test.tsx:108:21 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
136
-
137
- 108 expect(btn).toHaveAttribute('data-variant', 'outline');
138
-    ~~~~~~~~~~~~~~~
139
- src/__tests__/SortUI.test.tsx:123:23 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
140
-
141
- 123 expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
142
-    ~~~~~~~~~~~~~~~
143
- src/__tests__/SortUI.test.tsx:126:23 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
144
-
145
- 126 expect(dateBtn).toHaveAttribute('data-variant', 'outline');
146
-    ~~~~~~~~~~~~~~~
147
- src/__tests__/SortUI.test.tsx:157:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
148
-
149
- 157 expect(screen.getByText('Name')).toBeInTheDocument();
150
-    ~~~~~~~~~~~~~~~~~
151
- src/__tests__/SortUI.test.tsx:158:40 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
152
-
153
- 158 expect(screen.getByText('Date')).toBeInTheDocument();
154
-    ~~~~~~~~~~~~~~~~~
155
- src/__tests__/SortUI.test.tsx:164:45 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
156
-
157
- 164 expect(screen.getByText('Ascending')).toBeInTheDocument();
158
-    ~~~~~~~~~~~~~~~~~
159
- src/__tests__/SortUI.test.tsx:165:46 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
160
-
161
- 165 expect(screen.getByText('Descending')).toBeInTheDocument();
162
-    ~~~~~~~~~~~~~~~~~
163
- src/__tests__/SortUI.test.tsx:188:50 - error TS2339: Property 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
164
-
165
- 188 expect(screen.getByTestId('sort-builder')).toBeInTheDocument();
166
-    ~~~~~~~~~~~~~~~~~
167
- src/__tests__/SortUI.test.tsx:243:23 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
168
-
169
- 243 expect(dateBtn).toHaveAttribute('data-variant', 'secondary');
170
-    ~~~~~~~~~~~~~~~
171
- src/__tests__/SortUI.test.tsx:260:21 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
172
-
173
- 260 expect(btn).toHaveAttribute('data-variant', 'outline');
174
-    ~~~~~~~~~~~~~~~
175
- src/__tests__/SortUI.test.tsx:341:23 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
176
-
177
- 341 expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
178
-    ~~~~~~~~~~~~~~~
179
- src/__tests__/SortUI.test.tsx:342:23 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
180
-
181
- 342 expect(dateBtn).toHaveAttribute('data-variant', 'secondary');
182
-    ~~~~~~~~~~~~~~~
183
- src/__tests__/SortUI.test.tsx:376:21 - error TS2339: Property 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
184
-
185
- 376 expect(btn).toHaveAttribute('data-variant', 'outline');
186
-    ~~~~~~~~~~~~~~~
187
-
188
11
  computing gzip size...
189
- dist/index.js 47.74 kB │ gzip: 12.26 kB
190
- [vite:dts] Declaration files built in 5404ms.
12
+ dist/index.js 47.74 kB │ gzip: 12.27 kB
13
+ [vite:dts] Declaration files built in 4243ms.
191
14
  
192
15
  No name was provided for external module "@object-ui/core" in "output.globals" – guessing "core".
193
16
  No name was provided for external module "@object-ui/plugin-grid" in "output.globals" – guessing "pluginGrid".
@@ -195,5 +18,5 @@ computing gzip size...
195
18
  No name was provided for external module "@object-ui/components" in "output.globals" – guessing "components".
196
19
  No name was provided for external module "lucide-react" in "output.globals" – guessing "lucideReact".
197
20
  No name was provided for external module "@object-ui/react" in "output.globals" – guessing "react".
198
- dist/index.umd.cjs 33.54 kB │ gzip: 10.79 kB
199
- ✓ built in 5.86s
21
+ dist/index.umd.cjs 33.55 kB │ gzip: 10.79 kB
22
+ ✓ built in 4.70s
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @object-ui/plugin-view
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [adf2cc0]
8
+ - @object-ui/react@3.0.1
9
+ - @object-ui/components@3.0.1
10
+ - @object-ui/plugin-form@3.0.1
11
+ - @object-ui/plugin-grid@3.0.1
12
+ - @object-ui/types@3.0.1
13
+ - @object-ui/core@3.0.1
14
+
15
+ ## 3.0.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
20
+ - Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
21
+ - Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
22
+ - Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
23
+ - Added gzip + brotli pre-compression via vite-plugin-compression2
24
+ - Lazy MSW loading for build:server (~150 KB gzip saved)
25
+ - Added bundle analysis with rollup-plugin-visualizer
26
+
27
+ ### Patch Changes
28
+
29
+ - Updated dependencies [87979c3]
30
+ - @object-ui/types@3.0.0
31
+ - @object-ui/core@3.0.0
32
+ - @object-ui/react@3.0.0
33
+ - @object-ui/components@3.0.0
34
+ - @object-ui/plugin-form@3.0.0
35
+ - @object-ui/plugin-grid@3.0.0
36
+
3
37
  ## 2.0.0
4
38
 
5
39
  ### Major Changes
package/dist/index.js CHANGED
@@ -522,7 +522,7 @@ const Qt = ({
522
522
  $top: 100
523
523
  });
524
524
  let Y = [];
525
- Array.isArray(k) ? Y = k : k && typeof k == "object" && (Array.isArray(k.data) ? Y = k.data : Array.isArray(k.value) && (Y = k.value)), n && X(Y);
525
+ Array.isArray(k) ? Y = k : k && typeof k == "object" && (Array.isArray(k.data) ? Y = k.data : Array.isArray(k.records) && (Y = k.records)), n && X(Y);
526
526
  } catch (a) {
527
527
  console.error("ObjectView data fetch error:", a);
528
528
  } finally {
@@ -3,4 +3,4 @@
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} />`,j,_,W,_),h[_+j]=!0)}if(_=null,v!==void 0&&(c(v),_=""+v),F(p)&&(c(p.key),_=""+p.key),"key"in p){v={};for(var ae in p)ae!=="key"&&(v[ae]=p[ae])}else v=p;return _&&y(v,typeof r=="function"?r.displayName||r.name||"Unknown":r),N(r,_,v,w(),ee,te)}function s(r){S(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===de&&(r._payload.status==="fulfilled"?S(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function S(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var m=b,V=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),A=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),x=Symbol.for("react.consumer"),L=Symbol.for("react.context"),Z=Symbol.for("react.forward_ref"),ye=Symbol.for("react.suspense"),ue=Symbol.for("react.suspense_list"),M=Symbol.for("react.memo"),de=Symbol.for("react.lazy"),q=Symbol.for("react.activity"),De=Symbol.for("react.client.reference"),z=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Q=Object.prototype.hasOwnProperty,G=Array.isArray,ne=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(r){return r()}};var T,R={},ie=m.react_stack_bottom_frame.bind(m,g)(),ce=ne(u(g)),h={};le.Fragment=k,le.jsx=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!1,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)},le.jsxs=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!0,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)}})()),le}var Ce;function qe(){return Ce||(Ce=1,process.env.NODE_ENV==="production"?se.exports=Be():se.exports=Ue()),se.exports}var t=qe();function Se(e){var n,c,u="";if(typeof e=="string"||typeof e=="number")u+=e;else if(typeof e=="object")if(Array.isArray(e)){var w=e.length;for(n=0;n<w;n++)e[n]&&(c=Se(e[n]))&&(u&&(u+=" "),u+=c)}else for(c in e)e[c]&&(u&&(u+=" "),u+=c);return u}function Ye(){for(var e,n,c=0,u="",w=arguments.length;c<w;c++)(e=arguments[c])&&(n=Se(e))&&(u&&(u+=" "),u+=n);return u}const Ne=e=>typeof e=="boolean"?`${e}`:e===0?"0":e,Ve=Ye,X=(e,n)=>c=>{var u;if(n?.variants==null)return Ve(e,c?.class,c?.className);const{variants:w,defaultVariants:g}=n,F=Object.keys(w).map(N=>{const C=c?.[N],s=g?.[N];if(C===null)return null;const S=Ne(C)||Ne(s);return w[N][S]}),y=c&&Object.entries(c).reduce((N,C)=>{let[s,S]=C;return S===void 0||(N[s]=S),N},{}),E=n==null||(u=n.compoundVariants)===null||u===void 0?void 0:u.reduce((N,C)=>{let{class:s,className:S,...m}=C;return Object.entries(m).every(V=>{let[o,k]=V;return Array.isArray(k)?k.includes({...g,...y}[o]):{...g,...y}[o]===k})?[...N,s,S]:N},[]);return Ve(e,F,E,c?.class,c?.className)},We={list:"List",detail:"Detail",grid:"Grid",kanban:"Kanban",calendar:"Calendar",timeline:"Timeline",map:"Map"},Ge={list:$.List,detail:$.FileText,grid:$.Grid,kanban:$.LayoutGrid,calendar:$.Calendar,timeline:$.Activity,map:$.Map},He=X("flex gap-4",{variants:{position:{top:"flex-col",bottom:"flex-col-reverse",left:"flex-row",right:"flex-row-reverse"}},defaultVariants:{position:"top"}}),Ke=X("w-full",{variants:{orientation:{horizontal:"w-full",vertical:"w-48"}},defaultVariants:{orientation:"horizontal"}}),Je=X("flex gap-2",{variants:{orientation:{horizontal:"flex-row flex-wrap",vertical:"flex-col"}},defaultVariants:{orientation:"horizontal"}}),Xe=X("",{variants:{orientation:{horizontal:"",vertical:"flex h-auto flex-col items-stretch"}},defaultVariants:{orientation:"horizontal"}});function Ze(e){return e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}const Qe={Home:"House"};function et(e){if(!e)return null;const n=Ze(e),c=Qe[n]||n;return $.icons[c]||null}function fe(e){return e.label?e.label:We[e.type]||e.type}function Fe(e){return e.icon?et(e.icon):Ge[e.type]||null}function tt(e){return e.activeView?e.activeView:e.defaultView?e.defaultView:e.views?.[0]?.type}const pe=({schema:e,className:n,onViewChange:c,...u})=>{const w=O.useMemo(()=>e.storageKey?e.storageKey:`view-switcher${e.id?`-${e.id}`:""}`,[e.id,e.storageKey]),[g,F]=O.useState(()=>tt(e));O.useEffect(()=>{if(e.activeView){F(e.activeView);return}if(e.persistPreference)try{const d=localStorage.getItem(w);if(d){const x=e.views.find(L=>L.type===d)?.type;x&&F(x)}}catch{}},[e.activeView,e.persistPreference,e.views,w]),O.useEffect(()=>{if(!(!e.persistPreference||!g||e.activeView))try{localStorage.setItem(w,g)}catch{}},[g,e.activeView,e.persistPreference,w]);const y=O.useCallback(d=>{c?.(d),e.onViewChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onViewChange,{detail:{view:d}}))},[c,e.onViewChange]),E=O.useCallback(d=>{F(d),y(d)},[y]),N=g||e.views?.[0]?.type,C=N||"",s=e.views.find(d=>d.type===N)||e.views?.[0],S=e.variant||"tabs",m=e.position||"top",V=m==="left"||m==="right",o=V?"vertical":"horizontal",k=t.jsxs("div",{className:l.cn(Ke({orientation:o})),children:[S==="dropdown"&&t.jsxs(l.Select,{value:C,onValueChange:d=>E(d),children:[t.jsx(l.SelectTrigger,{className:l.cn("w-full",V?"h-10":"h-9"),children:t.jsx(l.SelectValue,{placeholder:"Select view"})}),t.jsx(l.SelectContent,{children:e.views.map((d,x)=>t.jsx(l.SelectItem,{value:d.type,children:fe(d)},`${d.type}-${x}`))})]}),S==="buttons"&&t.jsx("div",{className:l.cn(Je({orientation:o})),children:e.views.map((d,x)=>{const L=d.type===N,Z=Fe(d);return t.jsxs(l.Button,{type:"button",size:"sm",variant:L?"secondary":"ghost",className:l.cn("justify-start gap-2",V?"w-full":""),onClick:()=>E(d.type),children:[Z?t.jsx(Z,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})}),S==="tabs"&&t.jsx(l.Tabs,{value:C,onValueChange:d=>E(d),children:t.jsx(l.TabsList,{className:l.cn(Xe({orientation:o})),children:e.views.map((d,x)=>{const L=Fe(d);return t.jsxs(l.TabsTrigger,{value:d.type,className:l.cn("gap-2",V?"justify-start":""),children:[L?t.jsx(L,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})})})]}),A=s?.schema?Array.isArray(s.schema)?t.jsx("div",{className:"space-y-4",children:s.schema.map((d,x)=>t.jsx(je.SchemaRenderer,{schema:d,...u},`${s.type}-${x}`))}):t.jsx(je.SchemaRenderer,{schema:s.schema,...u}):null;return t.jsxs("div",{className:l.cn(He({position:m}),n),children:[t.jsx("div",{className:l.cn("shrink-0",V?"flex flex-col":"flex"),children:k}),t.jsx("div",{className:"flex-1 min-w-0",children:A})]})};let oe=null;try{oe=require("@object-ui/react").SchemaRenderer||null}catch{}const Te=({schema:e,dataSource:n,className:c,views:u,activeViewId:w,onViewChange:g,onRowClick:F,onEdit:y,renderListView:E,toolbarAddon:N})=>{const[C,s]=b.useState(null),[S,m]=b.useState(!1),[V,o]=b.useState("create"),[k,A]=b.useState(null),[d,x]=b.useState(0),[L,Z]=b.useState([]),[ye,ue]=b.useState(!1),[M,de]=b.useState({}),[q,De]=b.useState([]),z=e.listViews,Q=z!=null&&Object.keys(z).length>0,[G,ne]=b.useState(()=>e.defaultListView&&z?.[e.defaultListView]?e.defaultListView:z&&Object.keys(z)[0]||""),T=b.useMemo(()=>!Q||!G?null:z[G]||null,[Q,G,z]),R=b.useMemo(()=>u&&u.length>0?u:null,[u]),ie=R!=null&&R.length>0,ce=w||R?.[0]?.id,h=R?.find(i=>i.id===ce)||R?.[0],r=b.useMemo(()=>T?.type?T.type:h?.type?h.type:e.defaultViewType||"grid",[T,h,e.defaultViewType]),p=e.navigation;b.useEffect(()=>{let i=!0;const f=async()=>{try{const a=await n.getObjectSchema(e.objectName);i&&s(a)}catch(a){console.error("Failed to fetch object schema:",a)}};return e.objectName&&n&&f(),()=>{i=!1}},[e.objectName,n]),b.useEffect(()=>{let i=!0;return(async()=>{if(!(r==="grid"&&!E)&&!(!n||!e.objectName)){ue(!0);try{const a=T?.filter||h?.filter||e.table?.defaultFilters||[],U=Object.entries(M).filter(([,B])=>B!==void 0&&B!==""&&B!==null).map(([B,K])=>[B,"=",K]);let I=[];a.length>0&&U.length>0?I=["and",...a,...U]:U.length===1?I=U[0]:U.length>1?I=["and",...U]:I=a;const H=q.length>0?q.map(B=>({field:B.field,order:B.direction})):T?.sort||h?.sort||e.table?.defaultSort||void 0,D=await n.find(e.objectName,{$filter:I.length>0?I:void 0,$orderby:H,$top:100});let Y=[];Array.isArray(D)?Y=D:D&&typeof D=="object"&&(Array.isArray(D.data)?Y=D.data:Array.isArray(D.value)&&(Y=D.value)),i&&Z(Y)}catch(a){console.error("ObjectView data fetch error:",a)}finally{i&&ue(!1)}}})(),()=>{i=!1}},[e.objectName,n,r,M,q,d,T,h,E]);const v=e.layout||"drawer",j=e.operations||e.table?.operations||{create:!0,read:!0,update:!0,delete:!0},ee=b.useCallback(()=>{v==="page"&&e.onNavigate?e.onNavigate("new","edit"):(o("create"),A(null),m(!0))},[v,e]),te=b.useCallback(i=>{if(y){y(i);return}if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"edit")}else o("edit"),A(i),m(!0)},[v,e,y]),_=b.useCallback(i=>{if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"view")}else o("view"),A(i),m(!0)},[v,e]),W=b.useCallback(i=>{if(F){F(i);return}if(p){if(p.mode==="none"||p.preventNavigation)return;if(p.mode==="new_window"||p.openNewTab){const f=i._id||i.id,a=`/${e.objectName}/${f}`;window.open(a,"_blank");return}if(p.mode==="drawer"){o("view"),A(i),m(!0);return}if(p.mode==="modal"){o("view"),A(i),m(!0);return}if(p.mode==="page"){const f=i._id||i.id;e.onNavigate&&e.onNavigate(f,"view");return}}j.read!==!1&&_(i)},[F,p,j.read,_,e]),ae=b.useCallback(i=>{x(f=>f+1)},[]),ve=b.useCallback(i=>{x(f=>f+1)},[]),at=b.useCallback(()=>{m(!1),A(null),x(i=>i+1)},[]),st=b.useCallback(()=>{m(!1),A(null)},[]);b.useCallback(()=>{x(i=>i+1)},[]);const Pe=b.useMemo(()=>!ie||!R||R.length<=1?null:{type:"view-switcher",variant:"tabs",position:"top",persistPreference:!0,storageKey:`view-pref-${e.objectName}`,defaultView:h?.type||"grid",activeView:h?.type||"grid",views:R.map(i=>{const f={kanban:"kanban",calendar:"calendar",map:"map",gallery:"layout-grid",timeline:"activity",gantt:"gantt-chart",grid:"table",list:"list",detail:"file-text"};return{type:i.type,label:i.label,icon:f[i.type]||"table"}})},[ie,R,h,e.objectName]),ot=b.useCallback(i=>{if(!R)return;const f=R.find(a=>a.type===i);f&&g&&g(f.id)},[R,g]),ut=b.useCallback(i=>{ne(i)},[]);b.useMemo(()=>{if(e.showFilters===!1)return null;const i=e.filterableFields,f=C?.fields||{},U=(i?i.map(I=>[I,f[I]||{label:I}]):Object.entries(f).filter(([,I])=>!I.hidden).slice(0,8)).map(([I,H])=>{const D=H.type||"text";let Y="text",B;return D==="number"||D==="currency"||D==="percent"?Y="number":D==="boolean"||D==="toggle"?Y="boolean":D==="date"||D==="datetime"?Y="date":(D==="select"||H.options)&&(Y="select",B=(H.options||[]).map(K=>typeof K=="string"?{label:K,value:K}:{label:K.label,value:K.value})),{field:I,label:H.label||I,type:Y,placeholder:`Filter ${H.label||I}...`,...B?{options:B}:{}}});return U.length===0?null:{type:"filter-ui",layout:"popover",showClear:!0,showApply:!0,filters:U,values:M}},[e.showFilters,e.filterableFields,C,M]),b.useMemo(()=>{const i=C?.fields||{},f=Object.entries(i).filter(([,a])=>!a.hidden).slice(0,10).map(([a,U])=>({field:a,label:U.label||a}));return f.length===0?null:{type:"sort-ui",variant:"dropdown",multiple:!1,fields:f,sort:q}},[C,q]);const dt=b.useCallback(i=>{const f={objectName:e.objectName,fields:T?.columns||h?.columns||e.table?.fields,className:"h-full w-full",showSearch:!1},a=T?.options||h||{};switch(i){case"kanban":return{type:"object-kanban",...f,groupBy:a.kanban?.groupField||a.groupBy||a.groupField||"status",groupField:a.kanban?.groupField||a.groupField||"status",titleField:a.kanban?.titleField||a.titleField||"name",cardFields:f.fields||[],...a.kanban||{}};case"calendar":return{type:"object-calendar",...f,startDateField:a.calendar?.startDateField||a.startDateField||"start_date",endDateField:a.calendar?.endDateField||a.endDateField||"end_date",titleField:a.calendar?.titleField||a.titleField||"name",...a.calendar||{}};case"gallery":return{type:"object-gallery",...f,imageField:a.gallery?.imageField||a.imageField,titleField:a.gallery?.titleField||a.titleField||"name",subtitleField:a.gallery?.subtitleField||a.subtitleField,...a.gallery||{}};case"timeline":return{type:"object-timeline",...f,dateField:a.timeline?.dateField||a.dateField||"created_at",titleField:a.timeline?.titleField||a.titleField||"name",...a.timeline||{}};case"gantt":return{type:"object-gantt",...f,startDateField:a.gantt?.startDateField||a.startDateField||"start_date",endDateField:a.gantt?.endDateField||a.endDateField||"end_date",progressField:a.gantt?.progressField||a.progressField||"progress",dependenciesField:a.gantt?.dependenciesField||a.dependenciesField||"dependencies",...a.gantt||{}};case"map":return{type:"object-map",...f,locationField:a.map?.locationField||a.locationField||"location",...a.map||{}};default:return null}},[e.objectName,e.table?.fields,T,h]),ct=b.useMemo(()=>({type:"object-grid",objectName:e.objectName,title:e.table?.title,description:e.table?.description,fields:T?.columns||h?.columns||e.table?.fields,columns:T?.columns||h?.columns||e.table?.columns,operations:{...j,create:!1},defaultFilters:T?.filter||h?.filter||e.table?.defaultFilters,defaultSort:T?.sort||h?.sort||e.table?.defaultSort,pageSize:e.table?.pageSize,selectable:e.table?.selectable,className:e.table?.className}),[e,j,T,h]),Ie=()=>{const i=k?k._id||k.id:void 0;return{type:"object-form",objectName:e.objectName,mode:V,recordId:i,title:e.form?.title,description:e.form?.description,fields:e.form?.fields,customFields:e.form?.customFields,groups:e.form?.groups,layout:e.form?.layout,columns:e.form?.columns,showSubmit:e.form?.showSubmit,submitText:e.form?.submitText,showCancel:e.form?.showCancel,cancelText:e.form?.cancelText,showReset:e.form?.showReset,initialValues:e.form?.initialValues,readOnly:e.form?.readOnly||V==="view",className:e.form?.className,onSuccess:at,onCancel:st}},Re=()=>{if(e.form?.title)return e.form.title;const i=C?.label||e.objectName;switch(V){case"create":return`Create ${i}`;case"edit":return`Edit ${i}`;case"view":return`View ${i}`;default:return i}},$e=b.useMemo(()=>{const i=p?.width;return i?typeof i=="number"?`max-w-[${i}px]`:`max-w-[${i}]`:""},[p]),ft=()=>t.jsx(l.Drawer,{open:S,onOpenChange:m,direction:"right",children:t.jsxs(l.DrawerContent,{className:l.cn("w-full sm:max-w-2xl",$e),children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:Re()}),e.form?.description&&t.jsx(l.DrawerDescription,{children:e.form.description})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-4 pb-4",children:t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})})]})}),pt=()=>t.jsx(l.Dialog,{open:S,onOpenChange:m,children:t.jsxs(l.DialogContent,{className:l.cn("max-w-2xl max-h-[90vh] overflow-y-auto",$e),children:[t.jsxs(l.DialogHeader,{children:[t.jsx(l.DialogTitle,{children:Re()}),e.form?.description&&t.jsx(l.DialogDescription,{children:e.form.description})]}),t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})]})}),bt=b.useMemo(()=>Object.keys(M).some(f=>M[f]!==void 0&&M[f]!==""&&M[f]!==null)?Object.entries(M).filter(([,f])=>f!==void 0&&f!==""&&f!==null).map(([f,a])=>({field:f,operator:"equals",value:a})):T?.filter||h?.filter||e.table?.defaultFilters,[M,T,h,e.table?.defaultFilters]),wt=b.useMemo(()=>q.length>0?q:T?.sort||h?.sort||e.table?.defaultSort,[q,T,h,e.table?.defaultSort]),gt=()=>{const i=`${e.objectName}-${G||h?.id||"default"}-${r}-${d}`;if(E)return E({schema:{type:"list-view",objectName:e.objectName,viewType:r,fields:T?.columns||h?.columns||e.table?.fields,filters:bt,sort:wt,options:T?.options||h},dataSource:n,onEdit:te,onRowClick:W,className:"h-full"});if(r!=="grid"){const f=dt(r);if(f&&oe)return t.jsx(oe,{schema:f,dataSource:n,data:L,loading:ye},i);if(!oe)return t.jsx("div",{className:"flex items-center justify-center h-40 text-muted-foreground",children:t.jsxs("p",{children:["SchemaRenderer not available. Install @object-ui/react to render ",r," views."]})})}return t.jsx(Me.ObjectGrid,{schema:ct,dataSource:n,onRowClick:W,onEdit:j.update!==!1?te:void 0,onDelete:j.delete!==!1?ae:void 0,onBulkDelete:j.delete!==!1?ve:void 0},i)},yt=()=>{if(!Q)return null;const i=Object.entries(z);return i.length<=1?null:t.jsx(l.Tabs,{value:G,onValueChange:ut,className:"w-full",children:t.jsx(l.TabsList,{className:"w-auto",children:i.map(([f,a])=>t.jsx(l.TabsTrigger,{value:f,className:"text-sm",children:a.label||f},f))})})},vt=()=>{const i=e.showCreate!==!1&&j.create!==!1,f=e.showViewSwitcher===!0,a=yt();return!a&&!f&&!i&&!N?null:t.jsxs("div",{className:"flex flex-col gap-3",children:[a,(f||i||N)&&t.jsxs("div",{className:"flex items-center justify-between gap-4",children:[t.jsx("div",{className:"flex items-center gap-2",children:f&&Pe&&t.jsx(pe,{schema:Pe,onViewChange:ot,className:"overflow-x-auto"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[N,i&&t.jsxs(l.Button,{size:"sm",onClick:ee,children:[t.jsx($.Plus,{className:"h-4 w-4"}),"Create"]})]})]})]})},Le=p?.mode==="modal"?"modal":p?.mode==="drawer"?"drawer":v;return t.jsxs("div",{className:l.cn("flex flex-col h-full",c),children:[(e.title||e.description)&&t.jsxs("div",{className:"mb-4 shrink-0",children:[e.title&&t.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:e.title}),e.description&&t.jsx("p",{className:"text-muted-foreground mt-1",children:e.description})]}),t.jsx("div",{className:"mb-4 shrink-0",children:vt()}),t.jsx("div",{className:"flex-1 min-h-0",children:gt()}),Le==="drawer"&&ft(),Le==="modal"&&pt()]})},be=X("flex",{variants:{layout:{inline:"flex-col space-y-4",popover:"items-center",drawer:"items-center"}},defaultVariants:{layout:"inline"}}),rt=e=>e==null||e===""?!0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.values(e).every(n=>n==null||n===""):!1,lt=e=>Array.isArray(e)?{start:e[0]||"",end:e[1]||""}:e&&typeof e=="object"?{start:e.start||"",end:e.end||""}:{start:"",end:""},Ee=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(e.values||{}),[g,F]=O.useState(!1);O.useEffect(()=>{e.values&&w(e.values)},[e.values]);const y=O.useCallback(o=>{c?.(o),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{values:o}}))},[c,e.onChange]),E=O.useCallback((o,k)=>{const A={...u,[o]:k};w(A),e.showApply||y(A)},[y,e.showApply,u]),N=O.useCallback(()=>{const o={};if(w(o),e.showApply){y(o);return}y(o)},[y,e.showApply]),C=O.useCallback(()=>{y(u),F(!1)},[y,u]),s=O.useMemo(()=>Object.values(u).filter(o=>!rt(o)).length,[u]),S=o=>{const k=o.label||o.field,A=o.placeholder||`Filter by ${k}`;switch(o.type){case"number":return t.jsx(l.Input,{type:"number",value:u[o.field]??"",placeholder:A,onChange:d=>{const x=d.target.value,L=x===""?"":Number(x);E(o.field,L)}});case"select":return t.jsxs(l.Select,{value:u[o.field]!==void 0?String(u[o.field]):"",onValueChange:d=>{const x=o.options?.find(L=>String(L.value)===d);E(o.field,x?x.value:d)},children:[t.jsx(l.SelectTrigger,{children:t.jsx(l.SelectValue,{placeholder:A})}),t.jsx(l.SelectContent,{children:o.options?.map(d=>t.jsx(l.SelectItem,{value:String(d.value),children:d.label},String(d.value)))})]});case"date":return t.jsx(l.Input,{type:"date",value:u[o.field]??"",onChange:d=>E(o.field,d.target.value)});case"date-range":{const d=lt(u[o.field]);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Input,{type:"date",value:d.start??"",onChange:x=>{E(o.field,{...d,start:x.target.value})}}),t.jsx(l.Input,{type:"date",value:d.end??"",onChange:x=>{E(o.field,{...d,end:x.target.value})}})]})}case"boolean":return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Checkbox,{checked:!!u[o.field],onCheckedChange:d=>E(o.field,!!d)}),t.jsx("span",{className:"text-sm text-muted-foreground",children:"Enabled"})]});default:return t.jsx(l.Input,{value:u[o.field]??"",placeholder:A,onChange:d=>E(o.field,d.target.value)})}},m=t.jsxs("div",{className:"space-y-4",children:[t.jsx("div",{className:"grid gap-4 sm:grid-cols-2",children:e.filters.map(o=>t.jsxs("div",{className:"space-y-2",children:[t.jsx(l.Label,{className:"text-xs text-muted-foreground",children:o.label||o.field}),S(o)]},o.field))}),(e.showApply||e.showClear)&&t.jsxs("div",{className:"flex items-center justify-end gap-2 border-t pt-3",children:[e.showClear&&t.jsx(l.Button,{type:"button",variant:"ghost",size:"sm",onClick:N,children:"Clear"}),e.showApply&&t.jsx(l.Button,{type:"button",size:"sm",onClick:C,children:"Apply"})]})]}),V=e.layout||"inline";return V==="popover"?t.jsx("div",{className:l.cn(be({layout:V}),n),children:t.jsxs(l.Popover,{open:g,onOpenChange:F,children:[t.jsx(l.PopoverTrigger,{asChild:!0,children:t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]})}),t.jsx(l.PopoverContent,{align:"start",className:"w-[520px] p-4",children:m})]})}):V==="drawer"?t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",onClick:()=>F(!0),children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]}),t.jsx(l.Drawer,{open:g,onOpenChange:F,children:t.jsxs(l.DrawerContent,{children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:"Filters"}),t.jsx(l.DrawerDescription,{children:"Refine the data with advanced filters."})]}),t.jsx("div",{className:"px-4 pb-6",children:m})]})})]}):t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[m,!e.showApply&&e.showClear&&t.jsxs(l.Button,{type:"button",variant:"ghost",size:"sm",className:"gap-2",onClick:N,children:[t.jsx($.X,{className:"h-3.5 w-3.5"}),"Clear filters"]})]})},we=X("",{variants:{variant:{buttons:"flex flex-wrap gap-2",dropdown:"flex flex-wrap items-center gap-3",builder:"space-y-3"}},defaultVariants:{variant:"dropdown"}}),ge=e=>e?e.map(n=>({field:n.field,direction:n.direction})):[],_e=e=>e.map(n=>({id:`${n.field}-${n.direction}`,field:n.field,order:n.direction})),nt=e=>e.filter(n=>n.field).map(n=>({field:n.field,direction:n.order})),ke=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(()=>ge(e.sort)),[g,F]=O.useState(()=>_e(ge(e.sort)));O.useEffect(()=>{const s=ge(e.sort);w(s),F(_e(s))},[e.sort]);const y=O.useCallback(s=>{w(s),c?.(s),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{sort:s}}))},[c,e.onChange]),E=O.useCallback(s=>{const S=u.find(o=>o.field===s),m=!!e.multiple;if(!S){const o=m?[...u,{field:s,direction:"asc"}]:[{field:s,direction:"asc"}];y(o);return}if(S.direction==="asc"){const o=u.map(k=>k.field===s?{...k,direction:"desc"}:k);y(o);return}const V=u.filter(o=>o.field!==s);y(V)},[y,e.multiple,u]);if((e.variant||"dropdown")==="buttons")return t.jsx("div",{className:l.cn(we({variant:"buttons"}),n),children:e.fields.map(s=>{const S=u.find(V=>V.field===s.field),m=S?.direction==="asc"?$.ArrowUp:$.ArrowDown;return t.jsxs(l.Button,{type:"button",variant:S?"secondary":"outline",size:"sm",onClick:()=>E(s.field),className:"gap-2",children:[t.jsx("span",{children:s.label||s.field}),S&&t.jsx(m,{className:"h-3.5 w-3.5"})]},s.field)})});if(e.multiple)return t.jsx("div",{className:l.cn(we({variant:"builder"}),n),children:t.jsx(l.SortBuilder,{fields:e.fields.map(s=>({value:s.field,label:s.label||s.field})),value:g,onChange:s=>{F(s),y(nt(s))}})});const C=u[0];return t.jsxs("div",{className:l.cn(we({variant:"dropdown"}),n),children:[t.jsxs(l.Select,{value:C?.field||"",onValueChange:s=>{if(!s){y([]);return}y([{field:s,direction:C?.direction||"asc"}])},children:[t.jsx(l.SelectTrigger,{className:"w-56",children:t.jsx(l.SelectValue,{placeholder:"Select field"})}),t.jsx(l.SelectContent,{children:e.fields.map(s=>t.jsx(l.SelectItem,{value:s.field,children:s.label||s.field},s.field))})]}),t.jsxs(l.Select,{value:C?.direction||"asc",onValueChange:s=>{C?.field&&y([{field:C.field,direction:s}])},children:[t.jsx(l.SelectTrigger,{className:"w-36",children:t.jsx(l.SelectValue,{})}),t.jsxs(l.SelectContent,{children:[t.jsx(l.SelectItem,{value:"asc",children:"Ascending"}),t.jsx(l.SelectItem,{value:"desc",children:"Descending"})]})]})]})};let Oe=b.createContext(null);try{const e=require("@object-ui/react");e.SchemaRendererContext&&(Oe=e.SchemaRendererContext)}catch{}const Ae=({schema:e})=>{const c=b.useContext(Oe)?.dataSource??null;return t.jsx(Te,{schema:e,dataSource:c})};J.ComponentRegistry.register("object-view",Ae,{namespace:"plugin-view",label:"Object View",category:"view",icon:"LayoutDashboard",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Form Layout",enum:["drawer","modal","page"]},{name:"defaultViewType",type:"enum",label:"Default View Type",enum:["grid","kanban","gallery","calendar","timeline","gantt","map"]},{name:"defaultListView",type:"string",label:"Default Named View"},{name:"showSearch",type:"boolean",label:"Show Search"},{name:"showFilters",type:"boolean",label:"Show Filters"},{name:"showCreate",type:"boolean",label:"Show Create Button"},{name:"showRefresh",type:"boolean",label:"Show Refresh Button"},{name:"showViewSwitcher",type:"boolean",label:"Show View Switcher"},{name:"listViews",type:"object",label:"Named List Views"},{name:"navigation",type:"object",label:"Navigation Config"},{name:"searchableFields",type:"array",label:"Searchable Fields"},{name:"filterableFields",type:"array",label:"Filterable Fields"}],defaultProps:{layout:"drawer",defaultViewType:"grid",showSearch:!0,showFilters:!0,showCreate:!0,showRefresh:!0,showViewSwitcher:!0}}),J.ComponentRegistry.register("view",Ae,{namespace:"plugin-view",label:"View",category:"view"}),J.ComponentRegistry.register("view-switcher",pe,{namespace:"view",label:"View Switcher",category:"view",icon:"LayoutGrid",inputs:[{name:"views",type:"array",label:"Views",required:!0},{name:"defaultView",type:"string",label:"Default View"},{name:"activeView",type:"string",label:"Active View"},{name:"variant",type:"enum",label:"Variant",enum:["tabs","buttons","dropdown"]},{name:"position",type:"enum",label:"Position",enum:["top","bottom","left","right"]},{name:"persistPreference",type:"boolean",label:"Persist Preference"},{name:"storageKey",type:"string",label:"Storage Key"},{name:"onViewChange",type:"string",label:"On View Change Event"}],defaultProps:{variant:"tabs",position:"top",defaultView:"grid",views:[{type:"grid",label:"Grid",schema:{type:"text",content:"Grid view"}},{type:"list",label:"List",schema:{type:"text",content:"List view"}}]}}),J.ComponentRegistry.register("filter-ui",Ee,{namespace:"view",label:"Filter UI",category:"view",icon:"SlidersHorizontal",inputs:[{name:"filters",type:"array",label:"Filters",required:!0},{name:"values",type:"object",label:"Values"},{name:"onChange",type:"string",label:"On Change Event"},{name:"showClear",type:"boolean",label:"Show Clear Button"},{name:"showApply",type:"boolean",label:"Show Apply Button"},{name:"layout",type:"enum",label:"Layout",enum:["inline","popover","drawer"]}],defaultProps:{layout:"inline",showApply:!1,showClear:!0,filters:[{field:"name",label:"Name",type:"text",placeholder:"Search name"},{field:"status",label:"Status",type:"select",options:[{label:"Open",value:"open"},{label:"Closed",value:"closed"}]},{field:"created_at",label:"Created",type:"date"}]}}),J.ComponentRegistry.register("sort-ui",ke,{namespace:"view",label:"Sort UI",category:"view",icon:"ArrowUpDown",inputs:[{name:"fields",type:"array",label:"Fields",required:!0},{name:"sort",type:"array",label:"Sort"},{name:"onChange",type:"string",label:"On Change Event"},{name:"multiple",type:"boolean",label:"Allow Multiple"},{name:"variant",type:"enum",label:"Variant",enum:["dropdown","buttons"]}],defaultProps:{variant:"dropdown",multiple:!0,fields:[{field:"name",label:"Name"},{field:"created_at",label:"Created At"}],sort:[{field:"name",direction:"asc"}]}});const it=({schema:e,className:n,children:c,dataSource:u,...w})=>{const g=e.props?.columns?{display:"grid",gridTemplateColumns:`repeat(${e.props.columns}, 1fr)`,gap:"1rem"}:void 0;return t.jsx("div",{className:n,style:g,...w,children:c})};J.ComponentRegistry.register("view:simple",it,{namespace:"plugin-view",label:"Simple View",category:"view"}),P.FilterUI=Ee,P.ObjectView=Te,P.SortUI=ke,P.ViewSwitcher=pe,Object.defineProperty(P,Symbol.toStringTag,{value:"Module"})}));
6
+ <%s key={someKey} {...props} />`,j,_,W,_),h[_+j]=!0)}if(_=null,v!==void 0&&(c(v),_=""+v),F(p)&&(c(p.key),_=""+p.key),"key"in p){v={};for(var ae in p)ae!=="key"&&(v[ae]=p[ae])}else v=p;return _&&y(v,typeof r=="function"?r.displayName||r.name||"Unknown":r),N(r,_,v,w(),ee,te)}function s(r){S(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===de&&(r._payload.status==="fulfilled"?S(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function S(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var m=b,V=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),A=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),x=Symbol.for("react.consumer"),L=Symbol.for("react.context"),Z=Symbol.for("react.forward_ref"),ye=Symbol.for("react.suspense"),ue=Symbol.for("react.suspense_list"),M=Symbol.for("react.memo"),de=Symbol.for("react.lazy"),q=Symbol.for("react.activity"),De=Symbol.for("react.client.reference"),z=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Q=Object.prototype.hasOwnProperty,G=Array.isArray,ne=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(r){return r()}};var T,R={},ie=m.react_stack_bottom_frame.bind(m,g)(),ce=ne(u(g)),h={};le.Fragment=k,le.jsx=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!1,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)},le.jsxs=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!0,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)}})()),le}var Ce;function qe(){return Ce||(Ce=1,process.env.NODE_ENV==="production"?se.exports=Be():se.exports=Ue()),se.exports}var t=qe();function Se(e){var n,c,u="";if(typeof e=="string"||typeof e=="number")u+=e;else if(typeof e=="object")if(Array.isArray(e)){var w=e.length;for(n=0;n<w;n++)e[n]&&(c=Se(e[n]))&&(u&&(u+=" "),u+=c)}else for(c in e)e[c]&&(u&&(u+=" "),u+=c);return u}function Ye(){for(var e,n,c=0,u="",w=arguments.length;c<w;c++)(e=arguments[c])&&(n=Se(e))&&(u&&(u+=" "),u+=n);return u}const Ne=e=>typeof e=="boolean"?`${e}`:e===0?"0":e,Ve=Ye,X=(e,n)=>c=>{var u;if(n?.variants==null)return Ve(e,c?.class,c?.className);const{variants:w,defaultVariants:g}=n,F=Object.keys(w).map(N=>{const C=c?.[N],s=g?.[N];if(C===null)return null;const S=Ne(C)||Ne(s);return w[N][S]}),y=c&&Object.entries(c).reduce((N,C)=>{let[s,S]=C;return S===void 0||(N[s]=S),N},{}),E=n==null||(u=n.compoundVariants)===null||u===void 0?void 0:u.reduce((N,C)=>{let{class:s,className:S,...m}=C;return Object.entries(m).every(V=>{let[o,k]=V;return Array.isArray(k)?k.includes({...g,...y}[o]):{...g,...y}[o]===k})?[...N,s,S]:N},[]);return Ve(e,F,E,c?.class,c?.className)},We={list:"List",detail:"Detail",grid:"Grid",kanban:"Kanban",calendar:"Calendar",timeline:"Timeline",map:"Map"},Ge={list:$.List,detail:$.FileText,grid:$.Grid,kanban:$.LayoutGrid,calendar:$.Calendar,timeline:$.Activity,map:$.Map},He=X("flex gap-4",{variants:{position:{top:"flex-col",bottom:"flex-col-reverse",left:"flex-row",right:"flex-row-reverse"}},defaultVariants:{position:"top"}}),Ke=X("w-full",{variants:{orientation:{horizontal:"w-full",vertical:"w-48"}},defaultVariants:{orientation:"horizontal"}}),Je=X("flex gap-2",{variants:{orientation:{horizontal:"flex-row flex-wrap",vertical:"flex-col"}},defaultVariants:{orientation:"horizontal"}}),Xe=X("",{variants:{orientation:{horizontal:"",vertical:"flex h-auto flex-col items-stretch"}},defaultVariants:{orientation:"horizontal"}});function Ze(e){return e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}const Qe={Home:"House"};function et(e){if(!e)return null;const n=Ze(e),c=Qe[n]||n;return $.icons[c]||null}function fe(e){return e.label?e.label:We[e.type]||e.type}function Fe(e){return e.icon?et(e.icon):Ge[e.type]||null}function tt(e){return e.activeView?e.activeView:e.defaultView?e.defaultView:e.views?.[0]?.type}const pe=({schema:e,className:n,onViewChange:c,...u})=>{const w=O.useMemo(()=>e.storageKey?e.storageKey:`view-switcher${e.id?`-${e.id}`:""}`,[e.id,e.storageKey]),[g,F]=O.useState(()=>tt(e));O.useEffect(()=>{if(e.activeView){F(e.activeView);return}if(e.persistPreference)try{const d=localStorage.getItem(w);if(d){const x=e.views.find(L=>L.type===d)?.type;x&&F(x)}}catch{}},[e.activeView,e.persistPreference,e.views,w]),O.useEffect(()=>{if(!(!e.persistPreference||!g||e.activeView))try{localStorage.setItem(w,g)}catch{}},[g,e.activeView,e.persistPreference,w]);const y=O.useCallback(d=>{c?.(d),e.onViewChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onViewChange,{detail:{view:d}}))},[c,e.onViewChange]),E=O.useCallback(d=>{F(d),y(d)},[y]),N=g||e.views?.[0]?.type,C=N||"",s=e.views.find(d=>d.type===N)||e.views?.[0],S=e.variant||"tabs",m=e.position||"top",V=m==="left"||m==="right",o=V?"vertical":"horizontal",k=t.jsxs("div",{className:l.cn(Ke({orientation:o})),children:[S==="dropdown"&&t.jsxs(l.Select,{value:C,onValueChange:d=>E(d),children:[t.jsx(l.SelectTrigger,{className:l.cn("w-full",V?"h-10":"h-9"),children:t.jsx(l.SelectValue,{placeholder:"Select view"})}),t.jsx(l.SelectContent,{children:e.views.map((d,x)=>t.jsx(l.SelectItem,{value:d.type,children:fe(d)},`${d.type}-${x}`))})]}),S==="buttons"&&t.jsx("div",{className:l.cn(Je({orientation:o})),children:e.views.map((d,x)=>{const L=d.type===N,Z=Fe(d);return t.jsxs(l.Button,{type:"button",size:"sm",variant:L?"secondary":"ghost",className:l.cn("justify-start gap-2",V?"w-full":""),onClick:()=>E(d.type),children:[Z?t.jsx(Z,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})}),S==="tabs"&&t.jsx(l.Tabs,{value:C,onValueChange:d=>E(d),children:t.jsx(l.TabsList,{className:l.cn(Xe({orientation:o})),children:e.views.map((d,x)=>{const L=Fe(d);return t.jsxs(l.TabsTrigger,{value:d.type,className:l.cn("gap-2",V?"justify-start":""),children:[L?t.jsx(L,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})})})]}),A=s?.schema?Array.isArray(s.schema)?t.jsx("div",{className:"space-y-4",children:s.schema.map((d,x)=>t.jsx(je.SchemaRenderer,{schema:d,...u},`${s.type}-${x}`))}):t.jsx(je.SchemaRenderer,{schema:s.schema,...u}):null;return t.jsxs("div",{className:l.cn(He({position:m}),n),children:[t.jsx("div",{className:l.cn("shrink-0",V?"flex flex-col":"flex"),children:k}),t.jsx("div",{className:"flex-1 min-w-0",children:A})]})};let oe=null;try{oe=require("@object-ui/react").SchemaRenderer||null}catch{}const Te=({schema:e,dataSource:n,className:c,views:u,activeViewId:w,onViewChange:g,onRowClick:F,onEdit:y,renderListView:E,toolbarAddon:N})=>{const[C,s]=b.useState(null),[S,m]=b.useState(!1),[V,o]=b.useState("create"),[k,A]=b.useState(null),[d,x]=b.useState(0),[L,Z]=b.useState([]),[ye,ue]=b.useState(!1),[M,de]=b.useState({}),[q,De]=b.useState([]),z=e.listViews,Q=z!=null&&Object.keys(z).length>0,[G,ne]=b.useState(()=>e.defaultListView&&z?.[e.defaultListView]?e.defaultListView:z&&Object.keys(z)[0]||""),T=b.useMemo(()=>!Q||!G?null:z[G]||null,[Q,G,z]),R=b.useMemo(()=>u&&u.length>0?u:null,[u]),ie=R!=null&&R.length>0,ce=w||R?.[0]?.id,h=R?.find(i=>i.id===ce)||R?.[0],r=b.useMemo(()=>T?.type?T.type:h?.type?h.type:e.defaultViewType||"grid",[T,h,e.defaultViewType]),p=e.navigation;b.useEffect(()=>{let i=!0;const f=async()=>{try{const a=await n.getObjectSchema(e.objectName);i&&s(a)}catch(a){console.error("Failed to fetch object schema:",a)}};return e.objectName&&n&&f(),()=>{i=!1}},[e.objectName,n]),b.useEffect(()=>{let i=!0;return(async()=>{if(!(r==="grid"&&!E)&&!(!n||!e.objectName)){ue(!0);try{const a=T?.filter||h?.filter||e.table?.defaultFilters||[],U=Object.entries(M).filter(([,B])=>B!==void 0&&B!==""&&B!==null).map(([B,K])=>[B,"=",K]);let I=[];a.length>0&&U.length>0?I=["and",...a,...U]:U.length===1?I=U[0]:U.length>1?I=["and",...U]:I=a;const H=q.length>0?q.map(B=>({field:B.field,order:B.direction})):T?.sort||h?.sort||e.table?.defaultSort||void 0,D=await n.find(e.objectName,{$filter:I.length>0?I:void 0,$orderby:H,$top:100});let Y=[];Array.isArray(D)?Y=D:D&&typeof D=="object"&&(Array.isArray(D.data)?Y=D.data:Array.isArray(D.records)&&(Y=D.records)),i&&Z(Y)}catch(a){console.error("ObjectView data fetch error:",a)}finally{i&&ue(!1)}}})(),()=>{i=!1}},[e.objectName,n,r,M,q,d,T,h,E]);const v=e.layout||"drawer",j=e.operations||e.table?.operations||{create:!0,read:!0,update:!0,delete:!0},ee=b.useCallback(()=>{v==="page"&&e.onNavigate?e.onNavigate("new","edit"):(o("create"),A(null),m(!0))},[v,e]),te=b.useCallback(i=>{if(y){y(i);return}if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"edit")}else o("edit"),A(i),m(!0)},[v,e,y]),_=b.useCallback(i=>{if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"view")}else o("view"),A(i),m(!0)},[v,e]),W=b.useCallback(i=>{if(F){F(i);return}if(p){if(p.mode==="none"||p.preventNavigation)return;if(p.mode==="new_window"||p.openNewTab){const f=i._id||i.id,a=`/${e.objectName}/${f}`;window.open(a,"_blank");return}if(p.mode==="drawer"){o("view"),A(i),m(!0);return}if(p.mode==="modal"){o("view"),A(i),m(!0);return}if(p.mode==="page"){const f=i._id||i.id;e.onNavigate&&e.onNavigate(f,"view");return}}j.read!==!1&&_(i)},[F,p,j.read,_,e]),ae=b.useCallback(i=>{x(f=>f+1)},[]),ve=b.useCallback(i=>{x(f=>f+1)},[]),at=b.useCallback(()=>{m(!1),A(null),x(i=>i+1)},[]),st=b.useCallback(()=>{m(!1),A(null)},[]);b.useCallback(()=>{x(i=>i+1)},[]);const Pe=b.useMemo(()=>!ie||!R||R.length<=1?null:{type:"view-switcher",variant:"tabs",position:"top",persistPreference:!0,storageKey:`view-pref-${e.objectName}`,defaultView:h?.type||"grid",activeView:h?.type||"grid",views:R.map(i=>{const f={kanban:"kanban",calendar:"calendar",map:"map",gallery:"layout-grid",timeline:"activity",gantt:"gantt-chart",grid:"table",list:"list",detail:"file-text"};return{type:i.type,label:i.label,icon:f[i.type]||"table"}})},[ie,R,h,e.objectName]),ot=b.useCallback(i=>{if(!R)return;const f=R.find(a=>a.type===i);f&&g&&g(f.id)},[R,g]),ut=b.useCallback(i=>{ne(i)},[]);b.useMemo(()=>{if(e.showFilters===!1)return null;const i=e.filterableFields,f=C?.fields||{},U=(i?i.map(I=>[I,f[I]||{label:I}]):Object.entries(f).filter(([,I])=>!I.hidden).slice(0,8)).map(([I,H])=>{const D=H.type||"text";let Y="text",B;return D==="number"||D==="currency"||D==="percent"?Y="number":D==="boolean"||D==="toggle"?Y="boolean":D==="date"||D==="datetime"?Y="date":(D==="select"||H.options)&&(Y="select",B=(H.options||[]).map(K=>typeof K=="string"?{label:K,value:K}:{label:K.label,value:K.value})),{field:I,label:H.label||I,type:Y,placeholder:`Filter ${H.label||I}...`,...B?{options:B}:{}}});return U.length===0?null:{type:"filter-ui",layout:"popover",showClear:!0,showApply:!0,filters:U,values:M}},[e.showFilters,e.filterableFields,C,M]),b.useMemo(()=>{const i=C?.fields||{},f=Object.entries(i).filter(([,a])=>!a.hidden).slice(0,10).map(([a,U])=>({field:a,label:U.label||a}));return f.length===0?null:{type:"sort-ui",variant:"dropdown",multiple:!1,fields:f,sort:q}},[C,q]);const dt=b.useCallback(i=>{const f={objectName:e.objectName,fields:T?.columns||h?.columns||e.table?.fields,className:"h-full w-full",showSearch:!1},a=T?.options||h||{};switch(i){case"kanban":return{type:"object-kanban",...f,groupBy:a.kanban?.groupField||a.groupBy||a.groupField||"status",groupField:a.kanban?.groupField||a.groupField||"status",titleField:a.kanban?.titleField||a.titleField||"name",cardFields:f.fields||[],...a.kanban||{}};case"calendar":return{type:"object-calendar",...f,startDateField:a.calendar?.startDateField||a.startDateField||"start_date",endDateField:a.calendar?.endDateField||a.endDateField||"end_date",titleField:a.calendar?.titleField||a.titleField||"name",...a.calendar||{}};case"gallery":return{type:"object-gallery",...f,imageField:a.gallery?.imageField||a.imageField,titleField:a.gallery?.titleField||a.titleField||"name",subtitleField:a.gallery?.subtitleField||a.subtitleField,...a.gallery||{}};case"timeline":return{type:"object-timeline",...f,dateField:a.timeline?.dateField||a.dateField||"created_at",titleField:a.timeline?.titleField||a.titleField||"name",...a.timeline||{}};case"gantt":return{type:"object-gantt",...f,startDateField:a.gantt?.startDateField||a.startDateField||"start_date",endDateField:a.gantt?.endDateField||a.endDateField||"end_date",progressField:a.gantt?.progressField||a.progressField||"progress",dependenciesField:a.gantt?.dependenciesField||a.dependenciesField||"dependencies",...a.gantt||{}};case"map":return{type:"object-map",...f,locationField:a.map?.locationField||a.locationField||"location",...a.map||{}};default:return null}},[e.objectName,e.table?.fields,T,h]),ct=b.useMemo(()=>({type:"object-grid",objectName:e.objectName,title:e.table?.title,description:e.table?.description,fields:T?.columns||h?.columns||e.table?.fields,columns:T?.columns||h?.columns||e.table?.columns,operations:{...j,create:!1},defaultFilters:T?.filter||h?.filter||e.table?.defaultFilters,defaultSort:T?.sort||h?.sort||e.table?.defaultSort,pageSize:e.table?.pageSize,selectable:e.table?.selectable,className:e.table?.className}),[e,j,T,h]),Ie=()=>{const i=k?k._id||k.id:void 0;return{type:"object-form",objectName:e.objectName,mode:V,recordId:i,title:e.form?.title,description:e.form?.description,fields:e.form?.fields,customFields:e.form?.customFields,groups:e.form?.groups,layout:e.form?.layout,columns:e.form?.columns,showSubmit:e.form?.showSubmit,submitText:e.form?.submitText,showCancel:e.form?.showCancel,cancelText:e.form?.cancelText,showReset:e.form?.showReset,initialValues:e.form?.initialValues,readOnly:e.form?.readOnly||V==="view",className:e.form?.className,onSuccess:at,onCancel:st}},Re=()=>{if(e.form?.title)return e.form.title;const i=C?.label||e.objectName;switch(V){case"create":return`Create ${i}`;case"edit":return`Edit ${i}`;case"view":return`View ${i}`;default:return i}},$e=b.useMemo(()=>{const i=p?.width;return i?typeof i=="number"?`max-w-[${i}px]`:`max-w-[${i}]`:""},[p]),ft=()=>t.jsx(l.Drawer,{open:S,onOpenChange:m,direction:"right",children:t.jsxs(l.DrawerContent,{className:l.cn("w-full sm:max-w-2xl",$e),children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:Re()}),e.form?.description&&t.jsx(l.DrawerDescription,{children:e.form.description})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-4 pb-4",children:t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})})]})}),pt=()=>t.jsx(l.Dialog,{open:S,onOpenChange:m,children:t.jsxs(l.DialogContent,{className:l.cn("max-w-2xl max-h-[90vh] overflow-y-auto",$e),children:[t.jsxs(l.DialogHeader,{children:[t.jsx(l.DialogTitle,{children:Re()}),e.form?.description&&t.jsx(l.DialogDescription,{children:e.form.description})]}),t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})]})}),bt=b.useMemo(()=>Object.keys(M).some(f=>M[f]!==void 0&&M[f]!==""&&M[f]!==null)?Object.entries(M).filter(([,f])=>f!==void 0&&f!==""&&f!==null).map(([f,a])=>({field:f,operator:"equals",value:a})):T?.filter||h?.filter||e.table?.defaultFilters,[M,T,h,e.table?.defaultFilters]),wt=b.useMemo(()=>q.length>0?q:T?.sort||h?.sort||e.table?.defaultSort,[q,T,h,e.table?.defaultSort]),gt=()=>{const i=`${e.objectName}-${G||h?.id||"default"}-${r}-${d}`;if(E)return E({schema:{type:"list-view",objectName:e.objectName,viewType:r,fields:T?.columns||h?.columns||e.table?.fields,filters:bt,sort:wt,options:T?.options||h},dataSource:n,onEdit:te,onRowClick:W,className:"h-full"});if(r!=="grid"){const f=dt(r);if(f&&oe)return t.jsx(oe,{schema:f,dataSource:n,data:L,loading:ye},i);if(!oe)return t.jsx("div",{className:"flex items-center justify-center h-40 text-muted-foreground",children:t.jsxs("p",{children:["SchemaRenderer not available. Install @object-ui/react to render ",r," views."]})})}return t.jsx(Me.ObjectGrid,{schema:ct,dataSource:n,onRowClick:W,onEdit:j.update!==!1?te:void 0,onDelete:j.delete!==!1?ae:void 0,onBulkDelete:j.delete!==!1?ve:void 0},i)},yt=()=>{if(!Q)return null;const i=Object.entries(z);return i.length<=1?null:t.jsx(l.Tabs,{value:G,onValueChange:ut,className:"w-full",children:t.jsx(l.TabsList,{className:"w-auto",children:i.map(([f,a])=>t.jsx(l.TabsTrigger,{value:f,className:"text-sm",children:a.label||f},f))})})},vt=()=>{const i=e.showCreate!==!1&&j.create!==!1,f=e.showViewSwitcher===!0,a=yt();return!a&&!f&&!i&&!N?null:t.jsxs("div",{className:"flex flex-col gap-3",children:[a,(f||i||N)&&t.jsxs("div",{className:"flex items-center justify-between gap-4",children:[t.jsx("div",{className:"flex items-center gap-2",children:f&&Pe&&t.jsx(pe,{schema:Pe,onViewChange:ot,className:"overflow-x-auto"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[N,i&&t.jsxs(l.Button,{size:"sm",onClick:ee,children:[t.jsx($.Plus,{className:"h-4 w-4"}),"Create"]})]})]})]})},Le=p?.mode==="modal"?"modal":p?.mode==="drawer"?"drawer":v;return t.jsxs("div",{className:l.cn("flex flex-col h-full",c),children:[(e.title||e.description)&&t.jsxs("div",{className:"mb-4 shrink-0",children:[e.title&&t.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:e.title}),e.description&&t.jsx("p",{className:"text-muted-foreground mt-1",children:e.description})]}),t.jsx("div",{className:"mb-4 shrink-0",children:vt()}),t.jsx("div",{className:"flex-1 min-h-0",children:gt()}),Le==="drawer"&&ft(),Le==="modal"&&pt()]})},be=X("flex",{variants:{layout:{inline:"flex-col space-y-4",popover:"items-center",drawer:"items-center"}},defaultVariants:{layout:"inline"}}),rt=e=>e==null||e===""?!0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.values(e).every(n=>n==null||n===""):!1,lt=e=>Array.isArray(e)?{start:e[0]||"",end:e[1]||""}:e&&typeof e=="object"?{start:e.start||"",end:e.end||""}:{start:"",end:""},Ee=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(e.values||{}),[g,F]=O.useState(!1);O.useEffect(()=>{e.values&&w(e.values)},[e.values]);const y=O.useCallback(o=>{c?.(o),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{values:o}}))},[c,e.onChange]),E=O.useCallback((o,k)=>{const A={...u,[o]:k};w(A),e.showApply||y(A)},[y,e.showApply,u]),N=O.useCallback(()=>{const o={};if(w(o),e.showApply){y(o);return}y(o)},[y,e.showApply]),C=O.useCallback(()=>{y(u),F(!1)},[y,u]),s=O.useMemo(()=>Object.values(u).filter(o=>!rt(o)).length,[u]),S=o=>{const k=o.label||o.field,A=o.placeholder||`Filter by ${k}`;switch(o.type){case"number":return t.jsx(l.Input,{type:"number",value:u[o.field]??"",placeholder:A,onChange:d=>{const x=d.target.value,L=x===""?"":Number(x);E(o.field,L)}});case"select":return t.jsxs(l.Select,{value:u[o.field]!==void 0?String(u[o.field]):"",onValueChange:d=>{const x=o.options?.find(L=>String(L.value)===d);E(o.field,x?x.value:d)},children:[t.jsx(l.SelectTrigger,{children:t.jsx(l.SelectValue,{placeholder:A})}),t.jsx(l.SelectContent,{children:o.options?.map(d=>t.jsx(l.SelectItem,{value:String(d.value),children:d.label},String(d.value)))})]});case"date":return t.jsx(l.Input,{type:"date",value:u[o.field]??"",onChange:d=>E(o.field,d.target.value)});case"date-range":{const d=lt(u[o.field]);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Input,{type:"date",value:d.start??"",onChange:x=>{E(o.field,{...d,start:x.target.value})}}),t.jsx(l.Input,{type:"date",value:d.end??"",onChange:x=>{E(o.field,{...d,end:x.target.value})}})]})}case"boolean":return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Checkbox,{checked:!!u[o.field],onCheckedChange:d=>E(o.field,!!d)}),t.jsx("span",{className:"text-sm text-muted-foreground",children:"Enabled"})]});default:return t.jsx(l.Input,{value:u[o.field]??"",placeholder:A,onChange:d=>E(o.field,d.target.value)})}},m=t.jsxs("div",{className:"space-y-4",children:[t.jsx("div",{className:"grid gap-4 sm:grid-cols-2",children:e.filters.map(o=>t.jsxs("div",{className:"space-y-2",children:[t.jsx(l.Label,{className:"text-xs text-muted-foreground",children:o.label||o.field}),S(o)]},o.field))}),(e.showApply||e.showClear)&&t.jsxs("div",{className:"flex items-center justify-end gap-2 border-t pt-3",children:[e.showClear&&t.jsx(l.Button,{type:"button",variant:"ghost",size:"sm",onClick:N,children:"Clear"}),e.showApply&&t.jsx(l.Button,{type:"button",size:"sm",onClick:C,children:"Apply"})]})]}),V=e.layout||"inline";return V==="popover"?t.jsx("div",{className:l.cn(be({layout:V}),n),children:t.jsxs(l.Popover,{open:g,onOpenChange:F,children:[t.jsx(l.PopoverTrigger,{asChild:!0,children:t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]})}),t.jsx(l.PopoverContent,{align:"start",className:"w-[520px] p-4",children:m})]})}):V==="drawer"?t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",onClick:()=>F(!0),children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]}),t.jsx(l.Drawer,{open:g,onOpenChange:F,children:t.jsxs(l.DrawerContent,{children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:"Filters"}),t.jsx(l.DrawerDescription,{children:"Refine the data with advanced filters."})]}),t.jsx("div",{className:"px-4 pb-6",children:m})]})})]}):t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[m,!e.showApply&&e.showClear&&t.jsxs(l.Button,{type:"button",variant:"ghost",size:"sm",className:"gap-2",onClick:N,children:[t.jsx($.X,{className:"h-3.5 w-3.5"}),"Clear filters"]})]})},we=X("",{variants:{variant:{buttons:"flex flex-wrap gap-2",dropdown:"flex flex-wrap items-center gap-3",builder:"space-y-3"}},defaultVariants:{variant:"dropdown"}}),ge=e=>e?e.map(n=>({field:n.field,direction:n.direction})):[],_e=e=>e.map(n=>({id:`${n.field}-${n.direction}`,field:n.field,order:n.direction})),nt=e=>e.filter(n=>n.field).map(n=>({field:n.field,direction:n.order})),ke=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(()=>ge(e.sort)),[g,F]=O.useState(()=>_e(ge(e.sort)));O.useEffect(()=>{const s=ge(e.sort);w(s),F(_e(s))},[e.sort]);const y=O.useCallback(s=>{w(s),c?.(s),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{sort:s}}))},[c,e.onChange]),E=O.useCallback(s=>{const S=u.find(o=>o.field===s),m=!!e.multiple;if(!S){const o=m?[...u,{field:s,direction:"asc"}]:[{field:s,direction:"asc"}];y(o);return}if(S.direction==="asc"){const o=u.map(k=>k.field===s?{...k,direction:"desc"}:k);y(o);return}const V=u.filter(o=>o.field!==s);y(V)},[y,e.multiple,u]);if((e.variant||"dropdown")==="buttons")return t.jsx("div",{className:l.cn(we({variant:"buttons"}),n),children:e.fields.map(s=>{const S=u.find(V=>V.field===s.field),m=S?.direction==="asc"?$.ArrowUp:$.ArrowDown;return t.jsxs(l.Button,{type:"button",variant:S?"secondary":"outline",size:"sm",onClick:()=>E(s.field),className:"gap-2",children:[t.jsx("span",{children:s.label||s.field}),S&&t.jsx(m,{className:"h-3.5 w-3.5"})]},s.field)})});if(e.multiple)return t.jsx("div",{className:l.cn(we({variant:"builder"}),n),children:t.jsx(l.SortBuilder,{fields:e.fields.map(s=>({value:s.field,label:s.label||s.field})),value:g,onChange:s=>{F(s),y(nt(s))}})});const C=u[0];return t.jsxs("div",{className:l.cn(we({variant:"dropdown"}),n),children:[t.jsxs(l.Select,{value:C?.field||"",onValueChange:s=>{if(!s){y([]);return}y([{field:s,direction:C?.direction||"asc"}])},children:[t.jsx(l.SelectTrigger,{className:"w-56",children:t.jsx(l.SelectValue,{placeholder:"Select field"})}),t.jsx(l.SelectContent,{children:e.fields.map(s=>t.jsx(l.SelectItem,{value:s.field,children:s.label||s.field},s.field))})]}),t.jsxs(l.Select,{value:C?.direction||"asc",onValueChange:s=>{C?.field&&y([{field:C.field,direction:s}])},children:[t.jsx(l.SelectTrigger,{className:"w-36",children:t.jsx(l.SelectValue,{})}),t.jsxs(l.SelectContent,{children:[t.jsx(l.SelectItem,{value:"asc",children:"Ascending"}),t.jsx(l.SelectItem,{value:"desc",children:"Descending"})]})]})]})};let Oe=b.createContext(null);try{const e=require("@object-ui/react");e.SchemaRendererContext&&(Oe=e.SchemaRendererContext)}catch{}const Ae=({schema:e})=>{const c=b.useContext(Oe)?.dataSource??null;return t.jsx(Te,{schema:e,dataSource:c})};J.ComponentRegistry.register("object-view",Ae,{namespace:"plugin-view",label:"Object View",category:"view",icon:"LayoutDashboard",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Form Layout",enum:["drawer","modal","page"]},{name:"defaultViewType",type:"enum",label:"Default View Type",enum:["grid","kanban","gallery","calendar","timeline","gantt","map"]},{name:"defaultListView",type:"string",label:"Default Named View"},{name:"showSearch",type:"boolean",label:"Show Search"},{name:"showFilters",type:"boolean",label:"Show Filters"},{name:"showCreate",type:"boolean",label:"Show Create Button"},{name:"showRefresh",type:"boolean",label:"Show Refresh Button"},{name:"showViewSwitcher",type:"boolean",label:"Show View Switcher"},{name:"listViews",type:"object",label:"Named List Views"},{name:"navigation",type:"object",label:"Navigation Config"},{name:"searchableFields",type:"array",label:"Searchable Fields"},{name:"filterableFields",type:"array",label:"Filterable Fields"}],defaultProps:{layout:"drawer",defaultViewType:"grid",showSearch:!0,showFilters:!0,showCreate:!0,showRefresh:!0,showViewSwitcher:!0}}),J.ComponentRegistry.register("view",Ae,{namespace:"plugin-view",label:"View",category:"view"}),J.ComponentRegistry.register("view-switcher",pe,{namespace:"view",label:"View Switcher",category:"view",icon:"LayoutGrid",inputs:[{name:"views",type:"array",label:"Views",required:!0},{name:"defaultView",type:"string",label:"Default View"},{name:"activeView",type:"string",label:"Active View"},{name:"variant",type:"enum",label:"Variant",enum:["tabs","buttons","dropdown"]},{name:"position",type:"enum",label:"Position",enum:["top","bottom","left","right"]},{name:"persistPreference",type:"boolean",label:"Persist Preference"},{name:"storageKey",type:"string",label:"Storage Key"},{name:"onViewChange",type:"string",label:"On View Change Event"}],defaultProps:{variant:"tabs",position:"top",defaultView:"grid",views:[{type:"grid",label:"Grid",schema:{type:"text",content:"Grid view"}},{type:"list",label:"List",schema:{type:"text",content:"List view"}}]}}),J.ComponentRegistry.register("filter-ui",Ee,{namespace:"view",label:"Filter UI",category:"view",icon:"SlidersHorizontal",inputs:[{name:"filters",type:"array",label:"Filters",required:!0},{name:"values",type:"object",label:"Values"},{name:"onChange",type:"string",label:"On Change Event"},{name:"showClear",type:"boolean",label:"Show Clear Button"},{name:"showApply",type:"boolean",label:"Show Apply Button"},{name:"layout",type:"enum",label:"Layout",enum:["inline","popover","drawer"]}],defaultProps:{layout:"inline",showApply:!1,showClear:!0,filters:[{field:"name",label:"Name",type:"text",placeholder:"Search name"},{field:"status",label:"Status",type:"select",options:[{label:"Open",value:"open"},{label:"Closed",value:"closed"}]},{field:"created_at",label:"Created",type:"date"}]}}),J.ComponentRegistry.register("sort-ui",ke,{namespace:"view",label:"Sort UI",category:"view",icon:"ArrowUpDown",inputs:[{name:"fields",type:"array",label:"Fields",required:!0},{name:"sort",type:"array",label:"Sort"},{name:"onChange",type:"string",label:"On Change Event"},{name:"multiple",type:"boolean",label:"Allow Multiple"},{name:"variant",type:"enum",label:"Variant",enum:["dropdown","buttons"]}],defaultProps:{variant:"dropdown",multiple:!0,fields:[{field:"name",label:"Name"},{field:"created_at",label:"Created At"}],sort:[{field:"name",direction:"asc"}]}});const it=({schema:e,className:n,children:c,dataSource:u,...w})=>{const g=e.props?.columns?{display:"grid",gridTemplateColumns:`repeat(${e.props.columns}, 1fr)`,gap:"1rem"}:void 0;return t.jsx("div",{className:n,style:g,...w,children:c})};J.ComponentRegistry.register("view:simple",it,{namespace:"plugin-view",label:"Simple View",category:"view"}),P.FilterUI=Ee,P.ObjectView=Te,P.SortUI=ke,P.ViewSwitcher=pe,Object.defineProperty(P,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-view",
3
- "version": "2.0.0",
3
+ "version": "3.0.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Object View plugin for Object UI",
@@ -17,19 +17,19 @@
17
17
  "dependencies": {
18
18
  "class-variance-authority": "^0.7.1",
19
19
  "lucide-react": "^0.563.0",
20
- "@object-ui/components": "2.0.0",
21
- "@object-ui/core": "2.0.0",
22
- "@object-ui/plugin-form": "2.0.0",
23
- "@object-ui/plugin-grid": "2.0.0",
24
- "@object-ui/react": "2.0.0",
25
- "@object-ui/types": "2.0.0"
20
+ "@object-ui/components": "3.0.1",
21
+ "@object-ui/core": "3.0.1",
22
+ "@object-ui/plugin-form": "3.0.1",
23
+ "@object-ui/plugin-grid": "3.0.1",
24
+ "@object-ui/react": "3.0.1",
25
+ "@object-ui/types": "3.0.1"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": "^18.0.0 || ^19.0.0",
29
29
  "react-dom": "^18.0.0 || ^19.0.0"
30
30
  },
31
31
  "devDependencies": {
32
- "@vitejs/plugin-react": "^5.1.3",
32
+ "@vitejs/plugin-react": "^5.1.4",
33
33
  "typescript": "^5.9.3",
34
34
  "vite": "^7.3.1",
35
35
  "vite-plugin-dts": "^4.5.4"
@@ -320,8 +320,8 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
320
320
  } else if (results && typeof results === 'object') {
321
321
  if (Array.isArray((results as any).data)) {
322
322
  items = (results as any).data;
323
- } else if (Array.isArray((results as any).value)) {
324
- items = (results as any).value;
323
+ } else if (Array.isArray((results as any).records)) {
324
+ items = (results as any).records;
325
325
  }
326
326
  }
327
327
 
@@ -0,0 +1,755 @@
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
+ /**
10
+ * Toolbar Consistency Tests
11
+ *
12
+ * Verifies that toolbar, filter, sort, and view-switcher controls render
13
+ * with consistent structure and accessible attributes across all view types.
14
+ *
15
+ * Strategy: Each section renders the relevant component in isolation using
16
+ * the same lightweight Shadcn mocks from sibling test files, then asserts
17
+ * ARIA roles, labels, and keyboard-accessibility invariants.
18
+ */
19
+
20
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
21
+ import { render, screen, fireEvent } from '@testing-library/react';
22
+ import { ObjectView } from '../ObjectView';
23
+ import { FilterUI } from '../FilterUI';
24
+ import { SortUI } from '../SortUI';
25
+ import { ViewSwitcher } from '../ViewSwitcher';
26
+ import type {
27
+ ObjectViewSchema,
28
+ DataSource,
29
+ FilterUISchema,
30
+ SortUISchema,
31
+ ViewSwitcherSchema,
32
+ } from '@object-ui/types';
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Mocks – mirrors ObjectView.test.tsx
36
+ // ---------------------------------------------------------------------------
37
+ vi.mock('@object-ui/react', () => ({
38
+ SchemaRenderer: ({ schema }: any) => (
39
+ <div data-testid="schema-renderer" data-schema-type={schema?.type}>
40
+ {schema?.type}
41
+ </div>
42
+ ),
43
+ SchemaRendererContext: null,
44
+ }));
45
+
46
+ vi.mock('@object-ui/plugin-grid', () => ({
47
+ ObjectGrid: ({ schema }: any) => (
48
+ <div data-testid="object-grid" data-object={schema?.objectName}>
49
+ Grid
50
+ </div>
51
+ ),
52
+ }));
53
+
54
+ vi.mock('@object-ui/plugin-form', () => ({
55
+ ObjectForm: ({ schema }: any) => (
56
+ <div data-testid="object-form" data-mode={schema?.mode}>
57
+ Form ({schema?.mode})
58
+ </div>
59
+ ),
60
+ }));
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // Mock @object-ui/components – lightweight Shadcn stand-ins
64
+ // (mirrors FilterUI.test.tsx / SortUI.test.tsx)
65
+ // ---------------------------------------------------------------------------
66
+ vi.mock('@object-ui/components', async () => {
67
+ const React = await import('react');
68
+ const cn = (...args: any[]) => args.filter(Boolean).join(' ');
69
+
70
+ const Button = ({ children, onClick, variant, size, type, ...rest }: any) => (
71
+ <button onClick={onClick} data-variant={variant} data-size={size} type={type} {...rest}>
72
+ {children}
73
+ </button>
74
+ );
75
+
76
+ const Input = ({ value, onChange, placeholder, type, ...rest }: any) => (
77
+ <input
78
+ value={value}
79
+ onChange={onChange}
80
+ placeholder={placeholder}
81
+ type={type}
82
+ data-testid={`input-${type || 'text'}`}
83
+ {...rest}
84
+ />
85
+ );
86
+
87
+ const Label = ({ children, className, htmlFor }: any) => (
88
+ <label className={className} htmlFor={htmlFor}>
89
+ {children}
90
+ </label>
91
+ );
92
+
93
+ const Checkbox = ({ checked, onCheckedChange }: any) => (
94
+ <input
95
+ type="checkbox"
96
+ data-testid="checkbox"
97
+ checked={checked}
98
+ onChange={(e: any) => onCheckedChange?.(e.target.checked)}
99
+ />
100
+ );
101
+
102
+ // Select family with context for onValueChange propagation
103
+ const SelectCtx = React.createContext<((v: string) => void) | undefined>(undefined);
104
+
105
+ const Select = ({ children, value, onValueChange }: any) => (
106
+ <SelectCtx.Provider value={onValueChange}>
107
+ <div data-testid="select-root" data-value={value}>
108
+ {children}
109
+ </div>
110
+ </SelectCtx.Provider>
111
+ );
112
+
113
+ const SelectTrigger = ({ children, className }: any) => (
114
+ <button data-testid="select-trigger" className={className}>
115
+ {children}
116
+ </button>
117
+ );
118
+
119
+ const SelectValue = ({ placeholder }: any) => (
120
+ <span data-testid="select-value">{placeholder}</span>
121
+ );
122
+
123
+ const SelectContent = ({ children }: any) => (
124
+ <div data-testid="select-content">{children}</div>
125
+ );
126
+
127
+ const SelectItem = ({ children, value }: any) => {
128
+ const onValueChange = React.useContext(SelectCtx);
129
+ return (
130
+ <div
131
+ data-testid="select-item"
132
+ data-value={value}
133
+ role="option"
134
+ onClick={() => onValueChange?.(String(value))}
135
+ >
136
+ {children}
137
+ </div>
138
+ );
139
+ };
140
+
141
+ const Popover = ({ children, open }: any) => (
142
+ <div data-testid="popover" data-open={open}>{children}</div>
143
+ );
144
+ const PopoverTrigger = ({ children }: any) => (
145
+ <div data-testid="popover-trigger">{children}</div>
146
+ );
147
+ const PopoverContent = ({ children }: any) => (
148
+ <div data-testid="popover-content">{children}</div>
149
+ );
150
+
151
+ const Drawer = ({ children, open }: any) => (
152
+ <div data-testid="drawer" data-open={open}>{children}</div>
153
+ );
154
+ const DrawerContent = ({ children }: any) => (
155
+ <div data-testid="drawer-content">{children}</div>
156
+ );
157
+ const DrawerHeader = ({ children }: any) => (
158
+ <div data-testid="drawer-header">{children}</div>
159
+ );
160
+ const DrawerTitle = ({ children }: any) => (
161
+ <h2 data-testid="drawer-title">{children}</h2>
162
+ );
163
+ const DrawerDescription = ({ children }: any) => (
164
+ <p data-testid="drawer-description">{children}</p>
165
+ );
166
+
167
+ const Dialog = ({ children, open }: any) => (
168
+ <div data-testid="dialog" data-open={open}>{children}</div>
169
+ );
170
+ const DialogContent = ({ children }: any) => (
171
+ <div data-testid="dialog-content">{children}</div>
172
+ );
173
+ const DialogHeader = ({ children }: any) => (
174
+ <div data-testid="dialog-header">{children}</div>
175
+ );
176
+ const DialogTitle = ({ children }: any) => (
177
+ <h2 data-testid="dialog-title">{children}</h2>
178
+ );
179
+ const DialogDescription = ({ children }: any) => (
180
+ <p data-testid="dialog-description">{children}</p>
181
+ );
182
+
183
+ // Tabs family – render role="tablist" for TabsList
184
+ const TabsCtx = React.createContext<{ value: string; onValueChange?: (v: string) => void }>({
185
+ value: '',
186
+ });
187
+
188
+ const Tabs = ({ children, value, onValueChange }: any) => (
189
+ <TabsCtx.Provider value={{ value, onValueChange }}>
190
+ <div data-testid="tabs">{children}</div>
191
+ </TabsCtx.Provider>
192
+ );
193
+
194
+ const TabsList = ({ children, className }: any) => (
195
+ <div role="tablist" className={className}>{children}</div>
196
+ );
197
+
198
+ const TabsTrigger = ({ children, value, className }: any) => {
199
+ const ctx = React.useContext(TabsCtx);
200
+ const isActive = ctx.value === value;
201
+ return (
202
+ <button
203
+ role="tab"
204
+ aria-selected={isActive}
205
+ data-state={isActive ? 'active' : 'inactive'}
206
+ className={className}
207
+ onClick={() => ctx.onValueChange?.(value)}
208
+ >
209
+ {children}
210
+ </button>
211
+ );
212
+ };
213
+
214
+ const SortBuilder = ({ fields, value, onChange }: any) => (
215
+ <div data-testid="sort-builder" data-fields={JSON.stringify(fields)} data-value={JSON.stringify(value)}>
216
+ <button
217
+ data-testid="sort-builder-change"
218
+ onClick={() => onChange?.([{ id: 'date-desc', field: 'date', order: 'desc' }])}
219
+ >
220
+ Change Sort
221
+ </button>
222
+ </div>
223
+ );
224
+
225
+ return {
226
+ cn,
227
+ Button,
228
+ Input,
229
+ Label,
230
+ Checkbox,
231
+ Select,
232
+ SelectTrigger,
233
+ SelectValue,
234
+ SelectContent,
235
+ SelectItem,
236
+ Popover,
237
+ PopoverTrigger,
238
+ PopoverContent,
239
+ Drawer,
240
+ DrawerContent,
241
+ DrawerHeader,
242
+ DrawerTitle,
243
+ DrawerDescription,
244
+ Dialog,
245
+ DialogContent,
246
+ DialogHeader,
247
+ DialogTitle,
248
+ DialogDescription,
249
+ Tabs,
250
+ TabsList,
251
+ TabsTrigger,
252
+ SortBuilder,
253
+ };
254
+ });
255
+
256
+ // ---------------------------------------------------------------------------
257
+ // Shared helpers
258
+ // ---------------------------------------------------------------------------
259
+ const createMockDataSource = (overrides: Partial<DataSource> = {}): DataSource =>
260
+ ({
261
+ find: vi.fn().mockResolvedValue([]),
262
+ findOne: vi.fn().mockResolvedValue(null),
263
+ create: vi.fn().mockResolvedValue({}),
264
+ update: vi.fn().mockResolvedValue({}),
265
+ delete: vi.fn().mockResolvedValue({}),
266
+ getObjectSchema: vi.fn().mockResolvedValue({
267
+ label: 'Contacts',
268
+ fields: {
269
+ name: { label: 'Name', type: 'text' },
270
+ email: { label: 'Email', type: 'text' },
271
+ status: {
272
+ label: 'Status',
273
+ type: 'select',
274
+ options: [
275
+ { label: 'Active', value: 'active' },
276
+ { label: 'Inactive', value: 'inactive' },
277
+ ],
278
+ },
279
+ created_at: { label: 'Created', type: 'date' },
280
+ },
281
+ }),
282
+ ...overrides,
283
+ } as DataSource);
284
+
285
+ // ===========================================================================
286
+ // 1. ObjectView renders a toolbar region
287
+ // ===========================================================================
288
+ describe('Toolbar consistency across view types', () => {
289
+ let mockDataSource: DataSource;
290
+
291
+ beforeEach(() => {
292
+ vi.clearAllMocks();
293
+ mockDataSource = createMockDataSource();
294
+ });
295
+
296
+ describe('ObjectView toolbar region', () => {
297
+ it('renders a toolbar container that wraps action buttons', () => {
298
+ const schema: ObjectViewSchema = {
299
+ type: 'object-view',
300
+ objectName: 'contacts',
301
+ title: 'Contacts',
302
+ };
303
+
304
+ const { container } = render(
305
+ <ObjectView schema={schema} dataSource={mockDataSource} />,
306
+ );
307
+
308
+ // The Create button lives inside the toolbar area
309
+ const createBtn = screen.getByText('Create');
310
+ expect(createBtn).toBeDefined();
311
+ // Toolbar wrapper is a parent div
312
+ expect(createBtn.closest('div')).toBeDefined();
313
+ });
314
+
315
+ it('renders Create button as a focusable element', () => {
316
+ const schema: ObjectViewSchema = {
317
+ type: 'object-view',
318
+ objectName: 'contacts',
319
+ };
320
+
321
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
322
+
323
+ const btn = screen.getByText('Create');
324
+ expect(btn.tagName).toBe('BUTTON');
325
+ // Buttons are keyboard-focusable by default (no tabIndex=-1)
326
+ expect(btn.getAttribute('tabindex')).not.toBe('-1');
327
+ });
328
+
329
+ it('hides toolbar when no actions or tabs are needed', () => {
330
+ const schema: ObjectViewSchema = {
331
+ type: 'object-view',
332
+ objectName: 'contacts',
333
+ showCreate: false,
334
+ showViewSwitcher: false,
335
+ };
336
+
337
+ const { container } = render(
338
+ <ObjectView schema={schema} dataSource={mockDataSource} />,
339
+ );
340
+
341
+ // No Create button
342
+ expect(screen.queryByText('Create')).toBeNull();
343
+ });
344
+ });
345
+
346
+ // =========================================================================
347
+ // 2. Filter controls are accessible
348
+ // =========================================================================
349
+ describe('FilterUI accessibility', () => {
350
+ const makeFilterSchema = (overrides: Partial<FilterUISchema> = {}): FilterUISchema => ({
351
+ type: 'filter-ui',
352
+ filters: [
353
+ {
354
+ field: 'status',
355
+ label: 'Status',
356
+ type: 'select',
357
+ options: [
358
+ { label: 'Active', value: 'active' },
359
+ { label: 'Inactive', value: 'inactive' },
360
+ ],
361
+ },
362
+ { field: 'name', label: 'Name', type: 'text' },
363
+ ],
364
+ ...overrides,
365
+ });
366
+
367
+ it('renders a visible label for each filter field', () => {
368
+ render(<FilterUI schema={makeFilterSchema()} />);
369
+
370
+ expect(screen.getByText('Status')).toBeInTheDocument();
371
+ expect(screen.getByText('Name')).toBeInTheDocument();
372
+ });
373
+
374
+ it('renders text filter inputs with descriptive placeholders', () => {
375
+ render(
376
+ <FilterUI
377
+ schema={makeFilterSchema({
378
+ filters: [{ field: 'search', label: 'Search', type: 'text' }],
379
+ })}
380
+ />,
381
+ );
382
+
383
+ const input = screen.getByPlaceholderText('Filter by Search');
384
+ expect(input).toBeInTheDocument();
385
+ expect(input.tagName).toBe('INPUT');
386
+ });
387
+
388
+ it('renders select filters with option role="option" items', () => {
389
+ render(<FilterUI schema={makeFilterSchema()} />);
390
+
391
+ const options = screen.getAllByRole('option');
392
+ expect(options.length).toBeGreaterThanOrEqual(2);
393
+ expect(options[0]).toHaveAttribute('data-value', 'active');
394
+ expect(options[1]).toHaveAttribute('data-value', 'inactive');
395
+ });
396
+
397
+ it('renders filters consistently in popover layout', () => {
398
+ render(<FilterUI schema={makeFilterSchema({ layout: 'popover' })} />);
399
+
400
+ // Popover trigger should contain a "Filters" label
401
+ expect(screen.getByText('Filters')).toBeInTheDocument();
402
+ // Filter labels are still present inside popover content
403
+ expect(screen.getByText('Status')).toBeInTheDocument();
404
+ expect(screen.getByText('Name')).toBeInTheDocument();
405
+ });
406
+ });
407
+
408
+ // =========================================================================
409
+ // 3. Sort controls render consistently with proper attributes
410
+ // =========================================================================
411
+ describe('SortUI accessibility', () => {
412
+ const makeSortSchema = (overrides: Partial<SortUISchema> = {}): SortUISchema => ({
413
+ type: 'sort-ui',
414
+ fields: [
415
+ { field: 'name', label: 'Name' },
416
+ { field: 'date', label: 'Date' },
417
+ ],
418
+ ...overrides,
419
+ });
420
+
421
+ it('renders sort buttons as focusable button elements', () => {
422
+ render(<SortUI schema={makeSortSchema({ variant: 'buttons' })} />);
423
+
424
+ const buttons = screen.getAllByRole('button');
425
+ expect(buttons).toHaveLength(2);
426
+ buttons.forEach((btn) => {
427
+ expect(btn.tagName).toBe('BUTTON');
428
+ expect(btn.getAttribute('tabindex')).not.toBe('-1');
429
+ });
430
+ });
431
+
432
+ it('renders active sort with secondary variant for visual distinction', () => {
433
+ render(
434
+ <SortUI
435
+ schema={makeSortSchema({
436
+ variant: 'buttons',
437
+ sort: [{ field: 'name', direction: 'asc' }],
438
+ })}
439
+ />,
440
+ );
441
+
442
+ const nameBtn = screen.getByText('Name').closest('button')!;
443
+ expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
444
+
445
+ const dateBtn = screen.getByText('Date').closest('button')!;
446
+ expect(dateBtn).toHaveAttribute('data-variant', 'outline');
447
+ });
448
+
449
+ it('renders dropdown variant with select controls', () => {
450
+ render(<SortUI schema={makeSortSchema({ variant: 'dropdown' })} />);
451
+
452
+ const selectRoots = screen.getAllByTestId('select-root');
453
+ // Field selector + direction selector
454
+ expect(selectRoots).toHaveLength(2);
455
+ });
456
+
457
+ it('renders sort direction options (Ascending / Descending)', () => {
458
+ render(<SortUI schema={makeSortSchema({ variant: 'dropdown' })} />);
459
+
460
+ expect(screen.getByText('Ascending')).toBeInTheDocument();
461
+ expect(screen.getByText('Descending')).toBeInTheDocument();
462
+ });
463
+ });
464
+
465
+ // =========================================================================
466
+ // 4. Toolbar actions are keyboard-accessible
467
+ // =========================================================================
468
+ describe('Toolbar keyboard accessibility', () => {
469
+ it('Create button responds to keyboard activation', () => {
470
+ const schema: ObjectViewSchema = {
471
+ type: 'object-view',
472
+ objectName: 'contacts',
473
+ };
474
+
475
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
476
+
477
+ const createBtn = screen.getByText('Create');
478
+ // Simulate keyboard activation (Enter key on a focused button triggers click)
479
+ fireEvent.keyDown(createBtn, { key: 'Enter', code: 'Enter' });
480
+ fireEvent.keyUp(createBtn, { key: 'Enter', code: 'Enter' });
481
+ // Button is a native <button>, so keyboard activation is inherent
482
+ expect(createBtn.tagName).toBe('BUTTON');
483
+ });
484
+
485
+ it('sort buttons respond to click events (keyboard proxied)', () => {
486
+ const onChange = vi.fn();
487
+ render(
488
+ <SortUI
489
+ schema={{
490
+ type: 'sort-ui',
491
+ fields: [{ field: 'name', label: 'Name' }],
492
+ variant: 'buttons',
493
+ }}
494
+ onChange={onChange}
495
+ />,
496
+ );
497
+
498
+ const btn = screen.getByText('Name').closest('button')!;
499
+ fireEvent.click(btn);
500
+ expect(onChange).toHaveBeenCalledWith([{ field: 'name', direction: 'asc' }]);
501
+ });
502
+
503
+ it('filter text inputs accept keyboard input', () => {
504
+ const onChange = vi.fn();
505
+ render(
506
+ <FilterUI
507
+ schema={{
508
+ type: 'filter-ui',
509
+ filters: [{ field: 'query', label: 'Search', type: 'text' }],
510
+ }}
511
+ onChange={onChange}
512
+ />,
513
+ );
514
+
515
+ const input = screen.getByPlaceholderText('Filter by Search');
516
+ fireEvent.change(input, { target: { value: 'test' } });
517
+ expect(onChange).toHaveBeenCalledWith({ query: 'test' });
518
+ });
519
+ });
520
+
521
+ // =========================================================================
522
+ // 5. Search input in toolbar has proper label and role
523
+ // =========================================================================
524
+ describe('Search input accessibility', () => {
525
+ it('filter text input has an associated label element', () => {
526
+ render(
527
+ <FilterUI
528
+ schema={{
529
+ type: 'filter-ui',
530
+ filters: [{ field: 'search', label: 'Search', type: 'text' }],
531
+ }}
532
+ />,
533
+ );
534
+
535
+ // Label with text "Search" should exist
536
+ expect(screen.getByText('Search')).toBeInTheDocument();
537
+ // Input should have descriptive placeholder
538
+ const input = screen.getByPlaceholderText('Filter by Search');
539
+ expect(input).toBeInTheDocument();
540
+ });
541
+
542
+ it('filter text input is an <input> element that is focusable', () => {
543
+ render(
544
+ <FilterUI
545
+ schema={{
546
+ type: 'filter-ui',
547
+ filters: [{ field: 'q', label: 'Quick Search', type: 'text' }],
548
+ }}
549
+ />,
550
+ );
551
+
552
+ const input = screen.getByPlaceholderText('Filter by Quick Search');
553
+ expect(input.tagName).toBe('INPUT');
554
+ expect(input.getAttribute('tabindex')).not.toBe('-1');
555
+ });
556
+ });
557
+
558
+ // =========================================================================
559
+ // 6. View type selector renders with role="tablist"
560
+ // =========================================================================
561
+ describe('ViewSwitcher tablist rendering', () => {
562
+ const makeViewSwitcherSchema = (
563
+ overrides: Partial<ViewSwitcherSchema> = {},
564
+ ): ViewSwitcherSchema => ({
565
+ type: 'view-switcher',
566
+ views: [
567
+ { type: 'grid', label: 'Grid' },
568
+ { type: 'kanban', label: 'Kanban' },
569
+ { type: 'calendar', label: 'Calendar' },
570
+ ],
571
+ variant: 'tabs',
572
+ ...overrides,
573
+ });
574
+
575
+ it('renders tabs variant with role="tablist"', () => {
576
+ render(<ViewSwitcher schema={makeViewSwitcherSchema()} />);
577
+
578
+ const tablist = screen.getByRole('tablist');
579
+ expect(tablist).toBeInTheDocument();
580
+ });
581
+
582
+ it('renders individual tabs with role="tab"', () => {
583
+ render(<ViewSwitcher schema={makeViewSwitcherSchema()} />);
584
+
585
+ const tabs = screen.getAllByRole('tab');
586
+ expect(tabs).toHaveLength(3);
587
+ });
588
+
589
+ it('marks the active tab with aria-selected="true"', () => {
590
+ render(
591
+ <ViewSwitcher
592
+ schema={makeViewSwitcherSchema({ activeView: 'kanban' })}
593
+ />,
594
+ );
595
+
596
+ const tabs = screen.getAllByRole('tab');
597
+ const kanbanTab = tabs.find((t) => t.textContent?.includes('Kanban'));
598
+ expect(kanbanTab).toBeDefined();
599
+ expect(kanbanTab!.getAttribute('aria-selected')).toBe('true');
600
+ });
601
+
602
+ it('marks inactive tabs with aria-selected="false"', () => {
603
+ render(
604
+ <ViewSwitcher
605
+ schema={makeViewSwitcherSchema({ activeView: 'grid' })}
606
+ />,
607
+ );
608
+
609
+ const tabs = screen.getAllByRole('tab');
610
+ const kanbanTab = tabs.find((t) => t.textContent?.includes('Kanban'));
611
+ expect(kanbanTab!.getAttribute('aria-selected')).toBe('false');
612
+ });
613
+
614
+ it('tabs are keyboard-activatable via click', () => {
615
+ const onViewChange = vi.fn();
616
+ render(
617
+ <ViewSwitcher
618
+ schema={makeViewSwitcherSchema()}
619
+ onViewChange={onViewChange}
620
+ />,
621
+ );
622
+
623
+ const tabs = screen.getAllByRole('tab');
624
+ const calendarTab = tabs.find((t) => t.textContent?.includes('Calendar'));
625
+ fireEvent.click(calendarTab!);
626
+
627
+ expect(onViewChange).toHaveBeenCalledWith('calendar');
628
+ });
629
+
630
+ it('renders buttons variant without tablist role', () => {
631
+ render(
632
+ <ViewSwitcher
633
+ schema={makeViewSwitcherSchema({ variant: 'buttons' })}
634
+ />,
635
+ );
636
+
637
+ expect(screen.queryByRole('tablist')).not.toBeInTheDocument();
638
+ // Should render plain buttons instead
639
+ const buttons = screen.getAllByRole('button');
640
+ expect(buttons.length).toBe(3);
641
+ });
642
+ });
643
+
644
+ // =========================================================================
645
+ // 7. Density / view variant selector renders with accessible options
646
+ // =========================================================================
647
+ describe('ViewSwitcher dropdown variant accessibility', () => {
648
+ const makeDropdownSchema = (
649
+ overrides: Partial<ViewSwitcherSchema> = {},
650
+ ): ViewSwitcherSchema => ({
651
+ type: 'view-switcher',
652
+ views: [
653
+ { type: 'grid', label: 'Grid' },
654
+ { type: 'kanban', label: 'Kanban' },
655
+ ],
656
+ variant: 'dropdown',
657
+ ...overrides,
658
+ });
659
+
660
+ it('renders dropdown with select-root controls', () => {
661
+ render(<ViewSwitcher schema={makeDropdownSchema()} />);
662
+
663
+ const selectRoot = screen.getByTestId('select-root');
664
+ expect(selectRoot).toBeInTheDocument();
665
+ });
666
+
667
+ it('renders all view options inside the select', () => {
668
+ render(<ViewSwitcher schema={makeDropdownSchema()} />);
669
+
670
+ const items = screen.getAllByTestId('select-item');
671
+ expect(items).toHaveLength(2);
672
+ expect(items[0]).toHaveTextContent('Grid');
673
+ expect(items[1]).toHaveTextContent('Kanban');
674
+ });
675
+
676
+ it('renders option items with role="option"', () => {
677
+ render(<ViewSwitcher schema={makeDropdownSchema()} />);
678
+
679
+ const options = screen.getAllByRole('option');
680
+ expect(options.length).toBe(2);
681
+ });
682
+ });
683
+
684
+ // =========================================================================
685
+ // Cross-view consistency: named list views use tablist
686
+ // =========================================================================
687
+ describe('Named list views tablist consistency', () => {
688
+ it('renders named view tabs with role="tablist" for multiple views', () => {
689
+ const schema: ObjectViewSchema = {
690
+ type: 'object-view',
691
+ objectName: 'contacts',
692
+ listViews: {
693
+ all: { label: 'All Contacts', type: 'grid' },
694
+ active: { label: 'Active', type: 'grid', filter: [['status', '=', 'active']] },
695
+ },
696
+ defaultListView: 'all',
697
+ };
698
+
699
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
700
+
701
+ const tablist = screen.getByRole('tablist');
702
+ expect(tablist).toBeInTheDocument();
703
+ });
704
+
705
+ it('renders individual named view tabs with role="tab"', () => {
706
+ const schema: ObjectViewSchema = {
707
+ type: 'object-view',
708
+ objectName: 'contacts',
709
+ listViews: {
710
+ all: { label: 'All Contacts', type: 'grid' },
711
+ active: { label: 'Active', type: 'grid' },
712
+ archived: { label: 'Archived', type: 'grid' },
713
+ },
714
+ defaultListView: 'all',
715
+ };
716
+
717
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
718
+
719
+ const tabs = screen.getAllByRole('tab');
720
+ expect(tabs).toHaveLength(3);
721
+ });
722
+
723
+ it('marks default named view tab as active', () => {
724
+ const schema: ObjectViewSchema = {
725
+ type: 'object-view',
726
+ objectName: 'contacts',
727
+ listViews: {
728
+ all: { label: 'All Contacts', type: 'grid' },
729
+ active: { label: 'Active', type: 'grid' },
730
+ },
731
+ defaultListView: 'all',
732
+ };
733
+
734
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
735
+
736
+ const tabs = screen.getAllByRole('tab');
737
+ const allTab = tabs.find((t) => t.textContent?.includes('All Contacts'));
738
+ expect(allTab!.getAttribute('aria-selected')).toBe('true');
739
+ });
740
+
741
+ it('does not render tablist when only one named view exists', () => {
742
+ const schema: ObjectViewSchema = {
743
+ type: 'object-view',
744
+ objectName: 'contacts',
745
+ listViews: {
746
+ all: { label: 'All Contacts', type: 'grid' },
747
+ },
748
+ };
749
+
750
+ render(<ObjectView schema={schema} dataSource={mockDataSource} />);
751
+
752
+ expect(screen.queryByRole('tablist')).toBeNull();
753
+ });
754
+ });
755
+ });
package/vite.config.ts CHANGED
@@ -9,6 +9,7 @@ export default defineConfig({
9
9
  dts({
10
10
  insertTypesEntry: true,
11
11
  include: ['src'],
12
+ exclude: ['**/*.test.ts', '**/*.test.tsx'],
12
13
  }),
13
14
  ],
14
15
  build: {
@@ -1,8 +0,0 @@
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 {};
@@ -1,8 +0,0 @@
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 {};
@@ -1,8 +0,0 @@
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 {};
@@ -1,8 +0,0 @@
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 {};