@almadar/std 3.2.0 → 3.2.2

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 (262) hide show
  1. package/behaviors/exports/atoms/std-async.orb +41 -24
  2. package/behaviors/exports/atoms/std-browse.orb +12 -5
  3. package/behaviors/exports/atoms/std-cache-aside.orb +256 -42
  4. package/behaviors/exports/atoms/std-circuit-breaker.orb +577 -97
  5. package/behaviors/exports/atoms/std-collision.orb +278 -206
  6. package/behaviors/exports/atoms/std-combat-log.orb +6 -1
  7. package/behaviors/exports/atoms/std-combat.orb +6 -1
  8. package/behaviors/exports/atoms/std-confirmation.orb +212 -7
  9. package/behaviors/exports/atoms/std-dialogue-box.orb +6 -1
  10. package/behaviors/exports/atoms/std-display.orb +166 -21
  11. package/behaviors/exports/atoms/std-drawer.orb +208 -104
  12. package/behaviors/exports/atoms/std-filter.orb +211 -18
  13. package/behaviors/exports/atoms/std-game-audio.orb +6 -1
  14. package/behaviors/exports/atoms/std-game-canvas2d.orb +6 -1
  15. package/behaviors/exports/atoms/std-game-canvas3d.orb +6 -1
  16. package/behaviors/exports/atoms/std-game-hud.orb +6 -1
  17. package/behaviors/exports/atoms/std-game-menu.orb +6 -1
  18. package/behaviors/exports/atoms/std-game-over-screen.orb +6 -1
  19. package/behaviors/exports/atoms/std-gameflow.orb +100 -5
  20. package/behaviors/exports/atoms/std-input.orb +142 -137
  21. package/behaviors/exports/atoms/std-inventory-panel.orb +6 -1
  22. package/behaviors/exports/atoms/std-isometric-canvas.orb +6 -1
  23. package/behaviors/exports/atoms/std-loading.orb +27 -76
  24. package/behaviors/exports/atoms/std-modal.orb +177 -93
  25. package/behaviors/exports/atoms/std-movement.orb +401 -31
  26. package/behaviors/exports/atoms/std-notification.orb +46 -95
  27. package/behaviors/exports/atoms/std-overworld.orb +44 -16
  28. package/behaviors/exports/atoms/std-pagination.orb +26 -89
  29. package/behaviors/exports/atoms/std-physics2d.orb +6 -1
  30. package/behaviors/exports/atoms/std-platformer-canvas.orb +6 -1
  31. package/behaviors/exports/atoms/std-quest.orb +309 -34
  32. package/behaviors/exports/atoms/std-rate-limiter.orb +410 -157
  33. package/behaviors/exports/atoms/std-score-board.orb +6 -1
  34. package/behaviors/exports/atoms/std-score.orb +211 -11
  35. package/behaviors/exports/atoms/std-search.orb +28 -27
  36. package/behaviors/exports/atoms/std-selection.orb +160 -121
  37. package/behaviors/exports/atoms/std-simulation-canvas.orb +6 -1
  38. package/behaviors/exports/atoms/std-sort.orb +134 -24
  39. package/behaviors/exports/atoms/std-sprite.orb +6 -1
  40. package/behaviors/exports/atoms/std-tabs.orb +25 -15
  41. package/behaviors/exports/atoms/std-timer.orb +483 -91
  42. package/behaviors/exports/atoms/std-undo.orb +211 -81
  43. package/behaviors/exports/atoms/std-wizard.orb +31 -34
  44. package/behaviors/exports/molecules/std-builder-game.orb +6 -1
  45. package/behaviors/exports/molecules/std-cart.orb +6 -1
  46. package/behaviors/exports/molecules/std-classifier-game.orb +6 -1
  47. package/behaviors/exports/molecules/std-debugger-game.orb +6 -1
  48. package/behaviors/exports/molecules/std-detail.orb +12 -5
  49. package/behaviors/exports/molecules/std-event-handler-game.orb +6 -1
  50. package/behaviors/exports/molecules/std-geospatial.orb +28 -9
  51. package/behaviors/exports/molecules/std-inventory.orb +28 -9
  52. package/behaviors/exports/molecules/std-list.orb +392 -5
  53. package/behaviors/exports/molecules/std-messaging.orb +12 -5
  54. package/behaviors/exports/molecules/std-negotiator-game.orb +6 -1
  55. package/behaviors/exports/molecules/std-platformer-game.orb +40 -1
  56. package/behaviors/exports/molecules/std-puzzle-game.orb +26 -1
  57. package/behaviors/exports/molecules/std-sequencer-game.orb +6 -1
  58. package/behaviors/exports/molecules/std-simulator-game.orb +6 -1
  59. package/behaviors/exports/molecules/std-turn-based-battle.orb +40 -1
  60. package/behaviors/exports/organisms/std-api-gateway.orb +1145 -403
  61. package/behaviors/exports/organisms/std-arcade-game.orb +214 -16
  62. package/behaviors/exports/organisms/std-booking-system.orb +2165 -1605
  63. package/behaviors/exports/organisms/std-cicd-pipeline.orb +581 -47
  64. package/behaviors/exports/organisms/std-cms.orb +1713 -947
  65. package/behaviors/exports/organisms/std-coding-academy.orb +180 -380
  66. package/behaviors/exports/organisms/std-crm.orb +1669 -1153
  67. package/behaviors/exports/organisms/std-devops-dashboard.orb +1430 -378
  68. package/behaviors/exports/organisms/std-ecommerce.orb +2361 -1601
  69. package/behaviors/exports/organisms/std-finance-tracker.orb +622 -438
  70. package/behaviors/exports/organisms/std-healthcare.orb +1687 -1125
  71. package/behaviors/exports/organisms/std-helpdesk.orb +626 -407
  72. package/behaviors/exports/organisms/std-hr-portal.orb +1309 -714
  73. package/behaviors/exports/organisms/std-iot-dashboard.orb +1247 -335
  74. package/behaviors/exports/organisms/std-lms.orb +658 -362
  75. package/behaviors/exports/organisms/std-platformer-app.orb +56 -8
  76. package/behaviors/exports/organisms/std-project-manager.orb +1697 -1183
  77. package/behaviors/exports/organisms/std-puzzle-app.orb +20 -0
  78. package/behaviors/exports/organisms/std-realtime-chat.orb +552 -28
  79. package/behaviors/exports/organisms/std-rpg-game.orb +397 -56
  80. package/behaviors/exports/organisms/std-social-feed.orb +12 -8
  81. package/behaviors/exports/organisms/std-stem-lab.orb +175 -290
  82. package/behaviors/exports/organisms/std-strategy-game.orb +252 -395
  83. package/behaviors/exports/organisms/std-trading-dashboard.orb +718 -524
  84. package/behaviors/exports/validation-report.json +747 -0
  85. package/behaviors/exports/verify-results.json +13 -0
  86. package/dist/behaviors/exports/atoms/std-async.orb +41 -24
  87. package/dist/behaviors/exports/atoms/std-browse.orb +12 -5
  88. package/dist/behaviors/exports/atoms/std-cache-aside.orb +256 -42
  89. package/dist/behaviors/exports/atoms/std-circuit-breaker.orb +577 -97
  90. package/dist/behaviors/exports/atoms/std-collision.orb +278 -206
  91. package/dist/behaviors/exports/atoms/std-combat-log.orb +6 -1
  92. package/dist/behaviors/exports/atoms/std-combat.orb +6 -1
  93. package/dist/behaviors/exports/atoms/std-confirmation.orb +212 -7
  94. package/dist/behaviors/exports/atoms/std-dialogue-box.orb +6 -1
  95. package/dist/behaviors/exports/atoms/std-display.orb +166 -21
  96. package/dist/behaviors/exports/atoms/std-drawer.orb +208 -104
  97. package/dist/behaviors/exports/atoms/std-filter.orb +211 -18
  98. package/dist/behaviors/exports/atoms/std-game-audio.orb +6 -1
  99. package/dist/behaviors/exports/atoms/std-game-canvas2d.orb +6 -1
  100. package/dist/behaviors/exports/atoms/std-game-canvas3d.orb +6 -1
  101. package/dist/behaviors/exports/atoms/std-game-hud.orb +6 -1
  102. package/dist/behaviors/exports/atoms/std-game-menu.orb +6 -1
  103. package/dist/behaviors/exports/atoms/std-game-over-screen.orb +6 -1
  104. package/dist/behaviors/exports/atoms/std-gameflow.orb +100 -5
  105. package/dist/behaviors/exports/atoms/std-input.orb +142 -137
  106. package/dist/behaviors/exports/atoms/std-inventory-panel.orb +6 -1
  107. package/dist/behaviors/exports/atoms/std-isometric-canvas.orb +6 -1
  108. package/dist/behaviors/exports/atoms/std-loading.orb +27 -76
  109. package/dist/behaviors/exports/atoms/std-modal.orb +177 -93
  110. package/dist/behaviors/exports/atoms/std-movement.orb +401 -31
  111. package/dist/behaviors/exports/atoms/std-notification.orb +46 -95
  112. package/dist/behaviors/exports/atoms/std-overworld.orb +44 -16
  113. package/dist/behaviors/exports/atoms/std-pagination.orb +26 -89
  114. package/dist/behaviors/exports/atoms/std-physics2d.orb +6 -1
  115. package/dist/behaviors/exports/atoms/std-platformer-canvas.orb +6 -1
  116. package/dist/behaviors/exports/atoms/std-quest.orb +309 -34
  117. package/dist/behaviors/exports/atoms/std-rate-limiter.orb +410 -157
  118. package/dist/behaviors/exports/atoms/std-score-board.orb +6 -1
  119. package/dist/behaviors/exports/atoms/std-score.orb +211 -11
  120. package/dist/behaviors/exports/atoms/std-search.orb +28 -27
  121. package/dist/behaviors/exports/atoms/std-selection.orb +160 -121
  122. package/dist/behaviors/exports/atoms/std-simulation-canvas.orb +6 -1
  123. package/dist/behaviors/exports/atoms/std-sort.orb +134 -24
  124. package/dist/behaviors/exports/atoms/std-sprite.orb +6 -1
  125. package/dist/behaviors/exports/atoms/std-tabs.orb +25 -15
  126. package/dist/behaviors/exports/atoms/std-timer.orb +483 -91
  127. package/dist/behaviors/exports/atoms/std-undo.orb +211 -81
  128. package/dist/behaviors/exports/atoms/std-wizard.orb +31 -34
  129. package/dist/behaviors/exports/molecules/std-builder-game.orb +6 -1
  130. package/dist/behaviors/exports/molecules/std-cart.orb +6 -1
  131. package/dist/behaviors/exports/molecules/std-classifier-game.orb +6 -1
  132. package/dist/behaviors/exports/molecules/std-debugger-game.orb +6 -1
  133. package/dist/behaviors/exports/molecules/std-detail.orb +12 -5
  134. package/dist/behaviors/exports/molecules/std-event-handler-game.orb +6 -1
  135. package/dist/behaviors/exports/molecules/std-geospatial.orb +28 -9
  136. package/dist/behaviors/exports/molecules/std-inventory.orb +28 -9
  137. package/dist/behaviors/exports/molecules/std-list.orb +392 -5
  138. package/dist/behaviors/exports/molecules/std-messaging.orb +12 -5
  139. package/dist/behaviors/exports/molecules/std-negotiator-game.orb +6 -1
  140. package/dist/behaviors/exports/molecules/std-platformer-game.orb +40 -1
  141. package/dist/behaviors/exports/molecules/std-puzzle-game.orb +26 -1
  142. package/dist/behaviors/exports/molecules/std-sequencer-game.orb +6 -1
  143. package/dist/behaviors/exports/molecules/std-simulator-game.orb +6 -1
  144. package/dist/behaviors/exports/molecules/std-turn-based-battle.orb +40 -1
  145. package/dist/behaviors/exports/organisms/std-api-gateway.orb +1145 -403
  146. package/dist/behaviors/exports/organisms/std-arcade-game.orb +214 -16
  147. package/dist/behaviors/exports/organisms/std-booking-system.orb +2165 -1605
  148. package/dist/behaviors/exports/organisms/std-cicd-pipeline.orb +581 -47
  149. package/dist/behaviors/exports/organisms/std-cms.orb +1713 -947
  150. package/dist/behaviors/exports/organisms/std-coding-academy.orb +180 -380
  151. package/dist/behaviors/exports/organisms/std-crm.orb +1669 -1153
  152. package/dist/behaviors/exports/organisms/std-devops-dashboard.orb +1430 -378
  153. package/dist/behaviors/exports/organisms/std-ecommerce.orb +2361 -1601
  154. package/dist/behaviors/exports/organisms/std-finance-tracker.orb +622 -438
  155. package/dist/behaviors/exports/organisms/std-healthcare.orb +1687 -1125
  156. package/dist/behaviors/exports/organisms/std-helpdesk.orb +626 -407
  157. package/dist/behaviors/exports/organisms/std-hr-portal.orb +1309 -714
  158. package/dist/behaviors/exports/organisms/std-iot-dashboard.orb +1247 -335
  159. package/dist/behaviors/exports/organisms/std-lms.orb +658 -362
  160. package/dist/behaviors/exports/organisms/std-platformer-app.orb +56 -8
  161. package/dist/behaviors/exports/organisms/std-project-manager.orb +1697 -1183
  162. package/dist/behaviors/exports/organisms/std-puzzle-app.orb +20 -0
  163. package/dist/behaviors/exports/organisms/std-realtime-chat.orb +552 -28
  164. package/dist/behaviors/exports/organisms/std-rpg-game.orb +397 -56
  165. package/dist/behaviors/exports/organisms/std-social-feed.orb +12 -8
  166. package/dist/behaviors/exports/organisms/std-stem-lab.orb +175 -290
  167. package/dist/behaviors/exports/organisms/std-strategy-game.orb +252 -395
  168. package/dist/behaviors/exports/organisms/std-trading-dashboard.orb +718 -524
  169. package/dist/behaviors/exports/validation-report.json +747 -0
  170. package/dist/behaviors/exports/verify-results.json +13 -0
  171. package/dist/behaviors/functions/index.js +715 -593
  172. package/dist/behaviors/functions/index.js.map +1 -1
  173. package/dist/behaviors/index.js +715 -593
  174. package/dist/behaviors/index.js.map +1 -1
  175. package/dist/exports/atoms/std-async.orb +41 -24
  176. package/dist/exports/atoms/std-browse.orb +12 -5
  177. package/dist/exports/atoms/std-cache-aside.orb +256 -42
  178. package/dist/exports/atoms/std-circuit-breaker.orb +577 -97
  179. package/dist/exports/atoms/std-collision.orb +278 -206
  180. package/dist/exports/atoms/std-combat-log.orb +6 -1
  181. package/dist/exports/atoms/std-combat.orb +6 -1
  182. package/dist/exports/atoms/std-confirmation.orb +212 -7
  183. package/dist/exports/atoms/std-dialogue-box.orb +6 -1
  184. package/dist/exports/atoms/std-display.orb +166 -21
  185. package/dist/exports/atoms/std-drawer.orb +208 -104
  186. package/dist/exports/atoms/std-filter.orb +211 -18
  187. package/dist/exports/atoms/std-game-audio.orb +6 -1
  188. package/dist/exports/atoms/std-game-canvas2d.orb +6 -1
  189. package/dist/exports/atoms/std-game-canvas3d.orb +6 -1
  190. package/dist/exports/atoms/std-game-hud.orb +6 -1
  191. package/dist/exports/atoms/std-game-menu.orb +6 -1
  192. package/dist/exports/atoms/std-game-over-screen.orb +6 -1
  193. package/dist/exports/atoms/std-gameflow.orb +100 -5
  194. package/dist/exports/atoms/std-input.orb +142 -137
  195. package/dist/exports/atoms/std-inventory-panel.orb +6 -1
  196. package/dist/exports/atoms/std-isometric-canvas.orb +6 -1
  197. package/dist/exports/atoms/std-loading.orb +27 -76
  198. package/dist/exports/atoms/std-modal.orb +177 -93
  199. package/dist/exports/atoms/std-movement.orb +401 -31
  200. package/dist/exports/atoms/std-notification.orb +46 -95
  201. package/dist/exports/atoms/std-overworld.orb +44 -16
  202. package/dist/exports/atoms/std-pagination.orb +26 -89
  203. package/dist/exports/atoms/std-physics2d.orb +6 -1
  204. package/dist/exports/atoms/std-platformer-canvas.orb +6 -1
  205. package/dist/exports/atoms/std-quest.orb +309 -34
  206. package/dist/exports/atoms/std-rate-limiter.orb +410 -157
  207. package/dist/exports/atoms/std-score-board.orb +6 -1
  208. package/dist/exports/atoms/std-score.orb +211 -11
  209. package/dist/exports/atoms/std-search.orb +28 -27
  210. package/dist/exports/atoms/std-selection.orb +160 -121
  211. package/dist/exports/atoms/std-simulation-canvas.orb +6 -1
  212. package/dist/exports/atoms/std-sort.orb +134 -24
  213. package/dist/exports/atoms/std-sprite.orb +6 -1
  214. package/dist/exports/atoms/std-tabs.orb +25 -15
  215. package/dist/exports/atoms/std-timer.orb +483 -91
  216. package/dist/exports/atoms/std-undo.orb +211 -81
  217. package/dist/exports/atoms/std-wizard.orb +31 -34
  218. package/dist/exports/molecules/std-builder-game.orb +6 -1
  219. package/dist/exports/molecules/std-cart.orb +6 -1
  220. package/dist/exports/molecules/std-classifier-game.orb +6 -1
  221. package/dist/exports/molecules/std-debugger-game.orb +6 -1
  222. package/dist/exports/molecules/std-detail.orb +12 -5
  223. package/dist/exports/molecules/std-event-handler-game.orb +6 -1
  224. package/dist/exports/molecules/std-geospatial.orb +28 -9
  225. package/dist/exports/molecules/std-inventory.orb +28 -9
  226. package/dist/exports/molecules/std-list.orb +392 -5
  227. package/dist/exports/molecules/std-messaging.orb +12 -5
  228. package/dist/exports/molecules/std-negotiator-game.orb +6 -1
  229. package/dist/exports/molecules/std-platformer-game.orb +40 -1
  230. package/dist/exports/molecules/std-puzzle-game.orb +26 -1
  231. package/dist/exports/molecules/std-sequencer-game.orb +6 -1
  232. package/dist/exports/molecules/std-simulator-game.orb +6 -1
  233. package/dist/exports/molecules/std-turn-based-battle.orb +40 -1
  234. package/dist/exports/organisms/std-api-gateway.orb +1145 -403
  235. package/dist/exports/organisms/std-arcade-game.orb +214 -16
  236. package/dist/exports/organisms/std-booking-system.orb +2165 -1605
  237. package/dist/exports/organisms/std-cicd-pipeline.orb +581 -47
  238. package/dist/exports/organisms/std-cms.orb +1713 -947
  239. package/dist/exports/organisms/std-coding-academy.orb +180 -380
  240. package/dist/exports/organisms/std-crm.orb +1669 -1153
  241. package/dist/exports/organisms/std-devops-dashboard.orb +1430 -378
  242. package/dist/exports/organisms/std-ecommerce.orb +2361 -1601
  243. package/dist/exports/organisms/std-finance-tracker.orb +622 -438
  244. package/dist/exports/organisms/std-healthcare.orb +1687 -1125
  245. package/dist/exports/organisms/std-helpdesk.orb +626 -407
  246. package/dist/exports/organisms/std-hr-portal.orb +1309 -714
  247. package/dist/exports/organisms/std-iot-dashboard.orb +1247 -335
  248. package/dist/exports/organisms/std-lms.orb +658 -362
  249. package/dist/exports/organisms/std-platformer-app.orb +56 -8
  250. package/dist/exports/organisms/std-project-manager.orb +1697 -1183
  251. package/dist/exports/organisms/std-puzzle-app.orb +20 -0
  252. package/dist/exports/organisms/std-realtime-chat.orb +552 -28
  253. package/dist/exports/organisms/std-rpg-game.orb +397 -56
  254. package/dist/exports/organisms/std-social-feed.orb +12 -8
  255. package/dist/exports/organisms/std-stem-lab.orb +175 -290
  256. package/dist/exports/organisms/std-strategy-game.orb +252 -395
  257. package/dist/exports/organisms/std-trading-dashboard.orb +718 -524
  258. package/dist/exports/validation-report.json +747 -0
  259. package/dist/exports/verify-results.json +13 -0
  260. package/dist/index.js +715 -593
  261. package/dist/index.js.map +1 -1
  262. package/package.json +1 -1
