@burojs/ui-shadcn 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +9 -0
  2. package/dist/bulk-summary-2HLgz7Il.cjs +169 -0
  3. package/dist/bulk-summary-2HLgz7Il.cjs.map +1 -0
  4. package/dist/bulk-summary-D6A0ua21.js +169 -0
  5. package/dist/bulk-summary-D6A0ua21.js.map +1 -0
  6. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-C47mF260.cjs} +4 -4
  7. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-C47mF260.cjs.map} +1 -1
  8. package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CGXItMN0.js} +3 -3
  9. package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CGXItMN0.js.map} +1 -1
  10. package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-BT04Mieo.cjs} +475 -107
  11. package/dist/check-confirm-dialog-BT04Mieo.cjs.map +1 -0
  12. package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-CtiRzOAt.js} +391 -108
  13. package/dist/check-confirm-dialog-CtiRzOAt.js.map +1 -0
  14. package/dist/{dialog-B_rt9S1c.js → dialog-C123sVQ8.js} +4 -4
  15. package/dist/dialog-C123sVQ8.js.map +1 -0
  16. package/dist/{dialog-DRNUq9EA.cjs → dialog-vmMdfUWs.cjs} +3 -3
  17. package/dist/dialog-vmMdfUWs.cjs.map +1 -0
  18. package/dist/{filter-builder-nXqtM_h4.cjs → filter-builder-ByGhxLf_.cjs} +1021 -154
  19. package/dist/filter-builder-ByGhxLf_.cjs.map +1 -0
  20. package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-z3Axzf9Y.js} +929 -140
  21. package/dist/filter-builder-z3Axzf9Y.js.map +1 -0
  22. package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BVFjMU5-.cjs} +64 -29
  23. package/dist/flow-runtime-BVFjMU5-.cjs.map +1 -0
  24. package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DrUWyTS0.js} +65 -30
  25. package/dist/flow-runtime-DrUWyTS0.js.map +1 -0
  26. package/dist/{flow-screen-CCvgDI9G.js → flow-screen-3fk6J33y.js} +130 -87
  27. package/dist/flow-screen-3fk6J33y.js.map +1 -0
  28. package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-6y5E_HT6.cjs} +130 -87
  29. package/dist/flow-screen-6y5E_HT6.cjs.map +1 -0
  30. package/dist/index.cjs +1186 -950
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +631 -322
  33. package/dist/index.d.ts +631 -322
  34. package/dist/index.js +1100 -870
  35. package/dist/index.js.map +1 -1
  36. package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-C4KmZIYE.cjs} +5 -5
  37. package/dist/inline-flow-host-C4KmZIYE.cjs.map +1 -0
  38. package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-YnnvWjdU.js} +5 -5
  39. package/dist/inline-flow-host-YnnvWjdU.js.map +1 -0
  40. package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-BAKBRn3V.cjs} +10 -10
  41. package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +1 -0
  42. package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-DN4bvQfg.js} +11 -11
  43. package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +1 -0
  44. package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-CtEfqAvU.js} +35 -23
  45. package/dist/page-flow-route-CtEfqAvU.js.map +1 -0
  46. package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DEjAxHe3.cjs} +42 -30
  47. package/dist/page-flow-route-DEjAxHe3.cjs.map +1 -0
  48. package/dist/{place-node-NraNYKPx.js → place-node-BdxT-30h.js} +1980 -1041
  49. package/dist/place-node-BdxT-30h.js.map +1 -0
  50. package/dist/{place-node-C5SmIAYU.cjs → place-node-Bhl8B3fF.cjs} +2038 -1087
  51. package/dist/place-node-Bhl8B3fF.cjs.map +1 -0
  52. package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-Bc_vfCE_.cjs} +9 -4
  53. package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-Bc_vfCE_.cjs.map} +1 -1
  54. package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BvkD5OcC.js} +9 -4
  55. package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BvkD5OcC.js.map} +1 -1
  56. package/dist/related-list-timeline-DCrwN9oO.js +167 -0
  57. package/dist/related-list-timeline-DCrwN9oO.js.map +1 -0
  58. package/dist/related-list-timeline-k0DtnxTs.cjs +167 -0
  59. package/dist/related-list-timeline-k0DtnxTs.cjs.map +1 -0
  60. package/dist/{related-rows-ea43qhhy.cjs → related-rows-BW9Jr07T.cjs} +27 -16
  61. package/dist/related-rows-BW9Jr07T.cjs.map +1 -0
  62. package/dist/{related-rows-o0_t-Yce.js → related-rows-CPE-9FFr.js} +25 -14
  63. package/dist/related-rows-CPE-9FFr.js.map +1 -0
  64. package/dist/{search-access-CPPmfuvy.js → relation-create-C43cdPQt.js} +595 -13
  65. package/dist/relation-create-C43cdPQt.js.map +1 -0
  66. package/dist/{search-access-Dugvttlg.cjs → relation-create-DDEYcKfw.cjs} +633 -14
  67. package/dist/relation-create-DDEYcKfw.cjs.map +1 -0
  68. package/dist/{relation-many-picker-bvkjkv-k.js → relation-many-picker-BlrGRwMV.js} +210 -104
  69. package/dist/relation-many-picker-BlrGRwMV.js.map +1 -0
  70. package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-Br-zBHxT.cjs} +218 -112
  71. package/dist/relation-many-picker-Br-zBHxT.cjs.map +1 -0
  72. package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-ADjxI_TI.cjs} +36 -73
  73. package/dist/relation-picker-ADjxI_TI.cjs.map +1 -0
  74. package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-CyKliBkN.js} +134 -36
  75. package/dist/relation-picker-dialog-CyKliBkN.js.map +1 -0
  76. package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-DimVQF9Y.cjs} +133 -35
  77. package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +1 -0
  78. package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-x7P5HKie.js} +30 -61
  79. package/dist/relation-picker-x7P5HKie.js.map +1 -0
  80. package/dist/relation-select-B8Fq4o-t.js +48 -0
  81. package/dist/relation-select-B8Fq4o-t.js.map +1 -0
  82. package/dist/relation-select-Cr3CfNLy.cjs +55 -0
  83. package/dist/relation-select-Cr3CfNLy.cjs.map +1 -0
  84. package/dist/{resource-page-router-3RUf9d1j.js → resource-page-router-BRpUnhay.js} +634 -264
  85. package/dist/resource-page-router-BRpUnhay.js.map +1 -0
  86. package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-qEd2xb55.cjs} +694 -312
  87. package/dist/resource-page-router-qEd2xb55.cjs.map +1 -0
  88. package/dist/{rich-text-vTyVjDoa.cjs → rich-text-C_7JCvRo.cjs} +2 -2
  89. package/dist/{rich-text-vTyVjDoa.cjs.map → rich-text-C_7JCvRo.cjs.map} +1 -1
  90. package/dist/{rich-text-DFerywgz.js → rich-text-RcPBf6hr.js} +2 -2
  91. package/dist/{rich-text-DFerywgz.js.map → rich-text-RcPBf6hr.js.map} +1 -1
  92. package/dist/success-notices-Dl3M1fZP.cjs +46 -0
  93. package/dist/success-notices-Dl3M1fZP.cjs.map +1 -0
  94. package/dist/success-notices-LDEgEkc4.js +41 -0
  95. package/dist/success-notices-LDEgEkc4.js.map +1 -0
  96. package/dist/{toaster-Cr51X7bz.cjs → toaster-BbByOytP.cjs} +60 -15
  97. package/dist/toaster-BbByOytP.cjs.map +1 -0
  98. package/dist/{toaster-C02XbB9r.js → toaster-Ct_YHGs6.js} +43 -16
  99. package/dist/toaster-Ct_YHGs6.js.map +1 -0
  100. package/dist/{use-dialog-filter-state-C--oMAZG.js → use-dialog-filter-state-B_MqzHaT.js} +5 -4
  101. package/dist/use-dialog-filter-state-B_MqzHaT.js.map +1 -0
  102. package/dist/{use-dialog-filter-state-Dhe8PcB5.cjs → use-dialog-filter-state-tNvqAAjh.cjs} +6 -5
  103. package/dist/use-dialog-filter-state-tNvqAAjh.cjs.map +1 -0
  104. package/dist/use-record-subtitle-bfwIoUme.cjs +70 -0
  105. package/dist/use-record-subtitle-bfwIoUme.cjs.map +1 -0
  106. package/dist/use-record-subtitle-gIaCGgbI.js +53 -0
  107. package/dist/use-record-subtitle-gIaCGgbI.js.map +1 -0
  108. package/package.json +11 -11
  109. package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
  110. package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
  111. package/dist/bulk-summary-GxMDP4bw.js +0 -108
  112. package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
  113. package/dist/candidates-gate-Bb70LPAy.js.map +0 -1
  114. package/dist/candidates-gate-D33jXLHO.cjs.map +0 -1
  115. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +0 -1
  116. package/dist/check-confirm-dialog-bRT8lt0d.js.map +0 -1
  117. package/dist/dialog-B_rt9S1c.js.map +0 -1
  118. package/dist/dialog-DRNUq9EA.cjs.map +0 -1
  119. package/dist/filter-builder-Bhn-dhZV.js.map +0 -1
  120. package/dist/filter-builder-nXqtM_h4.cjs.map +0 -1
  121. package/dist/flow-runtime-D3avVH0I.cjs.map +0 -1
  122. package/dist/flow-runtime-s6lkRPKF.js.map +0 -1
  123. package/dist/flow-screen-CCvgDI9G.js.map +0 -1
  124. package/dist/flow-screen-Ci_Sik4Y.cjs.map +0 -1
  125. package/dist/inline-flow-host-B6FI0ctQ.js.map +0 -1
  126. package/dist/inline-flow-host-DV1et3c6.cjs.map +0 -1
  127. package/dist/page-flow-route-hdnULWqd.cjs.map +0 -1
  128. package/dist/page-flow-route-i3ZfJ1sd.js.map +0 -1
  129. package/dist/place-node-C5SmIAYU.cjs.map +0 -1
  130. package/dist/place-node-NraNYKPx.js.map +0 -1
  131. package/dist/related-list-timeline-CCzl71aA.cjs +0 -142
  132. package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
  133. package/dist/related-list-timeline-yrPsjA3F.js +0 -142
  134. package/dist/related-list-timeline-yrPsjA3F.js.map +0 -1
  135. package/dist/related-rows-ea43qhhy.cjs.map +0 -1
  136. package/dist/related-rows-o0_t-Yce.js.map +0 -1
  137. package/dist/relation-create-IA40t1hi.cjs +0 -364
  138. package/dist/relation-create-IA40t1hi.cjs.map +0 -1
  139. package/dist/relation-create-h6F9B4C4.js +0 -339
  140. package/dist/relation-create-h6F9B4C4.js.map +0 -1
  141. package/dist/relation-many-picker-C8zFEjwd.cjs.map +0 -1
  142. package/dist/relation-many-picker-bvkjkv-k.js.map +0 -1
  143. package/dist/relation-picker-Z0ZJJ5uS.js.map +0 -1
  144. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +0 -1
  145. package/dist/relation-picker-dialog-B6nIiJBf.js.map +0 -1
  146. package/dist/relation-picker-gag0qSR5.cjs.map +0 -1
  147. package/dist/resource-page-router-3RUf9d1j.js.map +0 -1
  148. package/dist/resource-page-router-PXfMW9nh.cjs.map +0 -1
  149. package/dist/search-access-CPPmfuvy.js.map +0 -1
  150. package/dist/search-access-Dugvttlg.cjs.map +0 -1
  151. package/dist/shell-BPlk8hEa.js +0 -205
  152. package/dist/shell-BPlk8hEa.js.map +0 -1
  153. package/dist/shell-DxhlsPwm.cjs +0 -271
  154. package/dist/shell-DxhlsPwm.cjs.map +0 -1
  155. package/dist/toaster-C02XbB9r.js.map +0 -1
  156. package/dist/toaster-Cr51X7bz.cjs.map +0 -1
  157. package/dist/use-dialog-filter-state-C--oMAZG.js.map +0 -1
  158. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +0 -1
@@ -1,13 +1,15 @@
1
1
  const require_use_theme = require("./use-theme-DFlpXils.cjs");
2
- const require_toaster = require("./toaster-Cr51X7bz.cjs");
3
- const require_check_confirm_dialog = require("./check-confirm-dialog--gPFnEeg.cjs");
2
+ const require_toaster = require("./toaster-BbByOytP.cjs");
3
+ const require_check_confirm_dialog = require("./check-confirm-dialog-BT04Mieo.cjs");
4
4
  const require_button = require("./button-BxnnE28H.cjs");
5
5
  const require_input = require("./input-BI0czGyI.cjs");
6
- const require_dialog = require("./dialog-DRNUq9EA.cjs");
7
- const require_search_access = require("./search-access-Dugvttlg.cjs");
6
+ const require_dialog = require("./dialog-vmMdfUWs.cjs");
7
+ const require_relation_create = require("./relation-create-DDEYcKfw.cjs");
8
8
  const require_skeleton = require("./skeleton-_1gP7wan.cjs");
9
- const require_filter_builder = require("./filter-builder-nXqtM_h4.cjs");
9
+ const require_filter_builder = require("./filter-builder-ByGhxLf_.cjs");
10
10
  const require_label = require("./label-w6JYf2cF.cjs");
11
+ const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-BAKBRn3V.cjs");
12
+ const require_relation_select = require("./relation-select-Cr3CfNLy.cjs");
11
13
  let _burojs_core = require("@burojs/core");
12
14
  let _burojs_react = require("@burojs/react");
13
15
  let _tabler_icons_react = require("@tabler/icons-react");
@@ -120,428 +122,91 @@ function toDisplayText(value) {
120
122
  }
121
123
  }
122
124
  //#endregion
123
- //#region src/fields/legacy-field.ts
124
- const STRING_ITEM = Object.freeze({ type: "string" });
125
- const LEGACY_KIND_DECLARATIONS = Object.freeze({
126
- string: { type: "string" },
127
- text: {
128
- type: "string",
129
- format: "text"
130
- },
131
- textarea: {
132
- type: "string",
133
- format: "textarea"
134
- },
135
- code: {
136
- type: "string",
137
- format: "code"
138
- },
139
- email: {
140
- type: "string",
141
- format: "email"
142
- },
143
- url: {
144
- type: "string",
145
- format: "url"
146
- },
147
- uuid: {
148
- type: "string",
149
- format: "uuid"
150
- },
151
- number: { type: "number" },
152
- boolean: { type: "boolean" },
153
- date: {
154
- type: "string",
155
- format: "date"
156
- },
157
- dateTime: {
158
- type: "string",
159
- format: "date-time"
160
- },
161
- enum: {
162
- type: "string",
163
- format: "enum"
164
- },
165
- json: {
166
- type: "object",
167
- format: "json"
168
- },
169
- richText: {
170
- type: "string",
171
- format: "rich-text"
172
- },
173
- file: {
174
- type: "array",
175
- format: "file",
176
- items: STRING_ITEM
177
- },
178
- relation: { type: "relation" },
179
- relationMany: {
180
- type: "array",
181
- format: "relation",
182
- items: STRING_ITEM
183
- }
184
- });
185
- const SEMANTIC_KEYS = Object.freeze([
186
- "type",
187
- "format",
188
- "meta",
189
- "required",
190
- "nullable",
191
- "empty",
192
- "default",
193
- "constraints",
194
- "texts",
195
- "options",
196
- "items",
197
- "properties",
198
- "additionalProperties",
199
- "variants"
200
- ]);
201
- function ownData(value, key) {
202
- if (value === null || typeof value !== "object" && typeof value !== "function") return { present: false };
203
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
204
- if (descriptor === void 0 || !Object.prototype.propertyIsEnumerable.call(value, key) || !("value" in descriptor)) return { present: false };
205
- return {
206
- present: true,
207
- value: descriptor.value
208
- };
209
- }
210
- function ownString(value, key) {
211
- const candidate = ownData(value, key).value;
212
- return typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
213
- }
214
- function projectUiSelection(input) {
215
- const selection = {};
216
- const inputId = ownString(input, "input");
217
- const displayId = ownString(input, "display");
218
- if (inputId !== void 0) selection.input = inputId;
219
- if (displayId !== void 0) selection.display = displayId;
220
- return inputId === void 0 && displayId === void 0 ? void 0 : Object.freeze(selection);
221
- }
222
- function projectFieldDeclaration(input) {
223
- const type = ownString(input, "type");
224
- if (type === void 0) return void 0;
225
- const projected = { type };
226
- for (const key of SEMANTIC_KEYS) {
227
- if (key === "type" || key === "items" || key === "properties" || key === "variants") continue;
228
- const candidate = ownData(input, key);
229
- if (candidate.present && candidate.value !== void 0) projected[key] = candidate.value;
230
- }
231
- const ui = projectUiSelection(ownData(input, "ui").value);
232
- if (ui !== void 0) projected.ui = ui;
233
- if (type === "array") {
234
- const item = projectFieldDeclaration(ownData(input, "items").value);
235
- if (item !== void 0) projected.items = item;
236
- }
237
- if (type === "object") {
238
- const properties = ownData(input, "properties").value;
239
- if (properties !== null && typeof properties === "object" && !Array.isArray(properties)) {
240
- const output = {};
241
- for (const key of Object.keys(properties)) {
242
- const child = projectFieldDeclaration(ownData(properties, key).value);
243
- if (child !== void 0) output[key] = child;
244
- }
245
- projected.properties = Object.freeze(output);
246
- }
247
- }
248
- if (type === "union") {
249
- const variants = ownData(input, "variants").value;
250
- if (Array.isArray(variants)) {
251
- const output = [];
252
- for (let index = 0; index < variants.length; index += 1) {
253
- const child = projectFieldDeclaration(ownData(variants, index).value);
254
- if (child !== void 0) output.push(child);
255
- }
256
- projected.variants = Object.freeze(output);
257
- }
258
- }
259
- return Object.freeze(projected);
260
- }
261
- function projectUiHints(input) {
262
- if (input === null || typeof input !== "object" || Array.isArray(input)) return void 0;
263
- const projected = {};
264
- for (const key of Object.keys(input)) {
265
- const candidate = ownData(input, key);
266
- if (candidate.present) projected[key] = candidate.value;
267
- }
268
- return Object.freeze(projected);
269
- }
270
- function lowerLegacyField(field) {
271
- const declaration = projectFieldDeclaration(ownData(field, "declaration").value);
272
- if (declaration !== void 0) return declaration;
273
- const direct = projectFieldDeclaration(field);
274
- const kind = ownString(field, "kind");
275
- const mapping = kind === void 0 ? void 0 : LEGACY_KIND_DECLARATIONS[kind];
276
- if (direct !== void 0) {
277
- const format = direct.format ?? mapping?.format ?? kind;
278
- return format === void 0 ? direct : Object.freeze({
279
- ...direct,
280
- format
281
- });
282
- }
283
- const ui = projectUiHints(ownData(field, "ui").value);
284
- const type = kind === "file" && ui?.multiple !== true ? "unknown" : mapping?.type ?? "unknown";
285
- const format = ownString(field, "format") ?? mapping?.format ?? kind;
286
- const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
287
- const meta = ownData(field, "meta");
288
- const texts = ownData(field, "texts");
289
- const required = ownData(field, "required");
290
- const nullable = ownData(field, "nullable");
291
- const opts = ownData(field, "opts").value;
292
- const optionRequired = ownData(opts, "required");
293
- const optionNullable = ownData(opts, "nullable");
294
- const requiredValue = required.present ? required.value : optionRequired.value;
295
- const nullableValue = nullable.present ? nullable.value : optionNullable.value;
296
- return Object.freeze({
297
- type,
298
- ...format === void 0 ? {} : { format },
299
- ...items === void 0 ? {} : { items },
300
- ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
301
- ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
302
- ...requiredValue === true ? { required: true } : {},
303
- ...nullableValue === true ? { nullable: true } : {}
304
- });
305
- }
306
- function lowerLegacyFieldSource(field) {
307
- const declaration = lowerLegacyField(field);
308
- const ui = projectUiHints(ownData(field, "ui").value);
309
- if (ui === void 0) return declaration;
310
- return Object.freeze({
311
- ...declaration,
312
- ui
313
- });
314
- }
315
- function fieldDescription(field) {
316
- const declaration = field?.declaration;
317
- return (0, _burojs_core.declaredText)("field", declaration, "description") ?? (0, _burojs_core.declaredText)("field", field, "description");
125
+ //#region src/data-table/annotate-if-clipped.ts
126
+ function annotateIfClipped(e) {
127
+ const el = e.currentTarget;
128
+ const text = el.scrollWidth > el.clientWidth || Array.from(el.querySelectorAll("*")).some((c) => c.scrollWidth > c.clientWidth) ? (el.textContent ?? "").trim() : "";
129
+ if (text) el.setAttribute("title", text);
130
+ else el.removeAttribute("title");
318
131
  }
319
132
  //#endregion
320
- //#region src/fields/resolved-field.tsx
321
- const EMPTY = Object.freeze({});
322
- const EMPTY_ISSUES$1 = Object.freeze([]);
323
- const EMPTY_OPTIONS = Object.freeze([]);
324
- function canonical(field) {
325
- return lowerLegacyField(field);
326
- }
327
- const warnedObjectLabels = new Set();
328
- function optionsFor(field, name) {
329
- if (Array.isArray(field.options)) return field.options;
330
- const candidate = field.meta?.options;
331
- if (!Array.isArray(candidate)) return EMPTY_OPTIONS;
332
- const output = [];
333
- for (const item of candidate) {
334
- if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
335
- const raw = item;
336
- if (typeof raw.value !== "string" && typeof raw.value !== "number" && typeof raw.value !== "boolean" && raw.value !== null) continue;
337
- const { value, label, description, ...legacyMeta } = raw;
338
- if (typeof label !== "string" && process.env.NODE_ENV !== "production" && !warnedObjectLabels.has(`${name}:${value}`)) {
339
- warnedObjectLabels.add(`${name}:${value}`);
340
- console.warn(`[buro/ui-shadcn] field '${name}': option '${value}' has a non-string label, so it renders its raw value. Declare a plain string label and put the translations under fields.${name}.options.${value} (see docs/i18n-guide.md).`);
341
- }
342
- output.push(Object.freeze({
343
- value,
344
- label: typeof label === "string" ? label : String(value),
345
- ...typeof description === "string" ? { description } : {},
346
- ...Object.keys(legacyMeta).length === 0 ? {} : { meta: Object.freeze(legacyMeta) }
347
- }));
348
- }
349
- return Object.freeze(output);
350
- }
351
- const readScope = (ctx) => ctx.scope;
352
- function useFieldRuntimeContext(resource, record, values, metaSources) {
353
- const scope = (0, _burojs_react.useCtx)(readScope);
354
- const locale = (0, _burojs_react.useLocale)();
355
- const caps = (0, _burojs_react.useI18nCaps)((0, _burojs_core.formatEntityRef)(resource));
356
- const metaSourcesOut = (0, _burojs_react.useFieldMetaSources)({
357
- record,
358
- values,
359
- extra: metaSources
360
- });
361
- return (0, react.useMemo)(() => Object.freeze({
362
- i18n: Object.freeze({
363
- locale,
364
- has: caps.has,
365
- t: caps.t
366
- }),
367
- sources: Object.freeze({
368
- record: record ?? EMPTY,
369
- values: values ?? EMPTY,
370
- scope: scope ?? EMPTY
371
- }),
372
- metaSources: metaSourcesOut
373
- }), [
374
- caps,
375
- locale,
376
- record,
377
- scope,
378
- values,
379
- metaSourcesOut
380
- ]);
381
- }
382
- function useFieldMetaDiagnostic(state, resource, name, field, surface) {
383
- const reported = (0, react.useRef)(void 0);
384
- const reason = state.status === "failed" ? state.reason : void 0;
385
- (0, react.useEffect)(() => {
386
- if (reason === void 0 || reported.current === reason || process.env.NODE_ENV === "production") return;
387
- reported.current = reason;
388
- const named = field.ui?.[surface];
389
- const implementation = typeof named === "string" ? named : field.format ?? field.type;
390
- console.error(`[burojs] field.meta-invalid: ${(0, _burojs_core.formatEntityRef)(resource)}.${name} (${implementation}): ${reason}`);
391
- }, [
392
- reason,
393
- resource,
394
- name,
395
- field,
396
- surface
397
- ]);
398
- }
399
- function MetaPlaceholder({ state }) {
133
+ //#region src/fields/field-value-frame.tsx
134
+ const COPY_CLASSES = [
135
+ "string",
136
+ "number",
137
+ "date"
138
+ ];
139
+ const COPIED_MS = 2e3;
140
+ const isRecord$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
141
+ const isEmpty = (value) => value === null || value === void 0 || value === "";
142
+ function copyText(value) {
143
+ if (value instanceof Date) return value.toISOString();
144
+ return typeof value === "string" ? value : String(value);
145
+ }
146
+ function FieldValueFrame({ field, value, surface, entry, children }) {
400
147
  const t = (0, _burojs_react.useOptionalT)();
401
- if (state.status === "pending") return (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
402
- "data-buro-skeleton": "",
403
- "data-buro-field-meta": "pending",
404
- className: "h-9 w-full"
405
- });
406
- return (0, react_jsx_runtime.jsx)("div", {
407
- role: "alert",
408
- "data-buro-field-meta": "failed",
409
- className: "rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
410
- children: t("field.misconfigured", { defaultValue: "This field is misconfigured" })
411
- });
412
- }
413
- function useFieldImplementationDiagnostic(diagnostic) {
414
- const reported = (0, react.useRef)(void 0);
148
+ const clipboard = (0, _burojs_react.useClipboard)();
149
+ const [copied, setCopied] = (0, react.useState)(null);
415
150
  (0, react.useEffect)(() => {
416
- if (diagnostic === void 0 || reported.current === diagnostic || process.env.NODE_ENV === "production") return;
417
- reported.current = diagnostic;
418
- console.warn("[buro/ui-shadcn] missing-field-implementation; rendering fallback.", diagnostic);
419
- }, [diagnostic]);
420
- }
421
- function ResolvedFieldDisplay({ resource, name, field: source, value, record, testId, fallback, presentation, metaSources }) {
422
- const sourceAtEdge = lowerLegacyFieldSource(source);
423
- const field = canonical(sourceAtEdge);
424
- const resolved = (0, _burojs_react.useFieldImplementation)({
425
- field,
426
- surface: "display"
427
- });
428
- const runtimeContext = useFieldRuntimeContext(resource, record, record, metaSources);
429
- const metaState = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, runtimeContext.metaSources);
430
- useFieldMetaDiagnostic(metaState, resource, name, field, "display");
431
- useFieldImplementationDiagnostic(resolved.diagnostic);
432
- if (resolved.Component === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback });
433
- if (metaState.status !== "ready") return (0, react_jsx_runtime.jsx)(MetaPlaceholder, { state: metaState });
434
- const Component = resolved.Component;
435
- const context = {
436
- owner: resource,
437
- resource,
151
+ if (copied === null) return;
152
+ const timer = setTimeout(() => setCopied(null), COPIED_MS);
153
+ return () => clearTimeout(timer);
154
+ }, [copied]);
155
+ const ui = isRecord$1(field.ui) ? field.ui : void 0;
156
+ const asksCopy = ui?.copy === true;
157
+ const valueClass = (0, react.useMemo)(() => asksCopy ? (0, _burojs_core.displayClassOf)({
158
+ ...require_filter_builder.lowerLegacyField(field),
159
+ ...ui === void 0 ? {} : { ui }
160
+ }) : void 0, [
161
+ asksCopy,
438
162
  field,
439
- path: Object.freeze([name]),
440
- surface: "display",
441
- presentation: presentation ?? "default",
442
- record,
443
- meta: metaState.meta,
444
- ui: sourceAtEdge.ui ?? EMPTY,
445
- options: optionsFor(field, name),
446
- i18n: runtimeContext.i18n,
447
- sources: runtimeContext.sources,
448
- pending: false,
449
- touched: false,
450
- issues: EMPTY_ISSUES$1,
451
- accessibility: EMPTY,
452
- testIds: testId === void 0 ? EMPTY : Object.freeze({ display: testId })
453
- };
454
- if (resolved.multiple) return (0, react.createElement)(Component, {
455
- ...context,
456
- multiple: true,
457
- value: Array.isArray(value) ? value : []
458
- });
459
- return (0, react.createElement)(Component, {
460
- ...context,
461
- multiple: false,
462
- value
463
- });
464
- }
465
- function ResolvedFieldInput({ resource, name, field: source, value, record, form, testId, inputId, onChange, onBlur, disabled, required, placeholder, descriptionId, errorId, errorMessage, pending = false, touched = errorMessage != null, issues: suppliedIssues, relationSeeds, fixedFilters, metaSources, fallback }) {
466
- const sourceAtEdge = lowerLegacyFieldSource(source);
467
- const base = canonical(sourceAtEdge);
468
- const field = required === void 0 || required === base.required ? base : Object.freeze({
469
- ...base,
470
- required
471
- });
472
- const ui = Object.freeze({
473
- ...sourceAtEdge.ui ?? EMPTY,
474
- ...placeholder === void 0 ? {} : { placeholder }
475
- });
476
- const resolved = (0, _burojs_react.useFieldImplementation)({
477
- field: {
478
- ...field,
479
- ui
480
- },
481
- surface: "input"
163
+ ui
164
+ ]);
165
+ const { overflow: declared } = (0, _burojs_core.resolveSurfaceUi)(field, surface, entry);
166
+ const copyable = asksCopy && clipboard !== void 0 && !isEmpty(value) && valueClass !== void 0 && COPY_CLASSES.includes(valueClass);
167
+ if (!copyable && declared === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
168
+ const body = (declared ?? (surface === "column" ? "truncate" : "wrap")) === "wrap" ? (0, react_jsx_runtime.jsx)("span", {
169
+ className: "min-w-0 whitespace-normal [overflow-wrap:anywhere]",
170
+ "data-buro-overflow": "wrap",
171
+ children
172
+ }) : (0, react_jsx_runtime.jsx)("span", {
173
+ className: "inline-block min-w-0 max-w-full truncate align-bottom",
174
+ "data-buro-overflow": "truncate",
175
+ onPointerEnter: annotateIfClipped,
176
+ children
482
177
  });
483
- const runtimeContext = useFieldRuntimeContext(resource, record, form, metaSources);
484
- const metaState = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, runtimeContext.metaSources);
485
- useFieldMetaDiagnostic(metaState, resource, name, field, "input");
486
- useFieldImplementationDiagnostic(resolved.diagnostic);
487
- if (resolved.Component === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback });
488
- if (metaState.status !== "ready") return (0, react_jsx_runtime.jsx)(MetaPlaceholder, { state: metaState });
489
- const Component = resolved.Component;
490
- const issues = suppliedIssues ?? (errorMessage == null ? EMPTY_ISSUES$1 : Object.freeze([Object.freeze({
491
- code: "ui.field-error",
492
- message: {
493
- key: "ui.field-error",
494
- default: errorMessage
495
- },
496
- path: Object.freeze([]),
497
- source: "field",
498
- severity: "error"
499
- })]));
500
- const context = {
501
- owner: resource,
502
- resource,
503
- field,
504
- path: Object.freeze([name]),
505
- surface: "input",
506
- presentation: "default",
507
- record,
508
- form,
509
- meta: metaState.meta,
510
- ui,
511
- options: optionsFor(field, name),
512
- i18n: runtimeContext.i18n,
513
- sources: runtimeContext.sources,
514
- pending,
515
- touched,
516
- issues,
517
- accessibility: Object.freeze({
518
- input: inputId ?? name,
519
- description: descriptionId,
520
- error: errorId
521
- }),
522
- testIds: testId === void 0 ? EMPTY : Object.freeze({ input: testId })
178
+ if (!copyable) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: body });
179
+ const label = t("field.copy", { defaultValue: "Copy" });
180
+ const copy = (event) => {
181
+ event.preventDefault();
182
+ event.stopPropagation();
183
+ clipboard(copyText(value)).then(() => setCopied("copied"), () => setCopied("failed"));
523
184
  };
524
- if (resolved.multiple) return (0, react.createElement)(Component, {
525
- ...context,
526
- multiple: true,
527
- value: Array.isArray(value) ? value : [],
528
- onChange,
529
- onBlur,
530
- disabled,
531
- relationSeeds,
532
- fixedFilters,
533
- metaSources: runtimeContext.metaSources
534
- });
535
- return (0, react.createElement)(Component, {
536
- ...context,
537
- multiple: false,
538
- value,
539
- onChange,
540
- onBlur,
541
- disabled,
542
- relationSeeds,
543
- fixedFilters,
544
- metaSources: runtimeContext.metaSources
185
+ return (0, react_jsx_runtime.jsxs)("span", {
186
+ className: "inline-flex min-w-0 max-w-full items-center gap-1 align-bottom",
187
+ children: [
188
+ body,
189
+ (0, react_jsx_runtime.jsx)("button", {
190
+ type: "button",
191
+ "data-testid": `field-copy:${field.name}`,
192
+ "aria-label": label,
193
+ title: label,
194
+ onClick: copy,
195
+ className: "inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
196
+ children: copied === "copied" ? (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCheck, {
197
+ "aria-hidden": "true",
198
+ className: "size-3.5"
199
+ }) : (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCopy, {
200
+ "aria-hidden": "true",
201
+ className: "size-3.5"
202
+ })
203
+ }),
204
+ (0, react_jsx_runtime.jsx)("span", {
205
+ "aria-live": "polite",
206
+ className: "sr-only",
207
+ children: copied === "copied" ? t("field.copied", { defaultValue: "Copied" }) : copied === "failed" ? t("field.copyFailed", { defaultValue: "Could not copy" }) : ""
208
+ })
209
+ ]
545
210
  });
546
211
  }
547
212
  //#endregion
@@ -555,7 +220,7 @@ function resolveRef(resource, i18nPrefix) {
555
220
  };
556
221
  }
