@aphexcms/cms-core 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (616) hide show
  1. package/dist/api/api-keys.d.ts +37 -0
  2. package/dist/api/api-keys.d.ts.map +1 -0
  3. package/dist/api/api-keys.js +20 -0
  4. package/dist/api/assets.d.ts +27 -0
  5. package/dist/api/assets.d.ts.map +1 -1
  6. package/dist/api/assets.js +22 -1
  7. package/dist/api/index.d.ts +8 -0
  8. package/dist/api/index.d.ts.map +1 -1
  9. package/dist/api/index.js +4 -0
  10. package/dist/api/instance.d.ts +17 -0
  11. package/dist/api/instance.d.ts.map +1 -0
  12. package/dist/api/instance.js +21 -0
  13. package/dist/api/invitations.d.ts +37 -0
  14. package/dist/api/invitations.d.ts.map +1 -0
  15. package/dist/api/invitations.js +27 -0
  16. package/dist/api/organizations.d.ts +7 -0
  17. package/dist/api/organizations.d.ts.map +1 -1
  18. package/dist/api/organizations.js +7 -0
  19. package/dist/api/types.d.ts +1 -1
  20. package/dist/api/types.d.ts.map +1 -1
  21. package/dist/api/user.d.ts +23 -0
  22. package/dist/api/user.d.ts.map +1 -0
  23. package/dist/api/user.js +20 -0
  24. package/dist/auth/auth-errors.d.ts +1 -1
  25. package/dist/auth/auth-errors.d.ts.map +1 -1
  26. package/dist/auth/auth-hooks.d.ts.map +1 -1
  27. package/dist/auth/auth-hooks.js +39 -23
  28. package/dist/auth/provider.d.ts +2 -2
  29. package/dist/auth/provider.d.ts.map +1 -1
  30. package/dist/cli/generate-types.d.ts +14 -0
  31. package/dist/cli/generate-types.d.ts.map +1 -0
  32. package/dist/cli/generate-types.js +15 -7
  33. package/dist/cli/generate-types.js.map +1 -0
  34. package/dist/cli/index.d.ts +7 -0
  35. package/dist/cli/index.d.ts.map +1 -0
  36. package/dist/cli/index.js +1 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/client/index.d.ts +1 -0
  39. package/dist/client/index.d.ts.map +1 -1
  40. package/dist/client/index.js +2 -0
  41. package/dist/components/AdminApp.svelte +160 -63
  42. package/dist/components/AdminApp.svelte.d.ts +1 -1
  43. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  44. package/dist/components/admin/AdminLayout.svelte.d.ts +3 -3
  45. package/dist/components/admin/AssetBrowserModal.svelte +66 -0
  46. package/dist/components/admin/AssetBrowserModal.svelte.d.ts +15 -0
  47. package/dist/components/admin/AssetBrowserModal.svelte.d.ts.map +1 -0
  48. package/dist/components/admin/DocumentEditor.svelte +137 -69
  49. package/dist/components/admin/DocumentEditor.svelte.d.ts +1 -1
  50. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  51. package/dist/components/admin/DocumentsSkeleton.svelte +40 -0
  52. package/dist/components/admin/DocumentsSkeleton.svelte.d.ts +7 -0
  53. package/dist/components/admin/DocumentsSkeleton.svelte.d.ts.map +1 -0
  54. package/dist/components/admin/MediaBrowser.svelte +1398 -0
  55. package/dist/components/admin/MediaBrowser.svelte.d.ts +23 -0
  56. package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -0
  57. package/dist/components/admin/ObjectModal.svelte +3 -4
  58. package/dist/components/admin/ObjectModal.svelte.d.ts +1 -1
  59. package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
  60. package/dist/components/admin/SchemaField.svelte +109 -81
  61. package/dist/components/admin/SchemaField.svelte.d.ts +1 -1
  62. package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
  63. package/dist/components/admin/fields/ArrayField.svelte +611 -277
  64. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
  65. package/dist/components/admin/fields/DateField.svelte +3 -2
  66. package/dist/components/admin/fields/DateField.svelte.d.ts.map +1 -1
  67. package/dist/components/admin/fields/DateTimeField.svelte +3 -2
  68. package/dist/components/admin/fields/DateTimeField.svelte.d.ts.map +1 -1
  69. package/dist/components/admin/fields/ImageField.svelte +217 -120
  70. package/dist/components/admin/fields/ImageField.svelte.d.ts +1 -0
  71. package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
  72. package/dist/components/admin/fields/ReferenceField.svelte +11 -6
  73. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  74. package/dist/components/admin/fields/StringField.svelte +2 -1
  75. package/dist/components/admin/fields/StringField.svelte.d.ts.map +1 -1
  76. package/dist/components/index.d.ts +2 -0
  77. package/dist/components/index.d.ts.map +1 -1
  78. package/dist/components/index.js +2 -0
  79. package/dist/components/layout/OrganizationSwitcher.svelte +109 -45
  80. package/dist/components/layout/OrganizationSwitcher.svelte.d.ts.map +1 -1
  81. package/dist/components/layout/Sidebar.svelte +36 -14
  82. package/dist/components/layout/Sidebar.svelte.d.ts +2 -1
  83. package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
  84. package/dist/components/layout/sidebar/AppSidebar.svelte +1 -1
  85. package/dist/components/layout/sidebar/NavMain.svelte +1 -1
  86. package/dist/components/layout/sidebar/NavMain.svelte.d.ts +1 -1
  87. package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +1 -1
  88. package/dist/components/layout/sidebar/NavSecondary.svelte +3 -3
  89. package/dist/components/layout/sidebar/NavUser.svelte +22 -10
  90. package/dist/components/layout/sidebar/NavUser.svelte.d.ts +2 -2
  91. package/dist/components/layout/sidebar/NavUser.svelte.d.ts.map +1 -1
  92. package/dist/db/interfaces/document.d.ts +20 -0
  93. package/dist/db/interfaces/document.d.ts.map +1 -1
  94. package/dist/db/interfaces/index.d.ts +3 -1
  95. package/dist/db/interfaces/index.d.ts.map +1 -1
  96. package/dist/db/interfaces/instance.d.ts +7 -0
  97. package/dist/db/interfaces/instance.d.ts.map +1 -0
  98. package/dist/db/interfaces/instance.js +1 -0
  99. package/dist/db/interfaces/organization.d.ts +1 -0
  100. package/dist/db/interfaces/organization.d.ts.map +1 -1
  101. package/dist/engine.d.ts.map +1 -1
  102. package/dist/engine.js +4 -3
  103. package/dist/field-validation/date-utils.d.ts.map +1 -1
  104. package/dist/field-validation/date-utils.js +12 -11
  105. package/dist/field-validation/rule.d.ts.map +1 -1
  106. package/dist/field-validation/rule.js +11 -10
  107. package/dist/field-validation/utils.d.ts.map +1 -1
  108. package/dist/field-validation/utils.js +16 -15
  109. package/dist/graphql/index.d.ts +23 -0
  110. package/dist/graphql/index.d.ts.map +1 -0
  111. package/dist/graphql/index.js +85 -0
  112. package/dist/graphql/resolvers.d.ts +4 -0
  113. package/dist/graphql/resolvers.d.ts.map +1 -0
  114. package/dist/graphql/resolvers.js +542 -0
  115. package/dist/graphql/schema.d.ts +3 -0
  116. package/dist/graphql/schema.d.ts.map +1 -0
  117. package/dist/graphql/schema.js +356 -0
  118. package/dist/hooks.d.ts +2 -0
  119. package/dist/hooks.d.ts.map +1 -1
  120. package/dist/hooks.js +62 -9
  121. package/dist/lib/api/api-keys.d.ts +37 -0
  122. package/dist/lib/api/api-keys.d.ts.map +1 -0
  123. package/dist/lib/api/api-keys.js +21 -0
  124. package/dist/lib/api/api-keys.js.map +1 -0
  125. package/dist/lib/api/assets.d.ts +75 -0
  126. package/dist/lib/api/assets.d.ts.map +1 -0
  127. package/dist/lib/api/assets.js +74 -0
  128. package/dist/lib/api/assets.js.map +1 -0
  129. package/dist/lib/api/client.d.ts +37 -0
  130. package/dist/lib/api/client.d.ts.map +1 -0
  131. package/dist/lib/api/client.js +132 -0
  132. package/dist/lib/api/client.js.map +1 -0
  133. package/dist/lib/api/documents.d.ts +57 -0
  134. package/dist/lib/api/documents.d.ts.map +1 -0
  135. package/dist/lib/api/documents.js +86 -0
  136. package/dist/lib/api/documents.js.map +1 -0
  137. package/dist/lib/api/index.d.ts +15 -0
  138. package/dist/lib/api/index.d.ts.map +1 -0
  139. package/dist/lib/api/index.js +10 -0
  140. package/dist/lib/api/index.js.map +1 -0
  141. package/dist/lib/api/instance.d.ts +17 -0
  142. package/dist/lib/api/instance.d.ts.map +1 -0
  143. package/dist/lib/api/instance.js +22 -0
  144. package/dist/lib/api/instance.js.map +1 -0
  145. package/dist/lib/api/invitations.d.ts +37 -0
  146. package/dist/lib/api/invitations.d.ts.map +1 -0
  147. package/dist/lib/api/invitations.js +28 -0
  148. package/dist/lib/api/invitations.js.map +1 -0
  149. package/dist/lib/api/organizations.d.ts +108 -0
  150. package/dist/lib/api/organizations.d.ts.map +1 -0
  151. package/dist/lib/api/organizations.js +100 -0
  152. package/dist/lib/api/organizations.js.map +1 -0
  153. package/dist/lib/api/types.d.ts +47 -0
  154. package/dist/lib/api/types.d.ts.map +1 -0
  155. package/dist/lib/api/types.js +2 -0
  156. package/dist/lib/api/types.js.map +1 -0
  157. package/dist/lib/api/user.d.ts +23 -0
  158. package/dist/lib/api/user.d.ts.map +1 -0
  159. package/dist/lib/api/user.js +21 -0
  160. package/dist/lib/api/user.js.map +1 -0
  161. package/dist/lib/auth/auth-errors.d.ts +7 -0
  162. package/dist/lib/auth/auth-errors.d.ts.map +1 -0
  163. package/dist/lib/auth/auth-errors.js +14 -0
  164. package/dist/lib/auth/auth-errors.js.map +1 -0
  165. package/dist/lib/auth/auth-hooks.d.ts +6 -0
  166. package/dist/lib/auth/auth-hooks.d.ts.map +1 -0
  167. package/dist/lib/auth/auth-hooks.js +139 -0
  168. package/dist/lib/auth/auth-hooks.js.map +1 -0
  169. package/dist/lib/auth/provider.d.ts +17 -0
  170. package/dist/lib/auth/provider.d.ts.map +1 -0
  171. package/dist/lib/auth/provider.js +1 -0
  172. package/dist/lib/auth/provider.js.map +1 -0
  173. package/dist/lib/client/index.d.ts +24 -0
  174. package/dist/lib/client/index.d.ts.map +1 -0
  175. package/dist/lib/client/index.js +33 -0
  176. package/dist/lib/client/index.js.map +1 -0
  177. package/dist/lib/components/fields/index.d.ts +9 -0
  178. package/dist/lib/components/fields/index.d.ts.map +1 -0
  179. package/dist/lib/components/fields/index.js +10 -0
  180. package/dist/lib/components/fields/index.js.map +1 -0
  181. package/dist/lib/components/index.d.ts +8 -0
  182. package/dist/lib/components/index.d.ts.map +1 -0
  183. package/dist/lib/components/index.js +14 -0
  184. package/dist/lib/components/index.js.map +1 -0
  185. package/dist/lib/config.d.ts +3 -0
  186. package/dist/lib/config.d.ts.map +1 -0
  187. package/dist/lib/config.js +16 -0
  188. package/dist/lib/config.js.map +1 -0
  189. package/dist/lib/db/adapters/index.d.ts +1 -0
  190. package/dist/lib/db/adapters/index.d.ts.map +1 -0
  191. package/dist/lib/db/adapters/index.js +5 -0
  192. package/dist/lib/db/adapters/index.js.map +1 -0
  193. package/dist/lib/db/index.d.ts +2 -0
  194. package/dist/lib/db/index.d.ts.map +1 -0
  195. package/dist/lib/db/index.js +1 -0
  196. package/dist/lib/db/index.js.map +1 -0
  197. package/dist/lib/db/interfaces/asset.d.ts +73 -0
  198. package/dist/lib/db/interfaces/asset.d.ts.map +1 -0
  199. package/dist/lib/db/interfaces/asset.js +1 -0
  200. package/dist/lib/db/interfaces/asset.js.map +1 -0
  201. package/dist/lib/db/interfaces/document.d.ts +79 -0
  202. package/dist/lib/db/interfaces/document.d.ts.map +1 -0
  203. package/dist/lib/db/interfaces/document.js +1 -0
  204. package/dist/lib/db/interfaces/document.js.map +1 -0
  205. package/dist/lib/db/interfaces/index.d.ts +76 -0
  206. package/dist/lib/db/interfaces/index.d.ts.map +1 -0
  207. package/dist/lib/db/interfaces/index.js +1 -0
  208. package/dist/lib/db/interfaces/index.js.map +1 -0
  209. package/dist/lib/db/interfaces/instance.d.ts +7 -0
  210. package/dist/lib/db/interfaces/instance.d.ts.map +1 -0
  211. package/dist/lib/db/interfaces/instance.js +2 -0
  212. package/dist/lib/db/interfaces/instance.js.map +1 -0
  213. package/dist/lib/db/interfaces/organization.d.ts +28 -0
  214. package/dist/lib/db/interfaces/organization.d.ts.map +1 -0
  215. package/dist/lib/db/interfaces/organization.js +1 -0
  216. package/dist/lib/db/interfaces/organization.js.map +1 -0
  217. package/dist/lib/db/interfaces/schema.d.ts +21 -0
  218. package/dist/lib/db/interfaces/schema.d.ts.map +1 -0
  219. package/dist/lib/db/interfaces/schema.js +1 -0
  220. package/dist/lib/db/interfaces/schema.js.map +1 -0
  221. package/dist/lib/db/interfaces/user.d.ts +17 -0
  222. package/dist/lib/db/interfaces/user.d.ts.map +1 -0
  223. package/dist/lib/db/interfaces/user.js +1 -0
  224. package/dist/lib/db/interfaces/user.js.map +1 -0
  225. package/dist/lib/db/utils/reference-resolver.d.ts +18 -0
  226. package/dist/lib/db/utils/reference-resolver.d.ts.map +1 -0
  227. package/dist/lib/db/utils/reference-resolver.js +81 -0
  228. package/dist/lib/db/utils/reference-resolver.js.map +1 -0
  229. package/dist/lib/define.d.ts +3 -0
  230. package/dist/lib/define.d.ts.map +1 -0
  231. package/dist/lib/define.js +5 -0
  232. package/dist/lib/define.js.map +1 -0
  233. package/dist/lib/email/index.d.ts +2 -0
  234. package/dist/lib/email/index.d.ts.map +1 -0
  235. package/dist/lib/email/index.js +1 -0
  236. package/dist/lib/email/index.js.map +1 -0
  237. package/dist/lib/email/interfaces/email.d.ts +42 -0
  238. package/dist/lib/email/interfaces/email.d.ts.map +1 -0
  239. package/dist/lib/email/interfaces/email.js +1 -0
  240. package/dist/lib/email/interfaces/email.js.map +1 -0
  241. package/dist/lib/engine.d.ts +26 -0
  242. package/dist/lib/engine.d.ts.map +1 -0
  243. package/dist/lib/engine.js +71 -0
  244. package/dist/lib/engine.js.map +1 -0
  245. package/dist/lib/field-validation/date-utils.d.ts +30 -0
  246. package/dist/lib/field-validation/date-utils.d.ts.map +1 -0
  247. package/dist/lib/field-validation/date-utils.js +13 -11
  248. package/dist/lib/field-validation/date-utils.js.map +1 -0
  249. package/dist/lib/field-validation/rule.d.ts +55 -0
  250. package/dist/lib/field-validation/rule.d.ts.map +1 -0
  251. package/dist/lib/field-validation/rule.js +12 -10
  252. package/dist/lib/field-validation/rule.js.map +1 -0
  253. package/dist/lib/field-validation/utils.d.ts +43 -0
  254. package/dist/lib/field-validation/utils.d.ts.map +1 -0
  255. package/dist/lib/field-validation/utils.js +17 -15
  256. package/dist/lib/field-validation/utils.js.map +1 -0
  257. package/dist/lib/graphql/index.d.ts +23 -0
  258. package/dist/lib/graphql/index.d.ts.map +1 -0
  259. package/dist/lib/graphql/index.js +86 -0
  260. package/dist/lib/graphql/index.js.map +1 -0
  261. package/dist/lib/graphql/resolvers.d.ts +4 -0
  262. package/dist/lib/graphql/resolvers.d.ts.map +1 -0
  263. package/dist/lib/graphql/resolvers.js +543 -0
  264. package/dist/lib/graphql/resolvers.js.map +1 -0
  265. package/dist/lib/graphql/schema.d.ts +3 -0
  266. package/dist/lib/graphql/schema.d.ts.map +1 -0
  267. package/dist/lib/graphql/schema.js +357 -0
  268. package/dist/lib/graphql/schema.js.map +1 -0
  269. package/dist/lib/hooks.d.ts +27 -0
  270. package/dist/lib/hooks.d.ts.map +1 -0
  271. package/dist/lib/hooks.js +235 -0
  272. package/dist/lib/hooks.js.map +1 -0
  273. package/dist/lib/index.d.ts +2 -0
  274. package/dist/lib/index.d.ts.map +1 -0
  275. package/dist/lib/index.js +5 -0
  276. package/dist/lib/index.js.map +1 -0
  277. package/dist/lib/is-mobile.svelte.d.ts +5 -0
  278. package/dist/lib/is-mobile.svelte.d.ts.map +1 -0
  279. package/dist/lib/is-mobile.svelte.js +8 -0
  280. package/dist/lib/is-mobile.svelte.js.map +1 -0
  281. package/dist/lib/local-api/auth-helpers.d.ts +65 -0
  282. package/dist/lib/local-api/auth-helpers.d.ts.map +1 -0
  283. package/dist/lib/local-api/auth-helpers.js +103 -0
  284. package/dist/lib/local-api/auth-helpers.js.map +1 -0
  285. package/dist/lib/local-api/collection-api.d.ts +150 -0
  286. package/dist/lib/local-api/collection-api.d.ts.map +1 -0
  287. package/dist/lib/local-api/collection-api.js +311 -0
  288. package/dist/lib/local-api/collection-api.js.map +1 -0
  289. package/dist/lib/local-api/index.d.ts +108 -0
  290. package/dist/lib/local-api/index.d.ts.map +1 -0
  291. package/dist/lib/local-api/index.js +158 -0
  292. package/dist/lib/local-api/index.js.map +1 -0
  293. package/dist/lib/local-api/permissions.d.ts +45 -0
  294. package/dist/lib/local-api/permissions.d.ts.map +1 -0
  295. package/dist/lib/local-api/permissions.js +117 -0
  296. package/dist/lib/local-api/permissions.js.map +1 -0
  297. package/dist/lib/local-api/types.d.ts +65 -0
  298. package/dist/lib/local-api/types.d.ts.map +1 -0
  299. package/dist/lib/local-api/types.js +5 -0
  300. package/dist/lib/local-api/types.js.map +1 -0
  301. package/dist/lib/routes/assets-bulk.d.ts +3 -0
  302. package/dist/lib/routes/assets-bulk.d.ts.map +1 -0
  303. package/dist/lib/routes/assets-bulk.js +49 -0
  304. package/dist/lib/routes/assets-bulk.js.map +1 -0
  305. package/dist/lib/routes/assets-by-id.d.ts +5 -0
  306. package/dist/lib/routes/assets-by-id.d.ts.map +1 -0
  307. package/dist/lib/routes/assets-by-id.js +106 -0
  308. package/dist/lib/routes/assets-by-id.js.map +1 -0
  309. package/dist/lib/routes/assets-cdn.d.ts +3 -0
  310. package/dist/lib/routes/assets-cdn.d.ts.map +1 -0
  311. package/dist/lib/routes/assets-cdn.js +125 -0
  312. package/dist/lib/routes/assets-cdn.js.map +1 -0
  313. package/dist/lib/routes/assets-references-counts.d.ts +7 -0
  314. package/dist/lib/routes/assets-references-counts.d.ts.map +1 -0
  315. package/dist/lib/routes/assets-references-counts.js +32 -0
  316. package/dist/lib/routes/assets-references-counts.js.map +1 -0
  317. package/dist/lib/routes/assets-references.d.ts +7 -0
  318. package/dist/lib/routes/assets-references.d.ts.map +1 -0
  319. package/dist/lib/routes/assets-references.js +35 -0
  320. package/dist/lib/routes/assets-references.js.map +1 -0
  321. package/dist/lib/routes/assets.d.ts +4 -0
  322. package/dist/lib/routes/assets.d.ts.map +1 -0
  323. package/dist/lib/routes/assets.js +121 -0
  324. package/dist/lib/routes/assets.js.map +1 -0
  325. package/dist/lib/routes/documents-by-id.d.ts +5 -0
  326. package/dist/lib/routes/documents-by-id.d.ts.map +1 -0
  327. package/dist/lib/routes/documents-by-id.js +176 -0
  328. package/dist/lib/routes/documents-by-id.js.map +1 -0
  329. package/dist/lib/routes/documents-publish.d.ts +4 -0
  330. package/dist/lib/routes/documents-publish.d.ts.map +1 -0
  331. package/dist/lib/routes/documents-publish.js +138 -0
  332. package/dist/lib/routes/documents-publish.js.map +1 -0
  333. package/dist/lib/routes/documents-query.d.ts +26 -0
  334. package/dist/lib/routes/documents-query.d.ts.map +1 -0
  335. package/dist/lib/routes/documents-query.js +101 -0
  336. package/dist/lib/routes/documents-query.js.map +1 -0
  337. package/dist/lib/routes/documents.d.ts +4 -0
  338. package/dist/lib/routes/documents.d.ts.map +1 -0
  339. package/dist/lib/routes/documents.js +154 -0
  340. package/dist/lib/routes/documents.js.map +1 -0
  341. package/dist/lib/routes/index.d.ts +9 -0
  342. package/dist/lib/routes/index.d.ts.map +1 -0
  343. package/dist/lib/routes/index.js +15 -0
  344. package/dist/lib/routes/index.js.map +1 -0
  345. package/dist/lib/routes/organizations-by-id.d.ts +5 -0
  346. package/dist/lib/routes/organizations-by-id.d.ts.map +1 -0
  347. package/dist/lib/routes/organizations-by-id.js +189 -0
  348. package/dist/lib/routes/organizations-by-id.js.map +1 -0
  349. package/dist/lib/routes/organizations-invitations.d.ts +4 -0
  350. package/dist/lib/routes/organizations-invitations.d.ts.map +1 -0
  351. package/dist/lib/routes/organizations-invitations.js +127 -0
  352. package/dist/lib/routes/organizations-invitations.js.map +1 -0
  353. package/dist/lib/routes/organizations-members.d.ts +5 -0
  354. package/dist/lib/routes/organizations-members.d.ts.map +1 -0
  355. package/dist/lib/routes/organizations-members.js +208 -0
  356. package/dist/lib/routes/organizations-members.js.map +1 -0
  357. package/dist/lib/routes/organizations-switch.d.ts +3 -0
  358. package/dist/lib/routes/organizations-switch.d.ts.map +1 -0
  359. package/dist/lib/routes/organizations-switch.js +55 -0
  360. package/dist/lib/routes/organizations-switch.js.map +1 -0
  361. package/dist/lib/routes/organizations.d.ts +4 -0
  362. package/dist/lib/routes/organizations.d.ts.map +1 -0
  363. package/dist/lib/routes/organizations.js +111 -0
  364. package/dist/lib/routes/organizations.js.map +1 -0
  365. package/dist/lib/routes/schemas-by-type.d.ts +3 -0
  366. package/dist/lib/routes/schemas-by-type.d.ts.map +1 -0
  367. package/dist/lib/routes/schemas-by-type.js +27 -0
  368. package/dist/lib/routes/schemas-by-type.js.map +1 -0
  369. package/dist/lib/routes/schemas.d.ts +3 -0
  370. package/dist/lib/routes/schemas.d.ts.map +1 -0
  371. package/dist/lib/routes/schemas.js +12 -0
  372. package/dist/lib/routes/schemas.js.map +1 -0
  373. package/dist/lib/routes/user-preferences.d.ts +4 -0
  374. package/dist/lib/routes/user-preferences.d.ts.map +1 -0
  375. package/dist/lib/routes/user-preferences.js +79 -0
  376. package/dist/lib/routes/user-preferences.js.map +1 -0
  377. package/dist/lib/routes-exports.d.ts +17 -0
  378. package/dist/lib/routes-exports.d.ts.map +1 -0
  379. package/dist/lib/routes-exports.js +23 -0
  380. package/dist/lib/routes-exports.js.map +1 -0
  381. package/dist/lib/schema/index.d.ts +6 -0
  382. package/dist/lib/schema/index.d.ts.map +1 -0
  383. package/dist/lib/schema/index.js +12 -0
  384. package/dist/lib/schema/index.js.map +1 -0
  385. package/dist/lib/schema-context.svelte.d.ts +10 -0
  386. package/dist/lib/schema-context.svelte.d.ts.map +1 -0
  387. package/dist/lib/schema-context.svelte.js +19 -0
  388. package/dist/lib/schema-context.svelte.js.map +1 -0
  389. package/dist/lib/schema-utils/cleanup.d.ts +21 -0
  390. package/dist/lib/schema-utils/cleanup.d.ts.map +1 -0
  391. package/dist/lib/schema-utils/cleanup.js +81 -0
  392. package/dist/lib/schema-utils/cleanup.js.map +1 -0
  393. package/dist/lib/schema-utils/index.d.ts +4 -0
  394. package/dist/lib/schema-utils/index.d.ts.map +1 -0
  395. package/dist/lib/schema-utils/index.js +5 -0
  396. package/dist/lib/schema-utils/index.js.map +1 -0
  397. package/dist/lib/schema-utils/utils.d.ts +34 -0
  398. package/dist/lib/schema-utils/utils.d.ts.map +1 -0
  399. package/dist/lib/schema-utils/utils.js +59 -0
  400. package/dist/lib/schema-utils/utils.js.map +1 -0
  401. package/dist/lib/schema-utils/validator.d.ts +10 -0
  402. package/dist/lib/schema-utils/validator.d.ts.map +1 -0
  403. package/dist/lib/schema-utils/validator.js +167 -0
  404. package/dist/lib/schema-utils/validator.js.map +1 -0
  405. package/dist/lib/server/index.d.ts +19 -0
  406. package/dist/lib/server/index.d.ts.map +1 -0
  407. package/dist/lib/server/index.js +35 -0
  408. package/dist/lib/server/index.js.map +1 -0
  409. package/dist/lib/services/asset-service.d.ts +86 -0
  410. package/dist/lib/services/asset-service.d.ts.map +1 -0
  411. package/dist/lib/services/asset-service.js +189 -0
  412. package/dist/lib/services/asset-service.js.map +1 -0
  413. package/dist/lib/services/index.d.ts +3 -0
  414. package/dist/lib/services/index.d.ts.map +1 -0
  415. package/dist/lib/services/index.js +5 -0
  416. package/dist/lib/services/index.js.map +1 -0
  417. package/dist/lib/storage/adapters/index.d.ts +2 -0
  418. package/dist/lib/storage/adapters/index.d.ts.map +1 -0
  419. package/dist/lib/storage/adapters/index.js +3 -0
  420. package/dist/lib/storage/adapters/index.js.map +1 -0
  421. package/dist/lib/storage/adapters/local-storage-adapter.d.ts +54 -0
  422. package/dist/lib/storage/adapters/local-storage-adapter.d.ts.map +1 -0
  423. package/dist/lib/storage/adapters/local-storage-adapter.js +189 -0
  424. package/dist/lib/storage/adapters/local-storage-adapter.js.map +1 -0
  425. package/dist/lib/storage/index.d.ts +3 -0
  426. package/dist/lib/storage/index.d.ts.map +1 -0
  427. package/dist/lib/storage/index.js +7 -0
  428. package/dist/lib/storage/index.js.map +1 -0
  429. package/dist/lib/storage/interfaces/index.d.ts +2 -0
  430. package/dist/lib/storage/interfaces/index.d.ts.map +1 -0
  431. package/dist/lib/storage/interfaces/index.js +1 -0
  432. package/dist/lib/storage/interfaces/index.js.map +1 -0
  433. package/dist/lib/storage/interfaces/storage.d.ts +91 -0
  434. package/dist/lib/storage/interfaces/storage.d.ts.map +1 -0
  435. package/dist/lib/storage/interfaces/storage.js +1 -0
  436. package/dist/lib/storage/interfaces/storage.js.map +1 -0
  437. package/dist/lib/storage/providers/storage.d.ts +43 -0
  438. package/dist/lib/storage/providers/storage.d.ts.map +1 -0
  439. package/dist/lib/storage/providers/storage.js +65 -0
  440. package/dist/lib/storage/providers/storage.js.map +1 -0
  441. package/dist/lib/types/asset.d.ts +73 -0
  442. package/dist/lib/types/asset.d.ts.map +1 -0
  443. package/dist/lib/types/asset.js +1 -0
  444. package/dist/lib/types/asset.js.map +1 -0
  445. package/dist/lib/types/auth.d.ts +62 -0
  446. package/dist/lib/types/auth.d.ts.map +1 -0
  447. package/dist/lib/types/auth.js +7 -5
  448. package/dist/lib/types/auth.js.map +1 -0
  449. package/dist/lib/types/config.d.ts +77 -0
  450. package/dist/lib/types/config.d.ts.map +1 -0
  451. package/dist/lib/types/config.js +1 -0
  452. package/dist/lib/types/config.js.map +1 -0
  453. package/dist/lib/types/document.d.ts +35 -0
  454. package/dist/lib/types/document.d.ts.map +1 -0
  455. package/dist/lib/types/document.js +1 -0
  456. package/dist/lib/types/document.js.map +1 -0
  457. package/dist/lib/types/filters.d.ts +186 -0
  458. package/dist/lib/types/filters.d.ts.map +1 -0
  459. package/dist/lib/types/filters.js +1 -0
  460. package/dist/lib/types/filters.js.map +1 -0
  461. package/dist/lib/types/index.d.ts +11 -0
  462. package/dist/lib/types/index.d.ts.map +1 -0
  463. package/dist/lib/types/index.js +2 -0
  464. package/dist/lib/types/index.js.map +1 -0
  465. package/dist/lib/types/instance.d.ts +5 -0
  466. package/dist/lib/types/instance.d.ts.map +1 -0
  467. package/dist/lib/types/instance.js +3 -0
  468. package/dist/lib/types/instance.js.map +1 -0
  469. package/dist/lib/types/organization.d.ts +108 -0
  470. package/dist/lib/types/organization.d.ts.map +1 -0
  471. package/dist/lib/types/organization.js +1 -0
  472. package/dist/lib/types/organization.js.map +1 -0
  473. package/dist/lib/types/schemas.d.ts +179 -0
  474. package/dist/lib/types/schemas.d.ts.map +1 -0
  475. package/dist/lib/types/schemas.js +1 -0
  476. package/dist/lib/types/schemas.js.map +1 -0
  477. package/dist/lib/types/sidebar.d.ts +34 -0
  478. package/dist/lib/types/sidebar.d.ts.map +1 -0
  479. package/dist/lib/types/sidebar.js +1 -0
  480. package/dist/lib/types/sidebar.js.map +1 -0
  481. package/dist/lib/types/user.d.ts +14 -0
  482. package/dist/lib/types/user.d.ts.map +1 -0
  483. package/dist/lib/types/user.js +1 -0
  484. package/dist/lib/types/user.js.map +1 -0
  485. package/dist/lib/utils/asset-actions.d.ts +9 -0
  486. package/dist/lib/utils/asset-actions.d.ts.map +1 -0
  487. package/dist/lib/utils/asset-actions.js +28 -0
  488. package/dist/lib/utils/asset-actions.js.map +1 -0
  489. package/dist/lib/utils/content-hash.d.ts +22 -0
  490. package/dist/lib/utils/content-hash.d.ts.map +1 -0
  491. package/dist/lib/utils/content-hash.js +68 -0
  492. package/dist/lib/utils/content-hash.js.map +1 -0
  493. package/dist/lib/utils/default-orderings.d.ts +10 -0
  494. package/dist/lib/utils/default-orderings.d.ts.map +1 -0
  495. package/dist/lib/utils/default-orderings.js +64 -0
  496. package/dist/lib/utils/default-orderings.js.map +1 -0
  497. package/dist/lib/utils/element-events.d.ts +15 -0
  498. package/dist/lib/utils/element-events.d.ts.map +1 -0
  499. package/dist/lib/utils/element-events.js +17 -0
  500. package/dist/lib/utils/element-events.js.map +1 -0
  501. package/dist/lib/utils/field-defaults.d.ts +8 -0
  502. package/dist/lib/utils/field-defaults.d.ts.map +1 -0
  503. package/dist/lib/utils/field-defaults.js +21 -0
  504. package/dist/lib/utils/field-defaults.js.map +1 -0
  505. package/dist/lib/utils/image-url.d.ts +88 -0
  506. package/dist/lib/utils/image-url.d.ts.map +1 -0
  507. package/dist/lib/utils/image-url.js +167 -0
  508. package/dist/lib/utils/image-url.js.map +1 -0
  509. package/dist/lib/utils/index.d.ts +8 -0
  510. package/dist/lib/utils/index.d.ts.map +1 -0
  511. package/dist/lib/utils/index.js +13 -0
  512. package/dist/lib/utils/index.js.map +1 -0
  513. package/dist/lib/utils/initial-value-helpers.d.ts +50 -0
  514. package/dist/lib/utils/initial-value-helpers.d.ts.map +1 -0
  515. package/dist/lib/utils/initial-value-helpers.js +71 -0
  516. package/dist/lib/utils/initial-value-helpers.js.map +1 -0
  517. package/dist/lib/utils/logger.d.ts +9 -0
  518. package/dist/lib/utils/logger.d.ts.map +1 -0
  519. package/dist/lib/utils/logger.js +30 -0
  520. package/dist/lib/utils/logger.js.map +1 -0
  521. package/dist/lib/utils/slug.d.ts +13 -0
  522. package/dist/lib/utils/slug.d.ts.map +1 -0
  523. package/dist/lib/utils/slug.js +31 -0
  524. package/dist/lib/utils/slug.js.map +1 -0
  525. package/dist/lib/utils.d.ts +13 -0
  526. package/dist/lib/utils.d.ts.map +1 -0
  527. package/dist/lib/utils.js +6 -0
  528. package/dist/lib/utils.js.map +1 -0
  529. package/dist/local-api/index.d.ts.map +1 -1
  530. package/dist/local-api/permissions.d.ts.map +1 -1
  531. package/dist/local-api/permissions.js +3 -4
  532. package/dist/routes/assets-bulk.d.ts +3 -0
  533. package/dist/routes/assets-bulk.d.ts.map +1 -0
  534. package/dist/routes/assets-bulk.js +48 -0
  535. package/dist/routes/assets-by-id.d.ts.map +1 -1
  536. package/dist/routes/assets-by-id.js +22 -55
  537. package/dist/routes/assets-cdn.d.ts.map +1 -1
  538. package/dist/routes/assets-cdn.js +12 -50
  539. package/dist/routes/assets-references-counts.d.ts +7 -0
  540. package/dist/routes/assets-references-counts.d.ts.map +1 -0
  541. package/dist/routes/assets-references-counts.js +31 -0
  542. package/dist/routes/assets-references.d.ts +7 -0
  543. package/dist/routes/assets-references.d.ts.map +1 -0
  544. package/dist/routes/assets-references.js +34 -0
  545. package/dist/routes/assets.d.ts.map +1 -1
  546. package/dist/routes/assets.js +27 -6
  547. package/dist/routes/documents-by-id.d.ts.map +1 -1
  548. package/dist/routes/documents-by-id.js +4 -3
  549. package/dist/routes/documents-publish.d.ts.map +1 -1
  550. package/dist/routes/documents-publish.js +3 -2
  551. package/dist/routes/documents-query.d.ts.map +1 -1
  552. package/dist/routes/documents-query.js +2 -1
  553. package/dist/routes/documents.d.ts.map +1 -1
  554. package/dist/routes/documents.js +3 -2
  555. package/dist/routes/organizations-by-id.d.ts.map +1 -1
  556. package/dist/routes/organizations-by-id.js +4 -3
  557. package/dist/routes/organizations-invitations.d.ts.map +1 -1
  558. package/dist/routes/organizations-invitations.js +5 -4
  559. package/dist/routes/organizations-members.d.ts.map +1 -1
  560. package/dist/routes/organizations-members.js +7 -6
  561. package/dist/routes/organizations-switch.d.ts.map +1 -1
  562. package/dist/routes/organizations-switch.js +2 -1
  563. package/dist/routes/organizations.d.ts.map +1 -1
  564. package/dist/routes/organizations.js +3 -2
  565. package/dist/routes/schemas-by-type.d.ts.map +1 -1
  566. package/dist/routes/schemas-by-type.js +3 -2
  567. package/dist/routes/user-preferences.d.ts.map +1 -1
  568. package/dist/routes/user-preferences.js +3 -2
  569. package/dist/routes-exports.d.ts +3 -0
  570. package/dist/routes-exports.d.ts.map +1 -1
  571. package/dist/routes-exports.js +3 -0
  572. package/dist/schema/index.d.ts +6 -0
  573. package/dist/schema/index.d.ts.map +1 -0
  574. package/dist/schema/index.js +11 -0
  575. package/dist/schema-utils/validator.d.ts.map +1 -1
  576. package/dist/schema-utils/validator.js +4 -3
  577. package/dist/server/index.d.ts +2 -0
  578. package/dist/server/index.d.ts.map +1 -1
  579. package/dist/server/index.js +4 -0
  580. package/dist/services/asset-service.d.ts.map +1 -1
  581. package/dist/services/asset-service.js +8 -7
  582. package/dist/storage/adapters/local-storage-adapter.d.ts.map +1 -1
  583. package/dist/storage/adapters/local-storage-adapter.js +5 -4
  584. package/dist/types/auth.d.ts +13 -1
  585. package/dist/types/auth.d.ts.map +1 -1
  586. package/dist/types/auth.js +6 -5
  587. package/dist/types/config.d.ts +14 -1
  588. package/dist/types/config.d.ts.map +1 -1
  589. package/dist/types/document.d.ts +1 -1
  590. package/dist/types/document.d.ts.map +1 -1
  591. package/dist/types/index.d.ts +1 -0
  592. package/dist/types/index.d.ts.map +1 -1
  593. package/dist/types/index.js +1 -0
  594. package/dist/types/instance.d.ts +5 -0
  595. package/dist/types/instance.d.ts.map +1 -0
  596. package/dist/types/instance.js +2 -0
  597. package/dist/types/schemas.d.ts +1 -1
  598. package/dist/types/schemas.d.ts.map +1 -1
  599. package/dist/types/sidebar.d.ts +1 -0
  600. package/dist/types/sidebar.d.ts.map +1 -1
  601. package/dist/utils/asset-actions.d.ts +9 -0
  602. package/dist/utils/asset-actions.d.ts.map +1 -0
  603. package/dist/utils/asset-actions.js +27 -0
  604. package/dist/utils/element-events.d.ts +15 -0
  605. package/dist/utils/element-events.d.ts.map +1 -0
  606. package/dist/utils/element-events.js +16 -0
  607. package/dist/utils/image-url.d.ts.map +1 -1
  608. package/dist/utils/image-url.js +10 -9
  609. package/dist/utils/index.d.ts +1 -0
  610. package/dist/utils/index.d.ts.map +1 -1
  611. package/dist/utils/index.js +2 -0
  612. package/dist/utils/logger.d.ts +9 -0
  613. package/dist/utils/logger.d.ts.map +1 -0
  614. package/dist/utils/logger.js +29 -0
  615. package/package.json +132 -103
  616. package/LICENSE +0 -21