@@ -46,10 +46,10 @@ function buildTrait(c) {
46
46
  align: "center",
47
47
  children: [
48
48
  { type: "icon", name: headerIcon, size: "sm" },
49
- { type: "typography", variant: "h4", content: `@entity.${listFields[0] ?? "id"}` }
49
+ { type: "typography", variant: "h4", content: `@item.${listFields[0] ?? "id"}` }
50
50
  ]
51
51
  },
52
- ...listFields.length > 1 ? [{ type: "badge", label: `@entity.${listFields[1]}` }] : []
52
+ ...listFields.length > 1 ? [{ type: "badge", label: `@item.${listFields[1]}` }] : []
53
53
  ]
54
54
  }
55
55
  ];
@@ -58,7 +58,7 @@ function buildTrait(c) {
58
58
  type: "typography",
59
59
  variant: "caption",
60
60
  color: "muted",
61
- content: `@entity.${listFields[2]}`
61
+ content: `@item.${listFields[2]}`
62
62
  });
63
63
  }
64
64
  const headerChildren = [
@@ -134,7 +134,7 @@ function buildTrait(c) {
134
134
  ...c.itemActions.length > 0 ? { itemActions: c.itemActions } : {},
135
135
  // hover lift: cards rise on hover for interactive feel
136
136
  className: "transition-shadow hover:shadow-md cursor-pointer",
137
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
137
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
138
138
  }
139
139
  ]
140
140
  }]
@@ -173,37 +173,33 @@ function resolve2(params) {
173
173
  const nonIdFields = fields.filter((f) => f.name !== "id");
174
174
  const p = plural(entityName);
175
175
  const defaultContent = {
176
- type: "stack",
177
- direction: "vertical",
178
- gap: "md",
176
+ type: "modal",
177
+ title: params.modalTitle ?? "Details",
178
+ isOpen: true,
179
179
  children: [
180
180
  {
181
181
  type: "stack",
182
- direction: "horizontal",
183
- gap: "sm",
184
- align: "center",
185
- children: [
186
- { type: "icon", name: params.headerIcon ?? "maximize-2", size: "md" },
187
- { type: "typography", content: params.modalTitle ?? "Details", variant: "h3" }
188
- ]
189
- },
190
- { type: "divider" },
191
- ...nonIdFields.map((f) => ({
192
- type: "stack",
193
- direction: "horizontal",
182
+ direction: "vertical",
194
183
  gap: "md",
195
184
  children: [
196
- { type: "typography", variant: "caption", content: f.name.charAt(0).toUpperCase() + f.name.slice(1) },
197
- { type: "typography", variant: "body", content: `@entity.${f.name}` }
185
+ ...nonIdFields.map((f) => ({
186
+ type: "stack",
187
+ direction: "horizontal",
188
+ gap: "md",
189
+ children: [
190
+ { type: "typography", variant: "caption", content: f.name.charAt(0).toUpperCase() + f.name.slice(1) },
191
+ { type: "typography", variant: "body", content: ["object/get", ["array/first", "@entity"], f.name] }
192
+ ]
193
+ })),
194
+ { type: "divider" },
195
+ {
196
+ type: "stack",
197
+ direction: "horizontal",
198
+ gap: "sm",
199
+ justify: "end",
200
+ children: [{ type: "button", label: "Close", event: params.closeEvent ?? "CLOSE", variant: "ghost" }]
201
+ }
198
202
  ]
199
- })),
200
- { type: "divider" },
201
- {
202
- type: "stack",
203
- direction: "horizontal",
204
- gap: "sm",
205
- justify: "end",
206
- children: [{ type: "button", label: "Close", event: params.closeEvent ?? "CLOSE", variant: "ghost" }]
207
203
  }
208
204
  ]
209
205
  };
@@ -214,7 +210,7 @@ function resolve2(params) {
214
210
  persistence: params.persistence ?? "runtime",
215
211
  traitName: params.traitName ?? `${entityName}Modal`,
216
212
  modalTitle: params.modalTitle ?? "Details",
217
- headerIcon: params.headerIcon ?? "maximize-2",
213
+ headerIcon: params.headerIcon ?? "layout-panel-top",
218
214
  openContent: params.openContent ?? defaultContent,
219
215
  openEvent: params.openEvent ?? "OPEN",
220
216
  openPayload: params.openPayload ?? [],
@@ -258,7 +254,9 @@ function buildTrait2(c) {
258
254
  { type: "typography", content: c.modalTitle, variant: "h2" }
259
255
  ] },
260
256
  { type: "button", label: "Open", event: c.openEvent, variant: "primary", icon: c.headerIcon }
261
- ] }
257
+ ] },
258
+ { type: "divider" },
259
+ { type: "empty-state", icon: c.headerIcon, title: "Nothing open", description: "Click Open to view details in a modal overlay." }
262
260
  ]
263
261
  }]] : [["fetch", c.entityName]]
264
262
  },
@@ -269,8 +267,26 @@ function buildTrait2(c) {
269
267
  event: c.openEvent,
270
268
  effects: [...c.openEffects, ["render-ui", "modal", c.openContent]]
271
269
  },
272
- // CLOSE: open → closed
273
- { from: "open", to: "closed", event: c.closeEvent, effects: [["render-ui", "modal", null]] }
270
+ // CLOSE: open → closed (re-render main to avoid stale content)
271
+ { from: "open", to: "closed", event: c.closeEvent, effects: [
272
+ ["render-ui", "modal", null],
273
+ ...c.standalone ? [["fetch", c.entityName], ["render-ui", "main", {
274
+ type: "stack",
275
+ direction: "vertical",
276
+ gap: "lg",
277
+ children: [
278
+ { type: "stack", direction: "horizontal", gap: "md", justify: "space-between", children: [
279
+ { type: "stack", direction: "horizontal", gap: "md", children: [
280
+ { type: "icon", name: c.headerIcon, size: "lg" },
281
+ { type: "typography", content: c.modalTitle, variant: "h2" }
282
+ ] },
283
+ { type: "button", label: "Open", event: c.openEvent, variant: "primary", icon: c.headerIcon }
284
+ ] },
285
+ { type: "divider" },
286
+ { type: "empty-state", icon: c.headerIcon, title: "Nothing open", description: "Click Open to view details in a modal overlay." }
287
+ ]
288
+ }]] : []
289
+ ] }
274
290
  ];
275
291
  if (c.saveEvent) {
276
292
  transitions.push({
@@ -329,7 +345,7 @@ function resolve3(params) {
329
345
  confirmMessage: params.confirmMessage ?? "Are you sure?",
330
346
  confirmLabel: params.confirmLabel ?? "Confirm",
331
347
  cancelLabel: params.cancelLabel ?? "Cancel",
332
- headerIcon: params.headerIcon ?? "alert-triangle",
348
+ headerIcon: params.headerIcon ?? "shield-check",
333
349
  requestEvent: params.requestEvent ?? "REQUEST",
334
350
  confirmEvent: params.confirmEvent ?? "CONFIRM",
335
351
  confirmEffects: params.confirmEffects ?? [],
@@ -349,6 +365,66 @@ function buildEntity3(c) {
349
365
  }
350
366
  function buildTrait3(c) {
351
367
  const { entityName, displayField, pluralName, confirmTitle, confirmMessage, confirmLabel, cancelLabel, headerIcon } = c;
368
+ const idleMainView = {
369
+ type: "stack",
370
+ direction: "vertical",
371
+ gap: "lg",
372
+ children: [
373
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
374
+ { type: "icon", name: headerIcon, size: "lg" },
375
+ { type: "typography", content: pluralName, variant: "h2" }
376
+ ] },
377
+ { type: "divider" },
378
+ {
379
+ type: "data-grid",
380
+ entity: entityName,
381
+ emptyIcon: "inbox",
382
+ emptyTitle: `No ${pluralName.toLowerCase()} yet`,
383
+ emptyDescription: "Items will appear here.",
384
+ itemActions: [{ label: confirmTitle, event: c.requestEvent, variant: "danger" }],
385
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: [
386
+ { type: "typography", variant: "h4", content: `@item.${displayField}` }
387
+ ] }]
388
+ }
389
+ ]
390
+ };
391
+ const confirmModalView = {
392
+ type: "stack",
393
+ direction: "vertical",
394
+ gap: "md",
395
+ children: [
396
+ {
397
+ type: "stack",
398
+ direction: "horizontal",
399
+ gap: "sm",
400
+ align: "center",
401
+ children: [
402
+ { type: "icon", name: "alert-triangle", size: "md" },
403
+ { type: "typography", content: confirmTitle, variant: "h3" }
404
+ ]
405
+ },
406
+ { type: "divider" },
407
+ {
408
+ type: "alert",
409
+ variant: "danger",
410
+ message: confirmMessage
411
+ },
412
+ {
413
+ type: "stack",
414
+ direction: "horizontal",
415
+ gap: "sm",
416
+ justify: "end",
417
+ children: [
418
+ { type: "button", label: cancelLabel, event: "CANCEL", variant: "ghost" },
419
+ { type: "button", label: confirmLabel, event: c.confirmEvent, variant: "danger", icon: "check" }
420
+ ]
421
+ }
422
+ ]
423
+ };
424
+ const dismissAndRefresh = [
425
+ ["render-ui", "modal", null],
426
+ ...c.standalone ? [["fetch", entityName], ["render-ui", "main", idleMainView]] : [["fetch", entityName]]
427
+ ];
352
428
  return {
353
429
  name: c.traitName,
354
430
  linkedEntity: entityName,
@@ -367,36 +443,12 @@ function buildTrait3(c) {
367
443
  { key: "CLOSE", name: "Close" }
368
444
  ],
369
445
  transitions: [
370
- // INIT: idle -> idle
371
446
  {
372
447
  from: "idle",
373
448
  to: "idle",
374
449
  event: "INIT",
375
- effects: c.standalone ? [["fetch", entityName], ["render-ui", "main", {
376
- type: "stack",
377
- direction: "vertical",
378
- gap: "lg",
379
- children: [
380
- { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
381
- { type: "icon", name: headerIcon, size: "lg" },
382
- { type: "typography", content: pluralName, variant: "h2" }
383
- ] },
384
- { type: "divider" },
385
- {
386
- type: "data-grid",
387
- entity: entityName,
388
- emptyIcon: "inbox",
389
- emptyTitle: `No ${pluralName.toLowerCase()} yet`,
390
- emptyDescription: "Items will appear here.",
391
- itemActions: [{ label: confirmTitle, event: c.requestEvent, variant: "danger" }],
392
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: [
393
- { type: "typography", variant: "h4", content: `@entity.${displayField}` }
394
- ] }]
395
- }
396
- ]
397
- }]] : [["fetch", entityName]]
450
+ effects: c.standalone ? [["fetch", entityName], ["render-ui", "main", idleMainView]] : [["fetch", entityName]]
398
451
  },