557
222
  function Field({ resource, i18nPrefix, fallback, fixedFilters, field, doc, ...rest }) {
558
- const input = (0, react_jsx_runtime.jsx)(ResolvedFieldInput, {
223
+ const input = (0, react_jsx_runtime.jsx)(require_filter_builder.ResolvedFieldInput, {
559
224
  ...rest,
560
225
  field,
561
226
  ...fixedFilters === void 0 ? {} : { fixedFilters },
@@ -581,20 +246,30 @@ function Field({ resource, i18nPrefix, fallback, fixedFilters, field, doc, ...re
581
246
  });
582
247
  }
583
248
  function FieldDisplay({ resource, i18nPrefix, fallback, value, ...rest }) {
584
- return (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
585
- ...rest,
249
+ const frameField = (0, react.useMemo)(() => ({
250
+ ...rest.field,
251
+ name: rest.name
252
+ }), [rest.field, rest.name]);
253
+ return (0, react_jsx_runtime.jsx)(FieldValueFrame, {
254
+ field: frameField,
586
255
  value,
587
- resource: resolveRef(resource, i18nPrefix),
588
- fallback: fallback ?? (0, react_jsx_runtime.jsx)("span", { children: value == null || value === "" ? "—" : String(value) })
256
+ surface: "display",
257
+ children: (0, react_jsx_runtime.jsx)(require_filter_builder.ResolvedFieldDisplay, {
258
+ ...rest,
259
+ value,
260
+ resource: resolveRef(resource, i18nPrefix),
261
+ fallback: fallback ?? (0, react_jsx_runtime.jsx)("span", { children: value == null || value === "" ? "—" : String(value) })
262
+ })
589
263
  });
590
264
  }
591
265
  //#endregion
592
266
  //#region src/screen/field-leaf.tsx
593
267
  const SIZES = new Set(_burojs_core.LAYOUT_SIZES);
268
+ const SHOWN_ISSUES = 3;
594
269
  const FOCUSABLE = "input:not([type=\"hidden\"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])";
595
270
  function useLeafSize(field) {
596
271
  const implementation = (0, _burojs_react.useFieldImplementation)({
597
- field: lowerLegacyField(field),
272
+ field: require_filter_builder.lowerLegacyField(field),
598
273
  surface: "input"
599
274
  });
600
275
  const declared = field.ui?.size;
@@ -609,6 +284,10 @@ function leafAttributes(size, weight) {
609
284
  ...weight === void 0 ? {} : { "data-buro-weight": String(weight) }
610
285
  };
611
286
  }
287
+ function labelHiddenOf(compiled, node) {
288
+ return compiled.nodes[node.index]?.options.label === "hidden";
289
+ }
290
+ const labelRegion = (hidden, visible) => hidden ? "sr-only" : visible;
612
291
  function FieldLeaf({ node }) {
613
292
  const { leafIds } = useScreenTree();
614
293
  if (node.state === "failed" && node.failedOn.length > 0 && node.failedOn.every((name) => name.startsWith("meta:"))) return (0, react_jsx_runtime.jsx)(MisconfiguredLeaf, { node });
@@ -620,12 +299,13 @@ function FieldLeaf({ node }) {
620
299
  return (0, react_jsx_runtime.jsx)(RecordLeaf, { node });
621
300
  }
622
301
  function MisconfiguredLeaf({ node }) {
623
- const { leafIds, resource, mode, controller } = useScreenTree();
302
+ const { leafIds, resource, mode, compiled, controller } = useScreenTree();
303
+ const hidden = labelHiddenOf(compiled, node);
624
304
  const name = node.field;
625
305
  const binding = controller.field(name);
626
306
  const caps = (0, _burojs_react.useI18nCaps)(resource);
627
307
  const tid = (0, _burojs_react.useTestIds)();
628
- const field = lowerLegacyField(binding.field);
308
+ const field = require_filter_builder.lowerLegacyField(binding.field);
629
309
  const surface = mode === "show" ? "display" : "input";
630
310
  const resolved = (0, _burojs_react.useFieldImplementation)({
631
311
  field,
@@ -636,8 +316,8 @@ function MisconfiguredLeaf({ node }) {
636
316
  values: controller.values,
637
317
  extra: controller.sources
638
318
  });
639
- const state = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, sources);
640
- useFieldMetaDiagnostic(state, binding.resource, name, field, surface);
319
+ const state = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, sources, resolved.params);
320
+ require_filter_builder.useFieldMetaDiagnostic(state, binding.resource, name, field, surface);
641
321
  const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
642
322
  const testId = leafIds === "record" ? tid.formField(resource, mode, name) : `${leafIds.prefix}:field:${name}`;
643
323
  return (0, react_jsx_runtime.jsxs)("div", {
@@ -647,20 +327,30 @@ function MisconfiguredLeaf({ node }) {
647
327
  "data-buro-field-meta": "failed",
648
328
  children: [(0, react_jsx_runtime.jsx)("div", {
649
329
  "data-buro-region": "field-label",
650
- className: "text-sm font-medium leading-none",
330
+ className: labelRegion(hidden, "text-sm font-medium leading-none"),
651
331
  children: label
652
332
  }), (0, react_jsx_runtime.jsx)("div", {
653
333
  "data-buro-region": "field-control",
654
- children: (0, react_jsx_runtime.jsx)(MetaPlaceholder, { state })
334
+ children: (0, react_jsx_runtime.jsx)(require_filter_builder.MetaPlaceholder, { state })
655
335
  })]
656
336
  });
657
337
  }
338
+ function valueAt(record, path) {
339
+ let at = record;
340
+ for (const segment of path.split(".")) {
341
+ if (at === null || typeof at !== "object") return void 0;
342
+ at = at[segment];
343
+ }
344
+ return at;
345
+ }
658
346
  function RecordLeaf({ node }) {
659
347
  const { resource, mode, compiled, controller } = useScreenTree();
660
- const name = node.field;
348
+ const head = node.field;
349
+ const name = node.fieldPath ?? head;
661
350
  const binding = controller.field(name);
662
351
  const size = useLeafSize(binding.field);
663
352
  const weight = compiled.nodes[node.index]?.options.weight;
353
+ const hidden = labelHiddenOf(compiled, node);
664
354
  const caps = (0, _burojs_react.useI18nCaps)(resource);
665
355
  const tid = (0, _burojs_react.useTestIds)();
666
356
  const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
@@ -668,10 +358,7 @@ function RecordLeaf({ node }) {
668
358
  const t = (0, _burojs_react.useOptionalT)();
669
359
  if (node.restricted === true) {
670
360
  const rawReason = node.restrictedReason;
671
- const reason = rawReason === void 0 || rawReason === "" ? void 0 : (0, _burojs_core.resolveContentSlot)(caps, [rawReason], {
672
- resource,
673
- default: rawReason
674
- });
361
+ const reason = rawReason === void 0 || rawReason === "" ? void 0 : require_check_confirm_dialog.reasonText(caps, rawReason, resource);
675
362
  const restrictedId = tid.formFieldRestricted(resource, mode, name);
676
363
  return (0, react_jsx_runtime.jsxs)("div", {
677
364
  ...attributes,
@@ -680,7 +367,7 @@ function RecordLeaf({ node }) {
680
367
  "data-buro-restricted": "true",
681
368
  children: [(0, react_jsx_runtime.jsx)("div", {
682
369
  "data-buro-region": "field-label",
683
- className: "text-sm font-medium leading-none",
370
+ className: labelRegion(hidden, "text-sm font-medium leading-none"),
684
371
  children: label
685
372
  }), (0, react_jsx_runtime.jsx)("div", {
686
373
  "data-buro-region": "field-control",
@@ -700,7 +387,7 @@ function RecordLeaf({ node }) {
700
387
  });
701
388
  }
702
389
  const record = controller.record;
703
- const value = mode === "show" ? record?.[name] ?? controller.values[name] : mode === "edit" && controller.plan?.fields[name] !== "active" ? record?.[name] ?? controller.values[name] : controller.values[name];
390
+ const value = mode === "show" ? valueAt(record, name) ?? binding.value : mode === "edit" && controller.plan?.fields[head] !== "active" ? valueAt(record, name) ?? binding.value : binding.value;
704
391
  const display = (0, react_jsx_runtime.jsx)(FieldDisplay, {
705
392
  resource: binding.resource,
706
393
  name,
@@ -708,6 +395,8 @@ function RecordLeaf({ node }) {
708
395
  value,
709
396
  metaSources: controller.sources,
710
397
  ...record === void 0 ? {} : { record },
398
+ ...binding.absentPaths === void 0 ? {} : { absentPaths: binding.absentPaths },
399
+ ...binding.pathStatus === void 0 ? {} : { pathStatus: binding.pathStatus },
711
400
  fallback: value == null || value === "" ? (0, react_jsx_runtime.jsx)("span", {
712
401
  className: "text-muted-foreground",
713
402
  children: "—"
@@ -718,11 +407,11 @@ function RecordLeaf({ node }) {
718
407
  "data-testid": `show-field:${resource}:${name}`,
719
408
  children: [(0, react_jsx_runtime.jsxs)("dt", {
720
409
  "data-buro-region": "field-label",
721
- className: require_use_theme.cn("flex items-center gap-0.5", FIELD_LABEL_SHOW),
410
+ className: labelRegion(hidden, require_use_theme.cn("flex items-center gap-0.5", FIELD_LABEL_SHOW)),
722
411
  children: [(0, react_jsx_runtime.jsx)("span", {
723
412
  className: "min-w-0",
724
413
  children: label
725
- }), (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
414
+ }), hidden ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
726
415
  address: `${resource}/fields/${name}`,
727
416
  name: label
728
417
  })]
@@ -734,10 +423,7 @@ function RecordLeaf({ node }) {
734
423
  });
735
424
  if (node.editable !== true) {
736
425
  const rawReason = node.lockReason;
737
- const reason = rawReason === void 0 ? void 0 : (0, _burojs_core.resolveContentSlot)(caps, [rawReason], {
738
- resource,
739
- default: rawReason
740
- });
426
+ const reason = rawReason === void 0 ? void 0 : require_check_confirm_dialog.reasonText(caps, rawReason, resource);
741
427
  const locked = tid.formFieldLocked(resource, mode, name);
742
428
  return (0, react_jsx_runtime.jsxs)("div", {
743
429
  ...attributes,
@@ -745,8 +431,8 @@ function RecordLeaf({ node }) {
745
431
  "data-testid": tid.formField(resource, mode, name),
746
432
  children: [(0, react_jsx_runtime.jsxs)("div", {
747
433
  "data-buro-region": "field-label",
748
- className: "flex items-center gap-2",
749
- children: [(0, react_jsx_runtime.jsx)(require_label.Label, { children: label }), (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
434
+ className: labelRegion(hidden, "flex items-center gap-2"),
435
+ children: [(0, react_jsx_runtime.jsx)(require_label.Label, { children: label }), hidden ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
750
436
  address: `${resource}/fields/${name}`,
751
437
  name: label,
752
438
  testId: `${tid.formField(resource, mode, name)}:info`
@@ -782,14 +468,14 @@ function RecordLeaf({ node }) {
782
468
  node,
783
469
  binding,
784
470
  label,
471
+ labelHidden: hidden,
785
472
  attributes,
786
473
  inputId
787
474
  });
788
475
  }
789
- function ActiveLeaf({ node, binding, label, attributes, inputId }) {
476
+ function ActiveLeaf({ node, binding, label, labelHidden, attributes, inputId }) {
790
477
  const { resource, mode, controller, disabled: locked } = useScreenTree();
791
478
  const caps = (0, _burojs_react.useI18nCaps)(resource);
792
- const t = (0, _burojs_react.useOptionalT)();
793
479
  const tid = (0, _burojs_react.useTestIds)();
794
480
  const name = binding.name;
795
481
  const record = controller.record;
@@ -804,25 +490,22 @@ function ActiveLeaf({ node, binding, label, attributes, inputId }) {
804
490
  });
805
491
  const messageId = `${mode}-${name}-msg`;
806
492
  const placeholder = (0, _burojs_core.resolveFieldSlot)(caps, name, "placeholder");
807
- const hint = (0, _burojs_core.resolveFieldSlot)(caps, name, "description", fieldDescription(binding.field));
493
+ const hint = (0, _burojs_core.resolveFieldSlot)(caps, name, "description", require_filter_builder.fieldDescription(binding.field));
494
+ const chromeT = (0, _burojs_react.useChromeT)();
808
495
  const fieldKey = `resources.${resource}.fields.${name}`;
809
- const errorText = binding.error === void 0 ? null : (0, _burojs_react.resolveValidationMessage)({
810
- code: binding.error.code ?? "",
811
- message: binding.error.message,
812
- ...binding.error.params === void 0 ? {} : { params: binding.error.params }
813
- }, {
814
- t,
815
- fieldKey
816
- });
817
- const warning = errorText === null ? binding.warnings[0] : void 0;
818
- const warningText = warning === void 0 ? null : (0, _burojs_react.resolveValidationMessage)({
819
- code: warning.code ?? "",
820
- message: warning.message,
821
- ...warning.params === void 0 ? {} : { params: warning.params }
496
+ const text = (issue) => (0, _burojs_react.resolveValidationMessage)({
497
+ code: issue.code ?? "",
498
+ message: issue.message,
499
+ ...issue.check === void 0 ? {} : { check: issue.check }
822
500
  }, {
823
- t,
501
+ has: caps.has,
502
+ t: caps.t,
824
503
  fieldKey
825
504
  });
505
+ const shown = binding.issues.slice(0, SHOWN_ISSUES);
506
+ const more = binding.issues.length - shown.length;
507
+ const firstError = shown.find((issue) => issue.severity === "error");
508
+ const errorText = firstError === void 0 ? null : text(firstError);
826
509
  const disabled = binding.disabled || controller.isSubmitting || locked === true;
827
510
  const describedBy = errorText === null && hint ? messageId : void 0;
828
511
  const errorMessageId = errorText === null ? void 0 : messageId;
@@ -834,12 +517,13 @@ function ActiveLeaf({ node, binding, label, attributes, inputId }) {
834
517
  onBlur: binding.onBlur,
835
518
  children: [(0, react_jsx_runtime.jsxs)("div", {
836
519
  "data-buro-region": "field-label",
837
- className: "flex items-center gap-2",
520
+ className: labelRegion(labelHidden, "flex items-center gap-2"),
838
521
  children: [(0, react_jsx_runtime.jsx)(require_label.Label, {
522
+ id: `${inputId}-label`,
839
523
  htmlFor: inputId,
840
524
  required: binding.required,
841
525
  children: label
842
- }), (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
526
+ }), labelHidden ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
843
527
  address: `${resource}/fields/${name}`,
844
528
  name: label,
845
529
  testId: `${tid.formField(resource, mode, name)}:info`
@@ -851,6 +535,7 @@ function ActiveLeaf({ node, binding, label, attributes, inputId }) {
851
535
  resource: binding.resource,
852
536
  name,
853
537
  inputId,
538
+ labelId: `${inputId}-label`,
854
539
  field: binding.field,
855
540
  value: binding.value,
856
541
  onChange: binding.onChange,
@@ -861,11 +546,17 @@ function ActiveLeaf({ node, binding, label, attributes, inputId }) {
861
546
  ...mode === "create" || record === void 0 ? {} : { record },
862
547
  form: controller.values,
863
548
  metaSources: controller.sources,
549
+ ...controller.baseline === void 0 ? {} : { baseline: controller.baseline },
864
550
  ...describedBy === void 0 ? {} : { descriptionId: describedBy },
865
551
  ...errorMessageId === void 0 ? {} : { errorId: errorMessageId },
866
552
  errorMessage: errorText,
553
+ issues: binding.issues,
867
554
  ...binding.fixedFilters === void 0 ? {} : { fixedFilters: binding.fixedFilters },
555
+ ...binding.optionSubtitle === void 0 ? {} : { optionSubtitle: binding.optionSubtitle },
868
556
  ...binding.relationSeeds === void 0 ? {} : { relationSeeds: binding.relationSeeds },
557
+ ...binding.link === void 0 ? {} : { link: binding.link },
558
+ ...binding.absentPaths === void 0 ? {} : { absentPaths: binding.absentPaths },
559
+ ...binding.pathStatus === void 0 ? {} : { pathStatus: binding.pathStatus },
869
560
  fallback: (0, react_jsx_runtime.jsx)(require_input.Input, {
870
561
  id: inputId,
871
562
  name: inputId,
@@ -880,18 +571,23 @@ function ActiveLeaf({ node, binding, label, attributes, inputId }) {
880
571
  ...errorMessageId === void 0 ? {} : { "aria-errormessage": errorMessageId },
881
572
  onChange: (event) => binding.onChange(event.target.value)
882
573
  })
883
- }), errorText !== null ? (0, react_jsx_runtime.jsx)("p", {
884
- id: messageId,
885
- "aria-live": "polite",
886
- className: "text-sm text-destructive",
887
- "data-testid": tid.formFieldError(resource, mode, name),
888
- children: errorText
889
- }) : warningText !== null ? (0, react_jsx_runtime.jsx)("p", {
574
+ }), shown.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
890
575
  id: messageId,
891
576
  "aria-live": "polite",
892
- className: "text-sm text-warning-emphasis",
893
- "data-testid": `form-field-warning:${resource}:${mode}:${name}`,
894
- children: warningText
577
+ className: require_use_theme.cn("space-y-0.5 text-sm", errorText === null ? "text-warning-emphasis" : "text-destructive"),
578
+ "data-testid": errorText === null ? `form-field-warning:${resource}:${mode}:${name}` : tid.formFieldError(resource, mode, name),
579
+ children: [shown.map((issue, index) => (0, react_jsx_runtime.jsx)("p", {
580
+ "data-buro-severity": issue.severity,
581
+ className: issue.severity === "error" ? "text-destructive" : "text-warning-emphasis",
582
+ children: text(issue)
583
+ }, index)), more > 0 ? (0, react_jsx_runtime.jsx)("p", {
584
+ className: "text-muted-foreground",
585
+ "data-testid": `form-field-more:${resource}:${mode}:${name}`,
586
+ children: chromeT("validation.moreIssues", {
587
+ count: more,
588
+ defaultValue: "+{{count}} more"
589
+ })
590
+ }) : null]
895
591
  }) : hint ? (0, react_jsx_runtime.jsx)("p", {
896
592
  id: messageId,
897
593
  "data-testid": tid.formFieldHelp(resource, mode, name),
@@ -907,11 +603,12 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
907
603
  const binding = controller.field(name);
908
604
  const size = useLeafSize(binding.field);
909
605
  const weight = compiled.nodes[node.index]?.options.weight;
606
+ const hidden = labelHiddenOf(compiled, node);
910
607
  const attributes = leafAttributes(size, weight);
911
608
  const docRef = (0, _burojs_core.i18nPrefixToRef)(prefix);
912
609
  const docScope = docRef.namespace === "default" ? docRef.id : (0, _burojs_core.formatEntityRef)(docRef);
913
610
  const caps = (0, _burojs_react.useI18nCaps)(docScope);
914
- const t = (0, _burojs_react.useOptionalT)();
611
+ const issueCaps = (0, _burojs_react.useI18nCaps)();
915
612
  const uid = (0, react.useId)();
916
613
  const root = (0, react.useRef)(null);
917
614
  const inputId = `${inputIds ?? uid}-${name}`;
@@ -924,8 +621,8 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
924
621
  element.querySelector(FOCUSABLE)?.focus();
925
622
  });
926
623
  const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
927
- const hint = (0, _burojs_core.resolveFieldSlot)(caps, name, "description", fieldDescription(binding.field));
928
- const info = (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
624
+ const hint = (0, _burojs_core.resolveFieldSlot)(caps, name, "description", require_filter_builder.fieldDescription(binding.field));
625
+ const info = hidden ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
929
626
  address: `${docScope}/fields/${name}`,
930
627
  name: label,
931
628
  testId: `${prefix}:field:${name}:info`
@@ -942,7 +639,7 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
942
639
  children: [
943
640
  (0, react_jsx_runtime.jsxs)("div", {
944
641
  "data-buro-region": "field-label",
945
- className: "flex items-center gap-2",
642
+ className: labelRegion(hidden, "flex items-center gap-2"),
946
643
  children: [(0, react_jsx_runtime.jsx)("span", {
947
644
  className: FIELD_LABEL_SHOW,
948
645
  children: label
@@ -965,16 +662,19 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
965
662
  const text = (issue) => (0, _burojs_react.resolveValidationMessage)({
966
663
  code: issue.code ?? "",
967
664
  message: issue.message,
968
- ...issue.params === void 0 ? {} : { params: issue.params }
665
+ ...issue.check === void 0 ? {} : { check: issue.check }
969
666
  }, {
970
- t,
667
+ has: issueCaps.has,
668
+ t: issueCaps.t,
971
669
  fieldKey
972
670
  });
973
671
  const defaultNode = (0, react_jsx_runtime.jsx)(Field, {
974
672
  ...binding,
975
673
  field: binding.field,
976
674
  metaSources: controller.sources,
675
+ ...controller.baseline === void 0 ? {} : { baseline: controller.baseline },
977
676
  inputId,
677
+ labelId: `${inputId}-label`,
978
678
  i18nPrefix: prefix,
979
679
  disabled: disabled === true || binding.disabled
980
680
  });
@@ -988,8 +688,9 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
988
688
  children: [
989
689
  (0, react_jsx_runtime.jsxs)("div", {
990
690
  "data-buro-region": "field-label",
991
- className: "flex items-center gap-2",
691
+ className: labelRegion(hidden, "flex items-center gap-2"),
992
692
  children: [(0, react_jsx_runtime.jsx)(require_label.Label, {
693
+ id: `${inputId}-label`,
993
694
  htmlFor: inputId,
994
695
  required: binding.required,
995
696
  children: label
@@ -1030,9 +731,10 @@ function Notice({ children }) {
1030
731
  children
1031
732
  });
1032
733
  }
1033
- function FactsView({ props }) {
734
+ function FactsView({ props, empty }) {
1034
735
  const own = props;
1035
736
  const t = (0, _burojs_react.useOptionalT)();
737
+ const chromeT = (0, _burojs_react.useChromeT)();
1036
738
  const snapshot = (0, _burojs_react.useApplicationSnapshot)();
1037
739
  const queryId = (0, _burojs_core.formatEntityRef)(own.query);
1038
740
  const caps = (0, _burojs_react.useI18nCaps)();
@@ -1049,7 +751,10 @@ function FactsView({ props }) {
1049
751
  kind: "custom-query",
1050
752
  ref: own.query
1051
753
  }), [own.query]);
1052
- const result = (0, _burojs_react.useCustomQuery)(handle, blocked ? {} : input, { enabled: !blocked });
754
+ const result = (0, _burojs_react.useCustomQuery)(handle, blocked ? {} : input, {
755
+ enabled: !blocked,
756
+ ...own.refetchInterval === void 0 ? {} : { refetchInterval: own.refetchInterval }
757
+ });
1053
758
  const shown = (0, react.useMemo)(() => {
1054
759
  const byName = new Map(fields.map((field) => [field.name, field]));
1055
760
  return (own.rows ?? fields.map((field) => field.name)).flatMap((name) => {
@@ -1057,7 +762,7 @@ function FactsView({ props }) {
1057
762
  return field === void 0 ? [] : [field];
1058
763
  });
1059
764
  }, [fields, own.rows]);
1060
- if (blocked) return (0, react_jsx_runtime.jsx)(Notice, { children: own.missing ?? t("facts.empty", { defaultValue: "No data" }) });
765
+ if (blocked) return (0, react_jsx_runtime.jsx)(Notice, { children: own.missing ?? empty ?? t("facts.empty", { defaultValue: "No data" }) });
1061
766
  if (result.isError) return (0, react_jsx_runtime.jsxs)("div", {
1062
767
  role: "alert",
1063
768
  className: "flex flex-wrap items-center gap-2 rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
@@ -1066,7 +771,7 @@ function FactsView({ props }) {
1066
771
  variant: "outline",
1067
772
  size: "sm",
1068
773
  onClick: () => void result.refetch(),
1069
- children: t("actions.retry", { defaultValue: "Retry" })
774
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
1070
775
  })]
1071
776
  });
1072
777
  if (result.data === void 0) return own.view === "list" ? (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
@@ -1080,7 +785,7 @@ function FactsView({ props }) {
1080
785
  }, field.name))
1081
786
  });
1082
787
  const data = result.data;
1083
- if (data === null || typeof data !== "object" || shown.length === 0) return (0, react_jsx_runtime.jsx)(Notice, { children: own.missing ?? t("facts.empty", { defaultValue: "No data" }) });
788
+ if (data === null || typeof data !== "object" || shown.length === 0) return (0, react_jsx_runtime.jsx)(Notice, { children: own.missing ?? empty ?? t("facts.empty", { defaultValue: "No data" }) });
1084
789
  const pairs = shown.map((field) => {
1085
790
  const value = data[field.name];
1086
791
  const label = (0, _burojs_core.resolveContentSlot)(caps, [`queries.${queryId}.fields.${field.name}.label`, `queries.${queryId}.fields.${field.name}`], {
@@ -1090,13 +795,18 @@ function FactsView({ props }) {
1090
795
  const body = value === null || value === void 0 ? (0, react_jsx_runtime.jsx)("span", {
1091
796
  className: "text-muted-foreground",
1092
797
  children: "—"
1093
- }) : (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
1094
- resource: own.query,
1095
- name: field.name,
798
+ }) : (0, react_jsx_runtime.jsx)(FieldValueFrame, {
1096
799
  field,
1097
800
  value,
1098
- record: data,
1099
- fallback: toDisplayText(value).text
801
+ surface: "display",
802
+ children: (0, react_jsx_runtime.jsx)(require_filter_builder.ResolvedFieldDisplay, {
803
+ resource: own.query,
804
+ name: field.name,
805
+ field,
806
+ value,
807
+ record: data,
808
+ fallback: toDisplayText(value).text
809
+ })
1100
810
  });
1101
811
  return {
1102
812
  name: field.name,
@@ -1150,6 +860,9 @@ const PlacementFrameContext = (0, react.createContext)(null);
1150
860
  function usePlacementFrame() {
1151
861
  return (0, react.useContext)(PlacementFrameContext);
1152
862
  }
863
+ function placementLayoutId(frame) {
864
+ return frame?.owner === void 0 ? void 0 : `${frame.owner}/${frame.key.split(".").join("/")}`;
865
+ }
1153
866
  //#endregion
1154
867
  //#region src/flows/app-flow-button.tsx
1155
868
  function AppFlowButton({ action, variant = "ghost", size = "sm", className }) {
@@ -1237,10 +950,7 @@ function RecordInlineFlow({ name }) {
1237
950
  const id = frame?.recordId;
1238
951
  const asRead = frame === null ? void 0 : (0, _burojs_react.policyRecordOf)(frame.controller, frame.record);
1239
952
  const key = placement?.key ?? flowName;
1240
- const state = frame === null || id === void 0 || asRead === void 0 ? null : resolve(flowName, {
1241
- ...asRead,
1242
- id
1243
- });
953
+ const state = frame === null || id === void 0 || asRead === void 0 ? null : resolve(flowName, (0, _burojs_react.withRecordKeys)(asRead, { id }));
1244
954
  const kept = holder?.get(key);
1245
955
  const stale = state?.state === "absent" && state.cause === "when" && kept !== void 0 && kept.dirty;
1246
956
  const gone = state?.state === "absent" && !stale;
@@ -1252,10 +962,7 @@ function RecordInlineFlow({ name }) {
1252
962
  key
1253
963
  ]);
1254
964
  if (frame === null || asRead === void 0 || id === void 0 || compiled === null) return null;
1255
- const row = {
1256
- ...asRead,
1257
- id
1258
- };
965
+ const row = (0, _burojs_react.withRecordKeys)(asRead, { id });
1259
966
  const control = resolve(flowName, row);
1260
967
  switch (control.state) {
1261
968
  case "undecided":
@@ -1269,7 +976,7 @@ function RecordInlineFlow({ name }) {
1269
976
  return (0, react_jsx_runtime.jsx)(InlineHostLoader, {
1270
977
  resource,
1271
978
  name: flowName,
1272
- record: row,
979
+ ...hostRecord((0, _burojs_core.flowRecordOf)(compiled, row)),
1273
980
  placementKey: key,
1274
981
  lease: kept,
1275
982
  stale: true,
@@ -1285,7 +992,7 @@ function RecordInlineFlow({ name }) {
1285
992
  if (control.state === "disabled" && kept !== void 0 && kept.dirty) return (0, react_jsx_runtime.jsx)(InlineHostLoader, {
1286
993
  resource,
1287
994
  name: flowName,
1288
- record: row,
995
+ ...hostRecord((0, _burojs_core.flowRecordOf)(compiled, row)),
1289
996
  placementKey: key,
1290
997
  lease: kept,
1291
998
  stale: true,
@@ -1297,11 +1004,12 @@ function RecordInlineFlow({ name }) {
1297
1004
  return (0, react_jsx_runtime.jsx)(InlineHostLoader, {
1298
1005
  resource,
1299
1006
  name: flowName,
1300
- record: control.record ?? row,
1007
+ ...hostRecord((0, _burojs_core.flowRecordOf)(compiled, control.record ?? row)),
1301
1008
  placementKey: key,
1302
1009
  ...lease === void 0 ? {} : { lease }
1303
1010
  });
1304
1011
  }
1012
+ const hostRecord = (record) => record === void 0 ? {} : { record };
1305
1013
  function InlineHostLoader(props) {
1306
1014
  const loaded = require_check_confirm_dialog.useLoaded(require_check_confirm_dialog.loadInlineFlowHost);
1307
1015
  if (loaded.error !== void 0) return (0, react_jsx_runtime.jsx)("p", {
@@ -1517,6 +1225,7 @@ function placementSeeds(where, resolved, closure) {
1517
1225
  where.forEach((entry, index) => {
1518
1226
  const value = resolved[index]?.value;
1519
1227
  if (entry.op !== "eq" || value === null || value === void 0) return;
1228
+ if (typeof entry.field !== "string" || entry.field.includes(".")) return;
1520
1229
  if (resolved[index]?.field !== entry.field) return;
1521
1230
  const source = refSource(entry.value);
1522
1231
  if (source === null ? isLiteral(entry.value) : source === "record" || source === "user" || !UNTRUSTED.includes(source) && Object.hasOwn(closure, source) && !(closure[source] ?? []).some((input) => UNTRUSTED.includes(input))) seeds[entry.field] = value;
@@ -1524,6 +1233,28 @@ function placementSeeds(where, resolved, closure) {
1524
1233
  return Object.freeze(seeds);
1525
1234
  }
1526
1235
  //#endregion
1236
+ //#region src/enum/enum-settling.tsx
1237
+ function unknownEnumValueLabel(caps, def, ns, value) {
1238
+ const declared = (0, _burojs_core.enumFallbackText)(def);
1239
+ if (def.fallback === void 0 && declared === void 0) return {
1240
+ label: value,
1241
+ fallback: false
1242
+ };
1243
+ return {
1244
+ label: (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.enumFallbackKey)(ns)], { default: declared }) ?? value,
1245
+ fallback: true
1246
+ };
1247
+ }
1248
+ function EnumSettlingRow({ status, testid }) {
1249
+ const t = (0, _burojs_react.useOptionalT)();
1250
+ return (0, react_jsx_runtime.jsx)("div", {
1251
+ role: "status",
1252
+ "data-testid": testid === void 0 ? void 0 : `${testid}:${status}`,
1253
+ className: "px-2 py-1.5 text-sm text-muted-foreground",
1254
+ children: status === "pending" ? t("field.loading", { defaultValue: "Loading…" }) : t("relation.failed", { defaultValue: "Failed to load options." })
1255
+ });
1256
+ }
1257
+ //#endregion
1527
1258
  //#region src/enum/enum-badge.tsx
1528
1259
  function BadgeBody({ icon, label }) {
1529
1260
  return (0, react_jsx_runtime.jsxs)("span", {
@@ -1534,7 +1265,8 @@ function BadgeBody({ icon, label }) {
1534
1265
  }) : null, label]
1535
1266
  });
1536
1267
  }
1537
- function EnumBadge({ enumName, value, testid, className, presentation }) {
1268
+ function EnumBadge({ enumName: enumInput, value, testid, className, presentation }) {
1269
+ const enumName = (0, _burojs_core_internal.enumBindingKey)(enumInput) ?? "";
1538
1270
  const app = (0, _burojs_react.useApp)();
1539
1271
  const caps = (0, _burojs_react.useI18nCaps)();
1540
1272
  const def = app.registry.enums.get(enumName);
@@ -1593,9 +1325,9 @@ function EnumBadge({ enumName, value, testid, className, presentation }) {
1593
1325
  children: body
1594
1326
  });
1595
1327
  }
1596
- const declaredFallback = (0, _burojs_core.enumFallbackText)(def);
1597
- if (def?.fallback !== void 0 || declaredFallback !== void 0) {
1598
- const fallbackLabel = (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.enumFallbackKey)(ns)], { default: declaredFallback }) ?? value;
1328
+ const unknown = unknownEnumValueLabel(caps, def, ns, value);
1329
+ if (unknown.fallback) {
1330
+ const fallbackLabel = unknown.label;
1599
1331
  if (presentation === "plain") return (0, react_jsx_runtime.jsx)("span", {
1600
1332
  "data-testid": `${id}:fallback`,
1601
1333
  className,
@@ -1680,6 +1412,7 @@ function useExportRunWatcher() {
1680
1412
  const runtime = (0, _burojs_react.useDataRuntime)();
1681
1413
  const runs = (0, _burojs_react.useExportRuns)();
1682
1414
  const t = (0, _burojs_react.useOptionalT)();
1415
+ const caps = (0, _burojs_react.useI18nCaps)();
1683
1416
  react.useEffect(() => {
1684
1417
  const announced = announcedRunsFor(runtime);
1685
1418
  const unsubscribes = runs.map((run) => {
@@ -1698,7 +1431,7 @@ function useExportRunWatcher() {
1698
1431
  label: t("export.toast.download"),
1699
1432
  onClick: () => downloadArtifact(artifact)
1700
1433
  } });
1701
- } else if (state.status === "failed") sonner.toast.error(t("export.toast.failed", { params: { message: state.error.message } }));
1434
+ } else if (state.status === "failed") sonner.toast.error(t("export.toast.failed", { params: { message: (0, _burojs_react.resolveErrorText)(state.error, caps) } }));
1702
1435
  };
1703
1436
  check();
1704
1437
  return run.handle.subscribe(check);
@@ -1709,24 +1442,27 @@ function useExportRunWatcher() {
1709
1442
  }, [
1710
1443
  runs,
1711
1444
  runtime,
1712
- t
1445
+ t,
1446
+ caps
1713
1447
  ]);
1714
1448
  }
1715
1449
  //#endregion
1716
1450
  //#region src/actions/action-overflow.tsx
1717
1451
  const RowActionsCollapseContext = (0, react.createContext)(false);
1718
- function ActionOverflow({ resource, record, surface, className, hideFlows, collapse }) {
1719
- const t = (0, _burojs_react.useOptionalT)();
1452
+ function ActionOverflow({ resource: resourceInput, record, surface, className, hideFlows, collapse, sources }) {
1453
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
1454
+ const chromeT = (0, _burojs_react.useChromeT)();
1720
1455
  const tid = (0, _burojs_react.useTestIds)();
1456
+ const recordKey = String((0, _burojs_react.recordKeyOf)((0, _burojs_react.useApp)().registry.get(resource), record) ?? "");
1721
1457
  const collapsedRows = (0, react.useContext)(RowActionsCollapseContext);
1722
1458
  const [flowFor, setFlowFor] = (0, react.useState)(null);
1723
- const actions = useShownItemActions(resource, record, surface, hideFlows);
1459
+ const actions = useShownItemActions(resource, record, surface, hideFlows, sources);
1724
1460
  if (actions.length === 0) return null;
1725
1461
  const isRow = surface === "row";
1726
1462
  const folded = isRow && (collapse ?? collapsedRows);
1727
1463
  const standalone = folded ? [] : actions.filter((a) => a.placement === "standalone");
1728
1464
  const menu = folded ? actions : actions.filter((a) => a.placement === "menu");
1729
- const menuTestId = isRow ? tid.listRowActionsMenu(resource, record.id) : tid.formActionsMenu(resource, surface);
1465
+ const menuTestId = isRow ? tid.listRowActionsMenu(resource, recordKey) : tid.formActionsMenu(resource, surface);
1730
1466
  const firstDestructive = menu.findIndex((a) => a.variant === "destructive");
1731
1467
  const overlays = (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: flowFor != null ? (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.RuntimeFlowRunner, {
1732
1468
  resource,
@@ -1740,6 +1476,7 @@ function ActionOverflow({ resource, record, surface, className, hideFlows, colla
1740
1476
  actionName: a.name,
1741
1477
  record,
1742
1478
  scope: surface,
1479
+ ...sources === void 0 ? {} : { sources },
1743
1480
  density: a.density
1744
1481
  }, a.name));
1745
1482
  return (0, react_jsx_runtime.jsxs)("div", {
@@ -1763,7 +1500,7 @@ function ActionOverflow({ resource, record, surface, className, hideFlows, colla
1763
1500
  size: "icon",
1764
1501
  className: "size-7",
1765
1502
  "data-testid": menuTestId,
1766
- "aria-label": t("actions.more", { defaultValue: "More" }),
1503
+ "aria-label": chromeT("actions.more", { defaultValue: "More" }),
1767
1504
  children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconDots, {
1768
1505
  className: "h-4 w-4",
1769
1506
  "aria-hidden": "true"
@@ -1777,15 +1514,16 @@ function ActionOverflow({ resource, record, surface, className, hideFlows, colla
1777
1514
  children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconDots, {
1778
1515
  className: "h-4 w-4",
1779
1516
  "aria-hidden": "true"
1780
- }), t("actions.more", { defaultValue: "More" })]
1517
+ }), chromeT("actions.more", { defaultValue: "More" })]
1781
1518
  })
1782
1519
  }), (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuContent, {
1783
1520
  align: "end",
1784
- children: menu.map((a, index) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index === firstDestructive && index > 0 && (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuSeparator, { "data-testid": isRow ? `list-row-actions-separator:${resource}:${record.id}` : `form-actions-separator:${resource}:${surface}` }), a.flow === void 0 ? (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.ActionButton, {
1521
+ children: menu.map((a, index) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index === firstDestructive && index > 0 && (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuSeparator, { "data-testid": isRow ? `list-row-actions-separator:${resource}:${recordKey}` : `form-actions-separator:${resource}:${surface}` }), a.flow === void 0 ? (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.ActionButton, {
1785
1522
  resource,
1786
1523
  actionName: a.name,
1787
1524
  record,
1788
1525
  scope: surface,
1526
+ ...sources === void 0 ? {} : { sources },
1789
1527
  asMenuItem: true
1790
1528
  }) : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.FlowMenuItem, {
1791
1529
  resource,
@@ -1805,46 +1543,18 @@ function ActionOverflow({ resource, record, surface, className, hideFlows, colla
1805
1543
  ]
1806
1544
  });
1807
1545
  }
1808
- function useShownItemActions(resource, record, surface, hideFlows) {
1546
+ function useShownItemActions(resource, record, surface, hideFlows, sources) {
1809
1547
  const resolved = (0, _burojs_react.useItemActions)({
1810
1548
  resource,
1811
1549
  record,
1812
- surface
1550
+ surface,
1551
+ ...sources === void 0 ? {} : { sources }
1813
1552
  });
1814
1553
  const def = (0, _burojs_react.useApp)().registry.get(resource);
1815
1554
  const shown = def !== void 0 && (0, _burojs_core.isBuiltinItemAction)((def.actions?.item)?.find((action) => action.name === "edit"), "edit") && !(0, _burojs_core.recordEntries)(def).page.edit && (0, _burojs_core.recordEntries)(def).quick.edit === null ? resolved.filter((a) => a.name !== "edit") : resolved;
1816
1555
  return hideFlows === void 0 ? shown : shown.filter((a) => a.flow === void 0 || !hideFlows(a.name));
1817
1556
  }
1818
1557
  //#endregion
1819
- //#region src/layout/record-targets.ts
1820
- function recordRouteAvailable(registry, resource, action) {
1821
- if ((0, _burojs_core.resolveStaticAvailability)(registry, resource, action).state !== "available") return false;
1822
- const def = registry.get(resource);
1823
- return def !== void 0 && (0, _burojs_core.hasRecordPage)(def, action);
1824
- }
1825
- function isShowAvailable(registry, resource) {
1826
- return recordRouteAvailable(registry, resource, "show");
1827
- }
1828
- function showTarget(resource, id) {
1829
- return {
1830
- resource,
1831
- action: "show",
1832
- params: { id }
1833
- };
1834
- }
1835
- function listTarget(resource) {
1836
- return {
1837
- resource,
1838
- action: "list"
1839
- };
1840
- }
1841
- function recordReturnTarget(registry, resource, id) {
1842
- return isShowAvailable(registry, resource) ? showTarget(resource, id) : listTarget(resource);
1843
- }
1844
- function editBackHref(registry, resource, id, backHref) {
1845
- return backHref ?? (0, _burojs_react.resolveRoute)(recordReturnTarget(registry, resource, id), registry);
1846
- }
1847
- //#endregion
1848
1558
  //#region src/lib/typography.ts
1849
1559
  const typography = {
1850
1560
  h1: "text-2xl font-semibold tracking-tight",
@@ -1902,8 +1612,14 @@ function DocumentTitleProvider({ routeKey, children }) {
1902
1612
  });
1903
1613
  }
1904
1614
  //#endregion
1615
+ //#region src/resource/resource-title.ts
1616
+ function resolveResourceTitle(caps, t, resource, slot, params) {
1617
+ return (0, _burojs_core.resolveContentSlot)(caps, [`resources.${resource}.${slot}`], { params: { ...params } }) ?? t(`pageHeader.${slot}`, { params: { ...params } });
1618
+ }
1619
+ //#endregion
1905
1620
  //#region src/resource/page-header.tsx
1906
- function PageHeader({ resource, mode, recordName, backHref, backLabel, actions, title, breadcrumbs, backLink = false, visibleTitle = false, labelOverride, className }) {
1621
+ function PageHeader({ resource: resourceInput, mode, recordName, backHref, backLabel, actions, title, breadcrumbs, backLink = false, visibleTitle = false, labelOverride, className }) {
1622
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
1907
1623
  const app = (0, _burojs_react.useApp)();
1908
1624
  const t = (0, _burojs_react.useT)();
1909
1625
  const def = app.registry.get(resource);
@@ -1912,10 +1628,10 @@ function PageHeader({ resource, mode, recordName, backHref, backLabel, actions,
1912
1628
  const resourceSingle = (0, _burojs_core.resolveResourceLabel)(caps, resource, "single", def);
1913
1629
  const labelSingle = labelOverride ?? resourceSingle;
1914
1630
  const labelPlural = (0, _burojs_core.resolveResourceLabel)(caps, resource, "plural", def);
1915
- const computedTitle = title ?? (mode === "list" ? labelPlural : mode === "show" ? recordName ?? labelSingle : mode === "edit" ? recordName ? t("pageHeader.editTitleNamed", { params: {
1631
+ const computedTitle = title ?? (mode === "list" ? labelPlural : mode === "show" ? recordName ?? labelSingle : mode === "edit" ? recordName ? resolveResourceTitle(caps, t, resource, "editTitleNamed", {
1916
1632
  label: labelSingle,
1917
1633
  name: recordName
1918
- } }) : t("pageHeader.editTitle", { params: { label: labelSingle } }) : t("pageHeader.createTitle", { params: { label: labelSingle } }));
1634
+ }) : resolveResourceTitle(caps, t, resource, "editTitle", { label: labelSingle }) : resolveResourceTitle(caps, t, resource, "createTitle", { label: labelSingle }));
1919
1635
  useDocumentTitle(app?.name ? `${computedTitle} · ${app.name}` : computedTitle);
1920
1636
  const showBack = backLink && mode !== "list" && !breadcrumbs;
1921
1637
  const computedBackHref = backHref ?? def?.basePath ?? `/${resource}`;
@@ -1946,9 +1662,10 @@ function PageHeader({ resource, mode, recordName, backHref, backLabel, actions,
1946
1662
  ]
1947
1663
  });
1948
1664
  }
1949
- function ShowPageHeader({ resource, record, extraActions, breadcrumbs }) {
1665
+ function ShowPageHeader({ resource: resourceInput, record, extraActions, breadcrumbs }) {
1666
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
1950
1667
  const def = (0, _burojs_react.useApp)().registry.get(resource);
1951
- const recordName = (0, _burojs_react.useProjectedTitle)(resource, record?.id, record);
1668
+ const recordName = (0, _burojs_react.useProjectedTitle)(resource, (0, _burojs_react.recordKeyOf)(def, record), record);
1952
1669
  (0, _burojs_react.usePublishDocVariant)(resource, record);
1953
1670
  if (!def) return null;
1954
1671
  return (0, react_jsx_runtime.jsx)(PageHeader, {
@@ -1963,16 +1680,18 @@ function ShowPageHeader({ resource, record, extraActions, breadcrumbs }) {
1963
1680
  }), extraActions] })
1964
1681
  });
1965
1682
  }
1966
- function EditPageHeader({ resource, record, backHref, breadcrumbs }) {
1967
- const app = (0, _burojs_react.useApp)();
1968
- const def = app.registry.get(resource);
1683
+ function EditPageHeader({ resource: resourceInput, record, backHref, breadcrumbs }) {
1684
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
1685
+ const def = (0, _burojs_react.useApp)().registry.get(resource);
1969
1686
  const caps = (0, _burojs_react.useI18nCaps)(resource);
1970
- const recordName = (0, _burojs_react.useProjectedTitle)(resource, record?.id, record);
1687
+ const recordKey = (0, _burojs_react.recordKeyOf)(def, record);
1688
+ const recordName = (0, _burojs_react.useProjectedTitle)(resource, recordKey, record);
1689
+ const back = (0, _burojs_react.useReturnTarget)(resource, "edit", String(recordKey ?? ""));
1971
1690
  return (0, react_jsx_runtime.jsx)(PageHeader, {
1972
1691
  resource,
1973
1692
  mode: "edit",
1974
1693
  recordName,
1975
- backHref: editBackHref(app.registry, resource, String(record.id), backHref),
1694
+ backHref: backHref ?? back,
1976
1695
  breadcrumbs,
1977
1696
  backLabel: recordName ? `${(0, _burojs_core.resolveResourceLabel)(caps, resource, "single", def)}: ${recordName}` : void 0,
1978
1697
  actions: (0, react_jsx_runtime.jsx)(ActionOverflow, {
@@ -2172,7 +1891,8 @@ function ItemNode({ node, row, fallback }) {
2172
1891
  const viewProps = {
2173
1892
  props,
2174
1893
  data: {},
2175
- t: placement.viewProps?.t ?? ((name) => name)
1894
+ t: placement.viewProps?.t ?? ((name) => name),
1895
+ ...placement.viewProps?.empty === void 0 ? {} : { empty: placement.viewProps.empty }
2176
1896
  };
2177
1897
  return (0, react_jsx_runtime.jsx)(View, { ...viewProps });
2178
1898
  }
@@ -2254,24 +1974,32 @@ function BuroPanelFrame({ body, title, description, collapsible, open, onToggle,
2254
1974
  const t = (0, _burojs_react.useOptionalT)();
2255
1975
  return (0, react_jsx_runtime.jsxs)("section", {
2256
1976
  ...nodeAttributes,
1977
+ ...title === void 0 ? {} : { "aria-labelledby": titleId },
2257
1978
  children: [
2258
1979
  title === void 0 && info === null && !collapsible ? null : (0, react_jsx_runtime.jsxs)("div", {
2259
1980
  "data-buro-region": "panel-title",
2260
1981
  className: "flex items-center gap-1",
2261
1982
  children: [
2262
- collapsible ? (0, react_jsx_runtime.jsx)("button", {
1983
+ collapsible && title !== void 0 ? (0, react_jsx_runtime.jsx)("h3", {
1984
+ id: titleId,
1985
+ className: "min-w-0 flex-1 text-sm font-semibold",
1986
+ children: (0, react_jsx_runtime.jsxs)("button", {
1987
+ type: "button",
1988
+ "aria-expanded": open,
1989
+ "aria-controls": bodyId,
1990
+ onClick: () => onToggle(!open),
1991
+ className: "-mx-1 flex w-full items-center gap-1 rounded px-1 text-left hover:bg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
1992
+ children: [(0, react_jsx_runtime.jsx)(Chevron, { open }), title]
1993
+ })
1994
+ }) : collapsible ? (0, react_jsx_runtime.jsx)("button", {
2263
1995
  type: "button",
2264
1996
  "aria-expanded": open,
2265
1997
  "aria-controls": bodyId,
2266
1998
  "aria-label": open ? t("screen.collapse", { defaultValue: "Collapse" }) : t("screen.expand", { defaultValue: "Expand" }),
2267
1999
  onClick: () => onToggle(!open),
2268
2000
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:bg-muted",
2269
- children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconChevronRight, {
2270
- className: open ? "h-4 w-4 rotate-90 transition-transform" : "h-4 w-4 transition-transform",
2271
- "aria-hidden": "true"
2272
- })
2273
- }) : null,
2274
- title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
2001
+ children: (0, react_jsx_runtime.jsx)(Chevron, { open })
2002
+ }) : title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
2275
2003
  id: titleId,
2276
2004
  className: "text-sm font-semibold",
2277
2005
  children: title
@@ -2289,6 +2017,12 @@ function BuroPanelFrame({ body, title, description, collapsible, open, onToggle,
2289
2017
  ]
2290
2018
  });
2291
2019
  }
2020
+ function Chevron({ open }) {
2021
+ return (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconChevronRight, {
2022
+ className: open ? "h-4 w-4 shrink-0 rotate-90 text-muted-foreground transition-transform" : "h-4 w-4 shrink-0 text-muted-foreground transition-transform",
2023
+ "aria-hidden": "true"
2024
+ });
2025
+ }
2292
2026
  function BuroTabsFrame({ tabs, active, onSelect, info, nodeAttributes }) {
2293
2027
  if (tabs.length === 1) return (0, react_jsx_runtime.jsx)("div", {
2294
2028
  ...nodeAttributes,
@@ -2313,7 +2047,6 @@ function BuroTabsFrame({ tabs, active, onSelect, info, nodeAttributes }) {
2313
2047
  }), info]
2314
2048
  }), tabs.map((tab) => (0, react_jsx_runtime.jsx)(TabsContent, {
2315
2049
  value: tab.key,
2316
- forceMount: true,
2317
2050
  "data-buro-region": "tab-panel",
2318
2051
  "data-buro-key": tab.key,
2319
2052
  children: tab.panel
@@ -2401,17 +2134,17 @@ function BuroStepsFrame({ wizard, steps, goTo, back, next, headingRef, info, nod
2401
2134
  //#region src/primitives/checkbox.tsx
2402
2135
  const Checkbox = react.forwardRef(({ className, checked, ...props }, ref) => (0, react_jsx_runtime.jsx)(_radix_ui_react_checkbox.Root, {
2403
2136
  ref,
2404
- className: require_use_theme.cn("peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground", className),
2137
+ className: require_use_theme.cn("peer inline-flex h-4 w-4 shrink-0 items-center justify-center align-middle rounded-[4px] border border-primary ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground", className),
2405
2138
  checked,
2406
2139
  ...props,
2407
2140
  children: (0, react_jsx_runtime.jsx)(_radix_ui_react_checkbox.Indicator, {
2408
2141
  className: require_use_theme.cn("flex items-center justify-center text-current"),
2409
2142
  children: checked === "indeterminate" ? (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconMinus, {
2410
2143
  "data-icon": "minus",
2411
- className: "h-4 w-4"
2144
+ className: "size-3.5"
2412
2145
  }) : (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCheck, {
2413
2146
  "data-icon": "check",
2414
- className: "h-4 w-4"
2147
+ className: "size-3.5"
2415
2148
  })
2416
2149
  })
2417
2150
  }));
@@ -2436,6 +2169,17 @@ function useContainerNarrow(maxRem = 40) {
2436
2169
  return [setElement, narrow];
2437
2170
  }
2438
2171
  //#endregion
2172
+ //#region src/data-table/fill-column.ts
2173
+ function fillColumnId(columns) {
2174
+ const eligible = columns.filter((c) => !c.pinned && !c.service);
2175
+ const declared = eligible.find((c) => c.fill);
2176
+ if (declared !== void 0) return declared.id;
2177
+ for (let i = eligible.length - 1; i >= 0; i--) {
2178
+ const c = eligible[i];
2179
+ if (c.resize && c.max === void 0) return c.id;
2180
+ }
2181
+ }
2182
+ //#endregion
2439
2183
  //#region src/data-table/data-table.tsx
2440
2184
  function pinEdgeClass(isLastLeft, isFirstRight) {
2441
2185
  if (isLastLeft) return "after:pointer-events-none after:absolute after:inset-y-0 after:left-full after:z-10 after:w-1.5 after:bg-gradient-to-r after:from-overlay/[0.07] after:to-transparent dark:after:from-overlay/30";
@@ -2447,7 +2191,8 @@ function pinEdgeClassFor(column, overflowing) {
2447
2191
  if (!pinned || !overflowing) return "";
2448
2192
  return pinEdgeClass(pinned === "left" && column.getIsLastColumn("left"), pinned === "right" && column.getIsFirstColumn("right"));
2449
2193
  }
2450
- function getPinStyles(column, overflowing) {
2194
+ function getPinStyles(column, overflowing, fill = false) {
2195
+ if (fill) return {};
2451
2196
  const explicitWidth = { width: `calc(var(--col-${column.id}-size) * 1px)` };
2452
2197
  const pinned = column.getIsPinned();
2453
2198
  if (!pinned || !overflowing) return explicitWidth;
@@ -2472,21 +2217,35 @@ function columnMetaNoRowNav(meta) {
2472
2217
  function columnMetaNoClip(meta) {
2473
2218
  return meta?.noClip === true;
2474
2219
  }
2475
- function annotateIfClipped(e) {
2476
- const el = e.currentTarget;
2477
- const text = el.scrollWidth > el.clientWidth || Array.from(el.querySelectorAll("*")).some((c) => c.scrollWidth > c.clientWidth) ? (el.textContent ?? "").trim() : "";
2478
- if (text) el.setAttribute("title", text);
2479
- else el.removeAttribute("title");
2220
+ function columnMetaWrap(meta) {
2221
+ return meta?.wrap === true;
2222
+ }
2223
+ function columnMetaFill(meta) {
2224
+ return meta?.fill === true;
2480
2225
  }
2481
- function renderCellMarkup({ cell, resizable, overflowing, testId, onCellClick, noRowNav }) {
2226
+ function tableFillColumnId(table) {
2227
+ if (table.options.enableColumnResizing !== true) return void 0;
2228
+ return fillColumnId(table.getVisibleLeafColumns().map((c) => {
2229
+ const max = c.columnDef.maxSize;
2230
+ return {
2231
+ id: c.id,
2232
+ fill: columnMetaFill(c.columnDef.meta),
2233
+ resize: c.getCanResize(),
2234
+ ...max !== void 0 && max < Number.MAX_SAFE_INTEGER ? { max } : {},
2235
+ pinned: c.getIsPinned() !== false,
2236
+ service: c.id.startsWith("__")
2237
+ };
2238
+ }));
2239
+ }
2240
+ function renderCellMarkup({ cell, resizable, overflowing, fill, testId, onCellClick, noRowNav }) {
2482
2241
  const liveColumn = cell.getContext().table.getColumn(cell.column.id) ?? cell.column;
2483
2242
  const pinEdge = pinEdgeClassFor(liveColumn, overflowing);
2484
- const noClip = columnMetaNoClip(cell.column.columnDef.meta);
2243
+ const noClip = columnMetaNoClip(cell.column.columnDef.meta) || columnMetaWrap(cell.column.columnDef.meta);
2485
2244
  return (0, react_jsx_runtime.jsx)(require_filter_builder.TableCell, {
2486
2245
  "data-testid": testId,
2487
2246
  "data-no-row-nav": columnMetaNoRowNav(cell.column.columnDef.meta) || noRowNav ? "" : void 0,
2488
2247
  onClick: onCellClick,
2489
- style: getPinStyles(liveColumn, overflowing),
2248
+ style: getPinStyles(liveColumn, overflowing, fill),
2490
2249
  className: require_use_theme.cn(resizable && !pinEdge && !noClip && "overflow-hidden", pinEdge && "relative", pinEdge, columnMetaClassName(cell.column.columnDef.meta), onCellClick && "cursor-pointer"),
2491
2250
  children: resizable && !noClip ? (0, react_jsx_runtime.jsx)("div", {
2492
2251
  className: "truncate",
@@ -2498,7 +2257,7 @@ function renderCellMarkup({ cell, resizable, overflowing, testId, onCellClick, n
2498
2257
  function MemoCellInner(props) {
2499
2258
  return renderCellMarkup(props);
2500
2259
  }
2501
- const MemoCell = (0, react.memo)(MemoCellInner, (prev, next) => prev.rowOriginal === next.rowOriginal && prev.cell.column.id === next.cell.column.id && prev.resizable === next.resizable && (!prev.pinned && !next.pinned || prev.overflowing === next.overflowing) && prev.pinned === next.pinned && prev.testId === next.testId);
2260
+ const MemoCell = (0, react.memo)(MemoCellInner, (prev, next) => prev.rowOriginal === next.rowOriginal && prev.cell.column.id === next.cell.column.id && prev.resizable === next.resizable && (!prev.pinned && !next.pinned || prev.overflowing === next.overflowing) && prev.pinned === next.pinned && prev.fill === next.fill && prev.testId === next.testId);
2502
2261
  function SelectionCellInner(props) {
2503
2262
  const row = props.cell.row;
2504
2263
  const toggle = (e) => {
@@ -2512,7 +2271,7 @@ function SelectionCellInner(props) {
2512
2271
  });
2513
2272
  }
2514
2273
  const SelectionCell = (0, react.memo)(SelectionCellInner);
2515
- function DataRowInner({ row, isSelected, resizable, overflowing, selectionColumnId, getCellTestId, getRowTestId, rowHref, onRowOpen, activateRow, rowClassName }) {
2274
+ function DataRowInner({ row, isSelected, resizable, overflowing, fillColumnId, selectionColumnId, getCellTestId, getRowTestId, rowHref, onRowOpen, activateRow, rowClassName }) {
2516
2275
  const clickable = rowHref !== void 0 || onRowOpen !== void 0;
2517
2276
  return (0, react_jsx_runtime.jsx)(require_filter_builder.TableRow, {
2518
2277
  "data-state": isSelected ? "selected" : void 0,
@@ -2525,6 +2284,7 @@ function DataRowInner({ row, isSelected, resizable, overflowing, selectionColumn
2525
2284
  isSelected,
2526
2285
  resizable,
2527
2286
  overflowing,
2287
+ fill: cell.column.id === fillColumnId,
2528
2288
  pinned: cell.getContext().table.getColumn(cell.column.id)?.getIsPinned() ?? false,
2529
2289
  testId: getCellTestId?.(row.original, cell.column.id)
2530
2290
  }, cell.id) : (0, react_jsx_runtime.jsx)(MemoCell, {
@@ -2532,13 +2292,14 @@ function DataRowInner({ row, isSelected, resizable, overflowing, selectionColumn
2532
2292
  rowOriginal: row.original,
2533
2293
  resizable,
2534
2294
  overflowing,
2295
+ fill: cell.column.id === fillColumnId,
2535
2296
  pinned: cell.getContext().table.getColumn(cell.column.id)?.getIsPinned() ?? false,
2536
2297
  testId: getCellTestId?.(row.original, cell.column.id)
2537
2298
  }, cell.id))
2538
2299
  });
2539
2300
  }
2540
- const MemoRow = (0, react.memo)(DataRowInner, (prev, next) => prev.row.original === next.row.original && prev.row.id === next.row.id && prev.isSelected === next.isSelected && prev.resizable === next.resizable && prev.overflowing === next.overflowing && prev.columnLayoutKey === next.columnLayoutKey && prev.selectionColumnId === next.selectionColumnId && prev.getCellTestId === next.getCellTestId && prev.getRowTestId === next.getRowTestId && prev.rowHref === next.rowHref && prev.onRowOpen === next.onRowOpen && prev.activateRow === next.activateRow && prev.rowClassName === next.rowClassName);
2541
- function DataTableBodyInner({ rows, isLoading, loadingRowCount, visibleColumnCount, emptyState, emptyText, resizable, overflowing, columnLayoutKey, selectionColumnId, getCellTestId, getRowTestId, rowHref, onRowOpen, activateRow, rowClassName }) {
2301
+ const MemoRow = (0, react.memo)(DataRowInner, (prev, next) => prev.row.original === next.row.original && prev.row.id === next.row.id && prev.isSelected === next.isSelected && prev.resizable === next.resizable && prev.overflowing === next.overflowing && prev.columnLayoutKey === next.columnLayoutKey && prev.fillColumnId === next.fillColumnId && prev.selectionColumnId === next.selectionColumnId && prev.getCellTestId === next.getCellTestId && prev.getRowTestId === next.getRowTestId && prev.rowHref === next.rowHref && prev.onRowOpen === next.onRowOpen && prev.activateRow === next.activateRow && prev.rowClassName === next.rowClassName);
2302
+ function DataTableBodyInner({ rows, isLoading, loadingRowCount, visibleColumnCount, emptyState, emptyText, resizable, overflowing, columnLayoutKey, fillColumnId, selectionColumnId, getCellTestId, getRowTestId, rowHref, onRowOpen, activateRow, rowClassName }) {
2542
2303
  return (0, react_jsx_runtime.jsx)(require_filter_builder.TableBody, { children: isLoading ? Array.from({ length: loadingRowCount }).map((_, i) => (0, react_jsx_runtime.jsx)(require_filter_builder.TableRow, {
2543
2304
  "aria-busy": "true",
2544
2305
  children: Array.from({ length: Math.max(1, visibleColumnCount) }).map((__, j) => (0, react_jsx_runtime.jsx)(require_filter_builder.TableCell, { children: (0, react_jsx_runtime.jsx)("div", { className: "h-4 w-3/4 animate-pulse rounded bg-muted" }) }, `skeleton-${i}-${j}`))
@@ -2555,6 +2316,7 @@ function DataTableBodyInner({ rows, isLoading, loadingRowCount, visibleColumnCou
2555
2316
  resizable,
2556
2317
  overflowing,
2557
2318
  columnLayoutKey,
2319
+ fillColumnId,
2558
2320
  selectionColumnId,
2559
2321
  getCellTestId,
2560
2322
  getRowTestId,
@@ -2566,7 +2328,7 @@ function DataTableBodyInner({ rows, isLoading, loadingRowCount, visibleColumnCou
2566
2328
  }
2567
2329
  const DataTableBody = (0, react.memo)(DataTableBodyInner, (prev, next) => {
2568
2330
  if (!next.isResizing) return false;
2569
- return prev.rows === next.rows && prev.overflowing === next.overflowing && prev.isLoading === next.isLoading && prev.columnLayoutKey === next.columnLayoutKey && prev.selectionColumnId === next.selectionColumnId;
2331
+ return prev.rows === next.rows && prev.overflowing === next.overflowing && prev.isLoading === next.isLoading && prev.columnLayoutKey === next.columnLayoutKey && prev.fillColumnId === next.fillColumnId && prev.selectionColumnId === next.selectionColumnId;
2570
2332
  });
2571
2333
  function DataTable({ table, tableTestId, getRowTestId, getCellTestId, isLoading = false, loadingRowCount = 5, emptyState, errorState, rowClassName, ariaLabel, onColumnReorder, rowHref, onRowOpen, selectionColumnId, className }) {
2572
2334
  const t = (0, _burojs_react.useOptionalT)();
@@ -2596,8 +2358,10 @@ function DataTable({ table, tableTestId, getRowTestId, getCellTestId, isLoading
2596
2358
  const rows = table.getRowModel().rows;
2597
2359
  const headerGroups = table.getHeaderGroups();
2598
2360
  const visibleColumnCount = table.getVisibleLeafColumns().length;
2361
+ const fillId = tableFillColumnId(table);
2599
2362
  const columnLayoutKey = table.getVisibleLeafColumns().map((c) => `${c.id}:${c.getIsPinned() || ""}`).join("|");
2600
2363
  const resizable = table.options.enableColumnResizing === true;
2364
+ const widthSum = resizable ? table.getVisibleLeafColumns().reduce((sum, c) => sum + c.getSize(), 0) : 0;
2601
2365
  const hasPinned = table.getState().columnPinning != null && (table.getState().columnPinning.left?.length || table.getState().columnPinning.right?.length);
2602
2366
  const sizingState = table.getState().columnSizing;
2603
2367
  const sizingInfo = table.getState().columnSizingInfo;
@@ -2689,7 +2453,7 @@ function DataTable({ table, tableTestId, getRowTestId, getCellTestId, isLoading
2689
2453
  className,
2690
2454
  style: resizable ? {
2691
2455
  ...columnSizeVars,
2692
- minWidth: "100%",
2456
+ width: fillId !== void 0 ? `max(100%, ${widthSum}px)` : `${widthSum}px`,
2693
2457
  tableLayout: "fixed"
2694
2458
  } : void 0,
2695
2459
  children: [(0, react_jsx_runtime.jsx)(require_filter_builder.TableHeader, { children: headerGroups.map((hg) => (0, react_jsx_runtime.jsx)(require_filter_builder.TableRow, { children: hg.headers.map((header) => {
@@ -2700,7 +2464,7 @@ function DataTable({ table, tableTestId, getRowTestId, getCellTestId, isLoading
2700
2464
  return (0, react_jsx_runtime.jsxs)(require_filter_builder.TableHead, {
2701
2465
  colSpan: header.colSpan,
2702
2466
  "aria-sort": ariaSort,
2703
- style: getPinStyles(header.column, overflowing),
2467
+ style: getPinStyles(header.column, overflowing, header.column.id === fillId),
2704
2468
  className: require_use_theme.cn("relative", resizable && !columnMetaNoClip(header.column.columnDef.meta) && (pinEdgeClassFor(header.column, overflowing) ? "[&>*:not([data-testid^=col-resize])]:truncate" : "overflow-hidden [&>*:not([data-testid^=col-resize])]:truncate"), canReorder && "cursor-grab", pinEdgeClassFor(header.column, overflowing), columnMetaClassName(header.column.columnDef.meta)),
2705
2469
  draggable: canReorder || void 0,
2706
2470
  onDragStart: canReorder ? (e) => {
@@ -2759,6 +2523,7 @@ function DataTable({ table, tableTestId, getRowTestId, getCellTestId, isLoading
2759
2523
  resizable,
2760
2524
  overflowing,
2761
2525
  columnLayoutKey,
2526
+ fillColumnId: fillId,
2762
2527
  selectionColumnId,
2763
2528
  isResizing: Boolean(sizingInfo.isResizingColumn),
2764
2529
  getCellTestId,
@@ -2875,7 +2640,8 @@ function ColumnHeaderMenu({ label, sortDirection, sortable, onSort, pinned, onPi
2875
2640
  }
2876
2641
  //#endregion
2877
2642
  //#region src/resource/column-accessor.ts
2878
- function columnAccessor(column) {
2643
+ function columnAccessor(column, objectPath = false) {
2644
+ if (objectPath) return { accessorFn: (row) => (0, _burojs_react.readColumnValue)(row, column, true) };
2879
2645
  return column.includes(".") ? { accessorFn: (row) => row[column] } : { accessorKey: column };
2880
2646
  }
2881
2647
  //#endregion
@@ -2982,104 +2748,292 @@ function resolveUpdater(updater, prev) {
2982
2748
  }
2983
2749
  //#endregion
2984
2750
  //#region src/resource/list-error-state.tsx
2985
- function ListErrorState({ error, onRetry, resource, title, className }) {
2986
- const t = (0, _burojs_react.useT)();
2987
- const raw = error.message ?? "";
2988
- const friendly = require_toaster.toFriendlyError(raw, "", require_toaster.friendlyStringsFrom(t));
2989
- const friendlyError = friendly.replaced ? friendly.detail : raw;
2990
- return (0, react_jsx_runtime.jsxs)("div", {
2991
- role: "alert",
2992
- className: require_use_theme.cn("flex flex-col items-center justify-center gap-3 px-6 py-16 rounded-lg border border-destructive/40 bg-destructive/5 text-center", className),
2993
- "data-testid": "error",
2994
- children: [
2995
- (0, react_jsx_runtime.jsx)("div", {
2996
- className: "rounded-full bg-destructive/10 p-3 text-destructive",
2997
- children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconAlertCircle, {
2998
- className: "size-6",
2999
- "aria-hidden": "true"
3000
- })
3001
- }),
3002
- (0, react_jsx_runtime.jsxs)("div", {
3003
- className: "space-y-1",
3004
- children: [(0, react_jsx_runtime.jsx)("h3", {
3005
- className: "text-base font-semibold tracking-tight text-destructive",
3006
- children: title ?? t("list.errorTitle")
3007
- }), (0, react_jsx_runtime.jsx)("p", {
3008
- className: "max-w-md text-sm text-muted-foreground",
3009
- children: friendlyError || t("list.errorBody")
3010
- })]
3011
- }),
3012
- raw && raw !== friendlyError ? (0, react_jsx_runtime.jsxs)("details", {
3013
- className: "max-w-md text-left",
3014
- children: [(0, react_jsx_runtime.jsx)("summary", {
3015
- className: "cursor-pointer text-xs text-muted-foreground hover:text-foreground",
3016
- children: t("list.errorDetails")
3017
- }), (0, react_jsx_runtime.jsx)("p", {
3018
- className: "mt-1.5 break-all font-mono text-xs text-muted-foreground",
3019
- "data-testid": "list-error-detail",
3020
- children: raw
3021
- })]
3022
- }) : null,
3023
- onRetry && (0, react_jsx_runtime.jsx)("div", {
3024
- className: "flex justify-center pt-2",
3025
- children: (0, react_jsx_runtime.jsxs)(require_button.Button, {
3026
- type: "button",
3027
- variant: "outline",
3028
- size: "sm",
3029
- "data-testid": resource ? `list-error-retry:${resource}` : "list-error-retry",
3030
- onClick: onRetry,
3031
- className: "gap-1.5",
3032
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconRefresh, {
3033
- className: "size-3.5",
3034
- "aria-hidden": "true"
3035
- }), t("actions.retry")]
3036
- })
3037
- })
3038
- ]
2751
+ function ListErrorState(props) {
2752
+ const { error, onRetry, resource, title, className } = props;
2753
+ return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
2754
+ surface: "list",
2755
+ error,
2756
+ ...onRetry === void 0 ? {} : { retry: onRetry },
2757
+ ...resource === void 0 ? {} : { resource },
2758
+ ...title === void 0 ? {} : { title },
2759
+ ...className === void 0 ? {} : { className }
3039
2760
  });
3040
2761
  }
3041
2762
  //#endregion
3042
- //#region src/list-kit/cursor-load-more.tsx
3043
- function CursorLoadMore({ hasMore, loading, onMore }) {
3044
- const t = (0, _burojs_react.useT)();
3045
- if (!hasMore) return null;
3046
- return (0, react_jsx_runtime.jsx)("div", {
3047
- className: "flex justify-center py-4",
3048
- children: (0, react_jsx_runtime.jsx)(require_button.Button, {
3049
- type: "button",
3050
- variant: "outline",
3051
- size: "sm",
3052
- disabled: loading,
3053
- onClick: onMore,
3054
- "data-testid": "cursor-load-more",
3055
- children: loading ? t("pagination.loadingMore") : t("pagination.loadMore")
3056
- })
3057
- });
2763
+ //#region src/resource/use-table-layout.ts
2764
+ const WRITE_DEBOUNCE_MS = 200;
2765
+ function mutate(run, ok, then) {
2766
+ try {
2767
+ run().then((result) => {
2768
+ if (ok(result.status)) then();
2769
+ }, () => void 0);
2770
+ } catch {}
3058
2771
  }
3059
- //#endregion
3060
- //#region src/resource/resource-list.tsx
3061
- function CountRowsTrigger({ label, loading, onClick, testid, variant, className }) {
3062
- return (0, react_jsx_runtime.jsxs)(require_button.Button, {
3063
- type: "button",
3064
- variant,
3065
- size: "sm",
3066
- "data-testid": testid,
3067
- onClick,
3068
- disabled: loading,
3069
- "aria-label": label,
3070
- "aria-busy": loading || void 0,
3071
- className: require_use_theme.cn("relative", className),
3072
- children: [(0, react_jsx_runtime.jsx)("span", {
3073
- className: loading ? "invisible" : void 0,
3074
- children: label
3075
- }), loading && (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLoader2, {
3076
- className: "absolute inset-0 m-auto size-3.5 animate-spin",
3077
- "aria-hidden": "true"
2772
+ function resolve(updater, current) {
2773
+ return typeof updater === "function" ? updater(current) : updater;
2774
+ }
2775
+ function sameNames(a, b) {
2776
+ return a.length === b.length && a.every((name, index) => name === b[index]);
2777
+ }
2778
+ function readSizes(sizes, rule) {
2779
+ const out = {};
2780
+ for (const [column, size] of Object.entries(sizes)) {
2781
+ const of = rule(column);
2782
+ if (of === void 0 || !of.resize) continue;
2783
+ out[column] = Math.min(Math.max(size, of.min), of.max ?? Number.POSITIVE_INFINITY);
2784
+ }
2785
+ return out;
2786
+ }
2787
+ function useTableLayout({ resource, layoutId, rule, defaultPinning, resetLayout }) {
2788
+ const params = (0, react.useMemo)(() => layoutId === void 0 ? null : {
2789
+ resource,
2790
+ list: layoutId
2791
+ }, [resource, layoutId]);
2792
+ const settings = (0, _burojs_react.useOptionalUiSettings)(_burojs_react.tableLayoutSetting, params);
2793
+ const settingsRef = (0, react.useRef)(settings);
2794
+ settingsRef.current = settings;
2795
+ const key = layoutId === void 0 ? void 0 : `${resource}\u0000${layoutId}`;
2796
+ const fallback = (0, react.useMemo)(() => ({
2797
+ sizes: {},
2798
+ order: [],
2799
+ pinning: defaultPinning
2800
+ }), [defaultPinning]);
2801
+ const [local, setLocal] = (0, react.useState)();
2802
+ const stored = settings?.snapshot.entries[0]?.value;
2803
+ const settled = settings === void 0 || !settings.snapshot.pending;
2804
+ const held = (0, react.useRef)(null);
2805
+ const layout = (local !== void 0 && local.key === key ? local.value : void 0) ?? stored ?? fallback;
2806
+ const latest = (0, react.useRef)(layout);
2807
+ latest.current = layout;
2808
+ const sizing = (0, react.useMemo)(() => readSizes(layout.sizes, rule), [layout.sizes, rule]);
2809
+ const sizingRef = (0, react.useRef)(sizing);
2810
+ sizingRef.current = sizing;
2811
+ const generation = (0, react.useRef)(0);
2812
+ const timer = (0, react.useRef)(null);
2813
+ const pending = (0, react.useRef)(null);
2814
+ const confirm = (0, react.useCallback)((sent) => {
2815
+ if (generation.current === sent && pending.current === null) setLocal(void 0);
2816
+ }, []);
2817
+ const write = (0, react.useCallback)((target, value) => {
2818
+ const scopeId = target.snapshot.entries[0]?.scope.id ?? target.snapshot.writeScopes[0]?.id;
2819
+ if (scopeId === void 0) return;
2820
+ const sent = generation.current;
2821
+ mutate(() => target.set({
2822
+ scopeId,
2823
+ value
2824
+ }), (status) => status === "created" || status === "updated", () => confirm(sent));
2825
+ }, [confirm]);
2826
+ const store = (0, react.useCallback)((target, next) => {
2827
+ if (!(Object.keys(next.sizes).length === 0 && next.order.length === 0 && sameNames(next.pinning.left, defaultPinning.left) && sameNames(next.pinning.right, defaultPinning.right))) {
2828
+ write(target, next);
2829
+ return;
2830
+ }
2831
+ const entry = target.snapshot.entries[0];
2832
+ if (entry === void 0) {
2833
+ setLocal(void 0);
2834
+ return;
2835
+ }
2836
+ const sent = generation.current;
2837
+ mutate(() => target.remove({ id: entry.id }), (status) => status === "removed", () => confirm(sent));
2838
+ }, [
2839
+ defaultPinning,
2840
+ write,
2841
+ confirm
2842
+ ]);
2843
+ const flush = (0, react.useCallback)(() => {
2844
+ if (timer.current !== null) clearTimeout(timer.current);
2845
+ timer.current = null;
2846
+ const due = pending.current;
2847
+ pending.current = null;
2848
+ if (due !== null) write(due.target, due.value);
2849
+ }, [write]);
2850
+ const change = (0, react.useCallback)((next, debounced, touch) => {
2851
+ latest.current = next;
2852
+ generation.current += 1;
2853
+ setLocal({
2854
+ key,
2855
+ value: next
2856
+ });
2857
+ const target = settingsRef.current;
2858
+ if (target === void 0) return;
2859
+ if (target.snapshot.pending || held.current !== null && held.current.key === key) {
2860
+ const edits = held.current !== null && held.current.key === key ? held.current : {
2861
+ key,
2862
+ resetAll: false,
2863
+ resetSizes: false,
2864
+ sizes: new Map()
2865
+ };
2866
+ held.current = edits;
2867
+ touch(edits);
2868
+ return;
2869
+ }
2870
+ pending.current = {
2871
+ target,
2872
+ value: next
2873
+ };
2874
+ if (!debounced) {
2875
+ flush();
2876
+ return;
2877
+ }
2878
+ if (timer.current !== null) clearTimeout(timer.current);
2879
+ timer.current = setTimeout(flush, WRITE_DEBOUNCE_MS);
2880
+ }, [key, flush]);
2881
+ (0, react.useEffect)(() => flush, [key]);
2882
+ (0, react.useEffect)(() => {
2883
+ const edits = held.current;
2884
+ if (edits === null) return;
2885
+ if (edits.key !== key) {
2886
+ held.current = null;
2887
+ return;
2888
+ }
2889
+ const target = settingsRef.current;
2890
+ if (!settled || target === void 0) return;
2891
+ held.current = null;
2892
+ const base = edits.resetAll ? fallback : stored ?? fallback;
2893
+ const sizes = edits.resetAll || edits.resetSizes ? {} : { ...readSizes(base.sizes, rule) };
2894
+ for (const [column, size] of edits.sizes) if (size === void 0) delete sizes[column];
2895
+ else sizes[column] = size;
2896
+ const next = {
2897
+ sizes,
2898
+ order: edits.order ?? base.order,
2899
+ pinning: edits.pinning ?? base.pinning
2900
+ };
2901
+ latest.current = next;
2902
+ generation.current += 1;
2903
+ setLocal({
2904
+ key,
2905
+ value: next
2906
+ });
2907
+ store(target, next);
2908
+ }, [settled, key]);
2909
+ const resetToken = resetLayout?.token ?? 0;
2910
+ const seenToken = (0, react.useRef)(resetToken);
2911
+ (0, react.useEffect)(() => {
2912
+ if (resetToken === seenToken.current) return;
2913
+ seenToken.current = resetToken;
2914
+ const all = resetLayout?.mode === "all";
2915
+ const next = all ? fallback : {
2916
+ ...latest.current,
2917
+ sizes: {}
2918
+ };
2919
+ if (timer.current !== null) clearTimeout(timer.current);
2920
+ timer.current = null;
2921
+ pending.current = null;
2922
+ latest.current = next;
2923
+ generation.current += 1;
2924
+ setLocal({
2925
+ key,
2926
+ value: next
2927
+ });
2928
+ const target = settingsRef.current;
2929
+ if (target === void 0) return;
2930
+ if (target.snapshot.pending || held.current !== null && held.current.key === key) {
2931
+ const prior = held.current !== null && held.current.key === key ? held.current : void 0;
2932
+ held.current = all ? {
2933
+ key,
2934
+ resetAll: true,
2935
+ resetSizes: false,
2936
+ sizes: new Map()
2937
+ } : {
2938
+ key,
2939
+ resetAll: prior?.resetAll ?? false,
2940
+ resetSizes: true,
2941
+ sizes: new Map(),
2942
+ ...prior?.order === void 0 ? {} : { order: prior.order },
2943
+ ...prior?.pinning === void 0 ? {} : { pinning: prior.pinning }
2944
+ };
2945
+ return;
2946
+ }
2947
+ store(target, next);
2948
+ }, [resetToken]);
2949
+ const setColumnSizing = (0, react.useCallback)((updater) => {
2950
+ const before = sizingRef.current;
2951
+ const sizes = resolve(updater, before);
2952
+ sizingRef.current = sizes;
2953
+ change({
2954
+ ...latest.current,
2955
+ sizes
2956
+ }, true, (edits) => {
2957
+ for (const column of new Set([...Object.keys(before), ...Object.keys(sizes)])) if (before[column] !== sizes[column]) edits.sizes.set(column, sizes[column]);
2958
+ });
2959
+ }, [change]);
2960
+ const setColumnOrder = (0, react.useCallback)((updater) => {
2961
+ const order = resolve(updater, latest.current.order);
2962
+ change({
2963
+ ...latest.current,
2964
+ order
2965
+ }, false, (edits) => {
2966
+ edits.order = order;
2967
+ });
2968
+ }, [change]);
2969
+ const setColumnPinning = (0, react.useCallback)((updater) => {
2970
+ const resolved = resolve(updater, latest.current.pinning);
2971
+ const pinning = {
2972
+ left: resolved.left ?? [],
2973
+ right: resolved.right ?? []
2974
+ };
2975
+ change({
2976
+ ...latest.current,
2977
+ pinning
2978
+ }, false, (edits) => {
2979
+ edits.pinning = pinning;
2980
+ });
2981
+ }, [change]);
2982
+ return {
2983
+ columnSizing: sizing,
2984
+ setColumnSizing,
2985
+ columnOrder: layout.order,
2986
+ setColumnOrder,
2987
+ columnPinning: layout.pinning,
2988
+ setColumnPinning
2989
+ };
2990
+ }
2991
+ //#endregion
2992
+ //#region src/list-kit/cursor-load-more.tsx
2993
+ function CursorLoadMore({ hasMore, loading, onMore }) {
2994
+ const t = (0, _burojs_react.useT)();
2995
+ if (!hasMore) return null;
2996
+ return (0, react_jsx_runtime.jsx)("div", {
2997
+ className: "flex justify-center py-4",
2998
+ children: (0, react_jsx_runtime.jsx)(require_button.Button, {
2999
+ type: "button",
3000
+ variant: "outline",
3001
+ size: "sm",
3002
+ disabled: loading,
3003
+ onClick: onMore,
3004
+ "data-testid": "cursor-load-more",
3005
+ children: loading ? t("pagination.loadingMore") : t("pagination.loadMore")
3006
+ })
3007
+ });
3008
+ }
3009
+ //#endregion
3010
+ //#region src/resource/resource-list.tsx
3011
+ function CountRowsTrigger({ label, loading, onClick, testid, variant, className }) {
3012
+ return (0, react_jsx_runtime.jsxs)(require_button.Button, {
3013
+ type: "button",
3014
+ variant,
3015
+ size: "sm",
3016
+ "data-testid": testid,
3017
+ onClick,
3018
+ disabled: loading,
3019
+ "aria-label": label,
3020
+ "aria-busy": loading || void 0,
3021
+ className: require_use_theme.cn("relative", className),
3022
+ children: [(0, react_jsx_runtime.jsx)("span", {
3023
+ className: loading ? "invisible" : void 0,
3024
+ children: label
3025
+ }), loading && (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLoader2, {
3026
+ className: "absolute inset-0 m-auto size-3.5 animate-spin",
3027
+ "aria-hidden": "true"
3078
3028
  })]
3079
3029
  });
3080
3030
  }
3081
3031
  const SELECT_COL_ID = "__select__";
3082
3032
  const ACTIONS_COL_ID = "__actions__";
3033
+ const DEFAULT_PINNING = Object.freeze({
3034
+ left: Object.freeze([SELECT_COL_ID, "id"]),
3035
+ right: Object.freeze([ACTIONS_COL_ID])
3036
+ });
3083
3037
  const ROW_ACTION_CONTROL_PX = 28;
3084
3038
  const ROW_ACTION_GAP_PX = 4;
3085
3039
  const ACTIONS_CELL_PADDING_PX = 16;
@@ -3091,29 +3045,30 @@ function actionsColumnSize(items) {
3091
3045
  const strip = controls * ROW_ACTION_CONTROL_PX + (controls - 1) * ROW_ACTION_GAP_PX + ACTIONS_CELL_PADDING_PX;
3092
3046
  return Math.max(ACTIONS_COL_MIN_PX, strip);
3093
3047
  }
3094
- const COLUMN_SIZE_BY_TYPE = {
3095
- boolean: 96,
3096
- number: 112
3048
+ const ALIGN_CLASS = {
3049
+ start: "text-start",
3050
+ center: "text-center",
3051
+ end: "text-end"
3097
3052
  };
3098
- const COLUMN_SIZE_BY_FORMAT = {
3099
- date: 132,
3100
- "date-time": 132
3101
- };
3102
- function columnSize(field) {
3103
- if (field?.format !== void 0 && COLUMN_SIZE_BY_FORMAT[field.format] !== void 0) return COLUMN_SIZE_BY_FORMAT[field.format];
3104
- if (field?.type !== void 0 && COLUMN_SIZE_BY_TYPE[field.type] !== void 0) return COLUMN_SIZE_BY_TYPE[field.type];
3105
- if (field?.kind === "date" || field?.kind === "dateTime") return COLUMN_SIZE_BY_FORMAT[field.kind === "dateTime" ? "date-time" : "date"];
3106
- return field?.kind === void 0 ? void 0 : COLUMN_SIZE_BY_TYPE[field.kind];
3107
- }
3108
- function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSize, onRequestCount, isCountingRows = false, pageSizeOptions = [
3053
+ const STANDALONE_COLUMN_UI = Object.freeze({
3054
+ default: 160,
3055
+ min: 90,
3056
+ align: "start",
3057
+ resize: true,
3058
+ fill: false,
3059
+ display: Object.freeze({ params: Object.freeze({}) })
3060
+ });
3061
+ function ResourceList({ resource: resourceInput, data, total, page = 1, pageSize = 10, onPageSize, onRequestCount, isCountingRows = false, pageSizeOptions = [
3109
3062
  10,
3110
3063
  25,
3111
3064
  50,
3112
3065
  100
3113
- ], onPage, loadMore, selectable = false, rowActions = true, selectedIds, onSelectionChange, className, isLoading = false, error = null, onRetry, createHref, isFiltered = false, onClearFilter, emptyState, rowsView, rowHref, rowQuick, rowLinkKey, renderCell, sort, onSort, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, tableRef }) {
3066
+ ], onPage, loadMore, selectable = false, rowActions = true, selectedIds, onSelectionChange, className, isLoading = false, error = null, onRetry, createHref, isFiltered = false, onClearFilter, emptyState, rowsView, rowHref, rowQuick, rowLinkKey, renderCell, sort, onSort, sortable, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, columnUi, layoutId, tableRef }) {
3067
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
3114
3068
  const app = (0, _burojs_react.useApp)();
3115
3069
  const tid = (0, _burojs_react.useTestIds)();
3116
3070
  const t = (0, _burojs_react.useOptionalT)();
3071
+ const chromeT = (0, _burojs_react.useChromeT)();
3117
3072
  const locale = (0, _burojs_react.useLocale)();
3118
3073
  const nf = (0, react.useMemo)(() => new Intl.NumberFormat(locale), [locale]);
3119
3074
  const i18nCaps = (0, _burojs_react.useI18nCaps)(resource);
@@ -3135,23 +3090,6 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3135
3090
  (0, react.useEffect)(() => {
3136
3091
  emittedRef.current = null;
3137
3092
  }, [controlledSelection]);
3138
- const layoutKey = `buro:table-layout:${resource}`;
3139
- const [columnSizing, setColumnSizing] = usePersistedState(`${layoutKey}:sizing`, {}, 200);
3140
- const [columnOrder, setColumnOrder] = usePersistedState(`${layoutKey}:order`, []);
3141
- const DEFAULT_PINNING = {
3142
- left: [SELECT_COL_ID, "id"],
3143
- right: [ACTIONS_COL_ID]
3144
- };
3145
- const [columnPinning, setColumnPinning] = usePersistedState(`${layoutKey}:pinning`, DEFAULT_PINNING);
3146
- const resetToken = resetLayout?.token ?? 0;
3147
- (0, react.useEffect)(() => {
3148
- if (!resetToken) return;
3149
- setColumnSizing({});
3150
- if (resetLayout?.mode === "all") {
3151
- setColumnOrder([]);
3152
- setColumnPinning(DEFAULT_PINNING);
3153
- }
3154
- }, [resetToken]);
3155
3093
  (0, react.useEffect)(() => {
3156
3094
  if (controlled) return;
3157
3095
  setOwnSelection({});
@@ -3161,7 +3099,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3161
3099
  const accessPending = listAccess.status === "pending" || pathAccess.pending;
3162
3100
  const declaredColumnKeys = (0, react.useMemo)(() => {
3163
3101
  if (!def) return [];
3164
- return [...columnsOverride ?? def.views?.list?.columns ?? Object.keys(def.fields)];
3102
+ return [...columnsOverride ?? def.views?.list?.columns?.map(_burojs_core.columnName) ?? Object.keys(def.fields)];
3165
3103
  }, [def, columnsOverride]);
3166
3104
  const visibleColumnKeys = (0, react.useMemo)(() => accessPending ? [] : declaredColumnKeys.filter((col) => listAccess.columnVisible(col) && (columnTarget(app.registry, resource, col) === void 0 || listAccess.columnVisible(col.split(".")[0]) && pathAccess.visible(col))), [
3167
3105
  accessPending,
@@ -3211,10 +3149,11 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3211
3149
  const resourceLabel = (0, _burojs_core.resolveResourceLabel)(i18nCaps, resource, "plural", def);
3212
3150
  const recordSingular = (0, _burojs_core.resolveResourceLabel)(i18nCaps, resource, "single", def);
3213
3151
  const ariaLabel = resourceLabel;
3214
- const actionsHeader = t("actions.column", { defaultValue: "Actions" });
3152
+ const actionsHeader = chromeT("actions.column", { defaultValue: "Actions" });
3215
3153
  const viewRow = (0, _burojs_react.useViewRow)(resource);
3216
3154
  const volatileRef = (0, react.useRef)({
3217
3155
  onSort,
3156
+ sortable,
3218
3157
  onHideColumn,
3219
3158
  requiredColumns,
3220
3159
  renderCell,
@@ -3226,6 +3165,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3226
3165
  });
3227
3166
  volatileRef.current = {
3228
3167
  onSort,
3168
+ sortable,
3229
3169
  onHideColumn,
3230
3170
  requiredColumns,
3231
3171
  renderCell,
@@ -3249,6 +3189,45 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3249
3189
  }, [rowLinkKey]);
3250
3190
  const stableRowClassName = (0, react.useCallback)((row) => volatileRef.current.rowHref?.(volatileRef.current.viewRow(row.original)) || (volatileRef.current.rowQuick?.(row.original) ?? null) !== null ? "cursor-pointer" : void 0, [rowLinkKey]);
3251
3191
  const [listRoot, narrow] = useContainerNarrow();
3192
+ const columnUiOf = (0, react.useMemo)(() => {
3193
+ const entries = new Map();
3194
+ for (const entry of [...def?.views?.list?.columns ?? [], ...def?.views?.list?.optionalColumns ?? []]) {
3195
+ const name = (0, _burojs_core.columnName)(entry);
3196
+ if (!entries.has(name)) entries.set(name, entry);
3197
+ }
3198
+ return (col) => columnUi?.[col] ?? (def === void 0 ? STANDALONE_COLUMN_UI : (0, _burojs_core.resolveColumnUi)(def, entries.get(col) ?? col, app.registry, _burojs_react.columnTypeWidth));
3199
+ }, [
3200
+ app,
3201
+ def,
3202
+ columnUi
3203
+ ]);
3204
+ const { columnSizing, setColumnSizing, columnOrder, setColumnOrder, columnPinning, setColumnPinning } = useTableLayout({
3205
+ resource,
3206
+ layoutId,
3207
+ rule: (0, react.useMemo)(() => {
3208
+ const known = new Set([
3209
+ ...declaredColumnKeys,
3210
+ ...(def?.views?.list?.columns ?? []).map(_burojs_core.columnName),
3211
+ ...(def?.views?.list?.optionalColumns ?? []).map(_burojs_core.columnName),
3212
+ ...Object.keys(def?.fields ?? {})
3213
+ ]);
3214
+ return (col) => {
3215
+ if (!known.has(col)) return void 0;
3216
+ const ui = columnUiOf(col);
3217
+ return {
3218
+ min: ui.min,
3219
+ max: ui.max,
3220
+ resize: ui.resize
3221
+ };
3222
+ };
3223
+ }, [
3224
+ declaredColumnKeys,
3225
+ def,
3226
+ columnUiOf
3227
+ ]),
3228
+ defaultPinning: DEFAULT_PINNING,
3229
+ resetLayout
3230
+ });
3252
3231
  const tableColumns = (0, react.useMemo)(() => {
3253
3232
  const cols = [];
3254
3233
  if (selectable) cols.push({
@@ -3271,19 +3250,36 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3271
3250
  });
3272
3251
  for (const col of visibleColumnKeys) {
3273
3252
  const target = columnTarget(app.registry, resource, col);
3274
- const field = target === void 0 ? def?.fields?.[col] : target.field;
3253
+ const objectPath = (0, _burojs_react.isObjectColumn)(app.registry, resource, col);
3254
+ const field = target !== void 0 ? target.field : objectPath ? (0, _burojs_react.resolveObjectColumn)(app.registry, resource, col)?.field : def === void 0 ? void 0 : (0, _burojs_core.declaredField)(def, col);
3275
3255
  const declaredLabel = (0, _burojs_core.declaredText)("field", field, "label");
3276
3256
  const headerLabel = target === void 0 ? (0, _burojs_core.resolveFieldLabel)(volatileRef.current.i18nCaps, col, declaredLabel) : (0, _burojs_core.resolveFieldLabel)(capsOf(volatileRef.current.i18nCaps, target.resource), target.name, declaredLabel);
3277
- const kindSize = columnSize(field);
3278
- const declared = target === void 0 && def !== void 0 ? (0, _burojs_core.declaredField)(def, col) : void 0;
3279
- const linkColumn = declared !== null && typeof declared === "object" && (0, _burojs_core.isLinkField)(declared);
3257
+ const ui = columnUiOf(col);
3258
+ const frameField = {
3259
+ ...field ?? { type: "unknown" },
3260
+ name: target === void 0 ? col : target.name
3261
+ };
3262
+ const cellEntry = { display: {
3263
+ ...ui.display,
3264
+ ...ui.display.dateDisplay
3265
+ } };
3266
+ const wraps = ui.display.overflow === "wrap";
3267
+ const columnSortable = volatileRef.current.sortable?.(col) ?? (def !== void 0 && (0, _burojs_core.isColumnSortable)(def, col, app, app.registry));
3280
3268
  cols.push({
3281
3269
  id: col,
3282
- ...columnAccessor(col),
3283
- ...kindSize !== void 0 ? { size: kindSize } : {},
3284
- enableSorting: !linkColumn && Boolean(volatileRef.current.onSort),
3270
+ ...columnAccessor(col, objectPath),
3271
+ size: ui.default,
3272
+ minSize: ui.min,
3273
+ maxSize: ui.max ?? Number.MAX_SAFE_INTEGER,
3274
+ enableResizing: ui.resize,
3275
+ enableSorting: columnSortable && Boolean(volatileRef.current.onSort),
3285
3276
  enableHiding: true,
3286
- meta: { testid: col },
3277
+ meta: {
3278
+ testid: col,
3279
+ className: ALIGN_CLASS[ui.align],
3280
+ ...wraps ? { wrap: true } : {},
3281
+ ...ui.fill ? { fill: true } : {}
3282
+ },
3287
3283
  header: ({ column, table }) => {
3288
3284
  const v = volatileRef.current;
3289
3285
  const pinSide = column.getIsPinned();
@@ -3314,9 +3310,9 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3314
3310
  };
3315
3311
  return (0, react_jsx_runtime.jsx)(ColumnHeaderMenu, {
3316
3312
  label: headerLabel,
3317
- sortable: !linkColumn && Boolean(v.onSort),
3313
+ sortable: columnSortable && Boolean(v.onSort),
3318
3314
  sortDirection: v.sort?.[0]?.field === col ? v.sort[0].direction : null,
3319
- onSort: !linkColumn && v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3315
+ onSort: columnSortable && v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3320
3316
  pinned: column.getIsPinned(),
3321
3317
  onPin: (side) => column.pin(side),
3322
3318
  canHide: Boolean(v.onHideColumn) && !v.requiredColumns?.includes(col),
@@ -3330,40 +3326,49 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3330
3326
  cell: ({ row }) => {
3331
3327
  const raw = row.original;
3332
3328
  const record = volatileRef.current.viewRow(raw);
3333
- const value = record[col];
3329
+ const value = (0, _burojs_react.readColumnValue)(record, col, objectPath);
3334
3330
  const customCell = volatileRef.current.renderCell?.(col, value, record);
3335
- const cellInner = customCell !== void 0 ? customCell : (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
3331
+ const cellInner = customCell !== void 0 ? customCell : (0, react_jsx_runtime.jsx)(require_filter_builder.ResolvedFieldDisplay, {
3336
3332
  resource: target === void 0 ? resourceRef : target.ref,
3337
3333
  name: target === void 0 ? col : target.name,
3338
3334
  field: field ?? { type: "unknown" },
3339
3335
  value,
3340
3336
  record,
3337
+ uiSurface: "column",
3338
+ columnEntry: cellEntry,
3341
3339
  fallback: (0, react_jsx_runtime.jsx)("span", { children: String(value ?? "") })
3342
3340
  });
3341
+ const framed = (node) => customCell !== void 0 ? node : (0, react_jsx_runtime.jsx)(FieldValueFrame, {
3342
+ field: frameField,
3343
+ value,
3344
+ surface: "column",
3345
+ entry: cellEntry,
3346
+ children: node
3347
+ });
3343
3348
  const href = volatileRef.current.rowHref?.(record);
3344
3349
  const isFirstContentCell = visibleColumnKeys.indexOf(col) === 0;
3345
3350
  const quick = isFirstContentCell ? volatileRef.current.rowQuick?.(raw) ?? null : null;
3346
- if (quick !== null) return href ? (0, react_jsx_runtime.jsx)(require_search_access.ClaimedQuickLink, {
3351
+ if (quick !== null) return framed(href ? (0, react_jsx_runtime.jsx)(require_relation_create.ClaimedQuickLink, {
3347
3352
  href,
3348
- className: require_search_access.relationLinkClassName,
3353
+ className: require_relation_create.relationLinkClassName,
3349
3354
  onOpen: quick,
3350
3355
  children: cellInner
3351
3356
  }) : (0, react_jsx_runtime.jsx)("button", {
3352
3357
  type: "button",
3353
3358
  [_burojs_react.QUICK_ANCHOR_ATTRIBUTE]: "",
3354
- className: `${require_search_access.relationLinkClassName} text-left`,
3359
+ className: `${require_relation_create.relationLinkClassName} text-left`,
3355
3360
  onClick: (e) => {
3356
3361
  e.stopPropagation();
3357
3362
  quick();
3358
3363
  },
3359
3364
  children: cellInner
3360
- });
3361
- return isFirstContentCell && href ? (0, react_jsx_runtime.jsx)(RouterLink, {
3365
+ }));
3366
+ return framed(isFirstContentCell && href ? (0, react_jsx_runtime.jsx)(RouterLink, {
3362
3367
  href,
3363
- className: require_search_access.relationLinkClassName,
3368
+ className: require_relation_create.relationLinkClassName,
3364
3369
  onClick: (e) => e.stopPropagation(),
3365
3370
  children: cellInner
3366
- }) : cellInner;
3371
+ }) : cellInner);
3367
3372
  }
3368
3373
  });
3369
3374
  }
@@ -3372,7 +3377,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3372
3377
  id: ACTIONS_COL_ID,
3373
3378
  enableSorting: false,
3374
3379
  enableResizing: false,
3375
- size: narrow ? 44 : actionsColumnSize(def?.actions?.item),
3380
+ size: narrow || typeof rowActions === "function" ? 44 : actionsColumnSize(def?.actions?.item),
3376
3381
  enableHiding: false,
3377
3382
  header: () => (0, react_jsx_runtime.jsx)("span", {
3378
3383
  className: "sr-only",
@@ -3383,7 +3388,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3383
3388
  noRowNav: true,
3384
3389
  noClip: true
3385
3390
  },
3386
- cell: ({ row }) => (0, react_jsx_runtime.jsx)(ActionOverflow, {
3391
+ cell: ({ row }) => typeof rowActions === "function" ? rowActions(row.original) : (0, react_jsx_runtime.jsx)(ActionOverflow, {
3387
3392
  resource,
3388
3393
  record: row.original,
3389
3394
  surface: "row"
@@ -3403,7 +3408,8 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3403
3408
  actionsHeader,
3404
3409
  i18nCaps,
3405
3410
  rowLinkKey,
3406
- narrow
3411
+ narrow,
3412
+ columnUiOf
3407
3413
  ]);
3408
3414
  const handleSelectionChange = (updater) => {
3409
3415
  if (controlled) {
@@ -3506,8 +3512,23 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3506
3512
  const isWrongPage = page > 1;
3507
3513
  const EmptyIcon = isFiltered ? _tabler_icons_react.IconFilterX : _tabler_icons_react.IconInbox;
3508
3514
  const items = resourceLabel.toLowerCase();
3509
- const heading = isWrongPage ? t("pagination.emptyPage") : isFiltered ? t("list.emptyFilteredTitle", { params: { items } }) : t("list.emptyTitle", { params: { items } });
3510
- const body = isWrongPage ? null : isFiltered ? t("list.emptyFilteredBody", { params: { items } }) : createHref ? t("list.emptyBody", { params: { item: recordSingular.toLowerCase() } }) : t("list.emptyBodyReadOnly", { params: { items } });
3515
+ const heading = isWrongPage ? t("pagination.emptyPage") : isFiltered ? t("list.emptyFilteredTitle", {
3516
+ resource,
3517
+ params: { items }
3518
+ }) : t("list.emptyTitle", {
3519
+ resource,
3520
+ params: { items }
3521
+ });
3522
+ const body = isWrongPage ? null : isFiltered ? t("list.emptyFilteredBody", {
3523
+ resource,
3524
+ params: { items }
3525
+ }) : createHref ? t("list.emptyBody", {
3526
+ resource,
3527
+ params: { item: recordSingular.toLowerCase() }
3528
+ }) : t("list.emptyBodyReadOnly", {
3529
+ resource,
3530
+ params: { items }
3531
+ });
3511
3532
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
3512
3533
  className: require_use_theme.cn("flex flex-col items-center justify-center gap-3 px-6 py-16 rounded-lg border border-dashed text-center", className),
3513
3534
  "data-testid": tid.listEmpty(resource),
@@ -3532,7 +3553,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3532
3553
  (0, react_jsx_runtime.jsxs)("div", {
3533
3554
  className: "flex justify-center gap-2 pt-2",
3534
3555
  children: [
3535
- isFiltered && onClearFilter && (0, react_jsx_runtime.jsx)(require_button.Button, {
3556
+ onClearFilter && (0, react_jsx_runtime.jsx)(require_button.Button, {
3536
3557
  type: "button",
3537
3558
  variant: "outline",
3538
3559
  size: "sm",
@@ -3720,43 +3741,46 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3720
3741
  })
3721
3742
  });
3722
3743
  }
3723
- function usePersistedState(key, initial, debounceMs = 0) {
3724
- const [state, setState] = (0, react.useState)(() => {
3725
- if (typeof window === "undefined") return initial;
3726
- try {
3727
- const raw = window.localStorage.getItem(key);
3728
- return raw ? JSON.parse(raw) : initial;
3729
- } catch {
3730
- return initial;
3731
- }
3744
+ //#endregion
3745
+ //#region src/blocks/related-list-unbound.tsx
3746
+ function UnboundRelatedList(props) {
3747
+ const t = (0, _burojs_react.useOptionalT)();
3748
+ return (0, react_jsx_runtime.jsxs)("div", {
3749
+ className: "flex flex-col gap-2",
3750
+ "data-testid": `list-unbound:${props.resource}`,
3751
+ children: [props.title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
3752
+ className: "text-sm font-semibold",
3753
+ children: props.title
3754
+ }), (0, react_jsx_runtime.jsx)("p", {
3755
+ className: "text-sm text-muted-foreground",
3756
+ children: props.empty ?? t("table.empty", { defaultValue: "No records" })
3757
+ })]
3732
3758
  });
3733
- (0, react.useEffect)(() => {
3734
- try {
3735
- if (window.localStorage.getItem(key) == null) window.localStorage.setItem(key, JSON.stringify(initial));
3736
- } catch {}
3737
- }, [key]);
3738
- const writeTimer = (0, react.useRef)(null);
3739
- const write = (value) => {
3740
- const doWrite = () => {
3741
- try {
3742
- window.localStorage.setItem(key, JSON.stringify(value));
3743
- } catch {}
3744
- };
3745
- if (debounceMs <= 0) {
3746
- doWrite();
3747
- return;
3748
- }
3749
- if (writeTimer.current) clearTimeout(writeTimer.current);
3750
- writeTimer.current = setTimeout(doWrite, debounceMs);
3751
- };
3752
- const set = (updater) => {
3753
- setState((prev) => {
3754
- const next = typeof updater === "function" ? updater(prev) : updater;
3755
- write(next);
3756
- return next;
3757
- });
3758
- };
3759
- return [state, set];
3759
+ }
3760
+ function placementScope(scope, owner) {
3761
+ return scope ?? (owner === void 0 ? "session" : "none");
3762
+ }
3763
+ //#endregion
3764
+ //#region src/list-kit/pieces/bulk-reach.tsx
3765
+ function useBulkFlowReachable(resource) {
3766
+ const app = (0, _burojs_react.useApp)();
3767
+ const control = (0, _burojs_react.useFlowRowResolver)(resource);
3768
+ return (app.registry.get(resource)?.actions.bulk ?? []).some((action) => (0, _burojs_core_internal.isFlowAction)(action) && control(action.name, void 0).state !== "absent");
3769
+ }
3770
+ function ExportReach(props) {
3771
+ const { available } = (0, _burojs_react.useResourceExport)(props.resource);
3772
+ const capability = (0, _burojs_react.useCapability)("run", {
3773
+ resource: props.resource,
3774
+ target: {
3775
+ kind: "action",
3776
+ name: "export"
3777
+ },
3778
+ mode: "list"
3779
+ });
3780
+ return props.children(available && capability.allowed);
3781
+ }
3782
+ function BulkExportReach(props) {
3783
+ return (0, _burojs_react.useOptionalDataRuntime)() !== null ? (0, react_jsx_runtime.jsx)(ExportReach, { ...props }) : props.children(false);
3760
3784
  }
3761
3785
  //#endregion
3762
3786
  //#region src/list-kit/pieces/piece.tsx
@@ -3824,15 +3848,47 @@ function ForceTableView(props) {
3824
3848
  }
3825
3849
  //#endregion
3826
3850
  //#region src/list-kit/pieces/list-body.tsx
3851
+ function LinkDetachRowButton(props) {
3852
+ const { resource, linkEditing } = useListSurface();
3853
+ const t = (0, _burojs_react.useOptionalT)();
3854
+ const [busy, setBusy] = (0, react.useState)(false);
3855
+ const detach = linkEditing?.detach;
3856
+ if (detach === void 0) return null;
3857
+ const label = t("field.link.detach", { defaultValue: "Detach" });
3858
+ return (0, react_jsx_runtime.jsx)(require_button.Button, {
3859
+ type: "button",
3860
+ size: "icon",
3861
+ variant: "ghost",
3862
+ className: "size-7",
3863
+ "aria-label": label,
3864
+ title: label,
3865
+ disabled: busy,
3866
+ "data-testid": `list-link-detach:${resource}:${props.row.id}`,
3867
+ onClick: (event) => {
3868
+ event.stopPropagation();
3869
+ setBusy(true);
3870
+ detach.onDetach([props.row]).finally(() => setBusy(false));
3871
+ },
3872
+ children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconUnlink, {
3873
+ className: "size-4",
3874
+ "aria-hidden": "true"
3875
+ })
3876
+ });
3877
+ }
3878
+ const linkDetachRow = (row) => (0, react_jsx_runtime.jsx)(LinkDetachRowButton, { row });
3827
3879
  function ListBodyView() {
3828
3880
  usePieceMount("body");
3829
3881
  const list = (0, _burojs_react.useResourceListContext)();
3830
- const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell, readOnly } = useListSurface();
3882
+ const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell, readOnly, linkEditing, layoutId } = useListSurface();
3883
+ const detachable = readOnly && linkEditing?.detach !== void 0;
3884
+ const flowReachable = useBulkFlowReachable(resource);
3885
+ const selectable = (exportReachable) => tableView && (detachable || !readOnly && (flowReachable || exportReachable));
3831
3886
  const item = (0, react.useContext)(ListItemContext);
3832
3887
  const rowsView = (0, react.useMemo)(() => rowsViewFor?.(item), [rowsViewFor, item]);
3833
3888
  const { query, pagination, cursor, count, columns, selection, filters, sorting, routing } = list;
3834
3889
  const rows = (0, _burojs_react.policyRowsOf)(list, list.rows);
3835
- return (0, react_jsx_runtime.jsx)(ResourceList, {
3890
+ if (query.unbound) return (0, react_jsx_runtime.jsx)(UnboundRelatedList, { resource });
3891
+ const view = (exportReachable) => (0, react_jsx_runtime.jsx)(ResourceList, {
3836
3892
  resource,
3837
3893
  data: rows,
3838
3894
  total: pagination.total,
@@ -3849,29 +3905,50 @@ function ListBodyView() {
3849
3905
  onRequestCount: count.available ? count.request : void 0,
3850
3906
  isCountingRows: count.isLoading,
3851
3907
  columns: columns.visible,
3908
+ columnUi: columns.ui,
3852
3909
  isLoading: query.isLoading,
3853
3910
  error: query.error,
3854
3911
  onRetry: query.refetch,
3855
3912
  createHref: route && createAvailable && createPage ? routing.createHref : void 0,
3856
3913
  ...rowProps,
3857
3914
  ...rowsView === void 0 ? {} : { rowsView },
3858
- selectable: tableView && !readOnly,
3859
- rowActions: !readOnly,
3915
+ selectable: selectable(exportReachable),
3916
+ rowActions: detachable ? linkDetachRow : !readOnly,
3860
3917
  selectedIds: selection.ids,
3861
3918
  onSelectionChange: selection.set,
3862
3919
  isFiltered: filters.isFiltered,
3863
- onClearFilter: filters.clearAll,
3920
+ onClearFilter: filters.canReset ? filters.reset : void 0,
3864
3921
  emptyState,
3865
3922
  sort: sorting.value ?? [],
3866
3923
  requiredColumns: columns.required,
3867
3924
  resetLayout: columns.resetLayout,
3925
+ layoutId,
3868
3926
  onHideColumn: columns.hide,
3869
3927
  onSort: sorting.toggle,
3928
+ sortable: sorting.sortable,
3870
3929
  renderCell
3871
3930
  });
3931
+ return (0, react_jsx_runtime.jsx)(BulkExportReach, {
3932
+ resource,
3933
+ children: view
3934
+ });
3872
3935
  }
3873
3936
  const ListBody = listPiece("ListBody", ListBodyView);
3874
3937
  //#endregion
3938
+ //#region src/resource/form-context.tsx
3939
+ const FormControlContext = (0, react.createContext)(null);
3940
+ const FormControlProvider = FormControlContext.Provider;
3941
+ function useFormControlOf(controller) {
3942
+ const latest = (0, react.useRef)(controller);
3943
+ latest.current = controller;
3944
+ return (0, react.useMemo)(() => ({ setValues: (patch) => {
3945
+ for (const [name, value] of Object.entries(patch)) latest.current.setValue(name, value);
3946
+ } }), []);
3947
+ }
3948
+ function useFormControl() {
3949
+ return (0, react.useContext)(FormControlContext);
3950
+ }
3951
+ //#endregion
3875
3952
  //#region src/record/route-screen-context.ts
3876
3953
  const RouteScreenClaimContext = (0, react.createContext)(false);
3877
3954
  const RouteScreenContext = (0, react.createContext)(false);
@@ -3995,7 +4072,7 @@ function PanelHost({ node, region = "panel-body", renderChildren }) {
3995
4072
  region,
3996
4073
  form,
3997
4074
  labelledBy: title === void 0 ? void 0 : titleId,
3998
- children: renderChildren(node.children)
4075
+ children: renderChildren(node.children, node)
3999
4076
  }) : null,
4000
4077
  ...title === void 0 ? {} : { title },
4001
4078
  ...description === void 0 ? {} : { description },
@@ -4030,10 +4107,12 @@ function TabsHost({ node, renderChildren }) {
4030
4107
  const state = (0, _burojs_react.useScreenState)();
4031
4108
  const text = useNodeText();
4032
4109
  const panels = node.children.filter((child) => child.state !== "absent");
4033
- const open = panels.find((child) => child.open === true) ?? panels[0];
4110
+ const declared = compiled.nodes[node.index].options.default;
4111
+ const effectiveDefault = (declared === void 0 ? void 0 : panels.find((child) => child.key === declared)) ?? panels[0];
4112
+ const open = panels.find((child) => child.open === true) ?? effectiveDefault;
4034
4113
  const urlSelect = useTabsUrlSelect();
4035
4114
  const select = (panel, reveal) => {
4036
- if (urlSelect !== null && node.key !== void 0 && panel.key !== void 0) urlSelect(node.key, panel.key, panel === panels[0], reveal);
4115
+ if (urlSelect !== null && node.key !== void 0 && panel.key !== void 0) urlSelect(node.key, panel.key, panel === effectiveDefault, reveal);
4037
4116
  else state?.openPanel(node.id, panelValue(panel));
4038
4117
  };
4039
4118
  const onSelect = (key) => {
@@ -4045,7 +4124,7 @@ function TabsHost({ node, renderChildren }) {
4045
4124
  key: panelValue(panel),
4046
4125
  title: titleOf(panel),
4047
4126
  errorCount: panel.key === void 0 ? 0 : controller.errorsIn(panel.key),
4048
- panel: panels.length === 1 || panel.open === true ? (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: renderChildren(panel.children) }) : null
4127
+ panel: panels.length === 1 || panel.open === true ? (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: renderChildren(panel.children, panel) }) : null
4049
4128
  }));
4050
4129
  const { view: View, id } = useNodeView(node, "tabs");
4051
4130
  const t = (0, _burojs_react.useFrameT)(id);
@@ -4156,7 +4235,7 @@ function WizardHost({ node, renderChildren }) {
4156
4235
  region: "step-panel",
4157
4236
  form,
4158
4237
  labelledBy: titleId,
4159
- children: renderChildren(panel.children)
4238
+ children: renderChildren(panel.children, panel)
4160
4239
  }),
4161
4240
  ...description === void 0 ? {} : { description },
4162
4241
  titleId,
@@ -4202,18 +4281,23 @@ function WizardHost({ node, renderChildren }) {
4202
4281
  //#region src/screen/nodes.tsx
4203
4282
  function FailedNode({ node }) {
4204
4283
  const { controller } = useScreenTree();
4205
- const t = (0, _burojs_react.useOptionalT)();
4206
- return (0, react_jsx_runtime.jsxs)("div", {
4207
- ...nodeAttributes(node),
4208
- role: "alert",
4209
- className: "flex flex-wrap items-center gap-2 rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
4210
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("screen.failed", { defaultValue: "This section could not be loaded." }) }), (0, react_jsx_runtime.jsx)(require_button.Button, {
4211
- type: "button",
4212
- variant: "outline",
4213
- size: "sm",
4214
- onClick: () => controller.retry(node.failedOn),
4215
- children: t("actions.retry", { defaultValue: "Retry" })
4216
- })]
4284
+ let error;
4285
+ for (const name of node.failedOn) {
4286
+ const source = controller.sources[name];
4287
+ if (source?.status === "failed") {
4288
+ error = source.error;
4289
+ break;
4290
+ }
4291
+ }
4292
+ return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
4293
+ surface: "tab",
4294
+ error,
4295
+ retry: () => controller.retry(node.failedOn),
4296
+ fallback: {
4297
+ key: "screen.failed",
4298
+ default: "This section could not be loaded."
4299
+ },
4300
+ attributes: nodeAttributes(node)
4217
4301
  });
4218
4302
  }
4219
4303
  function failedOnlyOnMeta(node) {
@@ -4226,8 +4310,17 @@ function drawn(node, hiddenFields) {
4226
4310
  if (node.state === "absent") return false;
4227
4311
  return !(node.kind === "field" && node.field !== void 0 && hiddenFields?.has(node.field));
4228
4312
  }
4229
- function SectionChildren({ nodes }) {
4230
- const { hiddenFields } = useScreenTree();
4313
+ function SectionChildren({ nodes, owner }) {
4314
+ const { compiled, hiddenFields } = useScreenTree();
4315
+ const text = useNodeText();
4316
+ if (owner !== void 0 && !nodes.some((node) => drawn(node, hiddenFields))) {
4317
+ const empty = text(compiled.nodes[owner.index]?.options.empty);
4318
+ return empty === void 0 || empty === "" ? null : (0, react_jsx_runtime.jsx)("p", {
4319
+ "data-buro-region": "empty",
4320
+ className: "text-sm text-muted-foreground",
4321
+ children: empty
4322
+ });
4323
+ }
4231
4324
  const out = [];
4232
4325
  let run = [];
4233
4326
  const flush = () => {
@@ -4249,8 +4342,11 @@ function SectionChildren({ nodes }) {
4249
4342
  flush();
4250
4343
  return out;
4251
4344
  }
4252
- function renderSection(nodes) {
4253
- return (0, react_jsx_runtime.jsx)(SectionChildren, { nodes });
4345
+ function renderSection(nodes, owner) {
4346
+ return (0, react_jsx_runtime.jsx)(SectionChildren, {
4347
+ nodes,
4348
+ owner
4349
+ });
4254
4350
  }
4255
4351
  function Layout({ node }) {
4256
4352
  return (0, react_jsx_runtime.jsx)("div", {
@@ -4372,17 +4468,14 @@ function pageHost(page) {
4372
4468
  }
4373
4469
  //#endregion
4374
4470
  //#region src/forms/declarative-form.tsx
4375
- function translateOrFallback(t, key, fallback) {
4376
- const translated = t(key);
4377
- return translated === key ? fallback : translated;
4378
- }
4379
- function issueText(issue, t, i18nPrefix) {
4471
+ function issueText(issue, caps, i18nPrefix) {
4380
4472
  return (0, _burojs_react.resolveValidationMessage)({
4381
4473
  code: issue.code ?? "",
4382
4474
  message: issue.message,
4383
- ...issue.params === void 0 ? {} : { params: issue.params }
4475
+ ...issue.check === void 0 ? {} : { check: issue.check }
4384
4476
  }, {
4385
- t,
4477
+ has: caps.has,
4478
+ t: caps.t,
4386
4479
  ...issue.field === "_form" ? {} : { fieldKey: `resources.${i18nPrefix}.fields.${issue.field}` }
4387
4480
  });
4388
4481
  }
@@ -4449,7 +4542,9 @@ function DeclarativeFormBody(props) {
4449
4542
  ...props.surface === void 0 ? {} : { surface: props.surface },
4450
4543
  ...props.onSubmit === void 0 ? {} : { onSubmit: props.onSubmit }
4451
4544
  });
4452
- const t = (0, _burojs_react.useOptionalT)();
4545
+ const formControl = useFormControlOf(form);
4546
+ const chromeT = (0, _burojs_react.useChromeT)();
4547
+ const caps = (0, _burojs_react.useI18nCaps)();
4453
4548
  const disabled = props.disabled === true;
4454
4549
  const uid = (0, react.useId)();
4455
4550
  const leafIds = (0, react.useMemo)(() => ({
@@ -4459,8 +4554,8 @@ function DeclarativeFormBody(props) {
4459
4554
  const formErrors = form.errors.filter((issue) => issue.field === "_form");
4460
4555
  const retryableChecks = [];
4461
4556
  for (const issue of form.checkOutcome?.blockers ?? []) {
4462
- const checkId = issue.params?.checkId;
4463
- if (issue.params?.cause === void 0 || typeof checkId !== "string") continue;
4557
+ const checkId = issue.check?.id;
4558
+ if (issue.check?.cause === void 0 || typeof checkId !== "string") continue;
4464
4559
  if (!retryableChecks.includes(checkId)) retryableChecks.push(checkId);
4465
4560
  }
4466
4561
  const formWarnings = form.warnings.filter((issue) => issue.field === "_form");
@@ -4473,7 +4568,7 @@ function DeclarativeFormBody(props) {
4473
4568
  formErrors.length > 0 && (0, react_jsx_runtime.jsx)("div", {
4474
4569
  role: "alert",
4475
4570
  className: "mb-4 flex flex-col gap-1 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive",
4476
- children: formErrors.map((issue, index) => (0, react_jsx_runtime.jsx)("p", { children: issueText(issue, t, prefix) }, index))
4571
+ children: formErrors.map((issue, index) => (0, react_jsx_runtime.jsx)("p", { children: issueText(issue, caps, prefix) }, index))
4477
4572
  }),
4478
4573
  retryableChecks.length > 0 && (0, react_jsx_runtime.jsx)("div", {
4479
4574
  className: "mb-4 flex flex-wrap gap-2",
@@ -4483,25 +4578,28 @@ function DeclarativeFormBody(props) {
4483
4578
  size: "sm",
4484
4579
  "data-testid": `form-check-retry:${checkId}`,
4485
4580
  onClick: () => void form.revalidate(),
4486
- children: translateOrFallback(t, "actions.retry", "Retry")
4581
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
4487
4582
  }, checkId))
4488
4583
  }),
4489
4584
  formWarnings.length > 0 && (0, react_jsx_runtime.jsx)("div", {
4490
4585
  role: "status",
4491
4586
  "aria-live": "polite",
4492
4587
  className: "mb-4 flex flex-col gap-1 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm text-warning-emphasis",
4493
- children: formWarnings.map((issue, index) => (0, react_jsx_runtime.jsx)("p", { children: issueText(issue, t, prefix) }, index))
4588
+ children: formWarnings.map((issue, index) => (0, react_jsx_runtime.jsx)("p", { children: issueText(issue, caps, prefix) }, index))
4494
4589
  }),
4495
- (0, react_jsx_runtime.jsx)(ScreenTree, {
4496
- region: "form-body",
4497
- resource: prefix,
4498
- mode: "create",
4499
- compiled: form.screen,
4500
- controller: form,
4501
- leafIds,
4502
- ...props.renderField === void 0 ? {} : { renderField: props.renderField },
4503
- disabled,
4504
- ...props.bodyClassName === void 0 ? {} : { className: props.bodyClassName }
4590
+ (0, react_jsx_runtime.jsx)(FormControlProvider, {
4591
+ value: formControl,
4592
+ children: (0, react_jsx_runtime.jsx)(ScreenTree, {
4593
+ region: "form-body",
4594
+ resource: prefix,
4595
+ mode: "create",
4596
+ compiled: form.screen,
4597
+ controller: form,
4598
+ leafIds,
4599
+ ...props.renderField === void 0 ? {} : { renderField: props.renderField },
4600
+ disabled,
4601
+ ...props.bodyClassName === void 0 ? {} : { className: props.bodyClassName }
4602
+ })
4505
4603
  }),
4506
4604
  props.slots?.footer === void 0 ? (0, react_jsx_runtime.jsx)("div", {
4507
4605
  className: "mt-4 flex justify-end",
@@ -4509,7 +4607,7 @@ function DeclarativeFormBody(props) {
4509
4607
  type: "submit",
4510
4608
  disabled: !form.canSubmit || disabled,
4511
4609
  onMouseDown: (event) => event.preventDefault(),
4512
- children: props.submitLabel ?? translateOrFallback(t, "actions.save", "Save")
4610
+ children: props.submitLabel ?? chromeT("actions.save", { defaultValue: "Save" })
4513
4611
  })
4514
4612
  }) : typeof props.slots.footer === "function" ? props.slots.footer({ canSubmit: form.canSubmit && !disabled }) : props.slots.footer
4515
4613
  ]
@@ -4594,7 +4692,8 @@ function ExportOptionsDirty({ dirty }) {
4594
4692
  return null;
4595
4693
  }
4596
4694
  function getNoRunState() {}
4597
- function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount, scope }) {
4695
+ function ExportDialog({ open, onOpenChange, resource: resourceInput, target, visibleColumns, estimatedCount, scope }) {
4696
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
4598
4697
  const t = (0, _burojs_react.useOptionalT)();
4599
4698
  const dialogTestId = (0, _burojs_react.useTestIds)().exportDialog(resource);
4600
4699
  const { formats, start, exporter, available, error, loading } = (0, _burojs_react.useResourceExport)(resource, {
@@ -4716,14 +4815,15 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4716
4815
  })] }), (0, react_jsx_runtime.jsx)(ExportProgressView, {
4717
4816
  state: runState,
4718
4817
  dialogTestId,
4719
- t
4818
+ t,
4819
+ caps
4720
4820
  })] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)(require_dialog.DialogHeader, { children: [(0, react_jsx_runtime.jsx)(require_dialog.DialogTitle, { children: titleText }), (0, react_jsx_runtime.jsx)(require_dialog.DialogDescription, {
4721
4821
  className: "sr-only",
4722
4822
  children: titleText
4723
4823
  })] }), !available ? (0, react_jsx_runtime.jsx)("p", {
4724
4824
  role: "alert",
4725
4825
  "data-testid": `${dialogTestId}:unavailable`,
4726
- children: error?.message ?? t("export.dialog.unavailable")
4826
+ children: error === void 0 || error === null ? t("export.dialog.unavailable") : (0, _burojs_react.resolveErrorText)(error, caps)
4727
4827
  }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4728
4828
  loading ? (0, react_jsx_runtime.jsx)("p", {
4729
4829
  role: "status",
@@ -4802,7 +4902,7 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4802
4902
  })
4803
4903
  });
4804
4904
  }
4805
- function ExportProgressView({ state, dialogTestId, t }) {
4905
+ function ExportProgressView({ state, dialogTestId, t, caps }) {
4806
4906
  if (state === void 0) return null;
4807
4907
  if (state.status === "running") {
4808
4908
  const total = state.progress?.total;
@@ -4823,7 +4923,7 @@ function ExportProgressView({ state, dialogTestId, t }) {
4823
4923
  if (state.status === "failed") return (0, react_jsx_runtime.jsx)("p", {
4824
4924
  role: "alert",
4825
4925
  "data-testid": `${dialogTestId}:error`,
4826
- children: `${t("export.dialog.failed")}: ${state.error.message}`
4926
+ children: `${t("export.dialog.failed")}: ${(0, _burojs_react.resolveErrorText)(state.error, caps)}`
4827
4927
  });
4828
4928
  if (state.status === "canceled") return (0, react_jsx_runtime.jsx)("p", {
4829
4929
  "data-testid": `${dialogTestId}:canceled`,
@@ -4836,6 +4936,7 @@ function ExportProgressView({ state, dialogTestId, t }) {
4836
4936
  function BulkSummary(props) {
4837
4937
  const loaded = require_check_confirm_dialog.useLoaded(require_check_confirm_dialog.loadBulkSummary);
4838
4938
  const t = (0, _burojs_react.useOptionalT)();
4939
+ const chromeT = (0, _burojs_react.useChromeT)();
4839
4940
  const failed = (retry) => (0, react_jsx_runtime.jsxs)("div", {
4840
4941
  role: "alert",
4841
4942
  className: "flex items-center gap-2 text-sm",
@@ -4844,7 +4945,7 @@ function BulkSummary(props) {
4844
4945
  size: "sm",
4845
4946
  variant: "outline",
4846
4947
  onClick: retry,
4847
- children: require_check_confirm_dialog.text(t, "actions.retry", "Retry")
4948
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
4848
4949
  })]
4849
4950
  });
4850
4951
  if (loaded.error !== void 0) return failed(loaded.retry);
@@ -4862,21 +4963,26 @@ function BulkFlowButton({ resource, actionName, ids, onSelectionChange }) {
4862
4963
  const control = (0, _burojs_react.useFlowRowResolver)(resource)(actionName, void 0);
4863
4964
  const chrome = require_check_confirm_dialog.useFlowChrome(resource, actionName);
4864
4965
  const def = app.registry.get(resource);
4865
- const each = (0, react.useMemo)(() => {
4966
+ const compiled = (0, react.useMemo)(() => {
4866
4967
  try {
4867
- return def === void 0 ? false : (0, _burojs_core.compileFlow)(def, actionName).each;
4968
+ return def === void 0 ? void 0 : (0, _burojs_core.compileFlow)(def, actionName);
4868
4969
  } catch {
4869
- return false;
4970
+ return;
4870
4971
  }
4871
4972
  }, [def, actionName]);
4973
+ const each = compiled?.each ?? false;
4872
4974
  const [running, setRunning] = (0, react.useState)(false);
4873
4975
  const [summary, setSummary] = (0, react.useState)(null);
4976
+ const afterSummary = (0, react.useRef)(null);
4874
4977
  const testid = tid.bulkAction(resource, actionName);
4875
4978
  if (control.state === "absent") return null;
4876
4979
  const variant = chrome.destructive ? "destructive" : "outline";
4877
4980
  const overLimit = each && ids.length > _burojs_core.BULK_EACH_LIMIT;
4878
4981
  if (overLimit || control.state === "disabled") return (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DisabledAction, {
4879
- reason: overLimit ? require_check_confirm_dialog.text(t, "flow.bulkLimit", `Select at most ${_burojs_core.BULK_EACH_LIMIT}.`, { count: _burojs_core.BULK_EACH_LIMIT }) : control.reason,
4982
+ reason: overLimit ? t("flow.bulkLimit", {
4983
+ defaultValue: `Select at most ${_burojs_core.BULK_EACH_LIMIT}.`,
4984
+ count: _burojs_core.BULK_EACH_LIMIT
4985
+ }) : control.reason,
4880
4986
  label: chrome.label,
4881
4987
  icon: chrome.icon,
4882
4988
  testid,
@@ -4890,11 +4996,20 @@ function BulkFlowButton({ resource, actionName, ids, onSelectionChange }) {
4890
4996
  const finish = (result, progress) => {
4891
4997
  setRunning(false);
4892
4998
  if (progress === void 0) return;
4893
- if (result.outcome !== "success") setSummary({
4999
+ const summarize = result.outcome !== "success" || progress.rereadSkipped.some((entry) => entry.policy === "warn");
5000
+ if (summarize) setSummary({
4894
5001
  progress,
4895
5002
  total: ids.length
4896
5003
  });
4897
- onSelectionChange?.(ids.filter((id) => !progress.success.includes(id)));
5004
+ const remaining = ids.filter((id) => !progress.success.includes(id));
5005
+ if (summarize && remaining.length === 0) afterSummary.current = () => onSelectionChange?.([]);
5006
+ else onSelectionChange?.(remaining);
5007
+ };
5008
+ const closeSummary = () => {
5009
+ setSummary(null);
5010
+ const pending = afterSummary.current;
5011
+ afterSummary.current = null;
5012
+ pending?.();
4898
5013
  };
4899
5014
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4900
5015
  (0, react_jsx_runtime.jsx)(require_button.Button, {
@@ -4924,7 +5039,7 @@ function BulkFlowButton({ resource, actionName, ids, onSelectionChange }) {
4924
5039
  (0, react_jsx_runtime.jsx)(require_dialog.Dialog, {
4925
5040
  open: summary !== null,
4926
5041
  onOpenChange: (open) => {
4927
- if (!open) setSummary(null);
5042
+ if (!open) closeSummary();
4928
5043
  },
4929
5044
  children: (0, react_jsx_runtime.jsxs)(require_dialog.DialogContent, {
4930
5045
  "data-testid": `${tid.bulkSummary(resource, actionName)}:dialog`,
@@ -4938,14 +5053,15 @@ function BulkFlowButton({ resource, actionName, ids, onSelectionChange }) {
4938
5053
  actionName,
4939
5054
  label: chrome.labelText,
4940
5055
  total: summary.total,
4941
- progress: summary.progress
5056
+ progress: summary.progress,
5057
+ texts: compiled?.flow.texts
4942
5058
  }),
4943
5059
  (0, react_jsx_runtime.jsx)(require_dialog.DialogFooter, { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
4944
5060
  type: "button",
4945
5061
  variant: "outline",
4946
5062
  "data-testid": `${tid.bulkSummary(resource, actionName)}:close`,
4947
- onClick: () => setSummary(null),
4948
- children: require_check_confirm_dialog.text(t, "flow.close", "Close")
5063
+ onClick: closeSummary,
5064
+ children: t("flow.close", { defaultValue: "Close" })
4949
5065
  }) })
4950
5066
  ]
4951
5067
  })
@@ -4961,10 +5077,12 @@ function orderBulkActions(actions) {
4961
5077
  seq: index
4962
5078
  })).sort((a, b) => a.weight - b.weight || a.seq - b.seq).map(({ action }) => action);
4963
5079
  }
4964
- function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns, scope }) {
5080
+ function BulkActionToolbar({ resource: resourceInput, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns, scope, actions }) {
5081
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
4965
5082
  const app = (0, _burojs_react.useApp)();
4966
5083
  const tid = (0, _burojs_react.useTestIds)();
4967
5084
  const t = (0, _burojs_react.useOptionalT)();
5085
+ const chromeT = (0, _burojs_react.useChromeT)();
4968
5086
  const def = app.registry.get(resource);
4969
5087
  const records = selectedRecords ?? (table ? table.getFilteredSelectedRowModel().rows.map((r) => r.original) : []);
4970
5088
  const ids = selectedIds ?? records.map((record) => record.id);
@@ -4997,7 +5115,8 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
4997
5115
  className: "mx-0.5 h-6 w-px bg-border",
4998
5116
  "aria-hidden": "true"
4999
5117
  }),
5000
- bulkActions.map((action) => (0, react_jsx_runtime.jsx)(BulkFlowButton, {
5118
+ actions !== void 0 ? actions : null,
5119
+ actions === void 0 && bulkActions.map((action) => (0, react_jsx_runtime.jsx)(BulkFlowButton, {
5001
5120
  resource,
5002
5121
  actionName: action.name,
5003
5122
  ids,
@@ -5006,7 +5125,7 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
5006
5125
  else if (next.length === 0) handleClear();
5007
5126
  }
5008
5127
  }, action.name)),
5009
- (0, react_jsx_runtime.jsx)(BulkExportButton, {
5128
+ actions === void 0 && (0, react_jsx_runtime.jsx)(BulkExportButton, {
5010
5129
  resource,
5011
5130
  ids,
5012
5131
  visibleColumns: visibleColumns ?? [],
@@ -5023,7 +5142,7 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
5023
5142
  "aria-hidden": "true"
5024
5143
  }), (0, react_jsx_runtime.jsx)("span", {
5025
5144
  className: "hidden sm:inline",
5026
- children: t("actions.clearSelection", { defaultValue: "Clear" })
5145
+ children: chromeT("actions.clearSelection", { defaultValue: "Clear" })
5027
5146
  })]
5028
5147
  })
5029
5148
  ]
@@ -5083,12 +5202,36 @@ function BulkExportButtonActive({ resource, ids, visibleColumns, scope }) {
5083
5202
  }
5084
5203
  //#endregion
5085
5204
  //#region src/list-kit/pieces/list-bulk-bar.tsx
5205
+ function LinkDetachBulkButton(props) {
5206
+ const { selection } = (0, _burojs_react.useResourceListContext)();
5207
+ const { resource } = useListSurface();
5208
+ const t = (0, _burojs_react.useOptionalT)();
5209
+ const [busy, setBusy] = (0, react.useState)(false);
5210
+ return (0, react_jsx_runtime.jsxs)(require_button.Button, {
5211
+ type: "button",
5212
+ size: "sm",
5213
+ variant: "ghost",
5214
+ className: "h-8 gap-1.5 rounded-full px-2.5 text-destructive",
5215
+ disabled: busy,
5216
+ "data-testid": `list-link-detach-bulk:${resource}`,
5217
+ onClick: () => {
5218
+ setBusy(true);
5219
+ props.onDetach(selection.records).finally(() => setBusy(false));
5220
+ },
5221
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconUnlink, {
5222
+ className: "size-4",
5223
+ "aria-hidden": "true"
5224
+ }), t("field.link.detach", { defaultValue: "Detach" })]
5225
+ });
5226
+ }
5086
5227
  function ListBulkBarView() {
5087
5228
  usePieceMount("bulk-bar");
5088
5229
  const { selection, columns, scope } = (0, _burojs_react.useResourceListContext)();
5089
- const { resource, tableView, readOnly } = useListSurface();
5090
- if (!tableView || readOnly || selection.ids.length === 0) return null;
5230
+ const { resource, tableView, readOnly, linkEditing } = useListSurface();
5231
+ const detach = readOnly ? linkEditing?.detach : void 0;
5232
+ if (!tableView || readOnly && detach === void 0 || selection.ids.length === 0) return null;
5091
5233
  return (0, react_jsx_runtime.jsx)(BulkActionToolbar, {
5234
+ ...detach === void 0 ? {} : { actions: (0, react_jsx_runtime.jsx)(LinkDetachBulkButton, { onDetach: detach.onDetach }) },
5092
5235
  resource,
5093
5236
  selectedRecords: selection.records,
5094
5237
  selectedIds: selection.ids,
@@ -5177,7 +5320,8 @@ function DataTableViewOptions({ table, getColumnLabel, isColumnRequired, getTest
5177
5320
  }
5178
5321
  //#endregion
5179
5322
  //#region src/list-kit/columns-toggle.tsx
5180
- function ColumnsToggle({ resource, def, allAvailable, required, visibleColumns, defaultVisible, onChange, onResetSizes, onRestoreDefaults }) {
5323
+ function ColumnsToggle({ resource: resourceInput, def, allAvailable, required, visibleColumns, defaultVisible, onChange, onResetSizes, onRestoreDefaults }) {
5324
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
5181
5325
  const t = (0, _burojs_react.useT)();
5182
5326
  const columnsCaps = (0, _burojs_react.useI18nCaps)(resource);
5183
5327
  const app = (0, _burojs_react.useApp)();
@@ -5284,12 +5428,16 @@ function ListColumnsView() {
5284
5428
  const ListColumns = listPiece("ListColumns", ListColumnsView);
5285
5429
  //#endregion
5286
5430
  //#region src/resource/create-button.tsx
5287
- function CreateButton({ resource, href, testid, size = "sm", variant, label, className, onOpen }) {
5431
+ function CreateButton({ resource: resourceInput, href, testid, size = "sm", variant, label, className, onOpen }) {
5432
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
5288
5433
  const t = (0, _burojs_react.useOptionalT)();
5289
5434
  const Link = require_toaster.useLinkComponent();
5290
5435
  const availability = (0, _burojs_react.useAvailability)(resource, "create");
5291
5436
  const gate = (0, _burojs_react.useEntryGate)();
5292
- const text = label ?? t("actions.create", { defaultValue: "Create" });
5437
+ const text = label ?? t("actions.create", {
5438
+ resource,
5439
+ defaultValue: "Create"
5440
+ });
5293
5441
  if (onOpen !== void 0) {
5294
5442
  const answer = gate(resource, "create");
5295
5443
  if (answer.state === "disabled") return (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DisabledAction, {
@@ -5360,7 +5508,8 @@ const ListCreate = listPiece("ListCreate", ListCreateView);
5360
5508
  //#endregion
5361
5509
  //#region src/export/export-button.tsx
5362
5510
  const warnedProviderQueryResources = new Set();
5363
- function ExportButton({ resource, className }) {
5511
+ function ExportButton({ resource: resourceInput, className }) {
5512
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
5364
5513
  if (!((0, _burojs_react.useOptionalDataRuntime)() !== null)) return null;
5365
5514
  return (0, react_jsx_runtime.jsx)(ExportButtonActive, {
5366
5515
  resource,
@@ -5381,36 +5530,19 @@ function ExportButtonActive({ resource, className }) {
5381
5530
  const tid = (0, _burojs_react.useTestIds)();
5382
5531
  const t = (0, _burojs_react.useOptionalT)();
5383
5532
  const [open, setOpen] = react.useState(false);
5384
- const searchContext = react.useMemo(() => ({
5385
- resource,
5386
- def: list.def
5387
- }), [resource, list.def]);
5533
+ const sent = list.query.sent;
5388
5534
  const target = react.useMemo(() => {
5389
- const filter = (0, _burojs_core.composeListFilter)({
5390
- fixed: list.filters.fixed,
5391
- pinned: list.filters.value,
5392
- group: list.filters.group,
5393
- search: list.filters.search,
5394
- searchDecl: list.filters.searchEnabled ? list.filters.searchDecl ?? list.def?.views?.list?.search : void 0,
5395
- searchContext
5396
- });
5397
- const sort = list.sorting.value;
5535
+ if (sent === null) return null;
5536
+ const { filter, sort } = sent;
5398
5537
  return {
5399
5538
  kind: "filter",
5400
5539
  ...filter === void 0 ? {} : { filter },
5401
5540
  ...sort.length > 0 ? { sort } : {}
5402
5541
  };
5403
- }, [
5404
- list.filters.fixed,
5405
- list.filters.value,
5406
- list.filters.group,
5407
- list.filters.search,
5408
- list.filters.searchDecl,
5409
- list.filters.searchEnabled,
5410
- list.def,
5411
- searchContext,
5412
- list.sorting.value
5413
- ]);
5542
+ }, [sent]);
5543
+ const lastTarget = react.useRef(target);
5544
+ if (target !== null) lastTarget.current = target;
5545
+ const dialogTarget = target ?? lastTarget.current;
5414
5546
  react.useEffect(() => {
5415
5547
  if (!available || !capability.allowed) return;
5416
5548
  if (list.providerQuery.value === void 0) return;
@@ -5424,7 +5556,9 @@ function ExportButtonActive({ resource, className }) {
5424
5556
  resource
5425
5557
  ]);
5426
5558
  if (!available || !capability.allowed || list.isForbidden) return null;
5427
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_button.Button, {
5559
+ if (target === null && !open) return null;
5560
+ if (dialogTarget === null) return null;
5561
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [target === null ? null : (0, react_jsx_runtime.jsx)(require_button.Button, {
5428
5562
  type: "button",
5429
5563
  variant: "outline",
5430
5564
  size: "icon",
@@ -5443,7 +5577,7 @@ function ExportButtonActive({ resource, className }) {
5443
5577
  open,
5444
5578
  onOpenChange: setOpen,
5445
5579
  resource,
5446
- target,
5580
+ target: dialogTarget,
5447
5581
  visibleColumns: list.columns.visible,
5448
5582
  estimatedCount: list.pagination.total,
5449
5583
  scope: list.scope
@@ -5461,8 +5595,9 @@ function ListExportView() {
5461
5595
  const ListExport = listPiece("ListExport", ListExportView);
5462
5596
  //#endregion
5463
5597
  //#region src/list-kit/list-search-input.tsx
5464
- function ListSearchInput({ resource, label, value, onCommit, placeholder }) {
5465
- const t = (0, _burojs_react.useT)();
5598
+ function ListSearchInput({ resource: resourceInput, value, onCommit, placeholder }) {
5599
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
5600
+ const caps = (0, _burojs_react.useI18nCaps)(resource);
5466
5601
  const [text, setText] = (0, react.useState)(value);
5467
5602
  const lastPushedRef = (0, react.useRef)(value);
5468
5603
  const timerRef = (0, react.useRef)(null);
@@ -5477,7 +5612,7 @@ function ListSearchInput({ resource, label, value, onCommit, placeholder }) {
5477
5612
  }, []);
5478
5613
  return (0, react_jsx_runtime.jsx)(require_input.Input, {
5479
5614
  type: "search",
5480
- placeholder: placeholder ?? t("toolbar.searchBy", { params: { name: label } }),
5615
+ placeholder: placeholder ?? (0, _burojs_core.resolveContentSlot)(caps, ["list.search"]) ?? "Search",
5481
5616
  value: text,
5482
5617
  "data-testid": `list-search:${resource}`,
5483
5618
  className: "h-8 w-full min-[420px]:w-72",
@@ -5495,24 +5630,18 @@ function ListSearchInput({ resource, label, value, onCommit, placeholder }) {
5495
5630
  //#endregion
5496
5631
  //#region src/list-kit/filter-builder/filter-region.tsx
5497
5632
  function FilterRegion({ search } = {}) {
5498
- const { resource, def, filters, pagination, access } = (0, _burojs_react.useResourceListContext)();
5499
- const t = (0, _burojs_react.useT)();
5500
- const listCaps = (0, _burojs_react.useI18nCaps)(resource);
5633
+ const { resource, def, filters, pagination } = (0, _burojs_react.useResourceListContext)();
5634
+ const chromeT = (0, _burojs_react.useChromeT)();
5501
5635
  const testIdBase = `list-filter:${resource}`;
5636
+ const caps = (0, _burojs_react.useI18nCaps)(resource);
5637
+ const placeholder = search === void 0 ? (0, _burojs_core.resolveContentSlot)(caps, ["list.searchPlaceholder", "list.search"]) ?? "Search" : void 0;
5502
5638
  const searchDecl = search === void 0 ? def?.views?.list?.search : search ?? void 0;
5503
- const searchField = searchDecl !== void 0 && typeof searchDecl !== "function" ? (() => {
5504
- return searchDecl.fields.map((entry) => typeof entry === "string" ? entry : entry.field).find((name) => access.fieldVisible(name));
5505
- })() : void 0;
5506
- const searchGenericLabel = (0, _burojs_core.resolveContentSlot)(listCaps, ["list.search"]) ?? "Search";
5507
- const searchLabel = searchField ? (0, _burojs_core.resolveFieldLabel)(listCaps, searchField, (0, _burojs_core.declaredText)("field", def?.fields[searchField], "label")) : searchGenericLabel;
5508
- const searchPlaceholder = searchField ? t("toolbar.searchBy", { params: { name: searchLabel } }) : searchGenericLabel;
5509
5639
  return (0, react_jsx_runtime.jsxs)("div", {
5510
5640
  className: "flex flex-wrap items-center gap-2",
5511
5641
  children: [
5512
5642
  searchDecl !== void 0 && filters.searchEnabled && (0, react_jsx_runtime.jsx)(ListSearchInput, {
5513
5643
  resource,
5514
- label: searchLabel,
5515
- placeholder: searchPlaceholder,
5644
+ ...placeholder === void 0 ? {} : { placeholder },
5516
5645
  value: filters.search,
5517
5646
  onCommit: (v) => {
5518
5647
  pagination.setPage(1);
@@ -5524,19 +5653,21 @@ function FilterRegion({ search } = {}) {
5524
5653
  setGroup: filters.setGroup,
5525
5654
  available: filters.available,
5526
5655
  fixed: filters.fixed,
5656
+ presets: filters.presets,
5657
+ setPreset: filters.setPreset,
5527
5658
  pinnedFields: filters.pinnedFields,
5528
5659
  pinnedValue: filters.value,
5529
5660
  setPinnedValue: filters.set,
5530
5661
  setPage: pagination.setPage,
5531
5662
  testIdBase
5532
5663
  }),
5533
- filters.isFiltered && (0, react_jsx_runtime.jsx)(require_button.Button, {
5664
+ filters.canReset && (0, react_jsx_runtime.jsx)(require_button.Button, {
5534
5665
  type: "button",
5535
5666
  variant: "ghost",
5536
5667
  size: "sm",
5537
5668
  "data-testid": `${testIdBase}:clear-all`,
5538
- onClick: filters.clearAll,
5539
- children: t("filters.clearAll")
5669
+ onClick: filters.reset,
5670
+ children: chromeT("filters.clearAll")
5540
5671
  })
5541
5672
  ]
5542
5673
  });
@@ -5666,6 +5797,7 @@ function ViewItem({ view, caps, resource, onClick, testid }) {
5666
5797
  });
5667
5798
  }
5668
5799
  function EntryRow({ entry, onApply, onRename, onFork, onDelete, forkAvailable, applyTestId, renameTestId, forkTestId, deleteTestId, tr }) {
5800
+ const chromeT = (0, _burojs_react.useChromeT)();
5669
5801
  const canRename = entry.permissions.update && onRename !== void 0;
5670
5802
  const canFork = forkAvailable && entry.permissions.fork && onFork !== void 0;
5671
5803
  const canDelete = entry.permissions.remove && onDelete !== void 0;
@@ -5711,8 +5843,8 @@ function EntryRow({ entry, onApply, onRename, onFork, onDelete, forkAvailable, a
5711
5843
  canDelete && (0, react_jsx_runtime.jsx)("button", {
5712
5844
  type: "button",
5713
5845
  onClick: onDelete,
5714
- "aria-label": tr("actions.delete", "Delete"),
5715
- title: tr("actions.delete", "Delete"),
5846
+ "aria-label": chromeT("actions.delete", { defaultValue: "Delete" }),
5847
+ title: chromeT("actions.delete", { defaultValue: "Delete" }),
5716
5848
  "data-testid": deleteTestId,
5717
5849
  className: "shrink-0 rounded-sm p-1 text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
5718
5850
  children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconTrash, {
@@ -5752,7 +5884,8 @@ function groupByScope(entries) {
5752
5884
  }
5753
5885
  return order.map((id) => byId.get(id));
5754
5886
  }
5755
- function SavedViewsDropdown({ resource, adopterViews, entries, issues = [], onApply, onSaveCurrent, canSaveCurrent = true, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork = true, getTestId, triggerLabel = "Views", iconOnly = false, triggerClassName = "h-9", popoverContentClassName = "w-64 p-1", popoverAlign = "start" }) {
5887
+ function SavedViewsDropdown({ resource: resourceInput, adopterViews, entries, issues = [], onApply, onSaveCurrent, canSaveCurrent = true, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork = true, getTestId, triggerLabel = "Views", iconOnly = false, triggerClassName = "h-9", popoverContentClassName = "w-64 p-1", popoverAlign = "start" }) {
5888
+ const resource = resourceInput === void 0 ? void 0 : (0, _burojs_core.routeResourceKey)(resourceInput);
5756
5889
  const t = (0, _burojs_react.useOptionalT)();
5757
5890
  const caps = (0, _burojs_react.useI18nCaps)(resource);
5758
5891
  const tr = (key, fallback) => t?.(key, { defaultValue: fallback }) ?? fallback;
@@ -5966,9 +6099,10 @@ function useOptionalFrameChrome() {
5966
6099
  //#endregion
5967
6100
  //#region src/record/frame-pieces.tsx
5968
6101
  function useFrameId() {
5969
- const { recordId, record } = (0, _burojs_react.useRecordFrame)();
6102
+ const { resource, recordId, record } = (0, _burojs_react.useRecordFrame)();
6103
+ const def = (0, _burojs_react.useApp)().registry.get(resource);
5970
6104
  if (recordId !== void 0) return recordId;
5971
- const id = record?.id;
6105
+ const id = (0, _burojs_react.recordKeyOf)(def, record);
5972
6106
  return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
5973
6107
  }
5974
6108
  function RecordTitleView() {
@@ -5979,7 +6113,7 @@ function RecordTitleView() {
5979
6113
  const t = (0, _burojs_react.useOptionalT)();
5980
6114
  const title = (0, _burojs_react.useRecordTitle)(resource, mode === "create" ? void 0 : id, record);
5981
6115
  if (useFrameChrome().hostTitle === true) return null;
5982
- const text = mode === "create" ? t("pageHeader.createTitle", { params: { label: (0, _burojs_core.resolveResourceLabel)(caps, resource, "single", app.registry.get(resource)) } }) : title;
6116
+ const text = mode === "create" ? resolveResourceTitle(caps, t, resource, "createTitle", { label: (0, _burojs_core.resolveResourceLabel)(caps, resource, "single", app.registry.get(resource)) }) : title;
5983
6117
  if (text === "") return null;
5984
6118
  return (0, react_jsx_runtime.jsx)("h2", {
5985
6119
  className: "min-w-0 break-words text-xl font-semibold tracking-tight",
@@ -5992,10 +6126,7 @@ function RecordActionsView() {
5992
6126
  const id = useFrameId();
5993
6127
  const holder = (0, _burojs_react.useScreenState)()?.inline;
5994
6128
  if (mode === "create" || record === void 0 || id === void 0) return null;
5995
- const row = {
5996
- ...(0, _burojs_react.policyRecordOf)(controller, record),
5997
- id
5998
- };
6129
+ const row = (0, _burojs_react.withRecordKeys)((0, _burojs_react.policyRecordOf)(controller) ?? record, { id });
5999
6130
  holder?.declare(inlineFlowNames(controller.screen, controller.plan));
6000
6131
  return (0, react_jsx_runtime.jsxs)("div", {
6001
6132
  className: "flex flex-wrap items-center gap-2",
@@ -6003,6 +6134,7 @@ function RecordActionsView() {
6003
6134
  resource,
6004
6135
  record: row,
6005
6136
  surface: mode,
6137
+ sources: controller.sources,
6006
6138
  ...holder === void 0 ? {} : { hideFlows: (name) => holder.suppressed(name) }
6007
6139
  }), mode === "show" ? extraActions : null]
6008
6140
  });
@@ -6032,24 +6164,38 @@ function FormActionsView() {
6032
6164
  const app = (0, _burojs_react.useApp)();
6033
6165
  const navigate = (0, _burojs_react.useRouteNavigate)();
6034
6166
  const t = (0, _burojs_react.useOptionalT)();
6167
+ const chromeT = (0, _burojs_react.useChromeT)();
6168
+ const caps = (0, _burojs_react.useI18nCaps)();
6169
+ const labelCaps = (0, _burojs_react.useI18nCaps)(resource);
6035
6170
  const tid = (0, _burojs_react.useTestIds)();
6036
6171
  const id = useFrameId();
6172
+ const back = (0, _burojs_react.useReturnTarget)(resource, mode === "create" ? "create" : "edit", mode === "edit" ? id : void 0);
6173
+ const failedIssues = chrome.serverIssues;
6174
+ const livePlan = controller.plan;
6175
+ const placed = (0, react.useMemo)(() => new Set(livePlan?.placedPaths ?? []), [livePlan]);
6176
+ const alertIssues = (0, react.useMemo)(() => failedIssues === void 0 || failedIssues.length === 0 ? NO_ALERT_ISSUES : (0, _burojs_core.routeServerIssues)({ issues: failedIssues }, (segment) => segment, (field, path) => field !== "_form" && (livePlan === null || livePlan.fields[field] === "active" && (0, _burojs_core_internal.deepestPlacedPath)(path, placed) !== void 0)).form, [
6177
+ failedIssues,
6178
+ livePlan,
6179
+ placed
6180
+ ]);
6181
+ const fieldDefs = app.registry.get(resource)?.fields;
6037
6182
  if (mode === "show") return null;
6038
- const busy = controller.isSubmitting;
6183
+ const busy = controller.isSubmitting || chrome.created === true;
6039
6184
  const cancel = () => {
6040
6185
  if (chrome.onCancel !== void 0) chrome.onCancel();
6041
- else navigate(mode === "edit" && id !== void 0 ? recordReturnTarget(app.registry, resource, id) : listTarget(resource));
6186
+ else navigate(back, { origin: "inherit" });
6042
6187
  };
6043
6188
  const plan = controller.plan;
6044
6189
  const undrawn = (field) => plan === null || plan.fields[field] === void 0 || plan.fields[field] === "inactive";
6045
- const recordLevel = (issue) => issue.field === "_form" || undrawn(issue.field);
6190
+ const recordLevel = (issue) => issue.field === "_form" || undrawn((0, _burojs_core_internal.pathHead)(issue.field)) || !placed.has(issue.field);
6046
6191
  const undrawnBlockers = (controller.checkOutcome?.blockers ?? []).flatMap((issue) => {
6047
6192
  const field = typeof issue.path?.[0] === "string" ? issue.path[0] : "_form";
6048
- if (field !== "_form" && !undrawn(field)) return [];
6193
+ if (field !== "_form" && !undrawn(field) && (0, _burojs_core_internal.deepestPlacedPath)(issue.path, placed) !== void 0) return [];
6049
6194
  if (controller.errors.some((own) => own.code === issue.code && own.field === field)) return [];
6050
6195
  return [{
6051
6196
  ...issue,
6052
- field
6197
+ field,
6198
+ path: field === "_form" ? [] : issue.path.slice(1)
6053
6199
  }];
6054
6200
  });
6055
6201
  const formErrors = firstPreferred([...controller.errors.filter(recordLevel), ...undrawnBlockers]);
@@ -6057,21 +6203,44 @@ function FormActionsView() {
6057
6203
  const text = (issue) => (0, _burojs_react.resolveValidationMessage)({
6058
6204
  code: issue.code ?? "",
6059
6205
  message: issue.message,
6060
- ...issue.params === void 0 ? {} : { params: issue.params }
6061
- }, { t });
6206
+ ...issue.check === void 0 ? {} : { check: issue.check }
6207
+ }, {
6208
+ has: caps.has,
6209
+ t: caps.t
6210
+ });
6062
6211
  const retryable = [];
6063
6212
  for (const issue of controller.checkOutcome?.blockers ?? []) {
6064
- const checkId = issue.params?.checkId;
6065
- if (issue.params?.cause === void 0 || typeof checkId !== "string") continue;
6213
+ const checkId = issue.check?.id;
6214
+ if (issue.check?.cause === void 0 || typeof checkId !== "string") continue;
6066
6215
  if (!retryable.includes(checkId)) retryable.push(checkId);
6067
6216
  }
6068
- const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, t);
6217
+ const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, chrome.submitApplied, t, caps);
6218
+ const serverIssues = bySeverity(alertIssues).flatMap((issue) => {
6219
+ const head = issue.path[0];
6220
+ const name = typeof head === "string" ? head : void 0;
6221
+ const declared = name === void 0 ? void 0 : fieldDefs?.[name];
6222
+ const message = (0, _burojs_react.resolveValidationMessage)({
6223
+ code: issue.code,
6224
+ message: issue.message,
6225
+ ...issue.check === void 0 ? {} : { check: issue.check }
6226
+ }, {
6227
+ has: caps.has,
6228
+ t: caps.t,
6229
+ ...declared === void 0 ? {} : { fieldKey: `resources.${resource}.fields.${name}` }
6230
+ });
6231
+ if (issue.path.length === 0 && message === failure) return [];
6232
+ return [{
6233
+ label: declared === void 0 || name === void 0 ? void 0 : (0, _burojs_core.resolveFieldLabel)(labelCaps, name, (0, _burojs_core.declaredText)("field", declared, "label")),
6234
+ message,
6235
+ severity: issue.severity
6236
+ }];
6237
+ });
6069
6238
  const steps = controller.steps;
6070
6239
  const midSteps = steps !== null && steps.ids.length > 1 && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1];
6071
6240
  return (0, react_jsx_runtime.jsxs)("div", {
6072
6241
  className: "flex flex-col gap-3",
6073
6242
  children: [
6074
- failure === void 0 && formErrors.length === 0 ? null : (0, react_jsx_runtime.jsxs)("div", {
6243
+ failure === void 0 && formErrors.length === 0 && serverIssues.length === 0 ? null : (0, react_jsx_runtime.jsxs)("div", {
6075
6244
  role: "alert",
6076
6245
  className: "flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive",
6077
6246
  children: [
@@ -6081,10 +6250,22 @@ function FormActionsView() {
6081
6250
  }),
6082
6251
  (0, react_jsx_runtime.jsxs)("div", {
6083
6252
  className: "leading-snug",
6084
- children: [failure === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
6085
- className: "font-medium",
6086
- children: failure
6087
- }), formErrors.map((issue) => (0, react_jsx_runtime.jsx)("p", { children: text(issue) }, issueKey(issue)))]
6253
+ children: [
6254
+ failure === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
6255
+ className: "font-medium",
6256
+ children: failure
6257
+ }),
6258
+ serverIssues.map((issue, index) => (0, react_jsx_runtime.jsxs)("p", {
6259
+ "data-testid": `form-server-issue:${resource}:${mode}:${index}`,
6260
+ "data-buro-severity": issue.severity,
6261
+ className: issue.severity === "error" ? void 0 : "text-warning-emphasis",
6262
+ children: [issue.label === void 0 ? null : (0, react_jsx_runtime.jsxs)("span", {
6263
+ className: "font-medium",
6264
+ children: [issue.label, ": "]
6265
+ }), issue.message]
6266
+ }, index)),
6267
+ formErrors.map((issue) => (0, react_jsx_runtime.jsx)("p", { children: text(issue) }, issueKey(issue)))
6268
+ ]
6088
6269
  }),
6089
6270
  failure !== void 0 && steps !== null ? (0, react_jsx_runtime.jsx)(require_button.Button, {
6090
6271
  type: "button",
@@ -6093,7 +6274,7 @@ function FormActionsView() {
6093
6274
  className: "ml-auto",
6094
6275
  onMouseDown: (event) => event.preventDefault(),
6095
6276
  onClick: () => void chrome.submit(),
6096
- children: t("actions.retry", { defaultValue: "Retry" })
6277
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
6097
6278
  }) : null
6098
6279
  ]
6099
6280
  }),
@@ -6105,7 +6286,7 @@ function FormActionsView() {
6105
6286
  size: "sm",
6106
6287
  "data-testid": `form-check-retry:${checkId}`,
6107
6288
  onClick: () => void controller.revalidate(),
6108
- children: t("actions.retry", { defaultValue: "Retry" })
6289
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
6109
6290
  }, checkId))
6110
6291
  }),
6111
6292
  formWarnings.length === 0 ? null : (0, react_jsx_runtime.jsxs)("div", {
@@ -6131,7 +6312,7 @@ function FormActionsView() {
6131
6312
  children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLoader2, {
6132
6313
  className: "h-3.5 w-3.5 animate-spin",
6133
6314
  "aria-hidden": "true"
6134
- }), (0, react_jsx_runtime.jsx)("span", { children: t("actions.validating", { defaultValue: "Validating…" }) })]
6315
+ }), (0, react_jsx_runtime.jsx)("span", { children: chromeT("actions.validating", { defaultValue: "Validating…" }) })]
6135
6316
  }) : null,
6136
6317
  (0, react_jsx_runtime.jsx)(require_button.Button, {
6137
6318
  type: "button",
@@ -6139,7 +6320,7 @@ function FormActionsView() {
6139
6320
  onClick: cancel,
6140
6321
  onMouseDown: (event) => event.preventDefault(),
6141
6322
  "data-testid": tid.formCancel(resource, mode),
6142
- children: t("actions.cancel", { defaultValue: "Cancel" })
6323
+ children: chromeT("actions.cancel", { defaultValue: "Cancel" })
6143
6324
  }),
6144
6325
  midSteps ? null : (0, react_jsx_runtime.jsxs)(require_button.Button, {
6145
6326
  type: "submit",
@@ -6156,37 +6337,71 @@ function FormActionsView() {
6156
6337
  children: [busy ? (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLoader2, {
6157
6338
  className: "mr-2 h-4 w-4 animate-spin",
6158
6339
  "aria-hidden": "true"
6159
- }) : null, busy ? mode === "edit" ? t("actions.saving", { defaultValue: "Saving…" }) : t("actions.creating", { defaultValue: "Creating…" }) : chrome.submitLabel ?? (mode === "edit" ? t("actions.save", { defaultValue: "Save" }) : t("actions.create", { defaultValue: "Create" }))]
6340
+ }) : null, busy ? mode === "edit" ? chromeT("actions.saving", { defaultValue: "Saving…" }) : chromeT("actions.creating", { defaultValue: "Creating…" }) : chrome.submitLabel ?? (mode === "edit" ? chromeT("actions.save", { defaultValue: "Save" }) : chromeT("actions.create", { defaultValue: "Create" }))]
6160
6341
  })
6161
6342
  ]
6162
6343
  })
6163
6344
  ]
6164
6345
  });
6165
6346
  }
6347
+ const NO_ALERT_ISSUES = Object.freeze([]);
6348
+ const SEVERITY_RANK = {
6349
+ error: 0,
6350
+ warning: 1,
6351
+ info: 2
6352
+ };
6353
+ function bySeverity(issues) {
6354
+ return [...issues].sort((a, b) => (SEVERITY_RANK[a.severity] ?? 3) - (SEVERITY_RANK[b.severity] ?? 3));
6355
+ }
6166
6356
  function firstPreferred(issues) {
6167
- const first = issues.find((issue) => issue.params?.checkId === void 0) ?? issues[0];
6357
+ const first = issues.find((issue) => issue.check?.id === void 0) ?? issues[0];
6168
6358
  return first === void 0 ? [] : [first];
6169
6359
  }
6170
6360
  function issueKey(issue) {
6171
6361
  return JSON.stringify([
6172
6362
  issue.code ?? "",
6173
6363
  issue.message.key,
6174
- issue.params ?? null
6364
+ issue.check?.id ?? null
6175
6365
  ]);
6176
6366
  }
6177
- function failureText(error, t) {
6178
- const friendly = require_toaster.toFriendlyError(safeMessage(error), void 0, require_toaster.friendlyStringsFrom(t));
6179
- return friendly.replaced ? friendly.title : t("errors.failed", { defaultValue: "Failed" });
6367
+ function failureText(error, settled, t, caps) {
6368
+ const texts = require_toaster.technicalTexts(error).filter((text) => text.length <= 1024);
6369
+ const strings = require_toaster.friendlyStringsFrom(t);
6370
+ const friendly = texts.map((text) => require_toaster.toFriendlyError(text, void 0, strings)).find((f) => f.replaced) ?? require_toaster.toFriendlyError(texts[0], void 0, strings);
6371
+ const applied = settled ?? ownDataProperty(error, "applied");
6372
+ if (applied === "partial" || applied === "unknown") {
6373
+ const key = applied === "partial" ? "errors.partlyApplied" : "errors.mayHaveBeenApplied";
6374
+ const sentence = caps.has(key) ? caps.t(key) : applied === "partial" ? "Part of this may have been saved. Check the record before trying again." : "It may have been saved. Check the record before trying again.";
6375
+ const lead = texts.some(require_toaster.isNetworkFailure) ? strings.offline : "";
6376
+ return lead === "" ? sentence : `${lead} ${sentence}`;
6377
+ }
6378
+ const code = ownDataProperty(error, "code");
6379
+ const kind = ownDataProperty(error, "kind");
6380
+ const hasOwnSentence = typeof code === "string" && typeof kind === "string" && kind !== "transport" && Object.hasOwn(_burojs_react.RECORD_KIND_KEYS, kind);
6381
+ const message = ownDataProperty(error, "message");
6382
+ if (friendly.replaced && !hasOwnSentence) return (typeof code === "string" ? (0, _burojs_react.specificErrorText)({
6383
+ code,
6384
+ ...isMessageReference(message) ? { message } : {}
6385
+ }, caps, { record: true }) : void 0) ?? friendly.title;
6386
+ if (typeof code !== "string") return strings.title;
6387
+ const reference = {
6388
+ code,
6389
+ ...isMessageReference(message) ? { message } : {}
6390
+ };
6391
+ return (0, _burojs_react.specificErrorText)(reference, caps, { record: true }) ?? (typeof kind === "string" ? (0, _burojs_react.kindErrorText)(kind, caps, { record: true }) : void 0) ?? strings.title;
6180
6392
  }
6181
- function safeMessage(error) {
6393
+ function ownDataProperty(error, name) {
6182
6394
  if (error === null || typeof error !== "object") return void 0;
6183
6395
  try {
6184
- const descriptor = Object.getOwnPropertyDescriptor(error, "message");
6185
- return descriptor !== void 0 && "value" in descriptor && typeof descriptor.value === "string" && descriptor.value.length <= 1024 ? descriptor.value : void 0;
6396
+ const descriptor = Object.getOwnPropertyDescriptor(error, name);
6397
+ return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
6186
6398
  } catch {
6187
6399
  return;
6188
6400
  }
6189
6401
  }
6402
+ function isMessageReference(value) {
6403
+ return value !== null && typeof value === "object" && typeof value.key === "string";
6404
+ }
6190
6405
  function inlineFlowNames(screen, plan) {
6191
6406
  if (screen === null) return [];
6192
6407
  const names = [];
@@ -6459,31 +6674,35 @@ function PlannedFrame(props) {
6459
6674
  })
6460
6675
  }, name);
6461
6676
  const { PlacementScope } = page;
6677
+ const claimedRoute = (0, react.useContext)(_burojs_react.RouteSourceContext);
6462
6678
  const itemNode = page.plan.slots.item?.[0];
6463
6679
  const item = (0, react.useMemo)(() => itemNode === void 0 ? void 0 : itemHandle(itemNode), [itemNode]);
6464
6680
  return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
6465
6681
  value: null,
6466
- children: (0, react_jsx_runtime.jsx)(PlacementScope, { children: (0, react_jsx_runtime.jsx)(ScreenTreeScope, {
6467
- resource,
6468
- mode: "show",
6469
- compiled,
6470
- page,
6471
- children: (0, react_jsx_runtime.jsx)(ListItemContext.Provider, {
6472
- value: item,
6473
- children: (0, react_jsx_runtime.jsx)(FrameView, {
6474
- resource,
6475
- compiled,
6476
- slots
6477
- })
6478
- })
6479
- }) })
6682
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ActionRouteContext.Provider, {
6683
+ value: claimedRoute,
6684
+ children: (0, react_jsx_runtime.jsx)(PlacementScope, { children: (0, react_jsx_runtime.jsx)(ScreenTreeScope, {
6685
+ resource,
6686
+ mode: "show",
6687
+ compiled,
6688
+ page,
6689
+ children: (0, react_jsx_runtime.jsx)(ListItemContext.Provider, {
6690
+ value: item,
6691
+ children: (0, react_jsx_runtime.jsx)(FrameView, {
6692
+ resource,
6693
+ compiled,
6694
+ slots
6695
+ })
6696
+ })
6697
+ }) })
6698
+ })
6480
6699
  });
6481
6700
  }
6482
6701
  function ListFrameHost({ resource }) {
6483
6702
  const compiled = useCompiledListScreen(resource);
6484
6703
  const hasDataRuntime = (0, _burojs_react.useOptionalDataRuntime)() !== null;
6485
6704
  const { def } = (0, _burojs_react.useResourceListContext)();
6486
- const rowsView = (def?.views?.list)?.view ?? "table";
6705
+ const rowsView = def?.views?.list?.initial?.view ?? "table";
6487
6706
  if (compiled === null) return (0, react_jsx_runtime.jsx)(Arrangement, {});
6488
6707
  if (compiled.nodes.length === 0 && rowsView === "table") {
6489
6708
  const empty = {};
@@ -6502,8 +6721,12 @@ function ListFrameHost({ resource }) {
6502
6721
  }
6503
6722
  //#endregion
6504
6723
  //#region src/list-kit/resource-list-surface.tsx
6505
- const RelatedCards = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-cards-CFq3meUn.cjs"))).RelatedCards }));
6506
- const RelatedTimeline = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-timeline-CCzl71aA.cjs"))).RelatedTimeline }));
6724
+ function declaresDisplay(field) {
6725
+ return field !== void 0 && (0, _burojs_core.resolveSurfaceUi)(field, "column").use !== void 0;
6726
+ }
6727
+ const NO_INITIAL_FILTERS = Object.freeze({});
6728
+ const RelatedCards = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-cards-Bc_vfCE_.cjs"))).RelatedCards }));
6729
+ const RelatedTimeline = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-timeline-k0DtnxTs.cjs"))).RelatedTimeline }));
6507
6730
  function discriminatorOptionLabel(field, value) {
6508
6731
  const text = (0, _burojs_core.fieldOptionText)(field, value);
6509
6732
  if (text !== void 0) return text;
@@ -6511,10 +6734,17 @@ function discriminatorOptionLabel(field, value) {
6511
6734
  const label = (Array.isArray(declared?.options) ? declared.options : Array.isArray(declared?.meta?.options) ? declared.meta.options : []).find((option) => option?.value === value)?.label;
6512
6735
  return typeof label === "string" ? label : value;
6513
6736
  }
6514
- function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize, search: searchField, columns: columnNames, open, title, scope, view, item, placementKey, onCreate, count: countPolicy, rowTarget, readOnly, exportable, meta, renderCell, emptyState }) {
6737
+ function declaredInitialSort(def) {
6738
+ return def?.views?.list?.initial?.sort;
6739
+ }
6740
+ function declaredRouteView(def) {
6741
+ return def?.views?.list?.initial?.view;
6742
+ }
6743
+ function ResourceListSurface({ resource, variant, state, fixedFilters, initial, search: searchField, columns: columnEntries, open, title, empty, scope, view, item, placementKey, onCreate, count: countPolicy, rowTarget, readOnly, linkEditing, exportable, layoutId, meta, renderCell, emptyState }) {
6515
6744
  const route = variant === "route";
6516
6745
  const t = (0, _burojs_react.useT)();
6517
6746
  const optionalT = (0, _burojs_react.useOptionalT)();
6747
+ const chromeT = (0, _burojs_react.useChromeT)();
6518
6748
  const tid = (0, _burojs_react.useTestIds)();
6519
6749
  const listCaps = (0, _burojs_react.useI18nCaps)(resource);
6520
6750
  const RouteFiltersSlot = require_check_confirm_dialog.useListSlot("filters", resource);
@@ -6529,17 +6759,45 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6529
6759
  console.error(`[burojs] list.body-removed: list.body.${require_check_confirm_dialog.canonicalResourceName(resource)} is no longer rendered; a whole-body override is a list frame (views.list.frame).`);
6530
6760
  }, [removedBody, resource]);
6531
6761
  const searchDecl = (0, react.useMemo)(() => searchField === void 0 ? void 0 : { fields: [searchField] }, [searchField]);
6532
- const list = (0, _burojs_react.useResourceList)(resource, route ? { meta } : {
6762
+ const appRegistry = (0, _burojs_react.useApp)().registry;
6763
+ const effectiveView = route ? declaredRouteView(appRegistry.get(resource)) ?? "table" : view ?? "table";
6764
+ const timeline = effectiveView === "timeline";
6765
+ const initialKey = JSON.stringify(initial ?? null);
6766
+ const placementInitial = (0, react.useMemo)(() => route ? void 0 : {
6767
+ ...initial,
6768
+ filters: initial?.filters ?? NO_INITIAL_FILTERS
6769
+ }, [route, initialKey]);
6770
+ const timelineAxis = (placementInitial?.sort ?? declaredInitialSort(appRegistry.get(resource)))?.[0]?.field;
6771
+ const columnNames = (0, react.useMemo)(() => columnEntries?.map(_burojs_core.columnName), [columnEntries]);
6772
+ const list = (0, _burojs_react.useResourceList)(resource, route ? {
6773
+ meta,
6774
+ ...timeline ? { timeline } : {}
6775
+ } : {
6776
+ ...timeline ? { timeline } : {},
6533
6777
  ...state === void 0 ? {} : { state },
6534
6778
  ...fixedFilters === void 0 ? {} : { fixedFilters },
6535
- ...pageSize === void 0 ? {} : { pageSize },
6779
+ ...placementInitial === void 0 ? {} : { initial: placementInitial },
6536
6780
  ...searchDecl === void 0 ? {} : { search: searchDecl },
6537
- ...columnNames === void 0 ? {} : { columns: columnNames },
6781
+ ...columnEntries === void 0 ? {} : { columns: columnEntries },
6538
6782
  ...scope === void 0 ? {} : { scope },
6539
6783
  ...countPolicy === void 0 ? {} : { countPolicy }
6540
6784
  });
6541
6785
  const { def, query, pagination, cursor, count, filters, sorting, columns, selection, savedViews, routing, live, droppedPredicates } = list;
6542
6786
  (0, _burojs_react.policyRowsOf)(list, list.rows);
6787
+ const selectionRef = (0, react.useRef)(selection);
6788
+ selectionRef.current = selection;
6789
+ const onDetach = linkEditing?.detach?.onDetach;
6790
+ const surfaceLinkEditing = (0, react.useMemo)(() => onDetach === void 0 ? void 0 : { detach: { onDetach: async (detached) => {
6791
+ const left = await onDetach(detached);
6792
+ if (left.length > 0) {
6793
+ const gone = new Set(left);
6794
+ const current = selectionRef.current;
6795
+ if (current.ids.some((id) => gone.has(id))) current.set(current.ids.filter((id) => !gone.has(id)));
6796
+ }
6797
+ return left;
6798
+ } } }, [onDetach]);
6799
+ const onAttach = linkEditing?.attach?.onAttach;
6800
+ const attachBusy = linkEditing?.attach?.busy === true;
6543
6801
  const hasDataRuntime = (0, _burojs_react.useOptionalDataRuntime)() !== null;
6544
6802
  const scopeLabel = (scope) => scope.id === _burojs_react.LOCAL_USER_SCOPE_ID ? t("toolbar.viewsMyScope") : scope.label;
6545
6803
  const createAvailable = (0, _burojs_react.useAvailability)(resource, "create").state === "available";
@@ -6587,7 +6845,6 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6587
6845
  resource,
6588
6846
  routing.rowHref
6589
6847
  ]);
6590
- const effectiveView = route ? (def?.views?.list)?.view ?? "table" : view ?? "table";
6591
6848
  const tableView = effectiveView === "table";
6592
6849
  const rowsViewFor = (0, react.useMemo)(() => tableView ? void 0 : (planned) => ({
6593
6850
  skeleton: effectiveView === "cards" ? (0, react_jsx_runtime.jsx)(RelatedCardsSkeleton, {}) : (0, react_jsx_runtime.jsx)(RelatedTimelineSkeleton, {}),
@@ -6599,11 +6856,15 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6599
6856
  item: route ? planned : item,
6600
6857
  columns: route ? columns.visible : columnNames,
6601
6858
  rowQuick,
6602
- rowHref
6859
+ rowHref,
6860
+ ...empty === void 0 ? {} : { empty }
6603
6861
  };
6604
6862
  return (0, react_jsx_runtime.jsx)(react.Suspense, {
6605
6863
  fallback: effectiveView === "cards" ? (0, react_jsx_runtime.jsx)(RelatedCardsSkeleton, {}) : (0, react_jsx_runtime.jsx)(RelatedTimelineSkeleton, {}),
6606
- children: effectiveView === "cards" ? (0, react_jsx_runtime.jsx)(RelatedCards, { ...common }) : (0, react_jsx_runtime.jsx)(RelatedTimeline, { ...common })
6864
+ children: effectiveView === "cards" ? (0, react_jsx_runtime.jsx)(RelatedCards, { ...common }) : (0, react_jsx_runtime.jsx)(RelatedTimeline, {
6865
+ ...common,
6866
+ axis: timelineAxis
6867
+ })
6607
6868
  });
6608
6869
  }
6609
6870
  }), [
@@ -6616,7 +6877,9 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6616
6877
  columns.visible,
6617
6878
  columnNames,
6618
6879
  rowQuick,
6619
- rowHref
6880
+ rowHref,
6881
+ empty,
6882
+ timelineAxis
6620
6883
  ]);
6621
6884
  const pageTitle = (0, _burojs_core.resolveResourceLabel)(listCaps, resource, "plural", def);
6622
6885
  const [saveOpen, setSaveOpen] = (0, react.useState)(false);
@@ -6698,6 +6961,10 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6698
6961
  sonner.toast.error(t("toolbar.viewsForkFailed"));
6699
6962
  }
6700
6963
  };
6964
+ const columnNamesDisplay = (col, field) => {
6965
+ const resolved = list.columns.ui[col];
6966
+ return resolved === void 0 ? declaresDisplay(field) : resolved.display.use !== void 0;
6967
+ };
6701
6968
  const renderCellLadder = (col, value, row) => {
6702
6969
  if (def?.types && col === def.types.by) {
6703
6970
  const raw = typeof value === "string" ? value : "";
@@ -6716,13 +6983,14 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6716
6983
  children: label
6717
6984
  });
6718
6985
  }
6986
+ const custom = (renderCell ?? CellSlot)?.(col, value, row);
6987
+ if (custom !== void 0) return custom;
6719
6988
  const fieldDef = def?.fields[col];
6720
- const enumName = fieldDef?.opts?.enum ?? fieldDef?.ui?.enum;
6721
- if (enumName && typeof value === "string") return (0, react_jsx_runtime.jsx)(EnumBadge, {
6989
+ const enumName = (0, _burojs_core_internal.enumBindingKey)(fieldDef?.opts?.enum ?? fieldDef?.ui?.enum);
6990
+ if (enumName && typeof value === "string" && !columnNamesDisplay(col, fieldDef)) return (0, react_jsx_runtime.jsx)(EnumBadge, {
6722
6991
  enumName,
6723
6992
  value
6724
6993
  });
6725
- return (renderCell ?? CellSlot)?.(col, value, row);
6726
6994
  };
6727
6995
  const surface = {
6728
6996
  resource,
@@ -6750,10 +7018,16 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6750
7018
  }
6751
7019
  },
6752
7020
  rowsViewFor,
6753
- emptyState,
7021
+ emptyState: empty !== void 0 && !list.filters.isFiltered && list.pagination.page <= 1 && (list.cursor === null || list.cursor.next === null) ? (0, react_jsx_runtime.jsx)("p", {
7022
+ "data-buro-region": "empty",
7023
+ className: "text-sm text-muted-foreground",
7024
+ children: empty
7025
+ }) : emptyState,
6754
7026
  renderCell: renderCellLadder,
6755
7027
  readOnly: readOnly === true,
6756
- exportable: exportable !== false
7028
+ exportable: exportable !== false,
7029
+ ...layoutId === void 0 ? {} : { layoutId },
7030
+ ...surfaceLinkEditing === void 0 ? {} : { linkEditing: surfaceLinkEditing }
6757
7031
  };
6758
7032
  return (0, react_jsx_runtime.jsx)(_burojs_react.ResourceListProvider, {
6759
7033
  value: list,
@@ -6766,22 +7040,44 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6766
7040
  resource,
6767
7041
  mode: "list",
6768
7042
  title: pageTitle
6769
- }) : title === void 0 && onCreate === void 0 ? null : (0, react_jsx_runtime.jsxs)("div", {
7043
+ }) : title === void 0 && onCreate === void 0 && onAttach === void 0 ? null : (0, react_jsx_runtime.jsxs)("div", {
6770
7044
  className: "flex items-center justify-between gap-2",
6771
- children: [title === void 0 ? (0, react_jsx_runtime.jsx)("span", {}) : (0, react_jsx_runtime.jsx)("h3", {
6772
- className: "text-sm font-semibold",
6773
- children: title
6774
- }), onCreate === void 0 ? null : (0, react_jsx_runtime.jsxs)(require_button.Button, {
6775
- type: "button",
6776
- size: "sm",
6777
- variant: "outline",
6778
- "data-testid": `list-create:${resource}`,
6779
- onClick: onCreate,
6780
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPlus, {
6781
- className: "mr-1 h-4 w-4",
6782
- "aria-hidden": "true"
6783
- }), optionalT("actions.create", { defaultValue: "Create" })]
6784
- })]
7045
+ children: [
7046
+ title === void 0 ? (0, react_jsx_runtime.jsx)("span", {}) : (0, react_jsx_runtime.jsx)("h3", {
7047
+ className: "text-sm font-semibold",
7048
+ children: title
7049
+ }),
7050
+ onAttach === void 0 ? null : (0, react_jsx_runtime.jsxs)(require_button.Button, {
7051
+ type: "button",
7052
+ size: "sm",
7053
+ variant: "outline",
7054
+ "data-testid": `list-link-attach:${resource}`,
7055
+ onClick: onAttach,
7056
+ disabled: attachBusy,
7057
+ "aria-busy": attachBusy,
7058
+ children: [attachBusy ? (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLoader2, {
7059
+ className: "mr-1 h-4 w-4 animate-spin",
7060
+ "aria-hidden": "true"
7061
+ }) : (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconLink, {
7062
+ className: "mr-1 h-4 w-4",
7063
+ "aria-hidden": "true"
7064
+ }), optionalT("field.link.attach", { defaultValue: "Attach" })]
7065
+ }),
7066
+ onCreate === void 0 ? null : (0, react_jsx_runtime.jsxs)(require_button.Button, {
7067
+ type: "button",
7068
+ size: "sm",
7069
+ variant: "outline",
7070
+ "data-testid": `list-create:${resource}`,
7071
+ onClick: onCreate,
7072
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPlus, {
7073
+ className: "mr-1 h-4 w-4",
7074
+ "aria-hidden": "true"
7075
+ }), optionalT("actions.create", {
7076
+ resource,
7077
+ defaultValue: "Create"
7078
+ })]
7079
+ })
7080
+ ]
6785
7081
  }),
6786
7082
  hasDataRuntime && (0, react_jsx_runtime.jsx)(ExportRunWatcherMount, {}),
6787
7083
  droppedPredicates > 0 && (0, react_jsx_runtime.jsx)("p", {
@@ -6830,13 +7126,13 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6830
7126
  variant: "outline",
6831
7127
  onClick: () => setSaveOpen(false),
6832
7128
  "data-testid": `list-saved-view-save-cancel:${resource}`,
6833
- children: t("actions.cancel")
7129
+ children: chromeT("actions.cancel")
6834
7130
  }), (0, react_jsx_runtime.jsx)(require_button.Button, {
6835
7131
  type: "button",
6836
7132
  onClick: handleSaveConfirm,
6837
7133
  disabled: saveLabel.trim().length === 0,
6838
7134
  "data-testid": `list-saved-view-save-confirm:${resource}`,
6839
- children: t("actions.save")
7135
+ children: chromeT("actions.save")
6840
7136
  })] })
6841
7137
  ]
6842
7138
  })
@@ -6873,7 +7169,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6873
7169
  variant: "outline",
6874
7170
  onClick: () => handleDeleteUserView(entry.id),
6875
7171
  "data-testid": `list-saved-view-manage-delete:${resource}:${entry.id}`,
6876
- children: t("actions.delete")
7172
+ children: chromeT("actions.delete")
6877
7173
  }) : (0, react_jsx_runtime.jsx)("span", {
6878
7174
  className: "shrink-0 text-xs text-muted-foreground",
6879
7175
  children: t("toolbar.viewsReadOnly")
@@ -6885,7 +7181,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6885
7181
  variant: "outline",
6886
7182
  onClick: () => setManageOpen(false),
6887
7183
  "data-testid": `list-saved-view-manage-close:${resource}`,
6888
- children: t("actions.close")
7184
+ children: chromeT("actions.close")
6889
7185
  }) })
6890
7186
  ]
6891
7187
  })
@@ -6918,13 +7214,13 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6918
7214
  setRenameTarget(null);
6919
7215
  },
6920
7216
  "data-testid": `list-saved-view-rename-cancel:${resource}`,
6921
- children: t("actions.cancel")
7217
+ children: chromeT("actions.cancel")
6922
7218
  }), (0, react_jsx_runtime.jsx)(require_button.Button, {
6923
7219
  type: "button",
6924
7220
  onClick: handleRenameConfirm,
6925
7221
  disabled: renameLabel.trim().length === 0,
6926
7222
  "data-testid": `list-saved-view-rename-confirm:${resource}`,
6927
- children: t("actions.save")
7223
+ children: chromeT("actions.save")
6928
7224
  })] })
6929
7225
  ]
6930
7226
  })
@@ -6959,7 +7255,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6959
7255
  setForkTarget(null);
6960
7256
  },
6961
7257
  "data-testid": `list-saved-view-fork-cancel:${resource}`,
6962
- children: t("actions.cancel")
7258
+ children: chromeT("actions.cancel")
6963
7259
  }), (0, react_jsx_runtime.jsx)(require_button.Button, {
6964
7260
  type: "button",
6965
7261
  onClick: handleForkConfirm,
@@ -6982,6 +7278,582 @@ function ExportRunWatcherMount() {
6982
7278
  return null;
6983
7279
  }
6984
7280
  //#endregion
7281
+ //#region src/fields/use-relation-picker.tsx
7282
+ const noop = () => void 0;
7283
+ function safeKey(input) {
7284
+ if (input === void 0 || input === null) return void 0;
7285
+ try {
7286
+ return (0, _burojs_core.resourceKey)(input);
7287
+ } catch {
7288
+ return;
7289
+ }
7290
+ }
7291
+ function sessionIdentity(runtime) {
7292
+ const state = runtime.dataSession.getState();
7293
+ const snapshot = state.status === "ready" ? state.snapshot : state.target;
7294
+ const selection = snapshot.scope?.selection;
7295
+ const partition = selection === void 0 ? snapshot.scopeKey : [snapshot.scopeKey, selection];
7296
+ let scopeKey;
7297
+ try {
7298
+ scopeKey = JSON.stringify(partition) ?? "";
7299
+ } catch {
7300
+ scopeKey = String(snapshot.scopeKey);
7301
+ }
7302
+ return {
7303
+ sessionKey: snapshot.sessionKey,
7304
+ scopeKey
7305
+ };
7306
+ }
7307
+ function PickerHost(props) {
7308
+ const { register } = props;
7309
+ react.useEffect(() => register(), [register]);
7310
+ return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: props.children });
7311
+ }
7312
+ function useRelationPicker(options) {
7313
+ const app = (0, _burojs_react.useApp)();
7314
+ const runtime = (0, _burojs_react.useDataRuntime)();
7315
+ const frame = (0, _burojs_react.useOptionalRecordFrame)();
7316
+ const frames = (0, _burojs_react.useRecordScopeFrames)();
7317
+ const multiple = options.multiple === true;
7318
+ const fieldName = options.field;
7319
+ let to;
7320
+ let declaredBy;
7321
+ let declaredCandidates;
7322
+ if (fieldName !== void 0) {
7323
+ const meta = ((frame === null ? void 0 : app.registry.get(frame.resource)?.fields)?.[fieldName])?.meta;
7324
+ to = safeKey(meta?.to);
7325
+ declaredBy = typeof meta?.by === "string" ? meta.by : void 0;
7326
+ declaredCandidates = Array.isArray(meta?.candidates) ? meta.candidates : void 0;
7327
+ } else to = safeKey(options.to);
7328
+ const target = to ?? "";
7329
+ const by = options.valueField ?? declaredBy;
7330
+ const scope = options.scope ?? "context";
7331
+ const selection = require_lazy_relation_picker_dialog.useCandidateSelection({
7332
+ to,
7333
+ candidates: options.candidates ?? declaredCandidates,
7334
+ sources: frame?.controller.sources,
7335
+ resource: frame?.resource ?? "",
7336
+ fieldName: fieldName ?? target,
7337
+ fixedFilters: options.fixedFilters
7338
+ });
7339
+ const held = selection.gate !== void 0;
7340
+ const pendingRef = react.useRef(null);
7341
+ const [active, setActive] = react.useState(null);
7342
+ const activeRef = react.useRef(null);
7343
+ activeRef.current = active;
7344
+ const rowsRef = react.useRef(new Map());
7345
+ const createdRowRef = react.useRef(void 0);
7346
+ const alive = react.useRef(true);
7347
+ const mounts = react.useRef(0);
7348
+ const sequence = react.useRef(0);
7349
+ const latest = react.useRef({
7350
+ multiple,
7351
+ select: options.select,
7352
+ idField: "id",
7353
+ valueField: "id",
7354
+ available: false,
7355
+ frames
7356
+ });
7357
+ const project = react.useCallback((row) => {
7358
+ const select = latest.current.select;
7359
+ if (select === void 0) return { ...row };
7360
+ const out = {};
7361
+ const key = row[latest.current.idField] !== void 0 ? row[latest.current.idField] : row.id;
7362
+ if (key !== void 0) out.id = key;
7363
+ const { valueField } = latest.current;
7364
+ if (Object.hasOwn(row, valueField)) out[valueField] = row[valueField];
7365
+ for (const name of select) if (Object.hasOwn(row, name)) out[name] = row[name];
7366
+ return out;
7367
+ }, []);
7368
+ const settle = react.useCallback((result) => {
7369
+ const pending = pendingRef.current;
7370
+ if (pending === null) return;
7371
+ pendingRef.current = null;
7372
+ pending.detach();
7373
+ if (alive.current) setActive(null);
7374
+ pending.resolve(result);
7375
+ }, []);
7376
+ const toggle = react.useCallback((key, row) => {
7377
+ setActive((current) => {
7378
+ if (current === null) return current;
7379
+ const has = current.selected.some((k) => String(k) === String(key));
7380
+ if (has) rowsRef.current.delete(String(key));
7381
+ else if (row !== void 0) rowsRef.current.set(String(key), row);
7382
+ const selected = has ? current.selected.filter((k) => String(k) !== String(key)) : [...current.selected, key];
7383
+ const next = {
7384
+ ...current,
7385
+ selected
7386
+ };
7387
+ activeRef.current = next;
7388
+ return next;
7389
+ });
7390
+ }, []);
7391
+ const onValue = react.useCallback((value) => {
7392
+ const row = createdRowRef.current;
7393
+ createdRowRef.current = void 0;
7394
+ if (latest.current.multiple) {
7395
+ const current = activeRef.current;
7396
+ if (current !== null && !current.selected.some((k) => String(k) === String(value))) toggle(value, row);
7397
+ return;
7398
+ }
7399
+ settle({
7400
+ kind: "selected",
7401
+ keys: [value],
7402
+ rows: row === void 0 ? [] : [project(row)]
7403
+ });
7404
+ }, [
7405
+ project,
7406
+ settle,
7407
+ toggle
7408
+ ]);
7409
+ const wiring = require_relation_select.useRelationSelect({
7410
+ to: target,
7411
+ by,
7412
+ fixedFilters: selection.fixedFilters,
7413
+ scope,
7414
+ ...fieldName === void 0 ? {} : { scopeField: fieldName },
7415
+ held,
7416
+ onValue
7417
+ });
7418
+ latest.current = {
7419
+ multiple,
7420
+ select: options.select,
7421
+ idField: wiring.idField,
7422
+ valueField: wiring.valueField,
7423
+ available: to !== void 0 && wiring.targetDef !== void 0 && !held,
7424
+ frames
7425
+ };
7426
+ const { create: shared } = wiring;
7427
+ const create = react.useMemo(() => ({
7428
+ ...shared,
7429
+ start: (openCreate) => shared.start(() => {
7430
+ const opened = openCreate();
7431
+ opened.then((row) => {
7432
+ createdRowRef.current = row === null ? void 0 : { ...row };
7433
+ }, noop);
7434
+ return opened;
7435
+ })
7436
+ }), [shared]);
7437
+ react.useEffect(() => runtime.dataSession.subscribe(() => {
7438
+ const pending = pendingRef.current;
7439
+ if (pending === null) return;
7440
+ const now = sessionIdentity(runtime);
7441
+ if (now.sessionKey !== pending.sessionKey || now.scopeKey !== pending.scopeKey) settle({
7442
+ kind: "cancelled",
7443
+ reason: "session-changed"
7444
+ });
7445
+ }), [runtime, settle]);
7446
+ react.useEffect(() => {
7447
+ alive.current = true;
7448
+ return () => {
7449
+ alive.current = false;
7450
+ settle({
7451
+ kind: "cancelled",
7452
+ reason: "unmounted"
7453
+ });
7454
+ };
7455
+ }, [settle]);
7456
+ react.useEffect(() => {
7457
+ if (held) settle({
7458
+ kind: "cancelled",
7459
+ reason: "unavailable"
7460
+ });
7461
+ }, [held, settle]);
7462
+ const register = react.useCallback(() => {
7463
+ mounts.current += 1;
7464
+ return () => {
7465
+ mounts.current -= 1;
7466
+ if (mounts.current === 0) settle({
7467
+ kind: "cancelled",
7468
+ reason: "unmounted"
7469
+ });
7470
+ };
7471
+ }, [settle]);
7472
+ const open = react.useCallback((opts = {}) => new Promise((resolve) => {
7473
+ settle({
7474
+ kind: "cancelled",
7475
+ reason: "superseded"
7476
+ });
7477
+ if (mounts.current === 0) {
7478
+ if (process.env.NODE_ENV !== "production") console.error("[burojs] useRelationPicker: open() was called but its element is not rendered — render `handle.element` once in your tree.");
7479
+ resolve({
7480
+ kind: "cancelled",
7481
+ reason: "not-mounted"
7482
+ });
7483
+ return;
7484
+ }
7485
+ const { signal } = opts;
7486
+ if (signal?.aborted === true) {
7487
+ resolve({
7488
+ kind: "cancelled",
7489
+ reason: "aborted"
7490
+ });
7491
+ return;
7492
+ }
7493
+ if (!latest.current.available) {
7494
+ resolve({
7495
+ kind: "cancelled",
7496
+ reason: "unavailable"
7497
+ });
7498
+ return;
7499
+ }
7500
+ sequence.current += 1;
7501
+ const id = sequence.current;
7502
+ const onAbort = () => {
7503
+ if (pendingRef.current?.id === id) settle({
7504
+ kind: "cancelled",
7505
+ reason: "aborted"
7506
+ });
7507
+ };
7508
+ signal?.addEventListener("abort", onAbort, { once: true });
7509
+ pendingRef.current = {
7510
+ id,
7511
+ ...sessionIdentity(runtime),
7512
+ resolve,
7513
+ detach: () => signal?.removeEventListener("abort", onAbort)
7514
+ };
7515
+ rowsRef.current = new Map();
7516
+ createdRowRef.current = void 0;
7517
+ const next = {
7518
+ id,
7519
+ frames: latest.current.frames,
7520
+ selected: opts.selected ?? []
7521
+ };
7522
+ activeRef.current = next;
7523
+ setActive(next);
7524
+ }), [runtime, settle]);
7525
+ const onSelectRow = react.useCallback((row) => {
7526
+ const field = wiring.valueField;
7527
+ const value = field === "id" ? row.id : row[field];
7528
+ if (typeof value !== "string" && typeof value !== "number") return;
7529
+ settle({
7530
+ kind: "selected",
7531
+ keys: [value],
7532
+ rows: [project(row)]
7533
+ });
7534
+ }, [
7535
+ wiring.valueField,
7536
+ settle,
7537
+ project
7538
+ ]);
7539
+ const onDone = react.useCallback(() => {
7540
+ const keys = activeRef.current?.selected ?? [];
7541
+ const rows = keys.flatMap((key) => {
7542
+ const row = rowsRef.current.get(String(key));
7543
+ return row === void 0 ? [] : [project(row)];
7544
+ });
7545
+ settle({
7546
+ kind: "selected",
7547
+ keys,
7548
+ rows
7549
+ });
7550
+ }, [settle, project]);
7551
+ const onOpenChange = react.useCallback((next) => {
7552
+ if (!next) settle({
7553
+ kind: "cancelled",
7554
+ reason: "dismissed"
7555
+ });
7556
+ }, [settle]);
7557
+ return {
7558
+ open,
7559
+ element: (0, react_jsx_runtime.jsx)(PickerHost, {
7560
+ register,
7561
+ children: active === null || held ? null : (0, react_jsx_runtime.jsxs)(_burojs_react.RecordScopeChain, {
7562
+ frames: active.frames,
7563
+ children: [(0, react_jsx_runtime.jsx)(require_lazy_relation_picker_dialog.LazyRelationPickerDialog, {
7564
+ to: target,
7565
+ open: true,
7566
+ onOpenChange,
7567
+ onSelect: noop,
7568
+ onSelectRow,
7569
+ valueField: wiring.valueField,
7570
+ ...selection.fixedFilters === void 0 ? {} : { fixedFilters: selection.fixedFilters },
7571
+ scope,
7572
+ ...fieldName === void 0 ? {} : { scopeField: fieldName },
7573
+ ...options.create === void 0 ? {} : {
7574
+ create,
7575
+ ...options.create.seeds === void 0 ? {} : { createSeeds: options.create.seeds }
7576
+ },
7577
+ fieldName: fieldName ?? target,
7578
+ ...options.disabledKeys === void 0 ? {} : { disabledKeys: options.disabledKeys },
7579
+ ...options.disabledLabel === void 0 ? {} : { disabledLabel: options.disabledLabel },
7580
+ ...multiple ? {
7581
+ multiple: true,
7582
+ selected: active.selected,
7583
+ onToggle: (value, row) => toggle(value, row),
7584
+ onDone
7585
+ } : {}
7586
+ }), wiring.reader]
7587
+ }, active.id)
7588
+ })
7589
+ };
7590
+ }
7591
+ //#endregion
7592
+ //#region src/blocks/link-write-summary.tsx
7593
+ function LinkWriteSummary(props) {
7594
+ const { report, titles, onClose } = props;
7595
+ const testid = props.testid ?? "link-write-summary";
7596
+ const t = (0, _burojs_react.useOptionalT)();
7597
+ const caps = (0, _burojs_react.useI18nCaps)();
7598
+ const chromeT = (0, _burojs_react.useChromeT)();
7599
+ const heading = t("field.link.partial", { defaultValue: "Some links were not changed" });
7600
+ return (0, react_jsx_runtime.jsx)(require_dialog.Dialog, {
7601
+ open: true,
7602
+ onOpenChange: (open) => {
7603
+ if (!open) onClose();
7604
+ },
7605
+ children: (0, react_jsx_runtime.jsxs)(require_dialog.DialogContent, {
7606
+ "data-testid": testid,
7607
+ className: "flex max-h-[85vh] flex-col overflow-hidden",
7608
+ children: [
7609
+ (0, react_jsx_runtime.jsxs)(require_dialog.DialogHeader, { children: [(0, react_jsx_runtime.jsx)(require_dialog.DialogTitle, { children: heading }), (0, react_jsx_runtime.jsx)(require_dialog.DialogDescription, {
7610
+ className: "sr-only",
7611
+ children: heading
7612
+ })] }),
7613
+ (0, react_jsx_runtime.jsx)("ul", {
7614
+ className: "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overscroll-contain",
7615
+ children: report.failed.map(({ id, error }) => (0, react_jsx_runtime.jsxs)("li", {
7616
+ "data-testid": `${testid}:item:${id}`,
7617
+ className: "text-sm",
7618
+ children: [(0, react_jsx_runtime.jsx)("span", {
7619
+ className: "font-medium",
7620
+ children: titles[id] ?? id
7621
+ }), (0, react_jsx_runtime.jsx)("span", {
7622
+ className: "text-destructive",
7623
+ children: `: ${(0, _burojs_react.resolveErrorText)(error, caps)}`
7624
+ })]
7625
+ }, id))
7626
+ }),
7627
+ (0, react_jsx_runtime.jsx)(require_dialog.DialogFooter, { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
7628
+ type: "button",
7629
+ onClick: onClose,
7630
+ "data-testid": `${testid}:close`,
7631
+ children: chromeT("actions.close", { defaultValue: "Close" })
7632
+ }) })
7633
+ ]
7634
+ })
7635
+ });
7636
+ }
7637
+ //#endregion
7638
+ //#region src/blocks/link-attach.tsx
7639
+ const NO_ISSUES = Object.freeze([]);
7640
+ function useLinkPanelWrites(options) {
7641
+ const { owner, junction, target, link, targetKey, valueField, junctionIdField, displayField, scope, record, ownerKey, placement } = options;
7642
+ const app = (0, _burojs_react.useApp)();
7643
+ const runtime = (0, _burojs_react.useDataRuntime)();
7644
+ const t = (0, _burojs_react.useOptionalT)();
7645
+ const rights = (0, _burojs_react.useLinkRights)(owner, link, {
7646
+ surface: "panel",
7647
+ record,
7648
+ ...placement === void 0 ? {} : { placement }
7649
+ });
7650
+ const writer = (0, _burojs_react.useLinkWriter)(owner, link);
7651
+ const linkedKeys = (0, _burojs_react.useLinkedKeys)(owner, link);
7652
+ const reverse = (0, react.useMemo)(() => (0, _burojs_core.reverseLinkOf)((name) => app.registry.get(name)?.fields, owner, link), [
7653
+ app.registry,
7654
+ owner,
7655
+ link
7656
+ ]);
7657
+ let liveHides = false;
7658
+ if (reverse !== void 0) try {
7659
+ const { providerId } = runtime.app.resolveDataBinding(target);
7660
+ liveHides = runtime.providers.resolve(providerId).provider.readRelations?.links === true && (0, _burojs_react.linkCapabilitiesOf)(runtime, providerId)?.links?.filter.none !== false;
7661
+ } catch {
7662
+ liveHides = false;
7663
+ }
7664
+ const liveHidesRef = (0, react.useRef)(liveHides);
7665
+ liveHidesRef.current = liveHides;
7666
+ const [frozenHides, setFrozenHides] = (0, react.useState)(null);
7667
+ const hides = frozenHides ?? liveHides;
7668
+ const ownerKeyId = JSON.stringify(ownerKey ?? null);
7669
+ const hidden = (0, react.useMemo)(() => hides && reverse !== void 0 ? [{
7670
+ field: reverse,
7671
+ op: "hasNone",
7672
+ value: [ownerKey]
7673
+ }] : void 0, [
7674
+ hides,
7675
+ reverse,
7676
+ ownerKeyId
7677
+ ]);
7678
+ const disabledKeys = (0, react.useCallback)((keys, signal) => linkedKeys(record, keys, signal), [linkedKeys, record]);
7679
+ const disabledLabel = (0, react.useCallback)((count) => t("field.link.alreadyLinked", {
7680
+ count,
7681
+ defaultValue: `${count} already linked`
7682
+ }), [t]);
7683
+ const picker = useRelationPicker({
7684
+ to: target,
7685
+ multiple: true,
7686
+ valueField,
7687
+ scope,
7688
+ ...hidden === void 0 ? {
7689
+ disabledKeys,
7690
+ disabledLabel
7691
+ } : { fixedFilters: hidden }
7692
+ });
7693
+ const openPicker = picker.open;
7694
+ const [summary, setSummary] = (0, react.useState)(null);
7695
+ const finish = (0, react.useCallback)((report, titles, done) => {
7696
+ if (report.outcome !== "success") {
7697
+ setSummary({
7698
+ report,
7699
+ titles
7700
+ });
7701
+ return;
7702
+ }
7703
+ const count = report.succeeded.length;
7704
+ if (count === 0) return;
7705
+ sonner.toast.success(t(`field.link.${done}`, {
7706
+ count,
7707
+ defaultValue: `${count} ${count === 1 ? "link" : "links"} ${done}`
7708
+ }));
7709
+ }, [t]);
7710
+ const attaching = (0, react.useRef)(false);
7711
+ const [attachWriting, setAttachWriting] = (0, react.useState)(false);
7712
+ const onAttach = (0, react.useCallback)(() => {
7713
+ if (attaching.current) return;
7714
+ attaching.current = true;
7715
+ (async () => {
7716
+ try {
7717
+ setFrozenHides(liveHidesRef.current);
7718
+ let result;
7719
+ try {
7720
+ result = await openPicker();
7721
+ } finally {
7722
+ setFrozenHides(null);
7723
+ }
7724
+ if (result.kind !== "selected" || result.keys.length === 0) return;
7725
+ const titles = {};
7726
+ for (const row of result.rows) {
7727
+ const key = valueField === "id" ? row.id : row[valueField];
7728
+ const title = row[displayField];
7729
+ if (key !== void 0 && key !== null && title !== void 0 && title !== null) titles[String(key)] = String(title);
7730
+ }
7731
+ setAttachWriting(true);
7732
+ try {
7733
+ finish(await writer.attach(result.keys, record), titles, "attached");
7734
+ } finally {
7735
+ setAttachWriting(false);
7736
+ }
7737
+ } finally {
7738
+ attaching.current = false;
7739
+ }
7740
+ })();
7741
+ }, [
7742
+ displayField,
7743
+ finish,
7744
+ openPicker,
7745
+ record,
7746
+ valueField,
7747
+ writer
7748
+ ]);
7749
+ const pending = (0, react.useRef)(null);
7750
+ const [confirming, setConfirming] = (0, react.useState)(null);
7751
+ const detaching = (0, react.useRef)(false);
7752
+ const [busy, setBusy] = (0, react.useState)(false);
7753
+ const onDetach = (0, react.useCallback)((rows) => new Promise((resolve) => {
7754
+ pending.current?.resolve([]);
7755
+ pending.current = {
7756
+ rows,
7757
+ resolve
7758
+ };
7759
+ setConfirming(rows.length);
7760
+ }), []);
7761
+ (0, react.useEffect)(() => () => {
7762
+ pending.current?.resolve([]);
7763
+ pending.current = null;
7764
+ }, []);
7765
+ const cancel = (0, react.useCallback)(() => {
7766
+ if (detaching.current) return;
7767
+ pending.current?.resolve([]);
7768
+ pending.current = null;
7769
+ setConfirming(null);
7770
+ }, []);
7771
+ const proceed = (0, react.useCallback)(() => {
7772
+ const current = pending.current;
7773
+ if (current === null || detaching.current) return;
7774
+ detaching.current = true;
7775
+ setBusy(true);
7776
+ (async () => {
7777
+ try {
7778
+ const titles = {};
7779
+ for (const row of current.rows) {
7780
+ const id = row[junctionIdField];
7781
+ if (id === void 0 || id === null) continue;
7782
+ const title = row[`${targetKey}.${displayField}`] ?? row[targetKey];
7783
+ if (title !== void 0 && title !== null) titles[String(id)] = String(title);
7784
+ }
7785
+ const report = await writer.detach(current.rows, record);
7786
+ pending.current = null;
7787
+ setConfirming(null);
7788
+ finish(report, titles, "detached");
7789
+ const left = new Set(report.succeeded);
7790
+ current.resolve(current.rows.filter((row) => {
7791
+ const id = row[junctionIdField];
7792
+ return id !== void 0 && id !== null && left.has(String(id));
7793
+ }).map((row) => String(row.id)));
7794
+ } finally {
7795
+ detaching.current = false;
7796
+ setBusy(false);
7797
+ }
7798
+ })();
7799
+ }, [
7800
+ displayField,
7801
+ finish,
7802
+ junctionIdField,
7803
+ record,
7804
+ targetKey,
7805
+ writer
7806
+ ]);
7807
+ const detachLabel = t("field.link.detach", { defaultValue: "Detach" });
7808
+ const count = confirming ?? 0;
7809
+ const gate = {
7810
+ resource: junction,
7811
+ open: confirming !== null,
7812
+ busy,
7813
+ header: t("field.link.confirmDetach", {
7814
+ count,
7815
+ defaultValue: `Detach ${count} ${count === 1 ? "link" : "links"}? The linked records themselves are not deleted.`
7816
+ }),
7817
+ blockers: NO_ISSUES,
7818
+ confirmable: NO_ISSUES,
7819
+ proceed,
7820
+ cancel
7821
+ };
7822
+ const attachAllowed = rights.attach.allowed;
7823
+ const detachAllowed = rights.detach.allowed;
7824
+ return {
7825
+ linkEditing: (0, react.useMemo)(() => !attachAllowed && !detachAllowed ? void 0 : {
7826
+ ...attachAllowed ? { attach: {
7827
+ onAttach,
7828
+ busy: attachWriting
7829
+ } } : {},
7830
+ ...detachAllowed ? { detach: { onDetach } } : {}
7831
+ }, [
7832
+ attachAllowed,
7833
+ attachWriting,
7834
+ detachAllowed,
7835
+ onAttach,
7836
+ onDetach
7837
+ ]),
7838
+ element: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
7839
+ picker.element,
7840
+ (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.CheckConfirmDialog, {
7841
+ state: gate,
7842
+ testid: `link-detach-confirm:${junction}`,
7843
+ title: detachLabel,
7844
+ proceedLabel: detachLabel,
7845
+ tone: "destructive"
7846
+ }),
7847
+ summary === null ? null : (0, react_jsx_runtime.jsx)(LinkWriteSummary, {
7848
+ report: summary.report,
7849
+ titles: summary.titles,
7850
+ onClose: () => setSummary(null),
7851
+ testid: `link-write-summary:${junction}`
7852
+ })
7853
+ ] })
7854
+ };
7855
+ }
7856
+ //#endregion
6985
7857
  //#region src/quick/peek-filter.ts
6986
7858
  function peekFieldDefinition(def, name) {
6987
7859
  return (0, _burojs_core.declaredField)(def, name);
@@ -7005,32 +7877,12 @@ function peekRecord(def, row, idField, capabilityFor, fieldVisible) {
7005
7877
  return peekRow(def, row, idField, capabilityFor, fieldVisible);
7006
7878
  }
7007
7879
  //#endregion
7008
- //#region src/blocks/related-list-unbound.tsx
7009
- function UnboundRelatedList(props) {
7010
- const t = (0, _burojs_react.useOptionalT)();
7011
- return (0, react_jsx_runtime.jsxs)("div", {
7012
- className: "flex flex-col gap-2",
7013
- "data-testid": `list-unbound:${props.resource}`,
7014
- children: [props.title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
7015
- className: "text-sm font-semibold",
7016
- children: props.title
7017
- }), (0, react_jsx_runtime.jsx)("p", {
7018
- className: "text-sm text-muted-foreground",
7019
- children: t("table.empty", { defaultValue: "No records" })
7020
- })]
7021
- });
7022
- }
7023
- function placementScope(scope, owner) {
7024
- return scope ?? (owner === void 0 ? "session" : "none");
7025
- }
7026
- //#endregion
7027
7880
  //#region src/blocks/link-panel.tsx
7028
7881
  const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
7029
7882
  const isResourceHandle = (value) => isRecord(value) && value.kind === "resource";
7030
- function qualify(ref, owner) {
7883
+ function qualify(ref) {
7031
7884
  try {
7032
- const namespace = (0, _burojs_core.normalizeEntityRef)(owner).namespace;
7033
- return (0, _burojs_core.resourceKey)((0, _burojs_core.normalizeEntityRef)(isResourceHandle(ref) ? ref.ref : ref, { defaultNamespace: namespace }));
7885
+ return (0, _burojs_core.resourceKey)((0, _burojs_core.normalizeEntityRef)(isResourceHandle(ref) ? ref.ref : ref));
7034
7886
  } catch {
7035
7887
  return;
7036
7888
  }
@@ -7049,7 +7901,7 @@ function linkField(registry, owner, link) {
7049
7901
  function linkTarget(registry, owner, link) {
7050
7902
  const found = linkField(registry, owner, link);
7051
7903
  if (found === void 0 || owner === void 0) return void 0;
7052
- return qualify(found.field.meta?.to, owner);
7904
+ return qualify(found.field.meta?.to);
7053
7905
  }
7054
7906
  function idFieldOf(def) {
7055
7907
  const declared = isRecord(def) && isRecord(def.data) ? def.data.idField : void 0;
@@ -7065,37 +7917,47 @@ function targetColumns(registry, target, def) {
7065
7917
  const source = def;
7066
7918
  const views = isRecord(def.views) ? def.views : void 0;
7067
7919
  const list = views !== void 0 && isRecord(views.list) ? views.list : void 0;
7068
- return (list !== void 0 && Array.isArray(list.columns) ? list.columns.filter((name) => typeof name === "string") : (0, _burojs_core.dtoFields)(source, "list")).filter((name) => {
7920
+ return (list !== void 0 && Array.isArray(list.columns) ? list.columns.flatMap((entry) => {
7921
+ const name = isRecord(entry) ? entry.field : entry;
7922
+ return typeof name === "string" ? [name] : [];
7923
+ }) : (0, _burojs_core.dtoFields)(source, "list")).filter((name) => {
7069
7924
  if (name.includes(".")) return name.split(".").length - 1 <= MAX_TARGET_HOPS && (0, _burojs_react.resolveColumnField)(registry, target, name) !== void 0;
7070
7925
  const field = peekFieldDefinition(source, name);
7071
7926
  return isRecord(field) && !(0, _burojs_core.isRelationField)(field) && (0, _burojs_core.fieldSensitivity)(field) === void 0;
7072
7927
  });
7073
7928
  }
7074
7929
  function LinkPanel(props) {
7075
- const { link, owner, own } = props;
7930
+ const { link, owner, own, empty } = props;
7076
7931
  const app = (0, _burojs_react.useApp)();
7077
7932
  const frame = usePlacementFrame();
7078
7933
  const routeScreen = useIsRouteScreen();
7079
7934
  const record = (0, _burojs_react.useOptionalRecordFrame)()?.record;
7935
+ const runtime = (0, _burojs_react.useOptionalDataRuntime)();
7080
7936
  const storage = (0, react.useMemo)(() => {
7081
7937
  const found = linkField(app.registry, owner, link);
7082
7938
  if (found === void 0) return void 0;
7083
7939
  const { declaration } = found;
7084
- const junction = qualify(declaration.junction, owner);
7085
- const target = qualify(found.field.meta?.to, owner);
7940
+ const junction = qualify(declaration.junction);
7941
+ const target = qualify(found.field.meta?.to);
7086
7942
  if (junction === void 0 || target === void 0) return void 0;
7087
7943
  const junctionDef = app.registry.get(junction);
7088
7944
  if (junctionDef === void 0) return void 0;
7089
7945
  const junctionFields = junctionDef.fields;
7946
+ const targetDef = app.registry.get(target);
7947
+ const targetBy = byOf(junctionFields[declaration.targetKey]);
7948
+ const declaredScope = found.field.meta?.scope;
7090
7949
  return {
7091
7950
  junction,
7092
7951
  target,
7093
7952
  sourceKey: declaration.sourceKey,
7094
7953
  targetKey: declaration.targetKey,
7095
7954
  ownerField: byOf(junctionFields[declaration.sourceKey]) ?? idFieldOf(app.registry.get(owner)),
7096
- targetKeyedBy: byOf(junctionFields[declaration.targetKey]) !== void 0,
7955
+ targetKeyedBy: targetBy !== void 0,
7956
+ targetValueField: targetBy ?? idFieldOf(targetDef),
7957
+ junctionIdField: idFieldOf(junctionDef),
7097
7958
  where: declaration.where,
7098
- targetDef: app.registry.get(target)
7959
+ targetDef,
7960
+ pickerScope: declaredScope === "context" || declaredScope === "session" || declaredScope === "none" ? declaredScope : void 0
7099
7961
  };
7100
7962
  }, [
7101
7963
  app.registry,
@@ -7107,10 +7969,11 @@ function LinkPanel(props) {
7107
7969
  const fixedFilters = (0, react.useMemo)(() => {
7108
7970
  if (storage === void 0 || ownerKey === null || ownerKey === void 0) return void 0;
7109
7971
  const { sourceKey, targetKey } = storage;
7972
+ const placed = (0, _burojs_core_internal.whereToFilter)(own.where ?? [], (field) => `${targetKey}.${field}`);
7110
7973
  return [
7111
7974
  (0, _burojs_core.whereEntryToFilter)(sourceKey, "eq", ownerKey),
7112
7975
  ...storage.where.map((entry) => (0, _burojs_core.whereEntryToFilter)(entry.field, entry.op, entry.value)),
7113
- ...(own.where ?? []).map((entry) => (0, _burojs_core.whereEntryToFilter)(`${targetKey}.${entry.field}`, entry.op, entry.value))
7976
+ ...placed === void 0 ? [] : [placed]
7114
7977
  ];
7115
7978
  }, [
7116
7979
  storage,
@@ -7120,7 +7983,12 @@ function LinkPanel(props) {
7120
7983
  const columnsKey = JSON.stringify([own.columns ?? null, own.linkColumns ?? null]);
7121
7984
  const columns = (0, react.useMemo)(() => {
7122
7985
  if (storage === void 0) return void 0;
7123
- return [...(own.columns ?? targetColumns(app.registry, storage.target, storage.targetDef)).map((name) => `${storage.targetKey}.${name}`), ...own.linkColumns ?? []];
7986
+ const shown = own.columns ?? targetColumns(app.registry, storage.target, storage.targetDef);
7987
+ const across = (entry) => typeof entry === "string" ? `${storage.targetKey}.${entry}` : {
7988
+ ...entry,
7989
+ field: `${storage.targetKey}.${entry.field}`
7990
+ };
7991
+ return [...shown.map(across), ...own.linkColumns ?? []];
7124
7992
  }, [
7125
7993
  storage,
7126
7994
  columnsKey,
@@ -7130,31 +7998,76 @@ function LinkPanel(props) {
7130
7998
  resource: storage.target,
7131
7999
  field: storage.targetKey
7132
8000
  }, [storage]);
7133
- const unbound = fixedFilters === void 0 || own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
8001
+ const unbound = fixedFilters === void 0 || own.where !== void 0 && (0, _burojs_core_internal.hasNullRef)(own.where);
7134
8002
  if (storage === void 0 || unbound) return (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7135
8003
  resource: storage?.target ?? "",
7136
- title: own.title
8004
+ title: own.title,
8005
+ ...empty === void 0 ? {} : { empty }
7137
8006
  });
7138
8007
  const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7139
- const count = own.count === false ? "off" : own.count;
7140
- return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
8008
+ let providerCounts;
8009
+ if (runtime !== null) try {
8010
+ providerCounts = (0, _burojs_react.linkCapabilitiesOf)(runtime, runtime.app.resolveDataBinding(storage.junction).providerId)?.links?.count;
8011
+ } catch {
8012
+ providerCounts = void 0;
8013
+ }
8014
+ const count = own.count === false ? "off" : own.count ?? (providerCounts === false ? "off" : void 0);
8015
+ const layoutId = frame === null ? void 0 : placementLayoutId({
8016
+ owner,
8017
+ key: frame.key
8018
+ });
8019
+ const surface = {
7141
8020
  resource: storage.junction,
7142
8021
  variant: "placement",
7143
8022
  state,
7144
8023
  fixedFilters,
7145
- ...own.pageSize === void 0 ? {} : { pageSize: own.pageSize },
8024
+ ...own.initial?.pageSize === void 0 ? {} : { initial: { pageSize: own.initial.pageSize } },
7146
8025
  ...own.search === void 0 ? {} : { search: `${storage.targetKey}.${own.search}` },
7147
8026
  ...columns === void 0 ? {} : { columns },
7148
8027
  open: rowTarget === void 0 || own.open === "none" ? "none" : "page",
7149
8028
  ...rowTarget === void 0 ? {} : { rowTarget },
7150
8029
  ...frame === null ? {} : { placementKey: frame.key },
8030
+ ...layoutId === void 0 ? {} : { layoutId },
7151
8031
  ...own.title === void 0 ? {} : { title: own.title },
8032
+ ...empty === void 0 ? {} : { empty },
7152
8033
  scope: placementScope(own.scope, owner),
7153
8034
  ...count === void 0 ? {} : { count },
7154
8035
  readOnly: true,
7155
8036
  exportable: false
8037
+ };
8038
+ if (runtime === null || record === void 0) return (0, react_jsx_runtime.jsx)(ResourceListSurface, { ...surface });
8039
+ return (0, react_jsx_runtime.jsx)(WritableLinkPanel, {
8040
+ surface,
8041
+ owner,
8042
+ link,
8043
+ storage,
8044
+ record,
8045
+ ownerKey,
8046
+ placement: own.linkActions
7156
8047
  });
7157
8048
  }
8049
+ function WritableLinkPanel(props) {
8050
+ const { surface, owner, link, storage, record, ownerKey, placement } = props;
8051
+ const displayField = isRecord(storage.targetDef) && typeof storage.targetDef.displayField === "string" ? storage.targetDef.displayField : storage.targetValueField;
8052
+ const { linkEditing, element } = useLinkPanelWrites({
8053
+ owner,
8054
+ junction: storage.junction,
8055
+ target: storage.target,
8056
+ link,
8057
+ targetKey: storage.targetKey,
8058
+ valueField: storage.targetValueField,
8059
+ junctionIdField: storage.junctionIdField,
8060
+ displayField,
8061
+ scope: storage.pickerScope ?? "context",
8062
+ record,
8063
+ ownerKey,
8064
+ placement
8065
+ });
8066
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(ResourceListSurface, {
8067
+ ...surface,
8068
+ ...linkEditing === void 0 ? {} : { linkEditing }
8069
+ }), element] });
8070
+ }
7158
8071
  //#endregion
7159
8072
  //#region src/blocks/route-list-context.ts
7160
8073
  const RouteListContext = (0, react.createContext)(null);
@@ -7163,7 +8076,7 @@ function useRouteList() {
7163
8076
  }
7164
8077
  //#endregion
7165
8078
  //#region src/blocks/related-list-view.tsx
7166
- function RelatedListView({ props }) {
8079
+ function RelatedListView({ props, empty }) {
7167
8080
  const own = props;
7168
8081
  const route = useRouteList();
7169
8082
  const frame = usePlacementFrame();
@@ -7171,7 +8084,7 @@ function RelatedListView({ props }) {
7171
8084
  const linked = own.link !== void 0;
7172
8085
  const resource = linked ? linkTarget(app.registry, frame?.owner, own.link) ?? "" : (0, _burojs_core.resourceKey)(own.resource);
7173
8086
  const whereKey = JSON.stringify(own.where ?? []);
7174
- const fixedFilters = (0, react.useMemo)(() => own.where === void 0 ? void 0 : own.where.map(({ field, op, value }) => (0, _burojs_core.whereEntryToFilter)(field, op, value)), [whereKey]);
8087
+ const fixedFilters = (0, react.useMemo)(() => own.where === void 0 || own.where.length === 0 ? void 0 : [(0, _burojs_core_internal.whereToFilter)(own.where)], [whereKey]);
7175
8088
  const columnsKey = JSON.stringify(own.columns ?? null);
7176
8089
  const columns = (0, react.useMemo)(() => own.columns, [columnsKey]);
7177
8090
  const routeScreen = useIsRouteScreen();
@@ -7183,20 +8096,23 @@ function RelatedListView({ props }) {
7183
8096
  const ownerDef = frame?.owner === void 0 ? void 0 : app.registry.get(frame.owner);
7184
8097
  const granted = ownerDef === void 0 ? "unknown" : (0, _burojs_core.grantedPlacementKeys)(ownerDef);
7185
8098
  const trusted = frame !== null && !frame.nested && granted !== "unknown" && !granted.has(frame.key);
7186
- const onCreate = route === null && !linked && trusted && gate(resource, "create").state === "open" && frame !== null ? () => void quick.create(resource, { defaults: placementSeeds(frame.where ?? [], own.where ?? [], frame.closure ?? {}) }) : void 0;
8099
+ const onCreate = route === null && !linked && trusted && gate(resource, "create").state === "open" && own.create !== false && (own.create === void 0 || (0, _burojs_core_internal.actionWhenHolds)(own.create, frame?.sources ?? {})) && frame !== null ? () => void quick.create(resource, { defaults: placementSeeds(frame.where ?? [], own.where ?? [], frame.closure ?? {}) }) : void 0;
7187
8100
  useDeepLinkOpen(frame?.key ?? null, resource, route === null && !linked && frame !== null && !frame.nested && routeScreen && (own.open ?? "quick") === "quick");
7188
- const unbound = own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
8101
+ const unbound = own.where !== void 0 && (0, _burojs_core_internal.hasNullRef)(own.where);
7189
8102
  if (linked) return frame?.owner === void 0 ? (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7190
8103
  resource,
7191
- title: own.title
8104
+ title: own.title,
8105
+ ...empty === void 0 ? {} : { empty }
7192
8106
  }) : (0, react_jsx_runtime.jsx)(LinkPanel, {
7193
8107
  link: own.link,
7194
8108
  owner: frame.owner,
7195
- own
8109
+ own,
8110
+ ...empty === void 0 ? {} : { empty }
7196
8111
  });
7197
8112
  if (route !== null) return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
7198
8113
  resource,
7199
8114
  variant: "route",
8115
+ layoutId: "route",
7200
8116
  ...route.meta === void 0 ? {} : { meta: route.meta },
7201
8117
  ...route.renderCell === void 0 ? {} : { renderCell: route.renderCell },
7202
8118
  ...route.emptyState === void 0 ? {} : { emptyState: route.emptyState }
@@ -7209,24 +8125,28 @@ function RelatedListView({ props }) {
7209
8125
  });
7210
8126
  if (unbound) return (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7211
8127
  resource,
7212
- title: own.title
8128
+ title: own.title,
8129
+ ...empty === void 0 ? {} : { empty }
7213
8130
  });
7214
8131
  const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7215
8132
  const scope = placementScope(own.scope, frame?.owner);
7216
8133
  const count = own.count === false ? "off" : own.count;
8134
+ const layoutId = placementLayoutId(frame);
7217
8135
  return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
7218
8136
  resource,
7219
8137
  variant: "placement",
7220
8138
  state,
7221
8139
  ...fixedFilters === void 0 ? {} : { fixedFilters },
7222
- ...own.pageSize === void 0 ? {} : { pageSize: own.pageSize },
8140
+ ...own.initial === void 0 ? {} : { initial: own.initial },
7223
8141
  ...own.search === void 0 ? {} : { search: own.search },
7224
8142
  ...columns === void 0 ? {} : { columns },
7225
8143
  open: own.open ?? "quick",
7226
8144
  ...own.view === void 0 ? {} : { view: own.view },
7227
8145
  ...isItemHandle(own.item) ? { item: own.item } : {},
7228
8146
  ...frame === null ? {} : { placementKey: frame.key },
8147
+ ...layoutId === void 0 ? {} : { layoutId },
7229
8148
  ...own.title === void 0 ? {} : { title: own.title },
8149
+ ...empty === void 0 ? {} : { empty },
7230
8150
  scope,
7231
8151
  ...count === void 0 ? {} : { count },
7232
8152
  ...onCreate === void 0 ? {} : { onCreate }
@@ -7261,7 +8181,7 @@ function Missing({ text }) {
7261
8181
  children: text ?? t("table.empty", { defaultValue: "No records" })
7262
8182
  });
7263
8183
  }
7264
- function RelatedRecordView({ props }) {
8184
+ function RelatedRecordView({ props, empty }) {
7265
8185
  const own = props;
7266
8186
  const app = (0, _burojs_react.useApp)();
7267
8187
  const resource = (0, _burojs_core.resourceKey)(own.resource);
@@ -7277,7 +8197,7 @@ function RelatedRecordView({ props }) {
7277
8197
  });
7278
8198
  const result = query.data;
7279
8199
  const raw = result?.data;
7280
- const dtoRow = (0, react.useMemo)(() => raw !== null && typeof raw === "object" && projection !== void 0 ? (0, _burojs_core.projectDto)(raw, projection) : void 0, [raw, projection]);
8200
+ const dtoRow = (0, react.useMemo)(() => raw !== null && typeof raw === "object" && projection !== void 0 ? (0, _burojs_react.deriveRecord)(raw, (record) => (0, _burojs_core.projectDto)(record, projection)) : void 0, [raw, projection]);
7281
8201
  const access = (0, _burojs_react.useFieldAccess)(resource, "record", dtoRow);
7282
8202
  const projected = (0, _burojs_react.useProjectedRecord)(resource, dtoRow, { placeholder: query.isPlaceholderData === true });
7283
8203
  const fieldsKey = JSON.stringify(own.fields ?? null);
@@ -7295,15 +8215,15 @@ function RelatedRecordView({ props }) {
7295
8215
  capabilityFor,
7296
8216
  access
7297
8217
  ]);
7298
- if (id === null) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing });
8218
+ if (id === null) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing ?? empty });
7299
8219
  if (result === void 0) {
7300
- if (query.error != null) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing });
8220
+ if (query.error != null) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing ?? empty });
7301
8221
  return (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
7302
8222
  "data-buro-skeleton": "",
7303
8223
  className: "h-9 w-full"
7304
8224
  });
7305
8225
  }
7306
- if (dtoRow === void 0) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing });
8226
+ if (dtoRow === void 0) return (0, react_jsx_runtime.jsx)(Missing, { text: own.missing ?? empty });
7307
8227
  if (projected.status === "pending" || projected.value === null) return (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
7308
8228
  "data-buro-skeleton": "",
7309
8229
  className: "h-9 w-full"
@@ -7318,10 +8238,7 @@ function RelatedRecordView({ props }) {
7318
8238
  children: own.title
7319
8239
  }), own.toolbar === "item" ? (0, react_jsx_runtime.jsx)(ActionOverflow, {
7320
8240
  resource,
7321
- record: {
7322
- ...dtoRow,
7323
- id
7324
- },
8241
+ record: (0, _burojs_react.withRecordKeys)(dtoRow, { id }),
7325
8242
  surface: "show"
7326
8243
  }) : null]
7327
8244
  }), (0, react_jsx_runtime.jsx)("dl", {
@@ -7336,13 +8253,21 @@ function RelatedRecordView({ props }) {
7336
8253
  children: (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", field, "label"))
7337
8254
  }), (0, react_jsx_runtime.jsx)("dd", {
7338
8255
  className: "min-w-0 break-words text-sm",
7339
- children: (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
7340
- resource: own.resource,
7341
- name,
7342
- field,
8256
+ children: (0, react_jsx_runtime.jsx)(FieldValueFrame, {
8257
+ field: {
8258
+ ...field ?? {},
8259
+ name
8260
+ },
7343
8261
  value,
7344
- record: row,
7345
- fallback: toDisplayText(value).text
8262
+ surface: "display",
8263
+ children: (0, react_jsx_runtime.jsx)(require_filter_builder.ResolvedFieldDisplay, {
8264
+ resource: own.resource,
8265
+ name,
8266
+ field,
8267
+ value,
8268
+ record: row,
8269
+ fallback: toDisplayText(value).text
8270
+ })
7346
8271
  })
7347
8272
  })]
7348
8273
  }, name);
@@ -7413,28 +8338,39 @@ function Chrome({ node, size, state, children }) {
7413
8338
  });
7414
8339
  }
7415
8340
  function isAuthError(error) {
7416
- return (0, _burojs_core.isDataError)(error) && error.kind === "auth";
8341
+ return (0, _burojs_core.normalizeDataError)(error).kind === "auth";
7417
8342
  }
7418
- function FailedPlacement({ node, size, message, retry }) {
8343
+ const PLACE_NODE_MESSAGES = {
8344
+ failed: "This section could not be loaded.",
8345
+ sessionExpired: "Your session has expired. Sign in again to continue.",
8346
+ notImplemented: "This section is not available."
8347
+ };
8348
+ function FailedPlacement({ node, size, message, retry, error }) {
7419
8349
  const t = (0, _burojs_react.useOptionalT)();
8350
+ const chromeT = (0, _burojs_react.useChromeT)();
8351
+ const fallback = {
8352
+ key: `block.${message}`,
8353
+ default: PLACE_NODE_MESSAGES[message]
8354
+ };
7420
8355
  return (0, react_jsx_runtime.jsx)(Chrome, {
7421
8356
  node,
7422
8357
  size,
7423
8358
  state: "failed",
7424
- children: (0, react_jsx_runtime.jsxs)("div", {
8359
+ children: message === "notImplemented" ? (0, react_jsx_runtime.jsxs)("div", {
7425
8360
  role: "alert",
7426
8361
  className: "flex flex-wrap items-center gap-2 rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
7427
- children: [(0, react_jsx_runtime.jsx)("span", { children: t(`block.${message}`, { defaultValue: {
7428
- failed: "This section could not be loaded.",
7429
- sessionExpired: "Your session has expired. Sign in again to continue.",
7430
- notImplemented: "This section is not available."
7431
- }[message] }) }), retry === void 0 ? null : (0, react_jsx_runtime.jsx)(require_button.Button, {
8362
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t(fallback.key, { defaultValue: fallback.default }) }), retry === void 0 ? null : (0, react_jsx_runtime.jsx)(require_button.Button, {
7432
8363
  type: "button",
7433
8364
  variant: "outline",
7434
8365
  size: "sm",
7435
8366
  onClick: retry,
7436
- children: t("actions.retry", { defaultValue: "Retry" })
8367
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
7437
8368
  })]
8369
+ }) : (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
8370
+ surface: "block",
8371
+ error,
8372
+ ...retry === void 0 ? {} : { retry },
8373
+ fallback
7438
8374
  })
7439
8375
  });
7440
8376
  }
@@ -7514,7 +8450,8 @@ function ReadyPlacement({ node, size, placement, implementation }) {
7514
8450
  nested,
7515
8451
  ...Array.isArray(declaredWhere) ? { where: declaredWhere } : {},
7516
8452
  closure: compiled.sourceClosure,
7517
- ...owner === void 0 ? {} : { owner }
8453
+ ...owner === void 0 ? {} : { owner },
8454
+ sources: controller.sources
7518
8455
  }), [
7519
8456
  node.key,
7520
8457
  node.id,
@@ -7522,7 +8459,8 @@ function ReadyPlacement({ node, size, placement, implementation }) {
7522
8459
  nested,
7523
8460
  declaredWhere,
7524
8461
  compiled.sourceClosure,
7525
- owner
8462
+ owner,
8463
+ controller.sources
7526
8464
  ]);
7527
8465
  return (0, react_jsx_runtime.jsx)(PlacementBoundary, {
7528
8466
  node,
@@ -7580,6 +8518,7 @@ function PlaceNode({ node }) {
7580
8518
  node,
7581
8519
  size,
7582
8520
  message: isAuthError(placement.error) ? "sessionExpired" : "failed",
8521
+ error: placement.error,
7583
8522
  ...placement.retry === void 0 ? {} : { retry: placement.retry }
7584
8523
  });
7585
8524
  if (implementation === void 0) return (0, react_jsx_runtime.jsx)(FailedPlacement, {
@@ -7691,6 +8630,12 @@ Object.defineProperty(exports, "EnumBadge", {
7691
8630
  return EnumBadge;
7692
8631
  }
7693
8632
  });
8633
+ Object.defineProperty(exports, "EnumSettlingRow", {
8634
+ enumerable: true,
8635
+ get: function() {
8636
+ return EnumSettlingRow;
8637
+ }
8638
+ });
7694
8639
  Object.defineProperty(exports, "ExportButton", {
7695
8640
  enumerable: true,
7696
8641
  get: function() {
@@ -7715,6 +8660,12 @@ Object.defineProperty(exports, "FieldDisplay", {
7715
8660
  return FieldDisplay;
7716
8661
  }
7717
8662
  });
8663
+ Object.defineProperty(exports, "FieldValueFrame", {
8664
+ enumerable: true,
8665
+ get: function() {
8666
+ return FieldValueFrame;
8667
+ }
8668
+ });
7718
8669
  Object.defineProperty(exports, "FilterRegion", {
7719
8670
  enumerable: true,
7720
8671
  get: function() {
@@ -7727,6 +8678,12 @@ Object.defineProperty(exports, "FormActions", {
7727
8678
  return FormActions;
7728
8679
  }
7729
8680
  });
8681
+ Object.defineProperty(exports, "FormControlProvider", {
8682
+ enumerable: true,
8683
+ get: function() {
8684
+ return FormControlProvider;
8685
+ }
8686
+ });
7730
8687
  Object.defineProperty(exports, "FrameChromeContext", {
7731
8688
  enumerable: true,
7732
8689
  get: function() {
@@ -7847,10 +8804,10 @@ Object.defineProperty(exports, "RelatedItem", {
7847
8804
  return RelatedItem;
7848
8805
  }
7849
8806
  });
7850
- Object.defineProperty(exports, "ResolvedFieldDisplay", {
8807
+ Object.defineProperty(exports, "RelatedTimelineSkeleton", {
7851
8808
  enumerable: true,
7852
8809
  get: function() {
7853
- return ResolvedFieldDisplay;
8810
+ return RelatedTimelineSkeleton;
7854
8811
  }
7855
8812
  });
7856
8813
  Object.defineProperty(exports, "ResourceList", {
@@ -7961,24 +8918,6 @@ Object.defineProperty(exports, "isBuiltinRecordView", {
7961
8918
  return isBuiltinRecordView;
7962
8919
  }
7963
8920
  });
7964
- Object.defineProperty(exports, "isShowAvailable", {
7965
- enumerable: true,
7966
- get: function() {
7967
- return isShowAvailable;
7968
- }
7969
- });
7970
- Object.defineProperty(exports, "listTarget", {
7971
- enumerable: true,
7972
- get: function() {
7973
- return listTarget;
7974
- }
7975
- });
7976
- Object.defineProperty(exports, "lowerLegacyField", {
7977
- enumerable: true,
7978
- get: function() {
7979
- return lowerLegacyField;
7980
- }
7981
- });
7982
8921
  Object.defineProperty(exports, "peekFieldDefinition", {
7983
8922
  enumerable: true,
7984
8923
  get: function() {
@@ -8003,22 +8942,16 @@ Object.defineProperty(exports, "peekRow", {
8003
8942
  return peekRow;
8004
8943
  }
8005
8944
  });
8006
- Object.defineProperty(exports, "recordReturnTarget", {
8007
- enumerable: true,
8008
- get: function() {
8009
- return recordReturnTarget;
8010
- }
8011
- });
8012
- Object.defineProperty(exports, "recordRouteAvailable", {
8945
+ Object.defineProperty(exports, "resolveFrameView", {
8013
8946
  enumerable: true,
8014
8947
  get: function() {
8015
- return recordRouteAvailable;
8948
+ return resolveFrameView;
8016
8949
  }
8017
8950
  });
8018
- Object.defineProperty(exports, "resolveFrameView", {
8951
+ Object.defineProperty(exports, "resolveResourceTitle", {
8019
8952
  enumerable: true,
8020
8953
  get: function() {
8021
- return resolveFrameView;
8954
+ return resolveResourceTitle;
8022
8955
  }
8023
8956
  });
8024
8957
  Object.defineProperty(exports, "resolveUpdater", {
@@ -8045,12 +8978,6 @@ Object.defineProperty(exports, "shadcnFrameViews", {
8045
8978
  return shadcnFrameViews;
8046
8979
  }
8047
8980
  });
8048
- Object.defineProperty(exports, "showTarget", {
8049
- enumerable: true,
8050
- get: function() {
8051
- return showTarget;
8052
- }
8053
- });
8054
8981
  Object.defineProperty(exports, "tanStackSortingToBuro", {
8055
8982
  enumerable: true,
8056
8983
  get: function() {
@@ -8069,6 +8996,12 @@ Object.defineProperty(exports, "typography", {
8069
8996
  return typography;
8070
8997
  }
8071
8998
  });
8999
+ Object.defineProperty(exports, "unknownEnumValueLabel", {
9000
+ enumerable: true,
9001
+ get: function() {
9002
+ return unknownEnumValueLabel;
9003
+ }
9004
+ });
8072
9005
  Object.defineProperty(exports, "useBuroDataTable", {
8073
9006
  enumerable: true,
8074
9007
  get: function() {
@@ -8087,6 +9020,18 @@ Object.defineProperty(exports, "useExportRunWatcher", {
8087
9020
  return useExportRunWatcher;
8088
9021
  }
8089
9022
  });
9023
+ Object.defineProperty(exports, "useFormControl", {
9024
+ enumerable: true,
9025
+ get: function() {
9026
+ return useFormControl;
9027
+ }
9028
+ });
9029
+ Object.defineProperty(exports, "useFormControlOf", {
9030
+ enumerable: true,
9031
+ get: function() {
9032
+ return useFormControlOf;
9033
+ }
9034
+ });
8090
9035
  Object.defineProperty(exports, "useFrameChrome", {
8091
9036
  enumerable: true,
8092
9037
  get: function() {
@@ -8111,6 +9056,12 @@ Object.defineProperty(exports, "usePaletteState", {
8111
9056
  return usePaletteState;
8112
9057
  }
8113
9058
  });
9059
+ Object.defineProperty(exports, "useRelationPicker", {
9060
+ enumerable: true,
9061
+ get: function() {
9062
+ return useRelationPicker;
9063
+ }
9064
+ });
8114
9065
  Object.defineProperty(exports, "useShell", {
8115
9066
  enumerable: true,
8116
9067
  get: function() {
@@ -8136,4 +9087,4 @@ Object.defineProperty(exports, "viewOf", {
8136
9087
  }
8137
9088
  });
8138
9089
 
8139
- //# sourceMappingURL=place-node-C5SmIAYU.cjs.map
9090
+ //# sourceMappingURL=place-node-Bhl8B3fF.cjs.map