@@ -11,6 +11,23 @@
11
11
  import ObjectModal from '../ObjectModal.svelte';
12
12
  import ImageField from './ImageField.svelte';
13
13
  import { getDefaultValueForFieldType } from '../../../utils/field-defaults';
14
+ import { DragDropProvider } from '@dnd-kit/svelte';
15
+ import { createSortable, isSortable } from '@dnd-kit/svelte/sortable';
16
+ import { arrayMove } from '@dnd-kit/helpers';
17
+ import {
18
+ GripVertical,
19
+ Ellipsis,
20
+ Pencil,
21
+ Trash2,
22
+ FileText,
23
+ Plus,
24
+ Upload,
25
+ Image as ImageIcon
26
+ } from '@lucide/svelte';
27
+ import { assets } from '../../../api/assets';
28
+ import type { ImageValue } from '../../../types/asset';
29
+ import { toast } from 'svelte-sonner';
30
+ import AssetBrowserModal from '../AssetBrowserModal.svelte';
14
31
 
15
32
  interface Props {
16
33
  field: ArrayFieldType;
@@ -18,7 +35,7 @@
18
35
  onUpdate: (value: any) => void;
19
36
  onOpenReference?: (documentId: string, documentType: string) => void;
20
37
  readonly?: boolean;
21
- organizationId?: string; // For asset uploads to org-specific storage
38
+ organizationId?: string;
22
39
  }