399
- // REQUEST: idle -> confirming (fetch entity by ID so server has context)
400
452
  {
401
453
  from: "idle",
402
454
  to: "confirming",
@@ -404,65 +456,30 @@ function buildTrait3(c) {
404
456
  effects: [
405
457
  ["set", "@entity.pendingId", "@payload.id"],
406
458
  ["fetch", entityName, "@payload.id"],
407
- ["render-ui", "modal", {
408
- type: "stack",
409
- direction: "vertical",
410
- gap: "md",
411
- children: [
412
- {
413
- type: "stack",
414
- direction: "horizontal",
415
- gap: "sm",
416
- align: "center",
417
- children: [
418
- { type: "icon", name: headerIcon, size: "md" },
419
- { type: "typography", content: confirmTitle, variant: "h3" }
420
- ]
421
- },
422
- { type: "divider" },
423
- { type: "typography", content: confirmMessage, variant: "body" },
424
- {
425
- type: "stack",
426
- direction: "horizontal",
427
- gap: "sm",
428
- justify: "end",
429
- children: [
430
- { type: "button", label: cancelLabel, event: "CANCEL", variant: "ghost" },
431
- { type: "button", label: confirmLabel, event: c.confirmEvent, variant: "danger", icon: "check" }
432
- ]
433
- }
434
- ]
435
- }]
459
+ ["render-ui", "modal", confirmModalView]
436
460
  ]
437
461
  },
438
- // CONFIRM: confirming -> idle (run injected effects, dismiss modal)
439
462
  {
440
463
  from: "confirming",
441
464
  to: "idle",
442
465
  event: c.confirmEvent,
443
466
  effects: [
444
467
  ...c.confirmEffects,
445
- ["render-ui", "modal", null],
468
+ ...dismissAndRefresh,
446
469
  ...c.emitOnConfirm ? [["emit", c.emitOnConfirm]] : []
447
470
  ]
448
471
  },
449
- // CANCEL: confirming -> idle (dismiss modal)
450
472
  {
451
473
  from: "confirming",
452
474
  to: "idle",
453
475
  event: "CANCEL",
454
- effects: [
455
- ["render-ui", "modal", null]
456
- ]
476
+ effects: dismissAndRefresh
457
477
  },
458
- // CLOSE: confirming -> idle (dismiss modal)
459
478
  {
460
479
  from: "confirming",
461
480
  to: "idle",
462
481
  event: "CLOSE",
463
- effects: [
464
- ["render-ui", "modal", null]
465
- ]
482
+ effects: dismissAndRefresh
466
483
  }
467
484
  ]
468
485
  }
@@ -492,8 +509,8 @@ function stdConfirmation(params) {
492
509
  function resolve4(params) {
493
510
  const { entityName } = params;
494
511
  const baseFields = ensureIdField(params.fields);
495
- const fields = baseFields.some((f) => f.name === "query") ? baseFields : [...baseFields, { name: "query", type: "string", default: "" }];
496
- const nonIdFields = baseFields.filter((f) => f.name !== "id" && f.name !== "query");
512
+ const fields = baseFields;
513
+ const nonIdFields = baseFields.filter((f) => f.name !== "id");
497
514
  const p = plural(entityName);
498
515
  return {
499
516
  entityName,
@@ -530,7 +547,8 @@ function buildTrait4(c) {
530
547
  ]
531
548
  },
532
549
  { type: "divider" },
533
- { type: "search-input", placeholder, event: "SEARCH" }
550
+ { type: "search-input", placeholder, event: "SEARCH" },
551
+ { type: "empty-state", icon: searchIcon, title: "Search to find results", description: `Type a query to search across ${pluralName.toLowerCase()}.` }
534
552
  ]
535
553
  };