23
40
 
24
41
  let {
@@ -30,19 +47,14 @@
30
47
  organizationId
31
48
  }: Props = $props();
32
49
 
33
- // Get schemas from context
34
50
  const schemas = getSchemaContext();
35
51
 
36
- // Get schema for a type - either from inline definition or registry
37
52
  function getSchemaForType(typeName: string): SchemaType | null {
38
- // First check if this type has an inline definition in field.of
39
- // Match by name OR type (since inline objects might use either)
40
53
  const inlineDef = field.of?.find(
41
54
  (ref) => (ref.name && ref.name === typeName) || ref.type === typeName
42
55
  );
43
56
 
44
57
  if (inlineDef && inlineDef.fields) {
45
- // Create a temporary SchemaType from inline definition
46
58
  return {
47
59
  type: 'object',
48
60
  name: inlineDef.name || typeName,
@@ -51,25 +63,20 @@
51
63
  };
52
64
  }
53
65
 
54
- // Otherwise look it up in the schema registry
55
66
  return getSchemaByName(schemas, typeName);
56
67
  }
57
68
 
58
- // Determine if this is a primitive array or object array
59
- // If the type is not found in schemas AND has no inline fields, it's a primitive type
60
69
  const isPrimitiveArray = $derived(
61
70
  field.of &&
62
71
  field.of.length > 0 &&
63
72
  field.of[0]?.type &&
64
- !field.of[0].fields && // Not an inline object
65
- !getSchemaByName(schemas, field.of[0].type) // Not in registry
73
+ !field.of[0].fields &&
74
+ !getSchemaByName(schemas, field.of[0].type)
66
75
  );
67
76
  const primitiveType = $derived(isPrimitiveArray ? field.of?.[0]?.type : null);
68
-
69
- // Get available types for this array field (for object arrays)
70
77
  const availableTypes = $derived(getArrayTypes(schemas, field));
71
78
 
72
- // Modal state (for object arrays)
79
+ // Modal state
73
80
  let modalOpen = $state(false);
74
81
  let editingIndex = $state<number | null>(null);
75
82
  let editingType = $state<string | null>(null);
@@ -79,22 +86,117 @@
79
86
  // Image modal state
80
87
  let imageModalOpen = $state(false);
81
88
  let imageModalValue = $state<any>(null);
89
+ let imageModalIndex = $state<number | null>(null);
90
+ function handleOpenImageModal(index: number) {
91
+ imageModalIndex = index;
92
+ imageModalValue = arrayValue[index];
93
+ imageModalOpen = true;
94
+ }
95
+
96
+ // Text editing modal state
97
+ let textModalOpen = $state(false);
98
+ let textModalIndex = $state<number | null>(null);
99
+ let textModalValue = $state('');
100
+
101
+ function handleOpenTextModal(index: number) {
102
+ textModalIndex = index;
103
+ textModalValue = arrayValue[index] ?? '';
104
+ textModalOpen = true;
105
+ }
106
+
107
+ function handleTextModalSave() {
108
+ if (textModalIndex !== null) {
109
+ handleUpdatePrimitive(textModalIndex, textModalValue);
110
+ }
111
+ textModalOpen = false;
112
+ textModalIndex = null;
113
+ }
114
+
115
+ function handleTextModalClose() {
116
+ textModalOpen = false;
117
+ textModalIndex = null;
118
+ }
82
119
 