536
554
  const resultsView = {
@@ -552,7 +570,7 @@ function buildTrait4(c) {
552
570
  align: "center",
553
571
  children: [
554
572
  { type: "icon", name: searchIcon, size: "lg" },
555
- { type: "typography", content: ["concat", 'Results for "', "@entity.query", '"'], variant: "h2" }
573
+ { type: "typography", content: ["concat", 'Results for "', "@payload.query", '"'], variant: "h2" }
556
574
  ]
557
575
  },
558
576
  { type: "button", label: "Clear", event: "CLEAR", variant: "ghost", icon: "x" }
@@ -565,12 +583,12 @@ function buildTrait4(c) {
565
583
  emptyIcon: searchIcon,
566
584
  emptyTitle: "No results found",
567
585
  emptyDescription: "Try a different search term.",
568
- children: [{
586
+ renderItem: ["fn", "item", {
569
587
  type: "stack",
570
588
  direction: "vertical",
571
589
  gap: "sm",
572
590
  children: [
573
- { type: "typography", variant: "h4", content: `@entity.${displayField}` }
591
+ { type: "typography", variant: "h4", content: `@item.${displayField}` }
574
592
  ]
575
593
  }]
576
594
  }
@@ -605,7 +623,6 @@ function buildTrait4(c) {
605
623
  to: "searching",
606
624
  event: "SEARCH",
607
625
  effects: [
608
- ["set", "@entity.query", "@payload.query"],
609
626
  ["fetch", entityName],
610
627
  ["render-ui", "main", resultsView]
611
628
  ]
@@ -615,7 +632,6 @@ function buildTrait4(c) {
615
632
  to: "searching",
616
633
  event: "SEARCH",
617
634
  effects: [
618
- ["set", "@entity.query", "@payload.query"],
619
635
  ["fetch", entityName],
620
636
  ["render-ui", "main", resultsView]
621
637
  ]
@@ -625,7 +641,6 @@ function buildTrait4(c) {
625
641
  to: "idle",
626
642
  event: "CLEAR",
627
643
  effects: [
628
- ["set", "@entity.query", ""],
629
644
  ["fetch", entityName],
630
645
  ["render-ui", "main", searchInputView]
631
646
  ]
@@ -683,61 +698,28 @@ function buildEntity5(c) {
683
698
  }
684
699
  function buildTrait5(c) {
685
700
  const { entityName, displayField, pluralName, headerIcon, pageTitle, filterableFields } = c;
686
- const filterButtons = filterableFields.map((f) => ({
687
- type: "stack",
688
- direction: "vertical",
689
- gap: "xs",
690
- children: [
691
- // overline group label for visual hierarchy
692
- {
693
- type: "typography",
694
- variant: "overline",
695
- color: "muted",
696
- content: f.name.charAt(0).toUpperCase() + f.name.slice(1)
697
- },
698
- {
699
- type: "stack",
700
- direction: "horizontal",
701
- gap: "sm",
702
- align: "center",
703
- children: (f.values ?? []).map((v) => ({
704
- type: "button",
705
- label: v,
706
- event: "FILTER",
707
- variant: "secondary"
708
- }))
709
- }
710
- ]
711
- }));
712
- const activeFilterButtons = filterableFields.map((f) => ({
701
+ const filterControls = filterableFields.length > 0 ? [{
702
+ type: "filter-group",
703
+ entity: entityName,
704
+ filters: filterableFields.map((f) => ({
705
+ field: f.name,
706
+ label: f.name.charAt(0).toUpperCase() + f.name.slice(1),
707
+ options: f.values ?? [],
708
+ filterType: f.type === "boolean" ? "toggle" : "select"
709
+ }))
710
+ }] : [{ type: "empty-state", icon: "filter-x", title: "No filter fields", description: "Add fields with predefined values to enable filtering." }];
711
+ const booleanFilters = filterableFields.filter((f) => f.type === "boolean");
712
+ const switchControls = booleanFilters.map((f) => ({
713
713
  type: "stack",
714
- direction: "vertical",
715
- gap: "xs",
714
+ direction: "horizontal",
715
+ gap: "sm",
716
+ align: "center",
717
+ justify: "space-between",
716
718
  children: [
717
- {
718
- type: "typography",
719
- variant: "overline",
720
- color: "muted",
721
- content: f.name.charAt(0).toUpperCase() + f.name.slice(1)
722
- },
723
- {
724
- type: "stack",
725
- direction: "horizontal",
726
- gap: "sm",
727
- align: "center",
728
- children: (f.values ?? []).map((v) => ({
729
- // active filter chip uses 'primary' variant so runtime highlights it
730
- type: "button",
731
- label: v,
732
- event: "FILTER",
733
- variant: "primary"
734
- }))
735
- }
719
+ { type: "typography", variant: "body", content: f.name.charAt(0).toUpperCase() + f.name.slice(1) },
720
+ { type: "switch", checked: false }
736
721
  ]
737
722
  }));
738
- if (filterButtons.length === 0) {
739
- filterButtons.push({ type: "badge", label: "No filter fields defined" });
740
- }
741
723
  const header = {
742
724
  type: "stack",
743
725
  direction: "horizontal",
@@ -759,17 +741,37 @@ function buildTrait5(c) {
759
741
  emptyTitle: `No ${pluralName.toLowerCase()} yet`,
760
742
  emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
761
743
  className: "transition-shadow hover:shadow-md cursor-pointer",
762
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: [
763
- { type: "typography", variant: "h4", content: `@entity.${displayField}` },
744
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: [
745
+ { type: "typography", variant: "h4", content: `@item.${displayField}` },
764
746
  // show the filterable field value to confirm what was filtered
765
- ...filterableFields[0] ? [{ type: "typography", variant: "caption", color: "muted", content: `@entity.${filterableFields[0].name}` }] : []
747
+ ...filterableFields[0] ? [{ type: "typography", variant: "caption", color: "muted", content: `@item.${filterableFields[0].name}` }] : []
766
748
  ] }]
767
749
  };
768
750
  const browsingView = {
769
751
  type: "stack",
770
752
  direction: "vertical",
771
753
  gap: "lg",
772
- children: [header, { type: "divider" }, ...filterButtons, { type: "divider" }, dataGrid]
754
+ children: [
755
+ header,
756
+ { type: "divider" },
757
+ ...filterControls,
758
+ ...switchControls.length > 0 ? [{ type: "divider" }, ...switchControls] : [],
759
+ { type: "divider" },
760
+ dataGrid
761
+ ]
762
+ };
763
+ const activeFilterIndicator = {
764
+ type: "stack",
765
+ direction: "horizontal",
766
+ gap: "sm",
767
+ align: "center",
768
+ children: [
769
+ { type: "icon", name: "filter", size: "sm" },
770
+ { type: "typography", variant: "caption", color: "muted", content: "Filtered by" },
771
+ { type: "badge", label: "@payload.field", variant: "secondary" },
772
+ { type: "typography", variant: "caption", content: "=" },
773
+ { type: "badge", label: "@payload.value", variant: "primary" }
774
+ ]
773
775
  };
774
776
  const filteredView = {
775
777
  type: "stack",
@@ -787,15 +789,16 @@ function buildTrait5(c) {
787
789
  { type: "icon", name: headerIcon, size: "lg" },
788
790
  { type: "typography", content: pageTitle, variant: "h2" }
789
791
  ] },
790
- { type: "stack", direction: "horizontal", gap: "sm", children: [
792
+ { type: "stack", direction: "horizontal", gap: "sm", align: "center", children: [
791
793
  { type: "badge", label: "Filtered", variant: "primary" },
792
- { type: "button", label: "Clear", event: "CLEAR_FILTERS", variant: "ghost", icon: "x" }
794
+ { type: "button", label: "Clear All", event: "CLEAR_FILTERS", variant: "ghost", icon: "x" }
793
795
  ] }
794
796
  ]
795
797
  },
798
+ activeFilterIndicator,
796
799
  { type: "divider" },
797
- // activeFilterButtons show primary variant for selected state
798
- ...activeFilterButtons,
800
+ ...filterControls,
801
+ ...switchControls.length > 0 ? [{ type: "divider" }, ...switchControls] : [],
799
802
  { type: "divider" },
800
803
  dataGrid
801
804
  ]
@@ -811,14 +814,29 @@ function buildTrait5(c) {
811
814
  ],
812
815
  events: [
813
816
  { key: "INIT", name: "Initialize" },
814
- { key: "FILTER", name: "Filter" },
817
+ { key: "FILTER", name: "Filter", payload: [
818
+ { name: "field", type: "string", required: true },
819
+ { name: "value", type: "string", required: true }
820
+ ] },
815
821
  { key: "CLEAR_FILTERS", name: "Clear Filters" }
816
822
  ],
817
823
  transitions: [
818
- { from: "browsing", to: "browsing", event: "INIT", effects: [["fetch", entityName], ["render-ui", "main", browsingView]] },
819
- { from: "browsing", to: "filtered", event: "FILTER", effects: [["fetch", entityName], ["render-ui", "main", filteredView]] },
820
- { from: "filtered", to: "filtered", event: "FILTER", effects: [["fetch", entityName], ["render-ui", "main", filteredView]] },
821
- { from: "filtered", to: "browsing", event: "CLEAR_FILTERS", effects: [["fetch", entityName], ["render-ui", "main", browsingView]] }
824
+ { from: "browsing", to: "browsing", event: "INIT", effects: [
825
+ ["fetch", entityName],
826
+ ["render-ui", "main", browsingView]
827
+ ] },
828
+ { from: "browsing", to: "filtered", event: "FILTER", effects: [
829
+ ["fetch", entityName, ["==", ["object/get", "@entity", "@payload.field"], "@payload.value"]],
830
+ ["render-ui", "main", filteredView]
831
+ ] },
832
+ { from: "filtered", to: "filtered", event: "FILTER", effects: [
833
+ ["fetch", entityName, ["==", ["object/get", "@entity", "@payload.field"], "@payload.value"]],
834
+ ["render-ui", "main", filteredView]
835
+ ] },
836
+ { from: "filtered", to: "browsing", event: "CLEAR_FILTERS", effects: [
837
+ ["fetch", entityName],
838
+ ["render-ui", "main", browsingView]
839
+ ] }
822
840
  ]
823
841
  }
824
842
  };
@@ -875,7 +893,7 @@ function buildTrait6(c) {
875
893
  type: "button",
876
894
  label: f.charAt(0).toUpperCase() + f.slice(1),
877
895
  event: "SORT",
878
- // secondary in idle; molecules can override active to primary
896
+ actionPayload: { field: f, direction: "asc" },
879
897
  variant: "secondary",
880
898
  icon: "arrow-up-down"
881
899
  }))
@@ -892,6 +910,7 @@ function buildTrait6(c) {
892
910
  type: "button",
893
911
  label: f.charAt(0).toUpperCase() + f.slice(1),
894
912
  event: "SORT",
913
+ actionPayload: { field: f, direction: f === activeField ? "desc" : "asc" },
895
914
  // highlight the active sort field with primary + directional arrow
896
915
  variant: f === activeField ? "primary" : "secondary",
897
916
  icon: f === activeField ? "chevron-up" : "arrow-up-down"
@@ -905,10 +924,9 @@ function buildTrait6(c) {
905
924
  emptyTitle: `No ${pluralName.toLowerCase()} yet`,
906
925
  emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
907
926
  className: "transition-shadow hover:shadow-md cursor-pointer",
908
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: [
909
- { type: "typography", variant: "h4", content: `@entity.${displayField}` },
910
- // Show the first sortable field as a secondary datum so sorting is visually meaningful
911
- ...sortableFields[1] ? [{ type: "typography", variant: "caption", color: "muted", content: `@entity.${sortableFields[1]}` }] : []
927
+ renderItem: ["fn", "item", { type: "stack", direction: "horizontal", gap: "md", align: "center", justify: "space-between", children: [
928
+ { type: "typography", variant: "h4", content: `@item.${displayField}` },
929
+ ...sortableFields[1] ? [{ type: "typography", variant: "caption", color: "muted", content: `@item.${sortableFields[1]}` }] : []
912
930
  ] }]
913
931
  };
914
932
  const mainView = {
@@ -923,7 +941,6 @@ function buildTrait6(c) {
923
941
  ] }
924
942
  ] },
925
943
  { type: "divider" },
926
- // Sort toolbar lives just above the data list
927
944
  sortToolbar,
928
945
  dataGrid
929
946
  ]
@@ -954,12 +971,21 @@ function buildTrait6(c) {
954
971
  states: [{ name: "idle", isInitial: true }, { name: "sorted" }],
955
972
  events: [
956
973
  { key: "INIT", name: "Initialize" },
957
- { key: "SORT", name: "Sort" }
974
+ { key: "SORT", name: "Sort", payload: [
975
+ { name: "field", type: "string", required: true },
976
+ { name: "direction", type: "string" }
977
+ ] }
958
978
  ],
959
979
  transitions: [
960
980
  { from: "idle", to: "idle", event: "INIT", effects: [["fetch", entityName], ["render-ui", "main", mainView]] },
961
- { from: "idle", to: "sorted", event: "SORT", effects: [["fetch", entityName], ["render-ui", "main", mainSortedView]] },
962
- { from: "sorted", to: "sorted", event: "SORT", effects: [["fetch", entityName], ["render-ui", "main", mainSortedView]] },
981
+ { from: "idle", to: "sorted", event: "SORT", effects: [
982
+ ["fetch", entityName, null, ["concat", "@payload.field", ":", "@payload.direction"]],
983
+ ["render-ui", "main", mainSortedView]
984
+ ] },
985
+ { from: "sorted", to: "sorted", event: "SORT", effects: [
986
+ ["fetch", entityName, null, ["concat", "@payload.field", ":", "@payload.direction"]],
987
+ ["render-ui", "main", mainSortedView]
988
+ ] },
963
989
  { from: "sorted", to: "idle", event: "INIT", effects: [["fetch", entityName], ["render-ui", "main", mainView]] }
964
990
  ]
965
991
  }
@@ -984,12 +1010,8 @@ function stdSort(params) {
984
1010
  function resolve7(params) {
985
1011
  const { entityName } = params;
986
1012
  const baseFields = ensureIdField(params.fields);
987
- const fields = [
988
- ...baseFields,
989
- ...baseFields.some((f) => f.name === "currentPage") ? [] : [{ name: "currentPage", type: "number", default: 1 }],
990
- ...baseFields.some((f) => f.name === "pageSize") ? [] : [{ name: "pageSize", type: "number", default: 10 }]
991
- ];
992
- const nonIdFields = baseFields.filter((f) => f.name !== "id" && f.name !== "currentPage" && f.name !== "pageSize");
1013
+ const fields = baseFields;
1014
+ const nonIdFields = baseFields.filter((f) => f.name !== "id");
993
1015
  const p = plural(entityName);
994
1016
  return {
995
1017
  entityName,
@@ -1043,34 +1065,22 @@ function buildTrait7(c) {
1043
1065
  emptyTitle: `No ${pluralName.toLowerCase()} yet`,
1044
1066
  emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
1045
1067
  className: "transition-shadow hover:shadow-md cursor-pointer",
1046
- children: [{
1068
+ renderItem: ["fn", "item", {
1047
1069
  type: "stack",
1048
1070
  direction: "vertical",
1049
1071
  gap: "sm",
1050
1072
  children: [
1051
- { type: "typography", variant: "h4", content: `@entity.${displayField}` },
1052
- // secondary caption row to distinguish items
1053
- { type: "typography", variant: "caption", color: "muted", content: `@entity.id` }
1073
+ { type: "typography", variant: "h4", content: "@item.name" },
1074
+ { type: "typography", variant: "caption", color: "muted", content: "@item.id" }
1054
1075
  ]
1055
1076
  }]
1056
1077
  },
1057
1078
  {
1058
- // Pagination footer with context: "Page N" and Prev/Next nav
1059
- type: "stack",
1060
- direction: "horizontal",
1061
- gap: "sm",
1062
- justify: "center",
1063
- align: "center",
1064
- children: [
1065
- { type: "button", label: "Previous", event: "PAGE", variant: "ghost", icon: "chevron-left" },
1066
- {
1067
- type: "typography",
1068
- variant: "body",
1069
- color: "muted",
1070
- content: ["concat", "Page ", "@entity.currentPage"]
1071
- },
1072
- { type: "button", label: "Next", event: "PAGE", variant: "ghost", icon: "chevron-right" }
1073
- ]
1079
+ type: "pagination",
1080
+ currentPage: 1,
1081
+ totalPages: 10,
1082
+ onPageChange: "PAGE",
1083
+ showPageSize: false
1074
1084
  }
1075
1085
  ]
1076
1086
  };
@@ -1104,10 +1114,58 @@ function buildTrait7(c) {
1104
1114
  to: "idle",
1105
1115
  event: "PAGE",
1106
1116
  effects: [
1107
- ["set", "@entity.currentPage", "@payload.page"],
1108
- ["set", "@entity.pageSize", "@payload.pageSize"],
1109
1117
  ["fetch", entityName],
1110
- ["render-ui", "main", mainView]
1118
+ ["render-ui", "main", {
1119
+ type: "stack",
1120
+ direction: "vertical",
1121
+ gap: "lg",
1122
+ children: [
1123
+ {
1124
+ type: "stack",
1125
+ direction: "horizontal",
1126
+ gap: "sm",
1127
+ justify: "space-between",
1128
+ align: "center",
1129
+ children: [
1130
+ {
1131
+ type: "stack",
1132
+ direction: "horizontal",
1133
+ gap: "sm",
1134
+ align: "center",
1135
+ children: [
1136
+ { type: "icon", name: headerIcon, size: "lg" },
1137
+ { type: "typography", content: pageTitle, variant: "h2" }
1138
+ ]
1139
+ }
1140
+ ]
1141
+ },
1142
+ { type: "divider" },
1143
+ {
1144
+ type: "data-grid",
1145
+ entity: entityName,
1146
+ emptyIcon: "inbox",
1147
+ emptyTitle: `No ${pluralName.toLowerCase()} yet`,
1148
+ emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
1149
+ className: "transition-shadow hover:shadow-md cursor-pointer",
1150
+ renderItem: ["fn", "item", {
1151
+ type: "stack",
1152
+ direction: "vertical",
1153
+ gap: "sm",
1154
+ children: [
1155
+ { type: "typography", variant: "h4", content: "@item.name" },
1156
+ { type: "typography", variant: "caption", color: "muted", content: "@item.id" }
1157
+ ]
1158
+ }]
1159
+ },
1160
+ {
1161
+ type: "pagination",
1162
+ currentPage: "@payload.page",
1163
+ totalPages: 10,
1164
+ onPageChange: "PAGE",
1165
+ showPageSize: false
1166
+ }
1167
+ ]
1168
+ }]
1111
1169
  ]
1112
1170
  }
1113
1171
  ]
@@ -1158,6 +1216,7 @@ function resolve8(params) {
1158
1216
  function buildEntity8(c) {
1159
1217
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
1160
1218
  }
1219
+ var ef = (field) => ["object/get", ["array/first", "@entity"], field];
1161
1220
  function buildTrait8(c) {
1162
1221
  const { entityName, nonIdFields, displayField, pluralName, drawerTitle, headerIcon } = c;
1163
1222
  const closedView = {
@@ -1192,60 +1251,63 @@ function buildTrait8(c) {
1192
1251
  emptyIcon: "inbox",
1193
1252
  emptyTitle: `No ${pluralName.toLowerCase()} yet`,
1194
1253
  emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
1195
- children: [{
1254
+ renderItem: ["fn", "item", {
1196
1255
  type: "stack",
1197
1256
  direction: "vertical",
1198
1257
  gap: "sm",
1199
1258
  children: [
1200
- { type: "typography", variant: "h4", content: `@entity.${displayField}` }
1259
+ { type: "typography", variant: "h4", content: `@item.${displayField}` }
1201
1260
  ]
1202
1261
  }]
1203
1262
  }
1204
1263
  ]
1205
1264
  };
1206
1265
  const openView = {
1207
- type: "stack",
1208
- direction: "vertical",
1209
- gap: "md",
1266
+ type: "drawer",
1267
+ title: drawerTitle,
1268
+ isOpen: true,
1210
1269
  children: [
1211
1270
  {
1212
1271
  type: "stack",
1213
- direction: "horizontal",
1214
- gap: "sm",
1215
- justify: "space-between",
1216
- align: "center",
1272
+ direction: "vertical",
1273
+ gap: "md",
1217
1274
  children: [
1275
+ {
1276
+ type: "accordion",
1277
+ items: [
1278
+ {
1279
+ id: "details",
1280
+ title: "Details",
1281
+ content: {
1282
+ type: "stack",
1283
+ direction: "vertical",
1284
+ gap: "sm",
1285
+ children: nonIdFields.map((field) => ({
1286
+ type: "stack",
1287
+ direction: "horizontal",
1288
+ gap: "md",
1289
+ justify: "space-between",
1290
+ children: [
1291
+ { type: "typography", variant: "caption", content: field.name.charAt(0).toUpperCase() + field.name.slice(1) },
1292
+ { type: "typography", variant: "body", content: ef(field.name) }
1293
+ ]
1294
+ }))
1295
+ }
1296
+ }
1297
+ ],
1298
+ defaultOpen: [0],
1299
+ multiple: true
1300
+ },
1301
+ { type: "divider" },
1218
1302
  {
1219
1303
  type: "stack",
1220
1304
  direction: "horizontal",
1221
1305
  gap: "sm",
1222
- align: "center",
1306
+ justify: "end",
1223
1307
  children: [
1224
- { type: "icon", name: headerIcon, size: "md" },
1225
- { type: "typography", content: drawerTitle, variant: "h3" }
1308
+ { type: "button", label: "Close", event: "CLOSE", variant: "ghost" }
1226
1309
  ]
1227
- },
1228
- { type: "button", label: "Close", event: "CLOSE", variant: "ghost", icon: "x" }
1229
- ]
1230
- },
1231
- { type: "divider" },
1232
- ...nonIdFields.map((field) => ({
1233
- type: "stack",
1234
- direction: "horizontal",
1235
- gap: "md",
1236
- children: [
1237
- { type: "typography", variant: "caption", content: field.name.charAt(0).toUpperCase() + field.name.slice(1) },
1238
- { type: "typography", variant: "body", content: `@entity.${field.name}` }
1239
- ]
1240
- })),
1241
- { type: "divider" },
1242
- {
1243
- type: "stack",
1244
- direction: "horizontal",
1245
- gap: "sm",
1246
- justify: "end",
1247
- children: [
1248
- { type: "button", label: "Close", event: "CLOSE", variant: "ghost" }
1310
+ }
1249
1311
  ]
1250
1312
  }
1251
1313
  ]
@@ -1288,7 +1350,9 @@ function buildTrait8(c) {
1288
1350
  to: "closed",
1289
1351
  event: "CLOSE",
1290
1352
  effects: [
1291
- ["render-ui", "drawer", null]
1353
+ ["render-ui", "drawer", null],
1354
+ ["fetch", entityName],
1355
+ ["render-ui", "main", closedView]
1292
1356
  ]
1293
1357
  }
1294
1358
  ]
@@ -1341,6 +1405,7 @@ function resolve9(params) {
1341
1405
  function buildEntity9(c) {
1342
1406
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
1343
1407
  }
1408
+ var ef2 = (field) => ["object/get", ["array/first", "@entity"], field];
1344
1409
  function buildTrait9(c) {
1345
1410
  const { entityName, headerIcon, pageTitle } = c;
1346
1411
  const hiddenView = {
@@ -1359,17 +1424,7 @@ function buildTrait9(c) {
1359
1424
  ]
1360
1425
  },
1361
1426
  { type: "divider" },
1362
- {
1363
- type: "stack",
1364
- direction: "vertical",
1365
- gap: "md",
1366
- align: "center",
1367
- children: [
1368
- { type: "icon", name: "bell-off", size: "lg" },
1369
- { type: "typography", content: "No notifications", variant: "body" },
1370
- { type: "typography", content: "New notifications will appear here.", variant: "caption" }
1371
- ]
1372
- }
1427
+ { type: "empty-state", icon: "bell-off", title: "No notifications", description: "New notifications will appear here." }
1373
1428
  ]
1374
1429
  };
1375
1430
  const visibleView = {
@@ -1399,22 +1454,9 @@ function buildTrait9(c) {
1399
1454
  },
1400
1455
  { type: "divider" },
1401
1456
  {
1402
- type: "stack",
1403
- direction: "horizontal",
1404
- gap: "md",
1405
- align: "center",
1406
- children: [
1407
- { type: "icon", name: headerIcon, size: "md" },
1408
- {
1409
- type: "stack",
1410
- direction: "vertical",
1411
- gap: "xs",
1412
- children: [
1413
- { type: "typography", content: "@entity.message", variant: "body" },
1414
- { type: "badge", label: "@entity.notificationType" }
1415
- ]
1416
- }
1417
- ]
1457
+ type: "alert",
1458
+ variant: ef2("notificationType"),
1459
+ message: ef2("message")
1418
1460
  }
1419
1461
  ]
1420
1462
  };
@@ -1529,6 +1571,7 @@ function resolve10(params) {
1529
1571
  function buildEntity10(c) {
1530
1572
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
1531
1573
  }
1574
+ var ef3 = (field) => ["object/get", ["array/first", "@entity"], field];
1532
1575
  function buildTrait10(c) {
1533
1576
  const { entityName, timerTitle, headerIcon } = c;
1534
1577
  const timerDisplay = {
@@ -1548,13 +1591,11 @@ function buildTrait10(c) {
1548
1591
  ]
1549
1592
  },
1550
1593
  { type: "divider" },
1551
- // Large MM:SS time display the entity.remaining field drives this
1552
- { type: "typography", content: "@entity.remaining", variant: "h1" },
1553
- // Unit/label subtitle: shows what is being timed
1554
- { type: "typography", content: "seconds remaining", variant: "caption", color: "muted" },
1555
- // Progress bar track — always visible, filled as timer decrements
1556
- { type: "progress-bar", value: "@entity.remaining", max: c.duration, color: "primary" },
1557
- { type: "badge", label: "@entity.status" }
1594
+ { type: "animated-counter", value: ef3("remaining"), suffix: "s", duration: 500 },
1595
+ { type: "stat-display", label: "Time Remaining", value: ef3("remaining"), max: c.duration },
1596
+ { type: "meter", value: ef3("remaining"), min: 0, max: c.duration },
1597
+ { type: "progress-bar", value: ef3("remaining"), max: c.duration, color: "primary", showPercentage: true },
1598
+ { type: "badge", label: ef3("status") }
1558
1599
  ]
1559
1600
  };
1560
1601
  const idleButtons = {
@@ -1764,11 +1805,7 @@ function resolve11(params) {
1764
1805
  const { entityName } = params;
1765
1806
  const baseFields = ensureIdField(params.fields);
1766
1807
  const p = plural(entityName);
1767
- const domainFields = [
1768
- { name: "activeTab", type: "string", default: "" }
1769
- ];
1770
- const userFieldNames = new Set(baseFields.map((f) => f.name));
1771
- const fields = [...baseFields, ...domainFields.filter((f) => !userFieldNames.has(f.name))];
1808
+ const fields = baseFields;
1772
1809
  const nonIdFields = fields.filter((f) => f.name !== "id");
1773
1810
  const tabItems = params.tabItems ?? nonIdFields.filter((f) => f.name !== "activeTab").map((f) => ({
1774
1811
  label: f.name.charAt(0).toUpperCase() + f.name.slice(1),
@@ -1795,7 +1832,21 @@ function buildEntity11(c) {
1795
1832
  }
1796
1833
  function buildTrait11(c) {
1797
1834
  const { entityName, displayField, pluralName, headerIcon, pageTitle, tabItems } = c;
1798
- const mainView = {
1835
+ const tabContentChildren = [
1836
+ {
1837
+ type: "data-grid",
1838
+ entity: entityName,
1839
+ emptyIcon: "inbox",
1840
+ emptyTitle: `No ${pluralName.toLowerCase()} yet`,
1841
+ emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
1842
+ className: "transition-shadow hover:shadow-md cursor-pointer",
1843
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: [
1844
+ { type: "typography", variant: "h4", content: `@item.${displayField}` },
1845
+ { type: "typography", variant: "caption", color: "muted", content: `@item.${tabItems[0]?.value ?? displayField}` }
1846
+ ] }]
1847
+ }
1848
+ ];
1849
+ const initView = {
1799
1850
  type: "stack",
1800
1851
  direction: "vertical",
1801
1852
  gap: "lg",
@@ -1809,24 +1860,31 @@ function buildTrait11(c) {
1809
1860
  type: "tabs",
1810
1861
  tabs: tabItems,
1811
1862
  defaultActiveTab: tabItems[0]?.value ?? "",
1812
- // active tab gets primary color underline and text
1813
- activeTab: "@entity.activeTab",
1814
1863
  onTabChange: "SELECT_TAB"
1815
1864
  },
1816
- // divider separates tab bar from content
1865
+ { type: "divider" },
1866
+ ...tabContentChildren
1867
+ ]
1868
+ };
1869
+ const tabSelectedView = {
1870
+ type: "stack",
1871
+ direction: "vertical",
1872
+ gap: "lg",
1873
+ children: [
1874
+ { type: "stack", direction: "horizontal", gap: "sm", align: "center", children: [
1875
+ { type: "icon", name: headerIcon, size: "lg" },
1876
+ { type: "typography", content: pageTitle, variant: "h2" }
1877
+ ] },
1817
1878
  { type: "divider" },
1818
1879
  {
1819
- type: "data-grid",
1820
- entity: entityName,
1821
- emptyIcon: "inbox",
1822
- emptyTitle: `No ${pluralName.toLowerCase()} yet`,
1823
- emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
1824
- className: "transition-shadow hover:shadow-md cursor-pointer",
1825
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: [
1826
- { type: "typography", variant: "h4", content: `@entity.${displayField}` },
1827
- { type: "typography", variant: "caption", color: "muted", content: `@entity.${tabItems[0]?.value ?? displayField}` }
1828
- ] }]
1829
- }
1880
+ type: "tabs",
1881
+ tabs: tabItems,
1882
+ defaultActiveTab: tabItems[0]?.value ?? "",
1883
+ activeTab: "@payload.tab",
1884
+ onTabChange: "SELECT_TAB"
1885
+ },
1886
+ { type: "divider" },
1887
+ ...tabContentChildren
1830
1888
  ]
1831
1889
  };
1832
1890
  return {
@@ -1837,11 +1895,13 @@ function buildTrait11(c) {
1837
1895
  states: [{ name: "idle", isInitial: true }],
1838
1896
  events: [
1839
1897
  { key: "INIT", name: "Initialize" },
1840
- { key: "SELECT_TAB", name: "Select Tab" }
1898
+ { key: "SELECT_TAB", name: "Select Tab", payload: [
1899
+ { name: "tab", type: "string", required: true }
1900
+ ] }
1841
1901
  ],
1842
1902
  transitions: [
1843
- { from: "idle", to: "idle", event: "INIT", effects: [["fetch", entityName], ["render-ui", "main", mainView]] },
1844
- { from: "idle", to: "idle", event: "SELECT_TAB", effects: [["fetch", entityName], ["render-ui", "main", mainView]] }
1903
+ { from: "idle", to: "idle", event: "INIT", effects: [["fetch", entityName], ["render-ui", "main", initView]] },
1904
+ { from: "idle", to: "idle", event: "SELECT_TAB", effects: [["fetch", entityName], ["render-ui", "main", tabSelectedView]] }
1845
1905
  ]
1846
1906
  }
1847
1907
  };
@@ -1897,7 +1957,6 @@ function buildTrait12(c) {
1897
1957
  align: "center",
1898
1958
  children: [
1899
1959
  {
1900
- // Neutral icon in idle (not the spinner — that lives only in the loading state)
1901
1960
  type: "stack",
1902
1961
  direction: "horizontal",
1903
1962
  gap: "sm",
@@ -1908,41 +1967,24 @@ function buildTrait12(c) {
1908
1967
  ]
1909
1968
  },
1910
1969
  { type: "divider" },
1911
- // Contextual description of what this loading operation does
1912
1970
  {
1913
1971
  type: "typography",
1914
1972
  variant: "body",
1915
1973
  color: "muted",
1916
- content: `Ready to load ${title.toLowerCase()}. Click Start to begin.`
1917
- },
1918
- { type: "button", label: "Start", event: "START", variant: "primary", icon: "play" }
1919
- ]
1920
- };
1921
- const loadingView = {
1922
- type: "stack",
1923
- direction: "vertical",
1924
- gap: "lg",
1925
- align: "center",
1926
- children: [
1927
- {
1928
- // Spinner icon appears only in the loading state — not permanently
1929
- type: "stack",
1930
- direction: "horizontal",
1931
- gap: "sm",
1932
- align: "center",
1933
- children: [
1934
- { type: "icon", name: "loader", size: "lg" },
1935
- { type: "typography", content: "Loading...", variant: "h2" }
1936
- ]
1937
- },
1938
- { type: "divider" },
1939
- { type: "progress-bar", value: 50 },
1940
- {
1941
- type: "typography",
1942
- variant: "caption",
1943
- color: "muted",
1944
- content: "Please wait while the operation completes."
1945
- }
1974
+ content: `Ready to load ${title.toLowerCase()}. Click Start to begin.`
1975
+ },
1976
+ { type: "button", label: "Start", event: "START", variant: "primary", icon: "play" }
1977
+ ]
1978
+ };
1979
+ const loadingView = {
1980
+ type: "stack",
1981
+ direction: "vertical",
1982
+ gap: "lg",
1983
+ align: "center",
1984
+ children: [
1985
+ { type: "loading-state", title: "Loading", message: `Loading ${title.toLowerCase()}...` },
1986
+ { type: "progress-bar", value: 50, showPercentage: true },
1987
+ { type: "skeleton", variant: "text" }
1946
1988
  ]
1947
1989
  };
1948
1990
  const successView = {
@@ -1962,7 +2004,7 @@ function buildTrait12(c) {
1962
2004
  ]
1963
2005
  },
1964
2006
  { type: "divider" },
1965
- { type: "typography", variant: "body", content: "Operation completed successfully." },
2007
+ { type: "alert", variant: "success", message: "Operation completed successfully." },
1966
2008
  { type: "button", label: "Reset", event: "RESET", variant: "ghost", icon: "rotate-ccw" }
1967
2009
  ]
1968
2010
  };
@@ -1972,18 +2014,7 @@ function buildTrait12(c) {
1972
2014
  gap: "lg",
1973
2015
  align: "center",
1974
2016
  children: [
1975
- {
1976
- type: "stack",
1977
- direction: "horizontal",
1978
- gap: "md",
1979
- align: "center",
1980
- children: [
1981
- { type: "icon", name: "alert-circle", size: "lg" },
1982
- { type: "typography", content: "Error", variant: "h2" }
1983
- ]
1984
- },
1985
- { type: "divider" },
1986
- { type: "typography", variant: "body", content: "Something went wrong." },
2017
+ { type: "error-state", title: "Error", message: "Something went wrong. Please try again.", onRetry: "START" },
1987
2018
  {
1988
2019
  type: "stack",
1989
2020
  direction: "horizontal",
@@ -2106,11 +2137,8 @@ function stdLoading(params) {
2106
2137
  function resolve13(params) {
2107
2138
  const { entityName } = params;
2108
2139
  const baseFields = ensureIdField(params.fields);
2109
- const fields = [
2110
- ...baseFields,
2111
- ...baseFields.some((f) => f.name === "selectedId") ? [] : [{ name: "selectedId", type: "string", default: "" }]
2112
- ];
2113
- const nonIdFields = baseFields.filter((f) => f.name !== "id" && f.name !== "selectedId");
2140
+ const fields = baseFields;
2141
+ const nonIdFields = baseFields.filter((f) => f.name !== "id");
2114
2142
  const p = plural(entityName);
2115
2143
  return {
2116
2144
  entityName,
@@ -2147,7 +2175,6 @@ function buildTrait13(c) {
2147
2175
  ]
2148
2176
  },
2149
2177
  { type: "divider" },
2150
- // Meaningful action prompt using entity name
2151
2178
  {
2152
2179
  type: "typography",
2153
2180
  variant: "caption",
@@ -2161,16 +2188,14 @@ function buildTrait13(c) {
2161
2188
  emptyTitle: `No ${pluralName.toLowerCase()} yet`,
2162
2189
  emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
2163
2190
  className: "transition-shadow hover:shadow-md cursor-pointer",
2164
- children: [{
2165
- // Checkbox-style affordance on LEFT of each row, then the entity name
2191
+ itemActions: [{ label: "Select", event: "SELECT", icon: "check" }],
2192
+ renderItem: ["fn", "item", {
2166
2193
  type: "stack",
2167
2194
  direction: "horizontal",
2168
2195
  gap: "sm",
2169
2196
  align: "center",
2170
2197
  children: [
2171
- { type: "icon", name: "circle", size: "sm", color: "muted" },
2172
- { type: "typography", variant: "h4", content: `@entity.${displayField}` },
2173
- { type: "button", label: "Select", event: "SELECT", variant: "ghost", icon: "check" }
2198
+ { type: "checkbox", label: `@item.${displayField}` }
2174
2199
  ]
2175
2200
  }]
2176
2201
  }
@@ -2212,22 +2237,35 @@ function buildTrait13(c) {
2212
2237
  },
2213
2238
  { type: "divider" },
2214
2239
  {
2215
- type: "stack",
2216
- direction: "horizontal",
2217
- gap: "md",
2218
- align: "center",
2219
- children: [
2220
- { type: "typography", variant: "caption", content: "Selected ID:" },
2221
- { type: "typography", variant: "body", content: "@entity.selectedId" }
2222
- ]
2240
+ type: "alert",
2241
+ variant: "info",
2242
+ message: ["concat", "Selected: ", "@payload.id"]
2243
+ },
2244
+ {
2245
+ type: "data-grid",
2246
+ entity: entityName,
2247
+ emptyIcon: "inbox",
2248
+ emptyTitle: `No ${pluralName.toLowerCase()} yet`,
2249
+ emptyDescription: `Add ${pluralName.toLowerCase()} to see them here.`,
2250
+ itemActions: [{ label: "Select", event: "SELECT", icon: "check" }],
2251
+ renderItem: ["fn", "item", {
2252
+ type: "stack",
2253
+ direction: "horizontal",
2254
+ gap: "sm",
2255
+ align: "center",
2256
+ children: [
2257
+ { type: "checkbox", label: `@item.${displayField}`, checked: ["==", "@item.id", "@payload.id"] }
2258
+ ]
2259
+ }]
2223
2260
  },
2261
+ { type: "divider" },
2224
2262
  {
2225
2263
  type: "stack",
2226
2264
  direction: "horizontal",
2227
2265
  gap: "sm",
2228
2266
  justify: "center",
2229
2267
  children: [
2230
- { type: "button", label: "Confirm", event: "CONFIRM_SELECTION", variant: "primary", icon: "check" },
2268
+ { type: "button", label: "Confirm", event: "CONFIRM_SELECTION", actionPayload: { id: "@payload.id" }, variant: "primary", icon: "check" },
2231
2269
  { type: "button", label: "Deselect", event: "DESELECT", variant: "ghost", icon: "x" }
2232
2270
  ]
2233
2271
  }
@@ -2259,6 +2297,11 @@ function buildTrait13(c) {
2259
2297
  ]
2260
2298
  },
2261
2299
  { type: "divider" },
2300
+ {
2301
+ type: "alert",
2302
+ variant: "success",
2303
+ message: "Selection confirmed successfully."
2304
+ },
2262
2305
  {
2263
2306
  type: "stack",
2264
2307
  direction: "horizontal",
@@ -2266,7 +2309,7 @@ function buildTrait13(c) {
2266
2309
  align: "center",
2267
2310
  children: [
2268
2311
  { type: "typography", variant: "caption", content: "Selected ID:" },
2269
- { type: "typography", variant: "body", content: "@entity.selectedId" }
2312
+ { type: "typography", variant: "body", content: "@payload.id" }
2270
2313
  ]
2271
2314
  },
2272
2315
  { type: "button", label: "Clear Selection", event: "CLEAR", variant: "ghost", icon: "rotate-ccw" }
@@ -2289,7 +2332,9 @@ function buildTrait13(c) {
2289
2332
  ] },
2290
2333
  { key: "DESELECT", name: "Deselect" },
2291
2334
  { key: "CLEAR", name: "Clear" },
2292
- { key: "CONFIRM_SELECTION", name: "Confirm Selection" }
2335
+ { key: "CONFIRM_SELECTION", name: "Confirm Selection", payload: [
2336
+ { name: "id", type: "string", required: true }
2337
+ ] }
2293
2338
  ],
2294
2339
  transitions: [
2295
2340
  {
@@ -2306,7 +2351,7 @@ function buildTrait13(c) {
2306
2351
  to: "selecting",
2307
2352
  event: "SELECT",
2308
2353
  effects: [
2309
- ["set", "@entity.selectedId", "@payload.id"],
2354
+ ["fetch", entityName],
2310
2355
  ["render-ui", "main", selectingView]
2311
2356
  ]
2312
2357
  },
@@ -2315,7 +2360,7 @@ function buildTrait13(c) {
2315
2360
  to: "selecting",
2316
2361
  event: "SELECT",
2317
2362
  effects: [
2318
- ["set", "@entity.selectedId", "@payload.id"],
2363
+ ["fetch", entityName],
2319
2364
  ["render-ui", "main", selectingView]
2320
2365
  ]
2321
2366
  },
@@ -2324,7 +2369,6 @@ function buildTrait13(c) {
2324
2369
  to: "idle",
2325
2370
  event: "DESELECT",
2326
2371
  effects: [
2327
- ["set", "@entity.selectedId", ""],
2328
2372
  ["fetch", entityName],
2329
2373
  ["render-ui", "main", idleView]
2330
2374
  ]
@@ -2334,7 +2378,6 @@ function buildTrait13(c) {
2334
2378
  to: "idle",
2335
2379
  event: "CLEAR",
2336
2380
  effects: [
2337
- ["set", "@entity.selectedId", ""],
2338
2381
  ["fetch", entityName],
2339
2382
  ["render-ui", "main", idleView]
2340
2383
  ]
@@ -2352,7 +2395,6 @@ function buildTrait13(c) {
2352
2395
  to: "idle",
2353
2396
  event: "CLEAR",
2354
2397
  effects: [
2355
- ["set", "@entity.selectedId", ""],
2356
2398
  ["fetch", entityName],
2357
2399
  ["render-ui", "main", idleView]
2358
2400
  ]
@@ -2408,6 +2450,7 @@ function resolve14(params) {
2408
2450
  function buildEntity14(c) {
2409
2451
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
2410
2452
  }
2453
+ var ef4 = (field) => ["object/get", ["array/first", "@entity"], field];
2411
2454
  function buildTrait14(c) {
2412
2455
  const { entityName, headerIcon, pageTitle } = c;
2413
2456
  const mainView = {
@@ -2421,17 +2464,22 @@ function buildTrait14(c) {
2421
2464
  { type: "typography", content: pageTitle, variant: "h2" }
2422
2465
  ] },
2423
2466
  { type: "stack", direction: "horizontal", gap: "sm", align: "center", children: [
2424
- { type: "button", label: "Undo", event: "UNDO", variant: "ghost", icon: "undo" },
2425
- { type: "button", label: "Redo", event: "REDO", variant: "ghost", icon: "redo" },
2426
- // gap-6 spacer between Redo and Clear to prevent misclicking destructive action
2467
+ { type: "tooltip", content: "Undo the last action", children: [
2468
+ { type: "button", label: "Undo", event: "UNDO", variant: "ghost", icon: "undo" }
2469
+ ] },
2470
+ { type: "tooltip", content: "Redo the last undone action", children: [
2471
+ { type: "button", label: "Redo", event: "REDO", variant: "ghost", icon: "redo" }
2472
+ ] },
2427
2473
  { type: "divider", orientation: "vertical" },
2428
- { type: "button", label: "Clear", event: "CLEAR", variant: "ghost", icon: "trash-2" }
2474
+ { type: "tooltip", content: "Clear all history", children: [
2475
+ { type: "button", label: "Clear", event: "CLEAR", variant: "ghost", icon: "trash-2" }
2476
+ ] }
2429
2477
  ] }
2430
2478
  ] },
2431
2479
  { type: "divider" },
2432
2480
  { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
2433
2481
  { type: "typography", variant: "caption", color: "muted", content: "Last action:" },
2434
- { type: "badge", label: "@entity.current" }
2482
+ { type: "badge", label: ef4("current") }
2435
2483
  ] }
2436
2484
  ]
2437
2485
  };
@@ -2528,6 +2576,7 @@ function resolve15(params) {
2528
2576
  function buildEntity15(c) {
2529
2577
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
2530
2578
  }
2579
+ var ef5 = (field) => ["object/get", ["array/first", "@entity"], field];
2531
2580
  function buildTrait15(c) {
2532
2581
  const { entityName, inputLabel, placeholder, headerIcon } = c;
2533
2582
  const inputView = {
@@ -2547,22 +2596,14 @@ function buildTrait15(c) {
2547
2596
  },
2548
2597
  { type: "divider" },
2549
2598
  {
2550
- // Form field pattern: label above, input below, help text below input
2551
- type: "stack",
2552
- direction: "vertical",
2553
- gap: "sm",
2599
+ type: "form-field",
2600
+ label: inputLabel,
2601
+ hint: "Type to enter a value.",
2554
2602
  children: [
2555
- { type: "typography", variant: "caption", content: inputLabel },
2556
- { type: "input", placeholder, event: "CHANGE" },
2557
- // show current entered value as status below the field (not a mystery bar)
2558
- {
2559
- type: "typography",
2560
- variant: "caption",
2561
- color: "muted",
2562
- content: "@entity.value"
2563
- }
2603
+ { type: "input", placeholder, event: "CHANGE" }
2564
2604
  ]
2565
- }
2605
+ },
2606
+ { type: "typography", variant: "caption", color: "muted", content: ef5("value") }
2566
2607
  ]
2567
2608
  };
2568
2609
  const validatingView = {
@@ -2582,21 +2623,14 @@ function buildTrait15(c) {
2582
2623
  },
2583
2624
  { type: "divider" },
2584
2625
  {
2585
- type: "stack",
2586
- direction: "vertical",
2587
- gap: "sm",
2626
+ type: "form-field",
2627
+ label: inputLabel,
2628
+ hint: "Validating...",
2588
2629
  children: [
2589
- { type: "typography", variant: "caption", content: inputLabel },
2590
- { type: "input", placeholder, event: "CHANGE" },
2591
- // semantic validation message — shown only in validating state
2592
- {
2593
- type: "typography",
2594
- variant: "caption",
2595
- color: "muted",
2596
- content: "Validating..."
2597
- }
2630
+ { type: "input", placeholder, event: "CHANGE" }
2598
2631
  ]
2599
- }
2632
+ },
2633
+ { type: "alert", variant: "info", message: "Validating input..." }
2600
2634
  ]
2601
2635
  };
2602
2636
  return {
@@ -2749,7 +2783,6 @@ function buildEntity16(c) {
2749
2783
  }
2750
2784
  function buildStepUI(c, stepIndex) {
2751
2785
  const step = c.steps[stepIndex];
2752
- const stepNumber = stepIndex + 1;
2753
2786
  const isFirst = stepIndex === 0;
2754
2787
  const navButtons = [];
2755
2788
  if (!isFirst) {
@@ -2771,7 +2804,7 @@ function buildStepUI(c, stepIndex) {
2771
2804
  { type: "typography", content: c.wizardTitle, variant: "h2" }
2772
2805
  ]
2773
2806
  },
2774
- { type: "badge", label: `Step ${stepNumber} of ${c.totalSteps}` },
2807
+ { type: "progress-dots", count: c.totalSteps, currentIndex: stepIndex },
2775
2808
  { type: "wizard-progress", steps: c.wizardProgressSteps, currentStep: stepIndex },
2776
2809
  { type: "divider" },
2777
2810
  { type: "typography", content: step.name, variant: "h3" },
@@ -2794,7 +2827,7 @@ function buildReviewUI(c) {
2794
2827
  justify: "space-between",
2795
2828
  children: [
2796
2829
  { type: "typography", variant: "caption", content: field.name.charAt(0).toUpperCase() + field.name.slice(1) },
2797
- { type: "typography", variant: "body", content: `@entity.${field.name}` }
2830
+ { type: "typography", variant: "body", content: `@item.${field.name}` }
2798
2831
  ]
2799
2832
  }));
2800
2833
  return {
@@ -2818,24 +2851,20 @@ function buildReviewUI(c) {
2818
2851
  {
2819
2852
  type: "data-list",
2820
2853
  entity: c.entityName,
2821
- children: [
2822
- {
2823
- type: "stack",
2824
- direction: "vertical",
2825
- gap: "sm",
2826
- children: reviewDetailChildren
2827
- }
2828
- ]
2854
+ renderItem: ["fn", "item", {
2855
+ type: "stack",
2856
+ direction: "vertical",
2857
+ gap: "sm",
2858
+ children: reviewDetailChildren
2859
+ }]
2829
2860
  },
2830
2861
  {
2831
- type: "stack",
2832
- direction: "horizontal",
2833
- gap: "sm",
2834
- justify: "end",
2835
- children: [
2836
- { type: "button", label: "Back", event: "PREV", variant: "ghost", icon: "arrow-left" },
2837
- { type: "button", label: c.submitButtonLabel, event: "COMPLETE", variant: "primary", icon: "check" }
2838
- ]
2862
+ type: "wizard-navigation",
2863
+ currentStep: c.totalSteps,
2864
+ totalSteps: c.totalSteps + 1,
2865
+ showBack: true,
2866
+ showComplete: true,
2867
+ showNext: false
2839
2868
  }
2840
2869
  ]
2841
2870
  };
@@ -3001,20 +3030,28 @@ function resolve17(params) {
3001
3030
  isInitial: params.isInitial ?? false
3002
3031
  };
3003
3032
  }
3033
+ var ef6 = (field) => ["object/get", ["array/first", "@entity"], field];
3004
3034
  function buildTrait17(c) {
3005
3035
  const { entityName, displayFields, headerIcon, pageTitle, refreshButtonLabel, columns } = c;
3006
- const cardChildren = displayFields.map((f) => ({
3007
- type: "card",
3008
- children: [{
3009
- type: "stack",
3010
- direction: "vertical",
3011
- gap: "sm",
3012
- children: [
3013
- { type: "typography", variant: "caption", content: f.charAt(0).toUpperCase() + f.slice(1) },
3014
- { type: "typography", variant: "h3", content: `@entity.${f}` }
3015
- ]
3016
- }]
3017
- }));
3036
+ const cardChildren = displayFields.map((f) => {
3037
+ const field = c.nonIdFields.find((nf) => nf.name === f);
3038
+ const isNumeric = field?.type === "number";
3039
+ if (isNumeric) {
3040
+ return { type: "stat-display", label: f.charAt(0).toUpperCase() + f.slice(1), value: ef6(f) };
3041
+ }
3042
+ return {
3043
+ type: "card",
3044
+ children: [{
3045
+ type: "stack",
3046
+ direction: "vertical",
3047
+ gap: "sm",
3048
+ children: [
3049
+ { type: "typography", variant: "caption", content: f.charAt(0).toUpperCase() + f.slice(1) },
3050
+ { type: "typography", variant: "h3", content: ef6(f) }
3051
+ ]
3052
+ }]
3053
+ };
3054
+ });
3018
3055
  const mainView = {
3019
3056
  type: "stack",
3020
3057
  direction: "vertical",
@@ -3119,6 +3156,7 @@ function buildTrait18(c) {
3119
3156
  ]
3120
3157
  },
3121
3158
  { type: "divider" },
3159
+ { type: "typography", variant: "body", color: "muted", content: `Ready to start ${entityName.toLowerCase()} operation.` },
3122
3160
  { type: "button", label: "Start", event: "START", variant: "primary", icon: "play" }
3123
3161
  ]
3124
3162
  };
@@ -3128,8 +3166,8 @@ function buildTrait18(c) {
3128
3166
  gap: "lg",
3129
3167
  align: "center",
3130
3168
  children: [
3131
- { type: "icon", name: "loader", size: "lg" },
3132
- { type: "typography", content: loadingMessage, variant: "h3" }
3169
+ { type: "loading-state", title: loadingMessage, message: `Processing ${entityName.toLowerCase()}...` },
3170
+ { type: "skeleton", variant: "text" }
3133
3171
  ]
3134
3172
  };
3135
3173
  const successUI = {
@@ -3139,7 +3177,7 @@ function buildTrait18(c) {
3139
3177
  align: "center",
3140
3178
  children: [
3141
3179
  { type: "icon", name: "check-circle", size: "lg" },
3142
- { type: "typography", content: successMessage, variant: "h3" },
3180
+ { type: "alert", variant: "success", message: successMessage },
3143
3181
  {
3144
3182
  type: "stack",
3145
3183
  direction: "horizontal",
@@ -3163,8 +3201,7 @@ function buildTrait18(c) {
3163
3201
  gap: "lg",
3164
3202
  align: "center",
3165
3203
  children: [
3166
- { type: "icon", name: "alert-circle", size: "lg" },
3167
- { type: "typography", content: errorMessage, variant: "h3" },
3204
+ { type: "error-state", title: "Operation Failed", message: errorMessage, onRetry: retryable ? "RETRY" : void 0 },
3168
3205
  {
3169
3206
  type: "stack",
3170
3207
  direction: "horizontal",
@@ -3495,6 +3532,7 @@ function resolve20(params) {
3495
3532
  function buildEntity19(c) {
3496
3533
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence, collection: c.collection });
3497
3534
  }
3535
+ var ef7 = (field) => ["object/get", ["array/first", "@entity"], field];
3498
3536
  function buildTrait20(c) {
3499
3537
  const { entityName, gameTitle, menuTitle, pauseTitle, gameoverTitle } = c;
3500
3538
  const menuUI = {
@@ -3508,8 +3546,8 @@ function buildTrait20(c) {
3508
3546
  const playingUI = {
3509
3547
  type: "game-hud",
3510
3548
  stats: [
3511
- { label: "Score", value: "@entity.score" },
3512
- { label: "Level", value: "@entity.level" }
3549
+ { label: "Score", value: ef7("score") },
3550
+ { label: "Level", value: ef7("level") }
3513
3551
  ]
3514
3552
  };
3515
3553
  const pausedModalUI = {
@@ -3524,8 +3562,8 @@ function buildTrait20(c) {
3524
3562
  type: "game-over-screen",
3525
3563
  title: gameoverTitle,
3526
3564
  stats: [
3527
- { label: "Score", value: "@entity.score" },
3528
- { label: "Level", value: "@entity.level" }
3565
+ { label: "Score", value: ef7("score") },
3566
+ { label: "Level", value: ef7("level") }
3529
3567
  ],
3530
3568
  menuItems: [
3531
3569
  { label: "Play Again", event: "RESTART", variant: "primary" },
@@ -3591,19 +3629,19 @@ function buildTrait20(c) {
3591
3629
  event: "PAUSE",
3592
3630
  effects: [["render-ui", "modal", pausedModalUI]]
3593
3631
  },
3594
- // RESUME: paused -> playing
3632
+ // RESUME: paused -> playing (dismiss modal, re-render main with HUD)
3595
3633
  {
3596
3634
  from: "paused",
3597
3635
  to: "playing",
3598
3636
  event: "RESUME",
3599
- effects: [["render-ui", "modal", null]]
3637
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
3600
3638
  },
3601
3639
  // CLOSE: paused -> playing (modal exit requirement)
3602
3640
  {
3603
3641
  from: "paused",
3604
3642
  to: "playing",
3605
3643
  event: "CLOSE",
3606
- effects: [["render-ui", "modal", null]]
3644
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
3607
3645
  },
3608
3646
  // GAME_OVER: playing -> gameover
3609
3647
  {
@@ -3675,19 +3713,35 @@ function resolve21(params) {
3675
3713
  };
3676
3714
  }
3677
3715
  function buildEntity20(c) {
3678
- return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence, collection: c.collection });
3716
+ const fields = [
3717
+ ...c.fields.filter((f) => !["x", "y"].includes(f.name)),
3718
+ { name: "x", type: "number", default: 0 },
3719
+ { name: "y", type: "number", default: 0 }
3720
+ ];
3721
+ return makeEntity({ name: c.entityName, fields, persistence: c.persistence, collection: c.collection });
3679
3722
  }
3723
+ var ef8 = (field) => ["object/get", ["array/first", "@entity"], field];
3680
3724
  function buildTrait21(c) {
3681
3725
  const { entityName, nonIdFields, headerIcon, pageTitle } = c;
3682
- const fieldSummaryChildren = nonIdFields.slice(0, 4).map((field) => ({
3683
- type: "stack",
3684
- direction: "horizontal",
3685
- gap: "md",
3686
- children: [
3687
- { type: "typography", variant: "caption", content: field.name.charAt(0).toUpperCase() + field.name.slice(1) },
3688
- { type: "typography", variant: "body", content: `@entity.${field.name}` }
3689
- ]
3690
- }));
3726
+ const fieldSummaryChildren = [
3727
+ {
3728
+ type: "simple-grid",
3729
+ columns: 2,
3730
+ children: [
3731
+ { type: "stat-display", label: "X", value: ef8(nonIdFields.find((f) => f.name === "x")?.name ?? "x") },
3732
+ { type: "stat-display", label: "Y", value: ef8(nonIdFields.find((f) => f.name === "y")?.name ?? "y") }
3733
+ ]
3734
+ },
3735
+ ...nonIdFields.slice(0, 4).filter((f) => f.name !== "x" && f.name !== "y").map((field) => ({
3736
+ type: "stack",
3737
+ direction: "horizontal",
3738
+ gap: "md",
3739
+ children: [
3740
+ { type: "typography", variant: "caption", content: field.name.charAt(0).toUpperCase() + field.name.slice(1) },
3741
+ { type: "typography", variant: "body", content: ef8(field.name) }
3742
+ ]
3743
+ }))
3744
+ ];
3691
3745
  const idleMainUI = {
3692
3746
  type: "stack",
3693
3747
  direction: "vertical",
@@ -3708,7 +3762,7 @@ function buildTrait21(c) {
3708
3762
  { type: "typography", content: pageTitle, variant: "h2" }
3709
3763
  ]
3710
3764
  },
3711
- { type: "badge", label: "Idle" }
3765
+ { type: "status-dot", status: "inactive", label: "Idle" }
3712
3766
  ]
3713
3767
  },
3714
3768
  { type: "divider" },
@@ -3745,7 +3799,7 @@ function buildTrait21(c) {
3745
3799
  { type: "typography", content: pageTitle, variant: "h2" }
3746
3800
  ]
3747
3801
  },
3748
- { type: "badge", label: "Moving" }
3802
+ { type: "status-dot", status: "active", pulse: true, label: "Moving" }
3749
3803
  ]
3750
3804
  },
3751
3805
  { type: "divider" },
@@ -3951,15 +4005,15 @@ function buildTrait22(c) {
3951
4005
  align: "center",
3952
4006
  children: [
3953
4007
  { type: "icon", name: headerIcon, size: "sm" },
3954
- { type: "typography", variant: "h4", content: `@entity.${listFields[0] ?? "id"}` }
4008
+ { type: "typography", variant: "h4", content: `@item.${listFields[0] ?? "id"}` }
3955
4009
  ]
3956
4010
  },
3957
- ...listFields.length > 1 ? [{ type: "badge", label: `@entity.${listFields[1]}` }] : []
4011
+ ...listFields.length > 1 ? [{ type: "badge", label: `@item.${listFields[1]}` }] : []
3958
4012
  ]
3959
4013
  }
3960
4014
  ];
3961
4015
  if (listFields.length > 2) {
3962
- listItemChildren.push({ type: "typography", variant: "caption", content: `@entity.${listFields[2]}` });
4016
+ listItemChildren.push({ type: "typography", variant: "caption", content: `@item.${listFields[2]}` });
3963
4017
  }
3964
4018
  const headerBar = {
3965
4019
  type: "stack",
@@ -3986,13 +4040,14 @@ function buildTrait22(c) {
3986
4040
  headerBar,
3987
4041
  { type: "divider" },
3988
4042
  {
3989
- type: "data-grid",
4043
+ type: "data-list",
3990
4044
  entity: entityName,
4045
+ groupBy: "status",
3991
4046
  emptyIcon: "inbox",
3992
4047
  emptyTitle,
3993
4048
  emptyDescription,
3994
4049
  itemActions: [{ label: "Accept", event: "ACCEPT" }],
3995
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4050
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
3996
4051
  }
3997
4052
  ]
3998
4053
  };
@@ -4020,6 +4075,7 @@ function buildTrait22(c) {
4020
4075
  ]
4021
4076
  },
4022
4077
  { type: "divider" },
4078
+ { type: "progress-bar", value: 50, showPercentage: true },
4023
4079
  {
4024
4080
  type: "data-grid",
4025
4081
  entity: entityName,
@@ -4031,7 +4087,7 @@ function buildTrait22(c) {
4031
4087
  { label: "Complete", event: "COMPLETE" },
4032
4088
  { label: "Fail", event: "FAIL", variant: "danger" }
4033
4089
  ],
4034
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4090
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4035
4091
  }
4036
4092
  ]
4037
4093
  };
@@ -4043,7 +4099,7 @@ function buildTrait22(c) {
4043
4099
  children: [
4044
4100
  { type: "icon", name: "check-circle", size: "lg" },
4045
4101
  { type: "typography", content: "Quest Complete", variant: "h2" },
4046
- { type: "typography", content: "Congratulations! The quest has been completed.", variant: "body" },
4102
+ { type: "alert", variant: "success", message: "Congratulations! The quest has been completed." },
4047
4103
  { type: "button", label: "View Quests", event: "RESET", variant: "primary", icon: "arrow-left" }
4048
4104
  ]
4049
4105
  };
@@ -4055,7 +4111,7 @@ function buildTrait22(c) {
4055
4111
  children: [
4056
4112
  { type: "icon", name: "x-circle", size: "lg" },
4057
4113
  { type: "typography", content: "Quest Failed", variant: "h2" },
4058
- { type: "typography", content: "The quest was not completed. You can try again.", variant: "body" },
4114
+ { type: "alert", variant: "danger", message: "The quest was not completed. You can try again." },
4059
4115
  { type: "button", label: "View Quests", event: "RESET", variant: "primary", icon: "arrow-left" }
4060
4116
  ]
4061
4117
  };
@@ -4152,19 +4208,27 @@ function buildTrait22(c) {
4152
4208
  ["render-ui", "main", activeMainUI]
4153
4209
  ]
4154
4210
  },
4155
- // CANCEL: progressing -> active
4211
+ // CANCEL: progressing -> active (re-render main to avoid stale content)
4156
4212
  {
4157
4213
  from: "progressing",
4158
4214
  to: "active",
4159
4215
  event: "CANCEL",
4160
- effects: [["render-ui", "modal", null]]
4216
+ effects: [
4217
+ ["render-ui", "modal", null],
4218
+ ["fetch", entityName],
4219
+ ["render-ui", "main", activeMainUI]
4220
+ ]
4161
4221
  },
4162
- // CLOSE: progressing -> active
4222
+ // CLOSE: progressing -> active (re-render main to avoid stale content)
4163
4223
  {
4164
4224
  from: "progressing",
4165
4225
  to: "active",
4166
4226
  event: "CLOSE",
4167
- effects: [["render-ui", "modal", null]]
4227
+ effects: [
4228
+ ["render-ui", "modal", null],
4229
+ ["fetch", entityName],
4230
+ ["render-ui", "main", activeMainUI]
4231
+ ]
4168
4232
  },
4169
4233
  // COMPLETE: active -> complete
4170
4234
  {
@@ -4272,15 +4336,15 @@ function buildTrait23(c) {
4272
4336
  align: "center",
4273
4337
  children: [
4274
4338
  { type: "icon", name: "map-pin", size: "sm" },
4275
- { type: "typography", variant: "h4", content: `@entity.${listFields[0] ?? "id"}` }
4339
+ { type: "typography", variant: "h4", content: `@item.${listFields[0] ?? "id"}` }
4276
4340
  ]
4277
4341
  },
4278
- ...listFields.length > 1 ? [{ type: "badge", label: `@entity.${listFields[1]}` }] : []
4342
+ ...listFields.length > 1 ? [{ type: "badge", label: `@item.${listFields[1]}` }] : []
4279
4343
  ]
4280
4344
  }
4281
4345
  ];
4282
4346
  if (listFields.length > 2) {
4283
- listItemChildren.push({ type: "typography", variant: "caption", content: `@entity.${listFields[2]}` });
4347
+ listItemChildren.push({ type: "typography", variant: "caption", content: `@item.${listFields[2]}` });
4284
4348
  }
4285
4349
  const exploringMainUI = {
4286
4350
  type: "stack",
@@ -4302,10 +4366,11 @@ function buildTrait23(c) {
4302
4366
  { type: "typography", content: worldTitle, variant: "h2" }
4303
4367
  ]
4304
4368
  },
4305
- { type: "badge", label: "Exploring" }
4369
+ { type: "status-dot", status: "active", pulse: false, label: "Exploring" }
4306
4370
  ]
4307
4371
  },
4308
4372
  { type: "divider" },
4373
+ { type: "map-view", markers: [], height: "200px", zoom: 10 },
4309
4374
  {
4310
4375
  type: "data-grid",
4311
4376
  entity: entityName,
@@ -4313,7 +4378,7 @@ function buildTrait23(c) {
4313
4378
  emptyTitle,
4314
4379
  emptyDescription,
4315
4380
  itemActions: [{ label: "Travel", event: "TRAVEL" }],
4316
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4381
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4317
4382
  }
4318
4383
  ]
4319
4384
  };
@@ -4356,7 +4421,7 @@ function buildTrait23(c) {
4356
4421
  { type: "typography", content: pageTitle, variant: "h2" }
4357
4422
  ]
4358
4423
  },
4359
- { type: "badge", label: "Entered" }
4424
+ { type: "status-dot", status: "success", label: "Entered" }
4360
4425
  ]
4361
4426
  },