83
- // Ensure value is always an array
84
120
  const arrayValue = $derived(Array.isArray(value) ? value : []);
85
121
 
122
+ function generateKey(): string {
123
+ return Math.random().toString(36).substring(2, 9);
124
+ }
125
+
126
+ // Stable key cache for object items that arrive without _key
127
+ const keyCache = new WeakMap<object, string>();
128
+
129
+ // Keyed items — ensures every object item has a _key before rendering
130
+ const keyedItems = $derived.by(() => {
131
+ if (isPrimitiveArray) return arrayValue;
132
+ return arrayValue.map((item: any) => {
133
+ if (item && typeof item === 'object' && !item._key) {
134
+ let cachedKey = keyCache.get(item);
135
+ if (!cachedKey) {
136
+ cachedKey = generateKey();
137
+ keyCache.set(item, cachedKey);
138
+ }
139
+ return { ...item, _key: cachedKey };
140
+ }
141
+ return item;
142
+ });
143
+ });
144
+
145
+ // Persist generated keys back to parent state
146
+ $effect(() => {
147
+ if (isPrimitiveArray) return;
148
+ const hasUnkeyed = arrayValue.some(
149
+ (item: any) => item && typeof item === 'object' && !item._key
150
+ );
151
+ if (hasUnkeyed) {
152
+ onUpdate(keyedItems);
153
+ }
154
+ });
155
+
156
+ // Key to force DragDropProvider remount after reorder, clearing stale transforms
157
+ let dndKey = $state(0);
158
+
159
+ // Drag-and-drop handler for object arrays
160
+ function handleDragEnd(event: any) {
161
+ const { source } = event.operation;
162
+ if (!source || !isSortable(source)) return;
163
+
164
+ const fromIndex = (source as any).initialIndex as number;
165
+ const toIndex = source.index;
166
+
167
+ if (fromIndex === toIndex) return;
168
+
169
+ const reordered = arrayMove([...keyedItems], fromIndex, toIndex);
170
+ onUpdate(reordered);
171
+ dndKey++;
172
+ }
173
+
174
+ // Drag-and-drop handler for primitive arrays
175
+ function handlePrimitiveDragEnd(event: any) {
176
+ const { source } = event.operation;
177
+ if (!source || !isSortable(source)) return;
178
+
179
+ const fromIndex = (source as any).initialIndex as number;
180
+ const toIndex = source.index;
181
+
182
+ if (fromIndex === toIndex) return;
183
+
184
+ const reordered = arrayMove([...arrayValue], fromIndex, toIndex);
185
+ onUpdate(reordered);
186
+ dndKey++;
187
+ }
188
+
86
189
  // Primitive array functions