4362
4427
  { type: "divider" },
@@ -4366,7 +4431,7 @@ function buildTrait23(c) {
4366
4431
  emptyIcon: "inbox",
4367
4432
  emptyTitle: "Nothing here",
4368
4433
  emptyDescription: "This zone is empty.",
4369
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4434
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4370
4435
  },
4371
4436
  { type: "divider" },
4372
4437
  {
@@ -4481,50 +4546,79 @@ function resolve24(params) {
4481
4546
  };
4482
4547
  }
4483
4548
  function buildEntity23(c) {
4484
- return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence, collection: c.collection });
4549
+ const fields = [
4550
+ ...c.fields.filter((f) => !["failureCount", "successCount", "threshold"].includes(f.name)),
4551
+ { name: "failureCount", type: "number", default: 0 },
4552
+ { name: "successCount", type: "number", default: 0 },
4553
+ { name: "threshold", type: "number", default: 5 }
4554
+ ];
4555
+ return makeEntity({ name: c.entityName, fields, persistence: c.persistence, collection: c.collection });
4485
4556
  }
4557
+ var ef9 = (field) => ["object/get", ["array/first", "@entity"], field];
4486
4558
  function buildTrait24(c) {
4487
4559
  const { entityName, headerIcon, closedLabel, openLabel, halfOpenLabel } = c;
4488
4560
  const closedUI = {
4489
4561
  type: "stack",
4490
4562
  direction: "vertical",
4491
4563
  gap: "lg",
4492
- align: "center",
4493
4564
  children: [
4494
4565
  {
4495
4566
  type: "stack",
4496
4567
  direction: "horizontal",
4497
4568
  gap: "md",
4498
4569
  align: "center",
4570
+ justify: "space-between",
4499
4571
  children: [
4500
- { type: "icon", name: headerIcon, size: "lg" },
4501
- { type: "typography", content: entityName, variant: "h2" }
4572
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
4573
+ { type: "icon", name: headerIcon, size: "lg" },
4574
+ { type: "typography", content: entityName, variant: "h2" }
4575
+ ] },
4576
+ { type: "status-dot", status: "success", pulse: false, label: closedLabel }
4502
4577
  ]
4503
4578
  },
4504
4579
  { type: "divider" },
4505
- { type: "badge", label: closedLabel },
4506
- { type: "typography", content: "Service is healthy. All requests are being processed.", variant: "body" }
4580
+ { type: "alert", variant: "success", message: "Service is healthy. All requests are being processed." },
4581
+ {
4582
+ type: "simple-grid",
4583
+ columns: 2,
4584
+ children: [
4585
+ { type: "stat-display", label: "Failures", value: ef9("failureCount") },
4586
+ { type: "stat-display", label: "Successes", value: ef9("successCount") }
4587
+ ]
4588
+ },
4589
+ { type: "meter", value: ef9("failureCount"), min: 0, max: ef9("threshold") }
4507
4590
  ]