87
190
  function handleAddPrimitive() {
88
191
  if (readonly) return;
89
192
 
90
- // For images, open the modal
91
193
  if (primitiveType === 'image') {
194
+ imageModalIndex = null;
92
195
  imageModalValue = null;
93
196
  imageModalOpen = true;
94
197
  return;
95
198
  }
96
199
 
97
- // For other primitives, add a new empty item
98
200
  const newArray = [...arrayValue];
99
201
  const defaultValue = primitiveType === 'boolean' ? false : primitiveType === 'number' ? 0 : '';
100
202
  newArray.push(defaultValue);
@@ -111,39 +213,126 @@
111
213
  function handleImageModalClose() {
112
214
  imageModalOpen = false;
113
215
  imageModalValue = null;
216
+ imageModalIndex = null;
114
217
  }
115
218
 
116
219
  function handleImageUpload(newValue: any) {
117
- if (newValue) {
118
- // Auto-add the image to the array
220
+ if (imageModalIndex !== null) {
221
+ // Editing existing image update in place (even if null/cleared)
222
+ const newArray = [...arrayValue];
223
+ newArray[imageModalIndex] = newValue;
224
+ imageModalValue = newValue;
225
+ onUpdate(newArray);
226
+ } else if (newValue) {
227
+ // Adding new image
119
228
  const newArray = [...arrayValue, newValue];
120
229
  onUpdate(newArray);
121
- // Close the modal
230
+ // Close modal after adding new image
122
231
  imageModalOpen = false;
123
232
  imageModalValue = null;
233
+ imageModalIndex = null;
234
+ }
235
+ }
236
+
237
+ // Multi-image upload for image arrays
238
+ let multiFileInputRef = $state<HTMLInputElement>(null!);
239
+ let isMultiUploading = $state(false);
240
+ let uploadProgress = $state({ current: 0, total: 0 });
241
+ let showArrayAssetBrowser = $state(false);
242
+
243
+ // IDs of assets already in the array (for showing ticks in the browser)
244
+ const existingAssetIds = $derived(
245
+ primitiveType === 'image'
246
+ ? new Set(arrayValue.filter((v: any) => v?.asset?._ref).map((v: any) => v.asset._ref))
247
+ : new Set<string>()
248
+ );
249
+
250
+ function openMultiFileDialog() {
251
+ if (readonly) return;
252
+ multiFileInputRef?.click();
253
+ }
254
+
255
+ async function uploadImageFile(file: File): Promise<ImageValue | null> {
256
+ try {
257
+ const formData = new FormData();
258
+ formData.append('file', file);
259
+ if (organizationId) formData.append('organizationId', organizationId);
260
+
261
+ const result = await assets.upload(formData);
262
+ if (!result.success) throw new Error(result.error || 'Upload failed');
263
+
264
+ return {
265
+ _type: 'image',
266
+ _key: generateKey(),
267
+ asset: { _type: 'reference', _ref: result.data!.id }
268
+ };
269
+ } catch (error) {
270
+ toast.error(`Failed to upload ${file.name}`);
271
+ return null;
124
272
  }
125
273
  }
126
274
 
275
+ async function handleMultiFileSelect(files: FileList | null) {
276
+ if (readonly || !files || files.length === 0) return;
277
+
278
+ isMultiUploading = true;
279
+ uploadProgress = { current: 0, total: files.length };
280
+
281
+ const newImages: ImageValue[] = [];
282
+ for (const file of Array.from(files)) {
283
+ uploadProgress.current++;
284
+ const imageValue = await uploadImageFile(file);
285
+ if (imageValue) newImages.push(imageValue);
286
+ }
287
+
288
+ if (newImages.length > 0) {
289
+ onUpdate([...arrayValue, ...newImages]);
290
+ toast.success(`Uploaded ${newImages.length} image${newImages.length > 1 ? 's' : ''}`);
291
+ }
292
+
293
+ isMultiUploading = false;
294
+ uploadProgress = { current: 0, total: 0 };
295
+ // Reset file input so same files can be re-selected
296
+ if (multiFileInputRef) multiFileInputRef.value = '';
297
+ }
298
+
299
+ function handleArrayAssetSelectMultiple(selectedAssets: any[]) {
300
+ const selectedRefIds = new Set(selectedAssets.map((a: any) => a.id));
301
+
302
+ // Keep existing items that are still selected (preserves order & extra data like alt)
303
+ const kept = arrayValue.filter((item: any) => {
304
+ const ref = item?.asset?._ref;
305
+ return ref && selectedRefIds.has(ref);
306
+ });
307
+ const keptIds = new Set(kept.map((item: any) => item.asset._ref));
308
+
309
+ // Add newly selected items
310
+ const added = selectedAssets
311
+ .filter((asset: any) => !keptIds.has(asset.id))
312
+ .map((asset: any) => ({
313
+ _type: 'image' as const,
314
+ _key: generateKey(),
315
+ asset: { _type: 'reference' as const, _ref: asset.id }
316
+ }));
317
+
318
+ onUpdate([...kept, ...added]);
319
+ }
320
+
127
321
  // Object array functions
128
322
  function handleTypeSelected(selectedType: string) {
129
323
  if (readonly || !selectedType) return;
130
324
 
131
- // Get the schema for the selected type (inline or from registry)
132
325
  const schema = getSchemaForType(selectedType);
133
326
  if (!schema) return;
134
327
 
135
- // Initialize empty object with default values
136
- const newItem: Record<string, any> = { _type: selectedType };
328
+ const newItem: Record<string, any> = { _type: selectedType, _key: generateKey() };
137
329
 
138
330
  if (schema.fields) {
139
331
  schema.fields.forEach((field) => {
140
332
  if ('initialValue' in field && field.initialValue !== undefined) {
141
- // Only use literal initialValue (skip functions to keep this synchronous)
142
333
  if (typeof field.initialValue !== 'function') {
143
334
  newItem[field.name] = field.initialValue;
144
335
  } else {
145
- // Function-based initialValues are skipped for nested items
146
- // They will use field type defaults instead
147
336
  newItem[field.name] = getDefaultValueForFieldType(field.type);
148
337
  }
149
338
  } else {
@@ -152,8 +341,7 @@
152
341
  });
153
342
  }
154
343
 
155
- // Set modal state directly
156
- editingIndex = arrayValue.length; // New item index
344
+ editingIndex = arrayValue.length;
157
345
  editingType = selectedType;
158
346
  editingSchema = schema;
159
347
  editingValue = newItem;
@@ -161,7 +349,7 @@
161
349
  }
162
350
 
163
351
  function handleEditItem(index: number) {
164
- const item = arrayValue[index];
352
+ const item = keyedItems[index];
165
353
  if (!item._type) return;
166
354
 
167
355
  const schema = getSchemaForType(item._type);
@@ -172,34 +360,35 @@
172
360
  editingSchema = schema;
173
361
  editingValue = item;
174
362
  modalOpen = true;
175
- console.log('MODAL IS OPEN: ', modalOpen);
176
363
  }
177
364
 
178
365
  function handleRemoveItem(index: number) {
179
366
  if (readonly) return;
180
- const newArray = arrayValue.filter((_, i) => i !== index);
367
+ const newArray = keyedItems.filter((_: any, i: number) => i !== index);
181
368
  onUpdate(newArray);
182
369
  }
183
370
 
184
371
  function handleModalSave(editedData: Record<string, any>) {
185
372
  if (editingIndex === null || !editingType) return;
186
373
 
187
- // Add the type information to the data
188
- const itemData = { ...editedData, _type: editingType };
374
+ const itemData: Record<string, any> = { ...editedData, _type: editingType };
375
+ // Preserve _key if editing existing item
376
+ if ((editingValue as any)._key) {
377
+ itemData._key = (editingValue as any)._key;
378
+ } else {
379
+ itemData._key = generateKey();
380
+ }
189
381
 
190
- const newArray = [...arrayValue];
382
+ const newArray = [...keyedItems];
191
383
 
192
384
  if (editingIndex >= newArray.length) {
193
- // Adding new item
194
385
  newArray.push(itemData);
195
386
  } else {
196
- // Editing existing item
197
387
  newArray[editingIndex] = itemData;
198
388
  }
199
389
 
200
390
  onUpdate(newArray);
201
391
 
202
- // Reset modal state
203
392
  modalOpen = false;
204
393
  editingIndex = null;
205
394
  editingType = null;
@@ -215,14 +404,12 @@
215
404
  editingValue = {};
216
405
  }
217
406
 
218
- // Get the title to display for an item
219
407
  function getItemTitle(item: any): string {
220
408
  if (!item._type) return 'Unknown Item';
221
409
 
222
- const schema = getSchemaByName(schemas, item._type);
410
+ const schema = getSchemaForType(item._type);
223
411
  if (!schema) return item._type;
224
412
 
225
- // Try to find a meaningful field to use as title
226
413
  const titleField = item.title || item.heading || item.name || item.label;
227
414
  if (titleField && typeof titleField === 'string' && titleField.trim()) {
228
415
  return titleField;
@@ -230,267 +417,350 @@
230
417
 
231
418
  return schema.title || item._type;
232
419
  }
420
+
421
+ function getItemIcon(item: any): any {
422
+ if (!item._type) return null;
423
+ const schema = getSchemaByName(schemas, item._type);
424
+ return schema?.icon || null;
425
+ }
233
426
  </script>
234
427
 
235
- <div class="border-border space-y-4 rounded-md border p-4">
236
- <h4 class="text-sm font-medium">{field.title}</h4>
428
+ {#if isPrimitiveArray}
429
+ <!-- Primitive array UI with DnD -->
430
+ {#if arrayValue.length === 0}
431
+ <div
432
+ class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
433
+ >
434
+ <p class="text-muted-foreground text-sm">No items added yet</p>
435
+ </div>
436
+ {:else if primitiveType === 'image'}
437
+ {#key dndKey}
438
+ <DragDropProvider onDragEnd={handlePrimitiveDragEnd}>
439
+ <div class="space-y-1">
440
+ {#each arrayValue as item, index (`prim-${index}`)}
441
+ {@const sortable = createSortable({ id: `prim-${index}`, index, disabled: readonly })}
442
+ <div
443
+ {@attach sortable.attach}
444
+ class="border-border/50 bg-background hover:bg-muted/50 flex h-16 items-center gap-1 rounded border px-1 transition-colors"
445
+ class:opacity-50={sortable.isDragging}
446
+ >
447
+ {#if !readonly}
448
+ <button
449
+ {@attach sortable.attachHandle}
450
+ class="text-muted-foreground hover:text-foreground flex h-8 w-6 cursor-grab items-center justify-center active:cursor-grabbing"
451
+ >
452
+ <GripVertical class="h-4 w-4" />
453
+ </button>
454
+ {/if}
237
455
 
238
- {#if isPrimitiveArray}
239
- <!-- Primitive array UI -->
240
- {#if arrayValue.length === 0}
241
- <!-- Empty state -->
242
- <div
243
- class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
244
- >
245
- <p class="text-muted-foreground text-sm">No items</p>
246
- </div>
247
- {:else}
248
- <div class="space-y-2">
249
- {#each arrayValue as item, index (index)}
250
- {#if primitiveType === 'image'}
251
- <!-- Image item in compact mode -->
252
- <ImageField
253
- field={{
254
- ...field.of?.[0],
255
- name: `image-${index}`,
256
- type: 'image',
257
- title: `Image ${index + 1}`
258
- }}
259
- value={item}
260
- onUpdate={(newValue) => {
261
- const newArray = [...arrayValue];
262
- if (newValue === null) {
263
- // Remove the image if null
264
- newArray.splice(index, 1);
265
- } else {
266
- newArray[index] = newValue;
267
- }
268
- onUpdate(newArray);
269
- }}
270
- {readonly}
271
- compact={true}
272
- {organizationId}
273
- />
274
- {:else}
275
- <!-- Always-editable primitive with options menu -->
276
- <div class="border-border/50 flex items-center gap-2 rounded border p-2">
277
- <span class="text-muted-foreground text-xs">#{index + 1}</span>
278
- {#if primitiveType === 'boolean'}
279
- <div class="flex flex-1 items-center gap-2">
280
- <Checkbox
281
- checked={item}
282
- onCheckedChange={(checked) => handleUpdatePrimitive(index, checked)}
283
- disabled={readonly}
284
- />
285
- <span class="text-sm">{item ? 'True' : 'False'}</span>
286
- </div>
287
- {:else if primitiveType === 'text'}
288
- <Textarea
289
- value={item}
290
- oninput={(e) => handleUpdatePrimitive(index, e.currentTarget.value)}
291
- {readonly}
292
- class="flex-1"
293
- rows={3}
294
- placeholder="Enter text..."
295
- />
296
- {:else if primitiveType === 'number'}
297
- <Input
298
- type="number"
299
- value={item}
300
- oninput={(e) =>
301
- handleUpdatePrimitive(index, parseFloat(e.currentTarget.value) || 0)}
302
- {readonly}
303
- class="flex-1"
304
- placeholder="Enter number..."
305
- />
306
- {:else}
307
- <Input
456
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
457
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
458
+ <div
459
+ class="min-w-0 flex-1 cursor-pointer text-left"
460
+ onclick={() => handleOpenImageModal(index)}
461
+ >
462
+ <ImageField
463
+ field={{
464
+ ...field.of?.[0],
465
+ name: `image-${index}`,
466
+ type: 'image',
467
+ title: `Image ${index + 1}`
468
+ }}
308
469
  value={item}
309
- oninput={(e) => handleUpdatePrimitive(index, e.currentTarget.value)}
470
+ onUpdate={() => {}}
310
471
  {readonly}
311
- class="flex-1"
312
- placeholder="Enter value..."
472
+ arrayItem={true}
473
+ {organizationId}
313
474
  />
314
- {/if}
475
+ </div>
476
+
315
477
  {#if !readonly}
316
478
  <DropdownMenu.Root>
317
479
  <DropdownMenu.Trigger>
318
- <Button variant="ghost" size="sm" class="h-8 w-8 p-0">
319
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
320
- <path
321
- stroke-linecap="round"
322
- stroke-linejoin="round"
323
- stroke-width="2"
324
- d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"
325
- />
326
- </svg>
327
- </Button>
480
+ {#snippet child({ props })}
481
+ <button
482
+ {...props}
483
+ class="text-muted-foreground hover:text-foreground flex h-8 w-8 shrink-0 items-center justify-center rounded transition-colors hover:bg-transparent"
484
+ >
485
+ <Ellipsis class="h-4 w-4" />
486
+ </button>
487
+ {/snippet}
328
488
  </DropdownMenu.Trigger>
329
489
  <DropdownMenu.Content align="end">
330
- <DropdownMenu.Item onclick={() => handleRemoveItem(index)}>
331
- <svg
332
- class="mr-2 h-4 w-4"
333
- fill="none"
334
- viewBox="0 0 24 24"
335
- stroke="currentColor"
490
+ <DropdownMenu.Item onclick={() => handleOpenImageModal(index)}>
491
+ <Pencil class="mr-2 h-4 w-4" />
492
+ Edit
493
+ </DropdownMenu.Item>
494
+ <DropdownMenu.Separator />
495
+ <DropdownMenu.Item
496
+ class="text-destructive focus:text-destructive"
497
+ onclick={() => handleRemoveItem(index)}
498
+ >
499
+ <Trash2 class="mr-2 h-4 w-4" />
500
+ Remove
501
+ </DropdownMenu.Item>
502
+ </DropdownMenu.Content>
503
+ </DropdownMenu.Root>
504
+ {/if}
505
+ </div>
506
+ {/each}
507
+ </div>
508
+ </DragDropProvider>
509
+ {/key}
510
+ {:else}
511
+ {#key dndKey}
512
+ <DragDropProvider onDragEnd={handlePrimitiveDragEnd}>
513
+ <div class="space-y-1">
514
+ {#each arrayValue as item, index (`prim-${index}`)}
515
+ {@const sortable = createSortable({ id: `prim-${index}`, index, disabled: readonly })}
516
+ <div
517
+ {@attach sortable.attach}
518
+ class="border-border/50 bg-background hover:bg-muted/50 flex h-10 items-center gap-1 rounded border px-1 transition-colors"
519
+ class:opacity-50={sortable.isDragging}
520
+ >
521
+ {#if !readonly}
522
+ <button
523
+ {@attach sortable.attachHandle}
524
+ class="text-muted-foreground hover:text-foreground flex h-8 w-6 cursor-grab items-center justify-center active:cursor-grabbing"
525
+ >
526
+ <GripVertical class="h-4 w-4" />
527
+ </button>
528
+ {/if}
529
+
530
+ <div class="min-w-0 flex-1">
531
+ {#if primitiveType === 'boolean'}
532
+ <div class="flex items-center gap-2 px-1">
533
+ <Checkbox
534
+ checked={item}
535
+ onCheckedChange={(checked) => handleUpdatePrimitive(index, checked)}
536
+ disabled={readonly}
537
+ />
538
+ <span class="text-sm">{item ? 'True' : 'False'}</span>
539
+ </div>
540
+ {:else if primitiveType === 'number'}
541
+ <Input
542
+ type="number"
543
+ value={item}
544
+ oninput={(e) =>
545
+ handleUpdatePrimitive(index, parseFloat(e.currentTarget.value) || 0)}
546
+ {readonly}
547
+ class="h-8 w-full border-none bg-transparent shadow-none focus-visible:ring-0"
548
+ placeholder="Enter number..."
549
+ />
550
+ {:else}
551
+ <Input
552
+ value={item}
553
+ oninput={(e) => handleUpdatePrimitive(index, e.currentTarget.value)}
554
+ {readonly}
555
+ class="h-8 w-full border-none bg-transparent shadow-none focus-visible:ring-0"
556
+ placeholder="Enter value..."
557
+ />
558
+ {/if}
559
+ </div>
560
+
561
+ {#if !readonly}
562
+ <DropdownMenu.Root>
563
+ <DropdownMenu.Trigger>
564
+ {#snippet child({ props })}
565
+ <button
566
+ {...props}
567
+ class="text-muted-foreground hover:text-foreground flex h-8 w-8 shrink-0 items-center justify-center rounded transition-colors hover:bg-transparent"
336
568
  >
337
- <path
338
- stroke-linecap="round"
339
- stroke-linejoin="round"
340
- stroke-width="2"
341
- d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
342
- />
343
- </svg>
569
+ <Ellipsis class="h-4 w-4" />
570
+ </button>
571
+ {/snippet}
572
+ </DropdownMenu.Trigger>
573
+ <DropdownMenu.Content align="end">
574
+ {#if primitiveType === 'text'}
575
+ <DropdownMenu.Item onclick={() => handleOpenTextModal(index)}>
576
+ <Pencil class="mr-2 h-4 w-4" />
577
+ Edit
578
+ </DropdownMenu.Item>
579
+ <DropdownMenu.Separator />
580
+ {/if}
581
+ <DropdownMenu.Item
582
+ class="text-destructive focus:text-destructive"
583
+ onclick={() => handleRemoveItem(index)}
584
+ >
585
+ <Trash2 class="mr-2 h-4 w-4" />
344
586
  Remove
345
587
  </DropdownMenu.Item>
346
588
  </DropdownMenu.Content>
347
589
  </DropdownMenu.Root>
348
590
  {/if}
349
591
  </div>
350
- {/if}
351
- {/each}
352
- </div>
353
- {/if}
592
+ {/each}
593
+ </div>
594
+ </DragDropProvider>
595
+ {/key}
596
+ {/if}
354
597
 
355
- <!-- Add primitive item section -->
356
- {#if !readonly}
357
- <Button variant="outline" class="w-full" onclick={handleAddPrimitive}>
358
- <svg class="mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
359
- <path
360
- stroke-linecap="round"
361
- stroke-linejoin="round"
362
- stroke-width="2"
363
- d="M12 4v16m8-8H4"
364
- />
365
- </svg>
366
- Add Item
367
- </Button>
598
+ {#if !readonly}
599
+ {#if primitiveType === 'image'}
600
+ <!-- Multi-upload actions for image arrays -->
601
+ <input
602
+ bind:this={multiFileInputRef}
603
+ type="file"
604
+ accept="image/*"
605
+ multiple
606
+ style="display: none"
607
+ onchange={(e) => handleMultiFileSelect(e.currentTarget.files)}
608
+ />
609
+ {#if isMultiUploading}
610
+ <div
611
+ class="border-border/50 bg-muted/30 flex h-10 w-full items-center justify-center gap-2 rounded border border-dashed text-sm"
612
+ >
613
+ <div
614
+ class="border-primary h-4 w-4 animate-spin rounded-full border-2 border-t-transparent"
615
+ ></div>
616
+ <span class="text-muted-foreground"
617
+ >Uploading {uploadProgress.current} of {uploadProgress.total}...</span
618
+ >
619
+ </div>
620
+ {:else}
621
+ <div class="flex gap-2">
622
+ <button
623
+ class="border-border/50 text-muted-foreground hover:text-foreground hover:bg-muted/50 flex h-10 flex-1 items-center justify-center gap-2 rounded border border-dashed text-sm transition-colors"
624
+ onclick={openMultiFileDialog}
625
+ >
626
+ <Upload class="h-4 w-4" />
627
+ Upload images...
628
+ </button>
629
+ <button
630
+ class="border-border/50 text-muted-foreground hover:text-foreground hover:bg-muted/50 flex h-10 flex-1 items-center justify-center gap-2 rounded border border-dashed text-sm transition-colors"
631
+ onclick={() => {
632
+ showArrayAssetBrowser = true;
633
+ }}
634
+ >
635
+ <ImageIcon class="h-4 w-4" />
636
+ Browse media...
637
+ </button>
638
+ </div>
639
+ {/if}
640
+ {:else}
641
+ <button
642
+ class="border-border/50 text-muted-foreground hover:text-foreground hover:bg-muted/50 flex h-10 w-full items-center justify-center gap-2 rounded border border-dashed text-sm transition-colors"
643
+ onclick={handleAddPrimitive}
644
+ >
645
+ <Plus class="h-4 w-4" />
646
+ Add item...
647
+ </button>
368
648
  {/if}
649
+ {/if}
650
+ {:else}
651
+ <!-- Object array UI — Sanity-style compact rows with DnD -->
652
+ {#if keyedItems.length === 0}
653
+ <div
654
+ class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
655
+ >
656
+ <p class="text-muted-foreground text-sm">No items added yet</p>
657
+ </div>
369
658
  {:else}
370
- <!-- Object array UI (existing code) -->
371
- {#if arrayValue.length === 0}
372
- <!-- Empty state -->
373
- <div
374
- class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
375
- >
376
- <p class="text-muted-foreground text-sm">No items</p>
377
- </div>
378
- {:else}
379
- <div class="space-y-2">
380
- {#each arrayValue as item, index (index)}
381
- <div class="border-border/50 space-y-2 rounded border p-3">
382
- <div class="flex items-center justify-between">
383
- <div class="flex items-center gap-2">
384
- <span class="text-muted-foreground text-xs">#{index + 1}</span>
385
- <h5 class="text-sm font-medium">{getItemTitle(item)}</h5>
386
- {#if item._type}
387
- <span class="bg-muted rounded px-2 py-1 text-xs">{item._type}</span>
388
- {/if}
389
- </div>
390
- <div class="flex items-center gap-2">
391
- <Button
392
- variant="ghost"
393
- size="sm"
394
- onclick={() => {
395
- handleEditItem(index);
396
- }}
397
- class="h-8 w-8 p-0"
398
- title={readonly ? 'View item' : 'Edit item'}
659
+ {#key dndKey}
660
+ <DragDropProvider onDragEnd={handleDragEnd}>
661
+ <div class="space-y-1">
662
+ {#each keyedItems as item, index (item._key)}
663
+ {@const sortable = createSortable({ id: item._key, index, disabled: readonly })}
664
+ <div
665
+ {@attach sortable.attach}
666
+ class="border-border/50 bg-background hover:bg-muted/50 flex h-10 items-center gap-1 rounded border px-1 transition-colors"
667
+ class:opacity-50={sortable.isDragging}
668
+ >
669
+ <!-- Drag handle -->
670
+ {#if !readonly}
671
+ <button
672
+ {@attach sortable.attachHandle}
673
+ class="text-muted-foreground hover:text-foreground flex h-8 w-6 cursor-grab items-center justify-center active:cursor-grabbing"
399
674
  >
400
- {#if readonly}
401
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
402
- <path
403
- stroke-linecap="round"
404
- stroke-linejoin="round"
405
- stroke-width="2"
406
- d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
407
- />
408
- <path
409
- stroke-linecap="round"
410
- stroke-linejoin="round"
411
- stroke-width="2"
412
- d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
413
- />
414
- </svg>
415
- {:else}
416
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
417
- <path
418
- stroke-linecap="round"
419
- stroke-linejoin="round"
420
- stroke-width="2"
421
- d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
422
- />
423
- </svg>
424
- {/if}
425
- </Button>
426
-
427
- {#if !readonly}
428
- <Button
429
- variant="ghost"
430
- size="sm"
431
- onclick={() => handleRemoveItem(index)}
432
- class="text-destructive hover:text-destructive h-8 w-8 p-0"
433
- title="Remove item"
434
- >
435
- <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
436
- <path
437
- stroke-linecap="round"
438
- stroke-linejoin="round"
439
- stroke-width="2"
440
- d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
441
- />
442
- </svg>
443
- </Button>
675
+ <GripVertical class="h-4 w-4" />
676
+ </button>
677
+ {/if}
678
+
679
+ <!-- Type icon -->
680
+ <div class="text-muted-foreground flex h-8 w-8 shrink-0 items-center justify-center">
681
+ {#if getItemIcon(item)}
682
+ {@const Icon = getItemIcon(item)}
683
+ <Icon class="h-4 w-4" />
684
+ {:else}
685
+ <FileText class="h-4 w-4" />
444
686
  {/if}
445
687
  </div>
446
- </div>
447
688
 
448
- <!-- Show a preview of the item content -->
449
- <div class="text-muted-foreground pl-6 text-xs">
450
- {#if item.title || item.heading}
451
- {item.title || item.heading}
452
- {:else if item.description}
453
- {item.description.substring(0, 100)}{item.description.length > 100 ? '...' : ''}
454
- {:else}
455
- {readonly ? 'Click view to see details' : 'Click edit to configure this item'}
456
- {/if}
689
+ <!-- Title (clickable to edit) -->
690
+ <button class="flex-1 truncate text-left text-sm" onclick={() => handleEditItem(index)}>
691
+ {getItemTitle(item)}
692
+ </button>
693
+
694
+ <!-- Context menu -->
695
+ <DropdownMenu.Root>
696
+ <DropdownMenu.Trigger>
697
+ {#snippet child({ props })}
698
+ <button
699
+ {...props}
700
+ class="text-muted-foreground hover:text-foreground flex h-8 w-8 shrink-0 items-center justify-center rounded transition-colors hover:bg-transparent"
701
+ >
702
+ <Ellipsis class="h-4 w-4" />
703
+ </button>
704
+ {/snippet}
705
+ </DropdownMenu.Trigger>
706
+ <DropdownMenu.Content align="end">
707
+ <DropdownMenu.Item onclick={() => handleEditItem(index)}>
708
+ <Pencil class="mr-2 h-4 w-4" />
709
+ {readonly ? 'View' : 'Edit'}
710
+ </DropdownMenu.Item>
711
+ {#if !readonly}
712
+ <DropdownMenu.Separator />
713
+ <DropdownMenu.Item
714
+ class="text-destructive focus:text-destructive"
715
+ onclick={() => handleRemoveItem(index)}
716
+ >
717
+ <Trash2 class="mr-2 h-4 w-4" />
718
+ Remove
719
+ </DropdownMenu.Item>
720
+ {/if}
721
+ </DropdownMenu.Content>
722
+ </DropdownMenu.Root>
457
723
  </div>
458
- </div>
459
- {/each}
460
- </div>
461
- {/if}
724
+ {/each}
725
+ </div>
726
+ </DragDropProvider>
727
+ {/key}
728
+ {/if}
462
729
 
463
- <!-- Add Item section (hidden for read-only) -->
464
- {#if !readonly}
465
- <div class="border-border border-t pt-2">
466
- <DropdownMenu.Root>
467
- <DropdownMenu.Trigger>
468
- {#snippet child({ props })}
469
- <Button {...props} variant="outline" class="w-full cursor-pointer">
470
- <svg class="mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
471
- <path
472
- stroke-linecap="round"
473
- stroke-linejoin="round"
474
- stroke-width="2"
475
- d="M12 4v16m8-8H4"
476
- />
477
- </svg>
478
- Add Item
479
- </Button>
480
- {/snippet}
481
- </DropdownMenu.Trigger>
482
- <DropdownMenu.Content class="w-56">
483
- {#each availableTypes as type, index (index)}
484
- <DropdownMenu.Item onclick={() => handleTypeSelected(type.name)}>
485
- {type.title}
486
- </DropdownMenu.Item>
487
- {/each}
488
- </DropdownMenu.Content>
489
- </DropdownMenu.Root>
490
- </div>
730
+ <!-- Add item button -->
731
+ {#if !readonly}
732
+ {#if availableTypes.length === 1}
733
+ <button
734
+ class="border-border/50 text-muted-foreground hover:text-foreground hover:bg-muted/50 flex h-10 w-full items-center justify-center gap-2 rounded border border-dashed text-sm transition-colors"
735
+ onclick={() => handleTypeSelected(availableTypes[0]!.name)}
736
+ >
737
+ <Plus class="h-4 w-4" />
738
+ Add item...
739
+ </button>
740
+ {:else}
741
+ <DropdownMenu.Root>
742
+ <DropdownMenu.Trigger>
743
+ {#snippet child({ props })}
744
+ <button
745
+ {...props}
746
+ class="border-border/50 text-muted-foreground hover:text-foreground hover:bg-muted/50 flex h-10 w-full cursor-pointer items-center justify-center gap-2 rounded border border-dashed text-sm transition-colors"
747
+ >
748
+ <Plus class="h-4 w-4" />
749
+ Add item...
750
+ </button>
751
+ {/snippet}
752
+ </DropdownMenu.Trigger>
753
+ <DropdownMenu.Content class="w-56">
754
+ {#each availableTypes as type, index (index)}
755
+ <DropdownMenu.Item onclick={() => handleTypeSelected(type.name)}>
756
+ {type.title}
757
+ </DropdownMenu.Item>
758
+ {/each}
759
+ </DropdownMenu.Content>
760
+ </DropdownMenu.Root>
491
761
  {/if}
492
762
  {/if}
493
- </div>
763
+ {/if}
494
764
 
495
765
  <!-- Object editing modal -->
496
766
  {#if editingSchema}
@@ -509,7 +779,7 @@
509
779
  <!-- Image upload modal -->
510
780
  {#if imageModalOpen}
511
781
  <div
512
- class="bg-background/80 backdrop-blur-xs fixed bottom-0 left-0 right-0 top-12 z-[100] flex items-center justify-center p-6 sm:absolute sm:top-0 sm:p-4"
782
+ class="bg-background/80 fixed top-12 right-0 bottom-0 left-0 z-40 flex items-center justify-center p-6 backdrop-blur-xs sm:absolute sm:top-0 sm:p-4"
513
783
  onclick={(e) => {
514
784
  if (e.target === e.currentTarget) handleImageModalClose();
515
785
  }}
@@ -519,12 +789,18 @@
519
789
  role="button"
520
790
  tabindex="-1"
521
791
  >
522
- <Card.Root class="flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden shadow-lg">
792
+ <Card.Root class="flex max-h-[85vh] w-full max-w-2xl flex-col shadow-lg">
523
793
  <Card.Header class="border-b">
524
794
  <div class="flex items-center justify-between">
525
795
  <div>
526
- <Card.Title>{field.title} - Add Image</Card.Title>
527
- <Card.Description>Upload a new image to add to the array</Card.Description>
796
+ <Card.Title
797
+ >{imageModalIndex !== null ? 'Edit Image' : `${field.title} - Add Image`}</Card.Title
798
+ >
799
+ <Card.Description
800
+ >{imageModalIndex !== null
801
+ ? 'Replace or remove this image'
802
+ : 'Upload a new image to add to the array'}</Card.Description
803
+ >
528
804
  </div>
529
805
  <Button variant="ghost" size="icon" onclick={handleImageModalClose}>
530
806
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -539,7 +815,7 @@
539
815
  </div>
540
816
  </Card.Header>
541
817
 
542
- <Card.Content class="flex-1 overflow-auto">
818
+ <Card.Content class="flex-1 overflow-visible">
543
819
  <ImageField
544
820
  field={{
545
821
  ...field.of?.[0],
@@ -555,3 +831,61 @@
555
831
  </Card.Root>
556
832
  </div>
557
833
  {/if}
834
+
835
+ <!-- Text editing modal -->
836
+ {#if textModalOpen}
837
+ <div
838
+ class="bg-background/80 fixed top-12 right-0 bottom-0 left-0 z-[100] flex items-center justify-center p-6 backdrop-blur-xs sm:absolute sm:top-0 sm:p-4"
839
+ onclick={(e) => {
840
+ if (e.target === e.currentTarget) handleTextModalClose();
841
+ }}
842
+ onkeydown={(e) => {
843
+ if (e.key === 'Escape') handleTextModalClose();
844
+ }}
845
+ role="button"
846
+ tabindex="-1"
847
+ >
848
+ <Card.Root class="flex max-h-[85vh] w-full max-w-lg flex-col overflow-hidden shadow-lg">
849
+ <Card.Header class="border-b">
850
+ <div class="flex items-center justify-between">
851
+ <Card.Title>Edit Text</Card.Title>
852
+ <Button variant="ghost" size="icon" onclick={handleTextModalClose}>
853
+ <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
854
+ <path
855
+ stroke-linecap="round"
856
+ stroke-linejoin="round"
857
+ stroke-width="2"
858
+ d="M6 18L18 6M6 6l12 12"
859
+ />
860
+ </svg>
861
+ </Button>
862
+ </div>
863
+ </Card.Header>
864
+
865
+ <Card.Content class="pt-4">
866
+ <Textarea
867
+ value={textModalValue}
868
+ oninput={(e) => (textModalValue = e.currentTarget.value)}
869
+ class="w-full"
870
+ rows={6}
871
+ placeholder="Enter text..."
872
+ />
873
+ </Card.Content>
874
+
875
+ <Card.Footer class="flex justify-end gap-2 border-t">
876
+ <Button variant="outline" onclick={handleTextModalClose}>Cancel</Button>
877
+ <Button onclick={handleTextModalSave}>Save</Button>
878
+ </Card.Footer>
879
+ </Card.Root>
880
+ </div>
881
+ {/if}
882
+
883
+ <!-- Asset Browser Modal for image arrays (multi-select) -->
884
+ <AssetBrowserModal
885
+ bind:open={showArrayAssetBrowser}
886
+ onOpenChange={(v) => (showArrayAssetBrowser = v)}
887
+ assetTypeFilter="image"
888
+ multiSelect
889
+ onSelectMultiple={handleArrayAssetSelectMultiple}
890
+ {existingAssetIds}
891
+ />