4508
4591
  };
4509
4592
  const openUI = {
4510
4593
  type: "stack",
4511
4594
  direction: "vertical",
4512
4595
  gap: "lg",
4513
- align: "center",
4514
4596
  children: [
4515
4597
  {
4516
4598
  type: "stack",
4517
4599
  direction: "horizontal",
4518
4600
  gap: "md",
4519
4601
  align: "center",
4602
+ justify: "space-between",
4520
4603
  children: [
4521
- { type: "icon", name: "alert-triangle", size: "lg" },
4522
- { type: "typography", content: entityName, variant: "h2" }
4604
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
4605
+ { type: "icon", name: "alert-triangle", size: "lg" },
4606
+ { type: "typography", content: entityName, variant: "h2" }
4607
+ ] },
4608
+ { type: "status-dot", status: "error", pulse: true, label: openLabel }
4523
4609
  ]
4524
4610
  },
4525
4611
  { type: "divider" },
4526
- { type: "badge", label: openLabel },
4527
- { type: "typography", content: "Circuit is open. Requests are being rejected to prevent cascading failures.", variant: "body" },
4612
+ { type: "alert", variant: "danger", message: "Circuit is open. Requests are being rejected to prevent cascading failures." },
4613
+ {
4614
+ type: "simple-grid",
4615
+ columns: 2,
4616
+ children: [
4617
+ { type: "stat-display", label: "Failures", value: ef9("failureCount") },
4618
+ { type: "stat-display", label: "Successes", value: ef9("successCount") }
4619
+ ]
4620
+ },
4621
+ { type: "meter", value: ef9("failureCount"), min: 0, max: ef9("threshold") },
4528
4622
  { type: "button", label: "Reset", event: "RESET", variant: "ghost", icon: "rotate-ccw" }
4529
4623
  ]
4530
4624
  };
@@ -4532,21 +4626,31 @@ function buildTrait24(c) {
4532
4626
  type: "stack",
4533
4627
  direction: "vertical",
4534
4628
  gap: "lg",
4535
- align: "center",
4536
4629
  children: [
4537
4630
  {
4538
4631
  type: "stack",
4539
4632
  direction: "horizontal",
4540
4633
  gap: "md",
4541
4634
  align: "center",
4635
+ justify: "space-between",
4542
4636
  children: [
4543
- { type: "icon", name: "activity", size: "lg" },
4544
- { type: "typography", content: entityName, variant: "h2" }
4637
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
4638
+ { type: "icon", name: "activity", size: "lg" },
4639
+ { type: "typography", content: entityName, variant: "h2" }
4640
+ ] },
4641
+ { type: "status-dot", status: "warning", pulse: true, label: halfOpenLabel }
4545
4642
  ]
4546
4643
  },
4547
4644
  { type: "divider" },
4548
- { type: "badge", label: halfOpenLabel },
4549
- { type: "typography", content: "Testing recovery. Limited requests are being allowed through.", variant: "body" }
4645
+ { type: "alert", variant: "warning", message: "Testing recovery. Limited requests are being allowed through." },
4646
+ {
4647
+ type: "simple-grid",
4648
+ columns: 2,
4649
+ children: [
4650
+ { type: "stat-display", label: "Failures", value: ef9("failureCount") },
4651
+ { type: "stat-display", label: "Successes", value: ef9("successCount") }
4652
+ ]
4653
+ }
4550
4654
  ]
4551
4655
  };
4552
4656
  return {
@@ -4675,8 +4779,14 @@ function resolve25(params) {
4675
4779
  };
4676
4780
  }
4677
4781
  function buildEntity24(c) {
4678
- return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence, collection: c.collection });
4782
+ const fields = [
4783
+ ...c.fields.filter((f) => !["hitCount", "cacheAge"].includes(f.name)),
4784
+ { name: "hitCount", type: "number", default: 0 },
4785
+ { name: "cacheAge", type: "number", default: 0 }
4786
+ ];
4787
+ return makeEntity({ name: c.entityName, fields, persistence: c.persistence, collection: c.collection });
4679
4788
  }
4789
+ var ef10 = (field) => ["object/get", ["array/first", "@entity"], field];
4680
4790
  function buildTrait25(c) {
4681
4791
  const { entityName, listFields, headerIcon } = c;
4682
4792
  const { pageTitle, emptyTitle, emptyDescription } = c;
@@ -4694,15 +4804,15 @@ function buildTrait25(c) {
4694
4804
  align: "center",
4695
4805
  children: [
4696
4806
  { type: "icon", name: headerIcon, size: "sm" },
4697
- { type: "typography", variant: "h4", content: `@entity.${listFields[0] ?? "id"}` }
4807
+ { type: "typography", variant: "h4", content: `@item.${listFields[0] ?? "id"}` }
4698
4808
  ]
4699
4809
  },
4700
- ...listFields.length > 1 ? [{ type: "badge", label: `@entity.${listFields[1]}` }] : []
4810
+ ...listFields.length > 1 ? [{ type: "badge", label: `@item.${listFields[1]}` }] : []
4701
4811
  ]
4702
4812
  }
4703
4813
  ];
4704
4814
  if (listFields.length > 2) {
4705
- listItemChildren.push({ type: "typography", variant: "caption", content: `@entity.${listFields[2]}` });
4815
+ listItemChildren.push({ type: "typography", variant: "caption", content: `@item.${listFields[2]}` });
4706
4816
  }
4707
4817
  const headerBar = {
4708
4818
  type: "stack",
@@ -4727,7 +4837,16 @@ function buildTrait25(c) {
4727
4837
  direction: "vertical",
4728
4838
  gap: "lg",
4729
4839
  children: [
4730
- headerBar,
4840
+ {
4841
+ type: "stack",
4842
+ direction: "horizontal",
4843
+ gap: "md",
4844
+ justify: "space-between",
4845
+ children: [
4846
+ headerBar,
4847
+ { type: "status-dot", status: "inactive", pulse: false, label: "Empty" }
4848
+ ]
4849
+ },
4731
4850
  { type: "divider" },
4732
4851
  { type: "empty-state", icon: "inbox", title: emptyTitle, description: emptyDescription }
4733
4852
  ]
@@ -4756,21 +4875,30 @@ function buildTrait25(c) {
4756
4875
  type: "stack",
4757
4876
  direction: "horizontal",
4758
4877
  gap: "sm",
4878
+ align: "center",
4759
4879
  children: [
4760
- { type: "badge", label: "Cached" },
4880
+ { type: "status-dot", status: "success", pulse: false, label: "Cached" },
4761
4881
  { type: "button", label: "Invalidate", event: "INVALIDATE", variant: "ghost", icon: "trash" }
4762
4882
  ]
4763
4883
  }
4764
4884
  ]
4765
4885
  },
4766
4886
  { type: "divider" },
4887
+ {
4888
+ type: "simple-grid",
4889
+ columns: 2,
4890
+ children: [
4891
+ { type: "stat-display", label: "Hit Count", value: ef10("hitCount") },
4892
+ { type: "stat-display", label: "Cache Age", value: ef10("cacheAge") }
4893
+ ]
4894
+ },
4767
4895
  {
4768
4896
  type: "data-grid",
4769
4897
  entity: entityName,
4770
4898
  emptyIcon: "inbox",
4771
4899
  emptyTitle,
4772
4900
  emptyDescription,
4773
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4901
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4774
4902
  }
4775
4903
  ]
4776
4904
  };
@@ -4798,21 +4926,23 @@ function buildTrait25(c) {
4798
4926
  type: "stack",
4799
4927
  direction: "horizontal",
4800
4928
  gap: "sm",
4929
+ align: "center",
4801
4930
  children: [
4802
- { type: "badge", label: "Stale" },
4931
+ { type: "status-dot", status: "warning", pulse: true, label: "Stale" },
4803
4932
  { type: "button", label: "Refresh", event: "REFRESH", variant: "primary", icon: "refresh-cw" }
4804
4933
  ]
4805
4934
  }
4806
4935
  ]
4807
4936
  },
4808
4937
  { type: "divider" },
4938
+ { type: "alert", variant: "warning", message: "Cache data is stale. Refresh to get the latest data." },
4809
4939
  {
4810
4940
  type: "data-grid",
4811
4941
  entity: entityName,
4812
4942
  emptyIcon: "inbox",
4813
4943
  emptyTitle,
4814
4944
  emptyDescription,
4815
- children: [{ type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4945
+ renderItem: ["fn", "item", { type: "stack", direction: "vertical", gap: "sm", children: listItemChildren }]
4816
4946
  }
4817
4947
  ]
4818
4948
  };
@@ -4956,6 +5086,7 @@ function resolve26(params) {
4956
5086
  function buildEntity25(c) {
4957
5087
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
4958
5088
  }
5089
+ var ef11 = (field) => ["object/get", ["array/first", "@entity"], field];
4959
5090
  function buildTrait26(c) {
4960
5091
  const { entityName } = c;
4961
5092
  const scoreView = {
@@ -4966,12 +5097,14 @@ function buildTrait26(c) {
4966
5097
  children: [
4967
5098
  {
4968
5099
  type: "score-board",
4969
- score: "@entity.total",
5100
+ score: ef11("total"),
4970
5101
  highScore: 0,
4971
- combo: "@entity.combo",
5102
+ combo: ef11("combo"),
4972
5103
  multiplier: 1,
4973
5104
  level: 1
4974
5105
  },
5106
+ { type: "animated-counter", value: ef11("total"), prefix: "Score: ", duration: 300 },
5107
+ { type: "trend-indicator", value: ef11("points"), showValue: true },
4975
5108
  {
4976
5109
  type: "stack",
4977
5110
  direction: "horizontal",
@@ -5104,46 +5237,35 @@ function resolve27(params) {
5104
5237
  function buildEntity26(c) {
5105
5238
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
5106
5239
  }
5240
+ var ef12 = (field) => ["object/get", ["array/first", "@entity"], field];
5107
5241
  function buildTrait27(c) {
5108
5242
  const { entityName, headerIcon, pageTitle } = c;
5109
5243
  const idleView = {
5110
5244
  type: "stack",
5111
5245
  direction: "vertical",
5112
5246
  gap: "lg",
5113
- align: "center",
5114
5247
  children: [
5115
5248
  {
5116
5249
  type: "stack",
5117
5250
  direction: "horizontal",
5118
5251
  gap: "md",
5119
5252
  align: "center",
5253
+ justify: "space-between",
5120
5254
  children: [
5121
- { type: "icon", name: headerIcon, size: "lg" },
5122
- { type: "typography", content: pageTitle, variant: "h2" }
5255
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
5256
+ { type: "icon", name: headerIcon, size: "lg" },
5257
+ { type: "typography", content: pageTitle, variant: "h2" }
5258
+ ] },
5259
+ { type: "status-dot", status: "inactive", label: "Idle" }
5123
5260
  ]
5124
5261
  },
5125
5262
  { type: "divider" },
5126
5263
  {
5127
- type: "card",
5264
+ type: "simple-grid",
5265
+ columns: 2,
5128
5266
  children: [
5129
- {
5130
- type: "stack",
5131
- direction: "vertical",
5132
- gap: "sm",
5133
- children: [
5134
- { type: "typography", content: "Position", variant: "caption" },
5135
- {
5136
- type: "stack",
5137
- direction: "horizontal",
5138
- gap: "md",
5139
- children: [
5140
- { type: "typography", content: "@entity.x", variant: "body" },
5141
- { type: "typography", content: "@entity.y", variant: "body" }
5142
- ]
5143
- },
5144
- { type: "badge", label: "@entity.collisionStatus" }
5145
- ]
5146
- }
5267
+ { type: "stat-display", label: "X", value: ef12("x") },
5268
+ { type: "stat-display", label: "Y", value: ef12("y") }
5147
5269
  ]
5148
5270
  },
5149
5271
  {
@@ -5161,43 +5283,32 @@ function buildTrait27(c) {
5161
5283
  type: "stack",
5162
5284
  direction: "vertical",
5163
5285
  gap: "lg",
5164
- align: "center",
5165
5286
  children: [
5166
5287
  {
5167
5288
  type: "stack",
5168
5289
  direction: "horizontal",
5169
5290
  gap: "md",
5170
5291
  align: "center",
5292
+ justify: "space-between",
5171
5293
  children: [
5172
- { type: "icon", name: headerIcon, size: "lg" },
5173
- { type: "typography", content: pageTitle, variant: "h2" }
5294
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
5295
+ { type: "icon", name: headerIcon, size: "lg" },
5296
+ { type: "typography", content: pageTitle, variant: "h2" }
5297
+ ] },
5298
+ { type: "status-dot", status: "warning", pulse: true, label: "Detecting" }
5174
5299
  ]
5175
5300
  },
5176
5301
  { type: "divider" },
5302
+ { type: "alert", variant: "warning", message: "Collision detection in progress..." },
5177
5303
  {
5178
- type: "card",
5304
+ type: "simple-grid",
5305
+ columns: 2,
5179
5306
  children: [
5180
- {
5181
- type: "stack",
5182
- direction: "vertical",
5183
- gap: "sm",
5184
- children: [
5185
- { type: "typography", content: "Position", variant: "caption" },
5186
- {
5187
- type: "stack",
5188
- direction: "horizontal",
5189
- gap: "md",
5190
- children: [
5191
- { type: "typography", content: "@entity.x", variant: "body" },
5192
- { type: "typography", content: "@entity.y", variant: "body" }
5193
- ]
5194
- },
5195
- { type: "badge", label: "Detecting..." },
5196
- { type: "typography", content: "@entity.targetId", variant: "body" }
5197
- ]
5198
- }
5307
+ { type: "stat-display", label: "X", value: ef12("x") },
5308
+ { type: "stat-display", label: "Y", value: ef12("y") }
5199
5309
  ]
5200
5310
  },
5311
+ { type: "typography", variant: "caption", color: "muted", content: ef12("targetId") },
5201
5312
  {
5202
5313
  type: "stack",
5203
5314
  direction: "horizontal",
@@ -5490,40 +5601,39 @@ function resolve29(params) {
5490
5601
  function buildEntity28(c) {
5491
5602
  return makeEntity({ name: c.entityName, fields: c.fields, persistence: c.persistence });
5492
5603
  }
5604
+ var ef13 = (field) => ["object/get", ["array/first", "@entity"], field];
5493
5605
  function buildTrait29(c) {
5494
5606
  const { entityName, headerIcon, pageTitle } = c;
5495
5607
  const openView = {
5496
5608
  type: "stack",
5497
5609
  direction: "vertical",
5498
5610
  gap: "lg",
5499
- align: "center",
5500
5611
  children: [
5501
5612
  {
5502
5613
  type: "stack",
5503
5614
  direction: "horizontal",
5504
5615
  gap: "md",
5505
5616
  align: "center",
5617
+ justify: "space-between",
5506
5618
  children: [
5507
- { type: "icon", name: headerIcon, size: "lg" },
5508
- { type: "typography", content: pageTitle, variant: "h2" }
5619
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
5620
+ { type: "icon", name: headerIcon, size: "lg" },
5621
+ { type: "typography", content: pageTitle, variant: "h2" }
5622
+ ] },
5623
+ { type: "status-dot", status: "success", pulse: false, label: "Open" }
5509
5624
  ]
5510
5625
  },
5511
5626
  { type: "divider" },
5512
5627
  {
5513
- type: "card",
5628
+ type: "simple-grid",
5629
+ columns: 2,
5514
5630
  children: [
5515
- {
5516
- type: "stack",
5517
- direction: "vertical",
5518
- gap: "sm",
5519
- children: [
5520
- { type: "typography", content: "Requests", variant: "caption" },
5521
- { type: "typography", content: "@entity.count", variant: "h4" },
5522
- { type: "badge", label: "@entity.limiterStatus" }
5523
- ]
5524
- }
5631
+ { type: "stat-display", label: "Requests", value: ef13("count") },
5632
+ { type: "stat-display", label: "Window", value: ef13("window") }
5525
5633
  ]
5526
5634
  },
5635
+ { type: "meter", value: ef13("count"), min: 0, max: 100 },
5636
+ { type: "progress-bar", value: ef13("count"), max: 100, showPercentage: true },
5527
5637
  {
5528
5638
  type: "stack",
5529
5639
  direction: "horizontal",
@@ -5540,34 +5650,32 @@ function buildTrait29(c) {
5540
5650
  type: "stack",
5541
5651
  direction: "vertical",
5542
5652
  gap: "lg",
5543
- align: "center",
5544
5653
  children: [
5545
5654
  {
5546
5655
  type: "stack",
5547
5656
  direction: "horizontal",
5548
5657
  gap: "md",
5549
5658
  align: "center",
5659
+ justify: "space-between",
5550
5660
  children: [
5551
- { type: "icon", name: headerIcon, size: "lg" },
5552
- { type: "typography", content: pageTitle, variant: "h2" }
5661
+ { type: "stack", direction: "horizontal", gap: "md", align: "center", children: [
5662
+ { type: "icon", name: headerIcon, size: "lg" },
5663
+ { type: "typography", content: pageTitle, variant: "h2" }
5664
+ ] },
5665
+ { type: "status-dot", status: "error", pulse: true, label: "Throttled" }
5553
5666
  ]
5554
5667
  },
5555
5668
  { type: "divider" },
5669
+ { type: "alert", variant: "danger", message: "Rate limit exceeded. Requests are being throttled." },
5556
5670
  {
5557
- type: "card",
5671
+ type: "simple-grid",
5672
+ columns: 2,
5558
5673
  children: [
5559
- {
5560
- type: "stack",
5561
- direction: "vertical",
5562
- gap: "sm",
5563
- children: [
5564
- { type: "typography", content: "Requests", variant: "caption" },
5565
- { type: "typography", content: "@entity.count", variant: "h4" },
5566
- { type: "badge", label: "Throttled" }
5567
- ]
5568
- }
5674
+ { type: "stat-display", label: "Requests", value: ef13("count") },
5675
+ { type: "stat-display", label: "Window", value: ef13("window") }
5569
5676
  ]
5570
5677
  },
5678
+ { type: "meter", value: ef13("count"), min: 0, max: 100 },
5571
5679
  {
5572
5680
  type: "stack",
5573
5681
  direction: "horizontal",
@@ -7031,6 +7139,11 @@ function stdList(params) {
7031
7139
  if (!existingKeys.has("CONFIRM_DELETE")) sm.events.push({ key: "CONFIRM_DELETE", name: "Confirm Delete" });
7032
7140
  if (!existingKeys.has("CANCEL")) sm.events.push({ key: "CANCEL", name: "Cancel" });
7033
7141
  if (!existingKeys.has("CLOSE")) sm.events.push({ key: "CLOSE", name: "Close" });
7142
+ const initTransition = sm.transitions[0];
7143
+ const initRenderEffect = initTransition.effects.find(
7144
+ (e) => Array.isArray(e) && e[0] === "render-ui" && e[1] === "main"
7145
+ );
7146
+ const browseMainView = initRenderEffect ? initRenderEffect[2] : null;
7034
7147
  sm.transitions.push(
7035
7148
  // DELETE: browsing → deleting (fetch entity by ID, show confirmation modal)
7036
7149
  { from: "browsing", to: "deleting", event: "DELETE", effects: [
@@ -7053,15 +7166,24 @@ function stdList(params) {
7053
7166
  ]
7054
7167
  }]
7055
7168
  ] },
7056
- // CONFIRM_DELETE: deleting → browsing (persist delete using selected entity's ID)
7169
+ // CONFIRM_DELETE: deleting → browsing (persist delete, dismiss modal, re-render main)
7057
7170
  { from: "deleting", to: "browsing", event: "CONFIRM_DELETE", effects: [
7058
7171
  ["persist", "delete", entityName, "@entity.id"],
7059
7172
  ["render-ui", "modal", null],
7060
- ["fetch", entityName]
7173
+ ["fetch", entityName],
7174
+ ["render-ui", "main", browseMainView]
7175
+ ] },
7176
+ // CANCEL/CLOSE from deleting (dismiss modal, re-render main)
7177
+ { from: "deleting", to: "browsing", event: "CANCEL", effects: [
7178
+ ["render-ui", "modal", null],
7179
+ ["fetch", entityName],
7180
+ ["render-ui", "main", browseMainView]
7061
7181
  ] },
7062
- // CANCEL/CLOSE from deleting
7063
- { from: "deleting", to: "browsing", event: "CANCEL", effects: [["render-ui", "modal", null]] },
7064
- { from: "deleting", to: "browsing", event: "CLOSE", effects: [["render-ui", "modal", null]] }
7182
+ { from: "deleting", to: "browsing", event: "CLOSE", effects: [
7183
+ ["render-ui", "modal", null],
7184
+ ["fetch", entityName],
7185
+ ["render-ui", "main", browseMainView]
7186
+ ] }
7065
7187
  );
7066
7188
  const entity = makeEntity({ name: entityName, fields, persistence: c.persistence, collection: c.collection });
7067
7189
  const page = {
@@ -8005,19 +8127,19 @@ function buildBattleFlowTrait(c) {
8005
8127
  event: "PAUSE",
8006
8128
  effects: [["render-ui", "modal", pausedModalUI]]
8007
8129
  },
8008
- // RESUME: paused -> playing
8130
+ // RESUME: paused -> playing (dismiss modal, re-render main)
8009
8131
  {
8010
8132
  from: "paused",
8011
8133
  to: "playing",
8012
8134
  event: "RESUME",
8013
- effects: [["render-ui", "modal", null]]
8135
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8014
8136
  },
8015
8137
  // CLOSE: paused -> playing (modal exit requirement)
8016
8138
  {
8017
8139
  from: "paused",
8018
8140
  to: "playing",
8019
8141
  event: "CLOSE",
8020
- effects: [["render-ui", "modal", null]]
8142
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8021
8143
  },
8022
8144
  // GAME_OVER: playing -> gameover
8023
8145
  {
@@ -8272,19 +8394,19 @@ function buildPlatformerFlowTrait(c) {
8272
8394
  event: "PAUSE",
8273
8395
  effects: [["render-ui", "modal", pausedModalUI]]
8274
8396
  },
8275
- // RESUME: paused -> playing
8397
+ // RESUME: paused -> playing (dismiss modal, re-render main)
8276
8398
  {
8277
8399
  from: "paused",
8278
8400
  to: "playing",
8279
8401
  event: "RESUME",
8280
- effects: [["render-ui", "modal", null]]
8402
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8281
8403
  },
8282
8404
  // CLOSE: paused -> playing (modal exit requirement)
8283
8405
  {
8284
8406
  from: "paused",
8285
8407
  to: "playing",
8286
8408
  event: "CLOSE",
8287
- effects: [["render-ui", "modal", null]]
8409
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8288
8410
  },
8289
8411
  // GAME_OVER: playing -> gameover
8290
8412
  {
@@ -8524,19 +8646,19 @@ function buildPuzzleFlowTrait(c) {
8524
8646
  event: "PAUSE",
8525
8647
  effects: [["render-ui", "modal", pausedModalUI]]
8526
8648
  },
8527
- // RESUME: paused -> playing
8649
+ // RESUME: paused -> playing (dismiss modal, re-render main)
8528
8650
  {
8529
8651
  from: "paused",
8530
8652
  to: "playing",
8531
8653
  event: "RESUME",
8532
- effects: [["render-ui", "modal", null]]
8654
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8533
8655
  },
8534
8656
  // CLOSE: paused -> playing (modal exit requirement)
8535
8657
  {
8536
8658
  from: "paused",
8537
8659
  to: "playing",
8538
8660
  event: "CLOSE",
8539
- effects: [["render-ui", "modal", null]]
8661
+ effects: [["render-ui", "modal", null], ["render-ui", "main", playingUI]]
8540
8662
  },
8541
8663
  // GAME_OVER: playing -> gameover
8542
8664
  {